Commit 30376a82b2

Luuk de Gram <luuk@degram.dev>
2021-07-24 19:48:55
Re-enable switch test cases and fix regressions
1 parent 5d98abd
Changed files (2)
src
codegen
test
stage2
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;
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);
-
-    //    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 = 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");
-    //}
+    {
+        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 = 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(
+            \\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);