authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-03-31 16:17:47-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-03-31 16:17:47-07:00
log08eedc962d8e2582db8fb5b4a50114f2913519fd
tree197860260fb9db85a17de025e43a3c8014d74ac4
parentabd06d8eab508319e5f7839c802f4a81d80a0025

Sema: fix else case code generation for switch


3 files changed, 82 insertions(+), 40 deletions(-)

src/Sema.zig+29-25
......@@ -2328,6 +2328,7 @@ fn analyzeSwitch(
23282328 switch_inst: zir.Inst.Index,
23292329 src_node_offset: i32,
23302330) InnerError!*Inst {
2331 const gpa = sema.gpa;
23312332 const special: struct { body: []const zir.Inst.Index, end: usize } = switch (special_prong) {
23322333 .none => .{ .body = &.{}, .end = extra_end },
23332334 .under, .@"else" => blk: {
......@@ -2353,7 +2354,7 @@ fn analyzeSwitch(
23532354 "'_' prong only allowed when switching on non-exhaustive enums",
23542355 .{},
23552356 );
2356 errdefer msg.destroy(sema.gpa);
2357 errdefer msg.destroy(gpa);
23572358 try sema.mod.errNote(
23582359 &block.base,
23592360 special_prong_src,
......@@ -2372,7 +2373,7 @@ fn analyzeSwitch(
23722373 .ErrorSet => return sema.mod.fail(&block.base, src, "TODO validate switch .ErrorSet", .{}),
23732374 .Union => return sema.mod.fail(&block.base, src, "TODO validate switch .Union", .{}),
23742375 .Int, .ComptimeInt => {
2375 var range_set = RangeSet.init(sema.gpa);
2376 var range_set = RangeSet.init(gpa);
23762377 defer range_set.deinit();
23772378
23782379 var extra_index: usize = special.end;
......@@ -2440,7 +2441,7 @@ fn analyzeSwitch(
24402441
24412442 check_range: {
24422443 if (operand.ty.zigTypeTag() == .Int) {
2443 var arena = std.heap.ArenaAllocator.init(sema.gpa);
2444 var arena = std.heap.ArenaAllocator.init(gpa);
24442445 defer arena.deinit();
24452446
24462447 const min_int = try operand.ty.minInt(&arena, sema.mod.getTarget());
......@@ -2549,7 +2550,7 @@ fn analyzeSwitch(
25492550 );
25502551 }
25512552
2552 var seen_values = ValueSrcMap.init(sema.gpa);
2553 var seen_values = ValueSrcMap.init(gpa);
25532554 defer seen_values.deinit();
25542555
25552556 var extra_index: usize = special.end;
......@@ -2712,16 +2713,16 @@ fn analyzeSwitch(
27122713 .is_comptime = block.is_comptime,
27132714 };
27142715 const merges = &child_block.label.?.merges;
2715 defer child_block.instructions.deinit(sema.gpa);
2716 defer merges.results.deinit(sema.gpa);
2717 defer merges.br_list.deinit(sema.gpa);
2716 defer child_block.instructions.deinit(gpa);
2717 defer merges.results.deinit(gpa);
2718 defer merges.br_list.deinit(gpa);
27182719
27192720 // TODO when reworking TZIR memory layout make multi cases get generated as cases,
27202721 // not as part of the "else" block.
27212722 const cases = try sema.arena.alloc(Inst.SwitchBr.Case, scalar_cases_len);
27222723
27232724 var case_block = child_block.makeSubBlock();
2724 defer case_block.instructions.deinit(sema.gpa);
2725 defer case_block.instructions.deinit(gpa);
27252726
27262727 var extra_index: usize = special.end;
27272728
......@@ -2747,7 +2748,7 @@ fn analyzeSwitch(
27472748 };
27482749 }
27492750
2750 var first_condbr: *Inst.CondBr = undefined;
2751 var first_else_body: Body = undefined;
27512752 var prev_condbr: ?*Inst.CondBr = null;
27522753
27532754 var multi_i: usize = 0;
......@@ -2822,12 +2823,6 @@ fn analyzeSwitch(
28222823 }
28232824 }
28242825
2825 const body = sema.code.extra[extra_index..][0..body_len];
2826 extra_index += body_len;
2827 _ = try sema.analyzeBody(&case_block, body);
2828 const then_body: Body = .{
2829 .instructions = try sema.arena.dupe(*Inst, case_block.instructions.items),
2830 };
28312826 const new_condbr = try sema.arena.create(Inst.CondBr);
28322827 new_condbr.* = .{
28332828 .base = .{
......@@ -2836,15 +2831,26 @@ fn analyzeSwitch(
28362831 .src = src,
28372832 },
28382833 .condition = any_ok.?,
2839 .then_body = then_body,
2834 .then_body = undefined,
28402835 .else_body = undefined,
28412836 };
2837 try case_block.instructions.append(gpa, &new_condbr.base);
2838
2839 const cond_body: Body = .{
2840 .instructions = try sema.arena.dupe(*Inst, case_block.instructions.items),
2841 };
2842
2843 case_block.instructions.shrinkRetainingCapacity(0);
2844 const body = sema.code.extra[extra_index..][0..body_len];
2845 extra_index += body_len;
2846 _ = try sema.analyzeBody(&case_block, body);
2847 new_condbr.then_body = .{
2848 .instructions = try sema.arena.dupe(*Inst, case_block.instructions.items),
2849 };
28422850 if (prev_condbr) |condbr| {
2843 condbr.else_body = .{
2844 .instructions = try sema.arena.dupe(*Inst, &[1]*Inst{&new_condbr.base}),
2845 };
2851 condbr.else_body = cond_body;
28462852 } else {
2847 first_condbr = new_condbr;
2853 first_else_body = cond_body;
28482854 }
28492855 prev_condbr = new_condbr;
28502856 }
......@@ -2856,11 +2862,9 @@ fn analyzeSwitch(
28562862 const else_body: Body = .{
28572863 .instructions = try sema.arena.dupe(*Inst, case_block.instructions.items),
28582864 };
2859 if (prev_condbr != null) {
2860 first_condbr.else_body = else_body;
2861 break :blk .{
2862 .instructions = try sema.arena.dupe(*Inst, &[1]*Inst{&first_condbr.base}),
2863 };
2865 if (prev_condbr) |condbr| {
2866 condbr.else_body = else_body;
2867 break :blk first_else_body;
28642868 } else {
28652869 break :blk else_body;
28662870 }
src/ir.zig+40-2
......@@ -774,6 +774,14 @@ const DumpTzir = struct {
774774 try dtz.fetchInstsAndResolveConsts(condbr.then_body);
775775 try dtz.fetchInstsAndResolveConsts(condbr.else_body);
776776 },
777 .switchbr => {
778 const switchbr = inst.castTag(.switchbr).?;
779 try dtz.findConst(switchbr.target);
780 try dtz.fetchInstsAndResolveConsts(switchbr.else_body);
781 for (switchbr.cases) |case| {
782 try dtz.fetchInstsAndResolveConsts(case.body);
783 }
784 },
777785
778786 .loop => {
779787 const loop = inst.castTag(.loop).?;
......@@ -791,7 +799,6 @@ const DumpTzir = struct {
791799 .assembly,
792800 .constant,
793801 .varptr,
794 .switchbr,
795802 => {},
796803 }
797804 }
......@@ -981,6 +988,38 @@ const DumpTzir = struct {
981988 try writer.writeAll("})\n");
982989 },
983990
991 .switchbr => {
992 const switchbr = inst.castTag(.switchbr).?;
993
994 const condition_kinky = try dtz.writeInst(writer, switchbr.target);
995 if (condition_kinky != null) {
996 try writer.writeAll(", { // Instruction does not dominate all uses!\n");
997 } else {
998 try writer.writeAll(", {\n");
999 }
1000 const old_indent = dtz.indent;
1001
1002 if (switchbr.else_body.instructions.len != 0) {
1003 dtz.indent += 2;
1004 try dtz.dumpBody(switchbr.else_body, writer);
1005
1006 try writer.writeByteNTimes(' ', old_indent);
1007 try writer.writeAll("}, {\n");
1008 dtz.indent = old_indent;
1009 }
1010 for (switchbr.cases) |case| {
1011 dtz.indent += 2;
1012 try dtz.dumpBody(case.body, writer);
1013
1014 try writer.writeByteNTimes(' ', old_indent);
1015 try writer.writeAll("}, {\n");
1016 dtz.indent = old_indent;
1017 }
1018
1019 try writer.writeByteNTimes(' ', old_indent);
1020 try writer.writeAll("})\n");
1021 },
1022
9841023 .loop => {
9851024 const loop = inst.castTag(.loop).?;
9861025
......@@ -1032,7 +1071,6 @@ const DumpTzir = struct {
10321071 .assembly,
10331072 .constant,
10341073 .varptr,
1035 .switchbr,
10361074 => {
10371075 try writer.writeAll("!TODO!)\n");
10381076 },
test/stage2/cbe.zig+13-13
......@@ -266,19 +266,19 @@ pub fn addCases(ctx: *TestContext) !void {
266266 , "");
267267
268268 // Switch expression
269 //case.addCompareOutput(
270 // \\export fn main() c_int {
271 // \\ var cond: c_int = 0;
272 // \\ var a: c_int = switch (cond) {
273 // \\ 1 => 1,
274 // \\ 2 => 2,
275 // \\ 99...300, 12 => 3,
276 // \\ 0 => 4,
277 // \\ else => 5,
278 // \\ };
279 // \\ return a - 4;
280 // \\}
281 //, "");
269 case.addCompareOutput(
270 \\export fn main() c_int {
271 \\ var cond: c_int = 0;
272 \\ var a: c_int = switch (cond) {
273 \\ 1 => 1,
274 \\ 2 => 2,
275 \\ 99...300, 12 => 3,
276 \\ 0 => 4,
277 \\ else => 5,
278 \\ };
279 \\ return a - 4;
280 \\}
281 , "");
282282 }
283283 //{
284284 // var case = ctx.exeFromCompiledC("optionals", .{});