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(...@@ -2328,6 +2328,7 @@ fn analyzeSwitch(
2328 switch_inst: zir.Inst.Index,2328 switch_inst: zir.Inst.Index,
2329 src_node_offset: i32,2329 src_node_offset: i32,
2330) InnerError!*Inst {2330) InnerError!*Inst {
2331 const gpa = sema.gpa;
2331 const special: struct { body: []const zir.Inst.Index, end: usize } = switch (special_prong) {2332 const special: struct { body: []const zir.Inst.Index, end: usize } = switch (special_prong) {
2332 .none => .{ .body = &.{}, .end = extra_end },2333 .none => .{ .body = &.{}, .end = extra_end },
2333 .under, .@"else" => blk: {2334 .under, .@"else" => blk: {
...@@ -2353,7 +2354,7 @@ fn analyzeSwitch(...@@ -2353,7 +2354,7 @@ fn analyzeSwitch(
2353 "'_' prong only allowed when switching on non-exhaustive enums",2354 "'_' prong only allowed when switching on non-exhaustive enums",
2354 .{},2355 .{},
2355 );2356 );
2356 errdefer msg.destroy(sema.gpa);2357 errdefer msg.destroy(gpa);
2357 try sema.mod.errNote(2358 try sema.mod.errNote(
2358 &block.base,2359 &block.base,
2359 special_prong_src,2360 special_prong_src,
...@@ -2372,7 +2373,7 @@ fn analyzeSwitch(...@@ -2372,7 +2373,7 @@ fn analyzeSwitch(
2372 .ErrorSet => return sema.mod.fail(&block.base, src, "TODO validate switch .ErrorSet", .{}),2373 .ErrorSet => return sema.mod.fail(&block.base, src, "TODO validate switch .ErrorSet", .{}),
2373 .Union => return sema.mod.fail(&block.base, src, "TODO validate switch .Union", .{}),2374 .Union => return sema.mod.fail(&block.base, src, "TODO validate switch .Union", .{}),
2374 .Int, .ComptimeInt => {2375 .Int, .ComptimeInt => {
2375 var range_set = RangeSet.init(sema.gpa);2376 var range_set = RangeSet.init(gpa);
2376 defer range_set.deinit();2377 defer range_set.deinit();
23772378
2378 var extra_index: usize = special.end;2379 var extra_index: usize = special.end;
...@@ -2440,7 +2441,7 @@ fn analyzeSwitch(...@@ -2440,7 +2441,7 @@ fn analyzeSwitch(
24402441
2441 check_range: {2442 check_range: {
2442 if (operand.ty.zigTypeTag() == .Int) {2443 if (operand.ty.zigTypeTag() == .Int) {
2443 var arena = std.heap.ArenaAllocator.init(sema.gpa);2444 var arena = std.heap.ArenaAllocator.init(gpa);
2444 defer arena.deinit();2445 defer arena.deinit();
24452446
2446 const min_int = try operand.ty.minInt(&arena, sema.mod.getTarget());2447 const min_int = try operand.ty.minInt(&arena, sema.mod.getTarget());
...@@ -2549,7 +2550,7 @@ fn analyzeSwitch(...@@ -2549,7 +2550,7 @@ fn analyzeSwitch(
2549 );2550 );
2550 }2551 }
25512552
2552 var seen_values = ValueSrcMap.init(sema.gpa);2553 var seen_values = ValueSrcMap.init(gpa);
2553 defer seen_values.deinit();2554 defer seen_values.deinit();
25542555
2555 var extra_index: usize = special.end;2556 var extra_index: usize = special.end;
...@@ -2712,16 +2713,16 @@ fn analyzeSwitch(...@@ -2712,16 +2713,16 @@ fn analyzeSwitch(
2712 .is_comptime = block.is_comptime,2713 .is_comptime = block.is_comptime,
2713 };2714 };
2714 const merges = &child_block.label.?.merges;2715 const merges = &child_block.label.?.merges;
2715 defer child_block.instructions.deinit(sema.gpa);2716 defer child_block.instructions.deinit(gpa);
2716 defer merges.results.deinit(sema.gpa);2717 defer merges.results.deinit(gpa);
2717 defer merges.br_list.deinit(sema.gpa);2718 defer merges.br_list.deinit(gpa);
27182719
2719 // TODO when reworking TZIR memory layout make multi cases get generated as cases,2720 // TODO when reworking TZIR memory layout make multi cases get generated as cases,
2720 // not as part of the "else" block.2721 // not as part of the "else" block.
2721 const cases = try sema.arena.alloc(Inst.SwitchBr.Case, scalar_cases_len);2722 const cases = try sema.arena.alloc(Inst.SwitchBr.Case, scalar_cases_len);
27222723
2723 var case_block = child_block.makeSubBlock();2724 var case_block = child_block.makeSubBlock();
2724 defer case_block.instructions.deinit(sema.gpa);2725 defer case_block.instructions.deinit(gpa);
27252726
2726 var extra_index: usize = special.end;2727 var extra_index: usize = special.end;
27272728
...@@ -2747,7 +2748,7 @@ fn analyzeSwitch(...@@ -2747,7 +2748,7 @@ fn analyzeSwitch(
2747 };2748 };
2748 }2749 }
27492750
2750 var first_condbr: *Inst.CondBr = undefined;2751 var first_else_body: Body = undefined;
2751 var prev_condbr: ?*Inst.CondBr = null;2752 var prev_condbr: ?*Inst.CondBr = null;
27522753
2753 var multi_i: usize = 0;2754 var multi_i: usize = 0;
...@@ -2822,12 +2823,6 @@ fn analyzeSwitch(...@@ -2822,12 +2823,6 @@ fn analyzeSwitch(
2822 }2823 }
2823 }2824 }
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 };
2831 const new_condbr = try sema.arena.create(Inst.CondBr);2826 const new_condbr = try sema.arena.create(Inst.CondBr);
2832 new_condbr.* = .{2827 new_condbr.* = .{
2833 .base = .{2828 .base = .{
...@@ -2836,15 +2831,26 @@ fn analyzeSwitch(...@@ -2836,15 +2831,26 @@ fn analyzeSwitch(
2836 .src = src,2831 .src = src,
2837 },2832 },
2838 .condition = any_ok.?,2833 .condition = any_ok.?,
2839 .then_body = then_body,2834 .then_body = undefined,
2840 .else_body = undefined,2835 .else_body = undefined,
2841 };2836 };
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 };
2842 if (prev_condbr) |condbr| {2850 if (prev_condbr) |condbr| {
2843 condbr.else_body = .{2851 condbr.else_body = cond_body;
2844 .instructions = try sema.arena.dupe(*Inst, &[1]*Inst{&new_condbr.base}),
2845 };
2846 } else {2852 } else {
2847 first_condbr = new_condbr;2853 first_else_body = cond_body;
2848 }2854 }
2849 prev_condbr = new_condbr;2855 prev_condbr = new_condbr;
2850 }2856 }
...@@ -2856,11 +2862,9 @@ fn analyzeSwitch(...@@ -2856,11 +2862,9 @@ fn analyzeSwitch(
2856 const else_body: Body = .{2862 const else_body: Body = .{
2857 .instructions = try sema.arena.dupe(*Inst, case_block.instructions.items),2863 .instructions = try sema.arena.dupe(*Inst, case_block.instructions.items),
2858 };2864 };
2859 if (prev_condbr != null) {2865 if (prev_condbr) |condbr| {
2860 first_condbr.else_body = else_body;2866 condbr.else_body = else_body;
2861 break :blk .{2867 break :blk first_else_body;
2862 .instructions = try sema.arena.dupe(*Inst, &[1]*Inst{&first_condbr.base}),
2863 };
2864 } else {2868 } else {
2865 break :blk else_body;2869 break :blk else_body;
2866 }2870 }
src/ir.zig+40-2
...@@ -774,6 +774,14 @@ const DumpTzir = struct {...@@ -774,6 +774,14 @@ const DumpTzir = struct {
774 try dtz.fetchInstsAndResolveConsts(condbr.then_body);774 try dtz.fetchInstsAndResolveConsts(condbr.then_body);
775 try dtz.fetchInstsAndResolveConsts(condbr.else_body);775 try dtz.fetchInstsAndResolveConsts(condbr.else_body);
776 },776 },
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
778 .loop => {786 .loop => {
779 const loop = inst.castTag(.loop).?;787 const loop = inst.castTag(.loop).?;
...@@ -791,7 +799,6 @@ const DumpTzir = struct {...@@ -791,7 +799,6 @@ const DumpTzir = struct {
791 .assembly,799 .assembly,
792 .constant,800 .constant,
793 .varptr,801 .varptr,
794 .switchbr,
795 => {},802 => {},
796 }803 }
797 }804 }
...@@ -981,6 +988,38 @@ const DumpTzir = struct {...@@ -981,6 +988,38 @@ const DumpTzir = struct {
981 try writer.writeAll("})\n");988 try writer.writeAll("})\n");
982 },989 },
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
984 .loop => {1023 .loop => {
985 const loop = inst.castTag(.loop).?;1024 const loop = inst.castTag(.loop).?;
9861025
...@@ -1032,7 +1071,6 @@ const DumpTzir = struct {...@@ -1032,7 +1071,6 @@ const DumpTzir = struct {
1032 .assembly,1071 .assembly,
1033 .constant,1072 .constant,
1034 .varptr,1073 .varptr,
1035 .switchbr,
1036 => {1074 => {
1037 try writer.writeAll("!TODO!)\n");1075 try writer.writeAll("!TODO!)\n");
1038 },1076 },
test/stage2/cbe.zig+13-13
...@@ -266,19 +266,19 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -266,19 +266,19 @@ pub fn addCases(ctx: *TestContext) !void {
266 , "");266 , "");
267267
268 // Switch expression268 // Switch expression
269 //case.addCompareOutput(269 case.addCompareOutput(
270 // \\export fn main() c_int {270 \\export fn main() c_int {
271 // \\ var cond: c_int = 0;271 \\ var cond: c_int = 0;
272 // \\ var a: c_int = switch (cond) {272 \\ var a: c_int = switch (cond) {
273 // \\ 1 => 1,273 \\ 1 => 1,
274 // \\ 2 => 2,274 \\ 2 => 2,
275 // \\ 99...300, 12 => 3,275 \\ 99...300, 12 => 3,
276 // \\ 0 => 4,276 \\ 0 => 4,
277 // \\ else => 5,277 \\ else => 5,
278 // \\ };278 \\ };
279 // \\ return a - 4;279 \\ return a - 4;
280 // \\}280 \\}
281 //, "");281 , "");
282 }282 }
283 //{283 //{
284 // var case = ctx.exeFromCompiledC("optionals", .{});284 // var case = ctx.exeFromCompiledC("optionals", .{});