Commit a97e5e119a

Andrew Kelley <andrew@ziglang.org>
2021-07-20 03:58:51
stage2: switch: fix Sema bugs and implement AIR printing
1 parent 495e60d
src/Liveness.zig
@@ -442,9 +442,9 @@ fn analyzeInst(
             return trackOperands(a, new_set, inst, main_tomb, .{ condition, .none, .none });
         },
         .switch_br => {
-            const inst_data = inst_datas[inst].pl_op;
-            const condition = inst_data.operand;
-            const switch_br = a.air.extraData(Air.SwitchBr, inst_data.payload);
+            const pl_op = inst_datas[inst].pl_op;
+            const condition = pl_op.operand;
+            const switch_br = a.air.extraData(Air.SwitchBr, pl_op.payload);
 
             const Table = std.AutoHashMapUnmanaged(Air.Inst.Index, void);
             const case_tables = try gpa.alloc(Table, switch_br.data.cases_len + 1); // +1 for else
@@ -456,8 +456,8 @@ fn analyzeInst(
             var air_extra_index: usize = switch_br.end;
             for (case_tables[0..switch_br.data.cases_len]) |*case_table| {
                 const case = a.air.extraData(Air.SwitchBr.Case, air_extra_index);
-                const case_body = a.air.extra[case.end..][0..case.data.body_len];
-                air_extra_index = case.end + case_body.len;
+                const case_body = a.air.extra[case.end + case.data.items_len ..][0..case.data.body_len];
+                air_extra_index = case.end + case.data.items_len + case_body.len;
                 try analyzeWithContext(a, case_table, case_body);
 
                 // Reset the table back to its state from before the case.
src/print_air.zig
@@ -300,33 +300,44 @@ const Writer = struct {
 
     fn writeSwitchBr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
         const pl_op = w.air.instructions.items(.data)[inst].pl_op;
-        const extra = w.air.extraData(Air.SwitchBr, pl_op.payload);
-        const cases = w.air.extra[extra.end..][0..extra.data.cases_len];
-        const else_body = w.air.extra[extra.end + cases.len ..][0..extra.data.else_body_len];
+        const switch_br = w.air.extraData(Air.SwitchBr, pl_op.payload);
+        var extra_index: usize = switch_br.end;
+        var case_i: u32 = 0;
 
         try w.writeInstRef(s, pl_op.operand);
-        try s.writeAll(", {\n");
-
         const old_indent = w.indent;
-        if (else_body.len != 0) {
-            w.indent += 2;
-            try w.writeBody(s, else_body);
-            try s.writeByteNTimes(' ', old_indent);
-            try s.writeAll("}, {\n");
-            w.indent = old_indent;
-        }
+        w.indent += 2;
 
-        for (cases) |case_index| {
-            const case = w.air.extraData(Air.SwitchBr.Case, case_index);
-            const case_body = w.air.extra[case.end..][0..case.data.body_len];
+        while (case_i < switch_br.data.cases_len) : (case_i += 1) {
+            const case = w.air.extraData(Air.SwitchBr.Case, extra_index);
+            const items = @bitCast([]const Air.Inst.Ref, w.air.extra[case.end..][0..case.data.items_len]);
+            const case_body = w.air.extra[case.end + items.len ..][0..case.data.body_len];
+            extra_index = case.end + case.data.items_len + case_body.len;
 
+            try s.writeAll(", [");
+            for (items) |item, item_i| {
+                if (item_i != 0) try s.writeAll(", ");
+                try w.writeInstRef(s, item);
+            }
+            try s.writeAll("] => {\n");
             w.indent += 2;
             try w.writeBody(s, case_body);
-            try s.writeByteNTimes(' ', old_indent);
-            try s.writeAll("}, {\n");
-            w.indent = old_indent;
+            w.indent -= 2;
+            try s.writeByteNTimes(' ', w.indent);
+            try s.writeAll("}");
+        }
+
+        const else_body = w.air.extra[extra_index..][0..switch_br.data.else_body_len];
+        if (else_body.len != 0) {
+            try s.writeAll(", else => {\n");
+            w.indent += 2;
+            try w.writeBody(s, else_body);
+            w.indent -= 2;
+            try s.writeByteNTimes(' ', w.indent);
+            try s.writeAll("}");
         }
 
+        try s.writeAll("\n");
         try s.writeByteNTimes(' ', old_indent);
         try s.writeAll("}");
     }
src/Sema.zig
@@ -4213,6 +4213,7 @@ fn analyzeSwitch(
     var prev_then_body: []const Air.Inst.Index = &.{};
     defer gpa.free(prev_then_body);
 
+    var cases_len = scalar_cases_len;
     var multi_i: usize = 0;
     while (multi_i < multi_cases_len) : (multi_i += 1) {
         const items_len = sema.code.extra[extra_index];
@@ -4232,6 +4233,8 @@ fn analyzeSwitch(
         // else prong. Otherwise, we can take advantage of multiple items
         // mapping to the same body.
         if (ranges_len == 0) {
+            cases_len += 1;
+
             const body = sema.code.extra[extra_index..][0..body_len];
             extra_index += body_len;
             _ = try sema.analyzeBody(&case_block, body);
@@ -4239,7 +4242,7 @@ fn analyzeSwitch(
             try cases_extra.ensureUnusedCapacity(gpa, 2 + items.len +
                 case_block.instructions.items.len);
 
-            cases_extra.appendAssumeCapacity(1); // items_len
+            cases_extra.appendAssumeCapacity(@intCast(u32, items.len));
             cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));
 
             for (items) |item_ref| {
@@ -4352,12 +4355,12 @@ fn analyzeSwitch(
     }
 
     try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.SwitchBr).Struct.fields.len +
-        cases_extra.items.len);
+        cases_extra.items.len + final_else_body.len);
 
     _ = try child_block.addInst(.{ .tag = .switch_br, .data = .{ .pl_op = .{
         .operand = operand,
         .payload = sema.addExtraAssumeCapacity(Air.SwitchBr{
-            .cases_len = @intCast(u32, scalar_cases_len + multi_cases_len),
+            .cases_len = @intCast(u32, cases_len),
             .else_body_len = @intCast(u32, final_else_body.len),
         }),
     } } });