From 30376a82b2c1b13047ff3b48391fcda44183e129 Mon Sep 17 00:00:00 2001 From: Luuk de Gram Date: Sat, 24 Jul 2021 19:48:55 +0200 Subject: [PATCH] Re-enable switch test cases and fix regressions --- src/codegen/wasm.zig | 48 ++++++++++++++---- test/stage2/wasm.zig | 114 +++++++++++++++++++++---------------------- 2 files changed, 94 insertions(+), 68 deletions(-) diff --git a/src/codegen/wasm.zig b/src/codegen/wasm.zig index 43401c9767..ca0d53988d 100644 --- a/src/codegen/wasm.zig +++ b/src/codegen/wasm.zig @@ -1084,6 +1084,42 @@ pub const Context = struct { } } + /// Returns a `Value` as a signed 32 bit value. + /// It's illegale to provide a value with a type that cannot be represented + /// as an integer value. + fn valueAsI32(self: Context, val: Value, ty: Type) i32 { + switch (ty.zigTypeTag()) { + .Enum => { + if (val.castTag(.enum_field_index)) |field_index| { + switch (ty.tag()) { + .enum_simple => return @bitCast(i32, field_index.data), + .enum_full, .enum_nonexhaustive => { + const enum_full = ty.cast(Type.Payload.EnumFull).?.data; + if (enum_full.values.count() != 0) { + const tag_val = enum_full.values.keys()[field_index.data]; + return self.valueAsI32(tag_val, enum_full.tag_ty); + } else return @bitCast(i32, field_index.data); + }, + else => unreachable, + } + } else { + var int_tag_buffer: Type.Payload.Bits = undefined; + const int_tag_ty = ty.intTagType(&int_tag_buffer); + return self.valueAsI32(val, int_tag_ty); + } + }, + .Int => switch (ty.intInfo(self.target).signedness) { + .signed => return @truncate(i32, val.toSignedInt()), + .unsigned => return @bitCast(i32, @truncate(u32, val.toUnsignedInt())), + }, + .ErrorSet => { + const error_index = self.global_error_set.get(val.getError().?).?; + return @bitCast(i32, error_index); + }, + else => unreachable, // Programmer called this function for an illegal type + } + } + fn airBlock(self: *Context, inst: Air.Inst.Index) InnerError!WValue { const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; const block_ty = try self.genBlockType(self.air.getRefType(ty_pl.ty)); @@ -1307,15 +1343,7 @@ pub const Context = struct { for (items) |ref, i| { const item_val = self.air.value(ref).?; - const int_val: i32 = blk: { - if (target_ty.intInfo(self.target).signedness == .signed) { - // safe to truncate the values as we only use them when - // the target's bits is 32 or lower. - break :blk @truncate(i32, item_val.toSignedInt()); - } - - break :blk @bitCast(i32, @truncate(u32, item_val.toUnsignedInt())); - }; + const int_val = self.valueAsI32(item_val, target_ty); if (int_val < lowest) { lowest = int_val; } @@ -1334,7 +1362,7 @@ pub const Context = struct { // When the target is an integer size larger than u32, we have no way to use the value // as an index, therefore we also use an if/else-chain for those cases. // TODO: Benchmark this to find a proper value, LLVM seems to draw the line at '40~45'. - const is_sparse = target_ty.intInfo(self.target).bits > 32 or highest - lowest > 50; + const is_sparse = highest - lowest > 50 or target_ty.bitSize(self.target) > 32; const else_body = self.air.extra[extra_index..][0..switch_br.data.else_body_len]; const has_else_body = else_body.len != 0; diff --git a/test/stage2/wasm.zig b/test/stage2/wasm.zig index a43c4e5de3..f746be99d2 100644 --- a/test/stage2/wasm.zig +++ b/test/stage2/wasm.zig @@ -479,68 +479,66 @@ pub fn addCases(ctx: *TestContext) !void { , "30\n"); } - // This test case is disabled until the codegen for switch is reworked - // to take advantage of br_table rather than a series of br_if opcodes. - //{ - // var case = ctx.exe("wasm switch", wasi); + { + var case = ctx.exe("wasm switch", wasi); - // case.addCompareOutput( - // \\pub export fn _start() u32 { - // \\ var val: u32 = 1; - // \\ var a: u32 = switch (val) { - // \\ 0, 1 => 2, - // \\ 2 => 3, - // \\ 3 => 4, - // \\ else => 5, - // \\ }; - // \\ - // \\ return a; - // \\} - // , "2\n"); + case.addCompareOutput( + \\pub export fn _start() u32 { + \\ var val: u32 = 1; + \\ var a: u32 = switch (val) { + \\ 0, 1 => 2, + \\ 2 => 3, + \\ 3 => 4, + \\ else => 5, + \\ }; + \\ + \\ return a; + \\} + , "2\n"); - // case.addCompareOutput( - // \\pub export fn _start() u32 { - // \\ var val: u32 = 2; - // \\ var a: u32 = switch (val) { - // \\ 0, 1 => 2, - // \\ 2 => 3, - // \\ 3 => 4, - // \\ else => 5, - // \\ }; - // \\ - // \\ return a; - // \\} - // , "3\n"); + case.addCompareOutput( + \\pub export fn _start() u32 { + \\ var val: u32 = 2; + \\ var a: u32 = switch (val) { + \\ 0, 1 => 2, + \\ 2 => 3, + \\ 3 => 4, + \\ else => 5, + \\ }; + \\ + \\ return a; + \\} + , "3\n"); - // case.addCompareOutput( - // \\pub export fn _start() u32 { - // \\ var val: u32 = 10; - // \\ var a: u32 = switch (val) { - // \\ 0, 1 => 2, - // \\ 2 => 3, - // \\ 3 => 4, - // \\ else => 5, - // \\ }; - // \\ - // \\ return a; - // \\} - // , "5\n"); + case.addCompareOutput( + \\pub export fn _start() u32 { + \\ var val: u32 = 10; + \\ var a: u32 = switch (val) { + \\ 0, 1 => 2, + \\ 2 => 3, + \\ 3 => 4, + \\ else => 5, + \\ }; + \\ + \\ return a; + \\} + , "5\n"); - // case.addCompareOutput( - // \\const MyEnum = enum { One, Two, Three }; - // \\ - // \\pub export fn _start() u32 { - // \\ var val: MyEnum = .Two; - // \\ var a: u32 = switch (val) { - // \\ .One => 1, - // \\ .Two => 2, - // \\ .Three => 3, - // \\ }; - // \\ - // \\ return a; - // \\} - // , "2\n"); - //} + case.addCompareOutput( + \\const MyEnum = enum { One, Two, Three }; + \\ + \\pub export fn _start() u32 { + \\ var val: MyEnum = .Two; + \\ var a: u32 = switch (val) { + \\ .One => 1, + \\ .Two => 2, + \\ .Three => 3, + \\ }; + \\ + \\ return a; + \\} + , "2\n"); + } { var case = ctx.exe("wasm error unions", wasi);