authorgravatar for timonkruiper@gmail.comTimon Kruiper <timonkruiper@gmail.com> 2021-03-24 15:26:09+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-03-24 19:54:03-07:00
log522707622e95ef17b94c7a3d78ca81cadde5274d
treef7518af54081f2e46b43ee5b324f1e7e303a25fe
parentd73a4940e0d907e017ce60d0a7183cd1618b3b39

astgen: implement breaking from a block


2 files changed, 63 insertions(+), 64 deletions(-)

src/Module.zig+31-2
......@@ -935,11 +935,11 @@ pub const Scope = struct {
935935 break_count: usize = 0,
936936 /// Tracks `break :foo bar` instructions so they can possibly be elided later if
937937 /// the labeled block ends up not needing a result location pointer.
938 labeled_breaks: std.ArrayListUnmanaged(zir.Inst.Index) = .{},
938 labeled_breaks: std.ArrayListUnmanaged(zir.Inst.Ref) = .{},
939939 /// Tracks `store_to_block_ptr` instructions that correspond to break instructions
940940 /// so they can possibly be elided later if the labeled block ends up not needing
941941 /// a result location pointer.
942 labeled_store_to_block_ptr_list: std.ArrayListUnmanaged(zir.Inst.Index) = .{},
942 labeled_store_to_block_ptr_list: std.ArrayListUnmanaged(zir.Inst.Ref) = .{},
943943
944944 pub const Label = struct {
945945 token: ast.TokenIndex,
......@@ -1222,6 +1222,35 @@ pub const Scope = struct {
12221222 });
12231223 }
12241224
1225 pub fn addBreak(
1226 gz: *GenZir,
1227 break_block: zir.Inst.Index,
1228 operand: zir.Inst.Ref,
1229 ) !zir.Inst.Ref {
1230 return try gz.add(.{
1231 .tag = .@"break",
1232 .data = .{ .@"break" = .{
1233 .block_inst = break_block,
1234 .operand = operand,
1235 } },
1236 });
1237 }
1238
1239 pub fn addBreakVoid(
1240 inner_gz: *GenZir,
1241 block_gz: *GenZir,
1242 break_block: zir.Inst.Index,
1243 node_index: ast.Node.Index,
1244 ) !zir.Inst.Ref {
1245 return try inner_gz.add(.{
1246 .tag = .break_void_node,
1247 .data = .{ .break_void_node = .{
1248 .src_node = block_gz.zir_code.decl.nodeIndexToRelative(node_index),
1249 .block_inst = break_block,
1250 } },
1251 });
1252 }
1253
12251254 pub fn addBin(
12261255 gz: *GenZir,
12271256 tag: zir.Inst.Tag,
src/astgen.zig+32-62
......@@ -672,62 +672,62 @@ fn breakExpr(
672672 rl: ResultLoc,
673673 node: ast.Node.Index,
674674) InnerError!zir.Inst.Ref {
675 if (true) @panic("TODO update for zir-memory-layout");
676675 const tree = parent_scope.tree();
677676 const node_datas = tree.nodes.items(.data);
678677 const main_tokens = tree.nodes.items(.main_token);
679678
679 const break_token = main_tokens[node];
680680 const break_label = node_datas[node].lhs;
681681 const rhs = node_datas[node].rhs;
682682
683 const parent_gz = parent_scope.getGenZir();
684
683685 // Look for the label in the scope.
684686 var scope = parent_scope;
685687 while (true) {
686688 switch (scope.tag) {
687689 .gen_zir => {
688 const gen_zir = scope.cast(Scope.GenZir).?;
690 const block_gz = scope.getGenZir();
689691
690692 const block_inst = blk: {
691693 if (break_label != 0) {
692 if (gen_zir.label) |*label| {
694 if (block_gz.label) |*label| {
693695 if (try tokenIdentEql(mod, parent_scope, label.token, break_label)) {
694696 label.used = true;
695697 break :blk label.block_inst;
696698 }
697699 }
698 } else if (gen_zir.break_block) |inst| {
699 break :blk inst;
700 } else if (block_gz.break_block != 0) {
701 break :blk block_gz.break_block;
700702 }
701 scope = gen_zir.parent;
703 scope = block_gz.parent;
702704 continue;
703705 };
704706
705707 if (rhs == 0) {
706 const result = try addZirInstTag(mod, parent_scope, src, .break_void, .{
707 .block = block_inst,
708 });
709 return rvalue(mod, parent_scope, rl, result);
708 const result = try parent_gz.addBreakVoid(block_gz, block_inst, node);
709 return rvalue(mod, parent_scope, rl, result, node);
710710 }
711 gen_zir.break_count += 1;
712 const prev_rvalue_rl_count = gen_zir.rvalue_rl_count;
713 const operand = try expr(mod, parent_scope, gen_zir.break_result_loc, rhs);
714 const have_store_to_block = gen_zir.rvalue_rl_count != prev_rvalue_rl_count;
715 const br = try addZirInstTag(mod, parent_scope, src, .@"break", .{
716 .block = block_inst,
717 .operand = operand,
718 });
719 if (gen_zir.break_result_loc == .block_ptr) {
720 try gen_zir.labeled_breaks.append(mod.gpa, br.castTag(.@"break").?);
711 block_gz.break_count += 1;
712 const prev_rvalue_rl_count = block_gz.rvalue_rl_count;
713 const operand = try expr(mod, parent_scope, block_gz.break_result_loc, rhs);
714 const have_store_to_block = block_gz.rvalue_rl_count != prev_rvalue_rl_count;
715
716 const br = try parent_gz.addBreak(block_inst, operand);
717
718 if (block_gz.break_result_loc == .block_ptr) {
719 try block_gz.labeled_breaks.append(mod.gpa, br);
721720
722721 if (have_store_to_block) {
723 const inst_list = parent_scope.getGenZir().instructions.items;
724 const last_inst = inst_list[inst_list.len - 2];
725 const store_inst = last_inst.castTag(.store_to_block_ptr).?;
726 assert(store_inst.positionals.lhs == gen_zir.rl_ptr.?);
727 try gen_zir.labeled_store_to_block_ptr_list.append(mod.gpa, store_inst);
722 const zir_tags = parent_gz.zir_code.instructions.items(.tag);
723 const zir_datas = parent_gz.zir_code.instructions.items(.data);
724 const last_inst = zir_tags.len - 2;
725 assert(zir_tags[last_inst] == .store_to_block_ptr);
726 assert(zir_datas[last_inst].bin.lhs == block_gz.rl_ptr);
727 try block_gz.labeled_store_to_block_ptr_list.append(mod.gpa, @intCast(zir.Inst.Ref, last_inst));
728728 }
729729 }
730 return rvalue(mod, parent_scope, rl, br);
730 return rvalue(mod, parent_scope, rl, br, node);
731731 },
732732 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,
733733 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,
......@@ -735,7 +735,7 @@ fn breakExpr(
735735 const label_name = try mod.identifierTokenString(parent_scope, break_label);
736736 return mod.failTok(parent_scope, break_label, "label not found: '{s}'", .{label_name});
737737 } else {
738 return mod.failTok(parent_scope, src, "break expression outside loop", .{});
738 return mod.failTok(parent_scope, break_token, "break expression outside loop", .{});
739739 },
740740 }
741741 }
......@@ -1769,23 +1769,11 @@ fn finishThenElseBlock(
17691769 switch (strat.tag) {
17701770 .break_void => {
17711771 if (!wzc.refIsNoReturn(then_result)) {
1772 _ = try then_scope.add(.{
1773 .tag = .break_void_node,
1774 .data = .{ .break_void_node = .{
1775 .src_node = wzc.decl.nodeIndexToRelative(then_src),
1776 .block_inst = then_break_block,
1777 } },
1778 });
1772 _ = try then_scope.addBreakVoid(block_scope, then_break_block, then_src);
17791773 }
17801774 const elide_else = if (else_result != .none) wzc.refIsNoReturn(else_result) else false;
17811775 if (!elide_else) {
1782 _ = try else_scope.add(.{
1783 .tag = .break_void_node,
1784 .data = .{ .break_void_node = .{
1785 .src_node = wzc.decl.nodeIndexToRelative(else_src),
1786 .block_inst = main_block,
1787 } },
1788 });
1776 _ = try else_scope.addBreakVoid(block_scope, main_block, else_src);
17891777 }
17901778 assert(!strat.elide_store_to_block_ptr_instructions);
17911779 try setCondBrPayload(condbr, cond, then_scope, else_scope);
......@@ -1793,32 +1781,14 @@ fn finishThenElseBlock(
17931781 },
17941782 .break_operand => {
17951783 if (!wzc.refIsNoReturn(then_result)) {
1796 _ = try then_scope.add(.{
1797 .tag = .@"break",
1798 .data = .{ .@"break" = .{
1799 .block_inst = then_break_block,
1800 .operand = then_result,
1801 } },
1802 });
1784 _ = try then_scope.addBreak(then_break_block, then_result);
18031785 }
18041786 if (else_result != .none) {
18051787 if (!wzc.refIsNoReturn(else_result)) {
1806 _ = try else_scope.add(.{
1807 .tag = .@"break",
1808 .data = .{ .@"break" = .{
1809 .block_inst = main_block,
1810 .operand = else_result,
1811 } },
1812 });
1788 _ = try else_scope.addBreak(main_block, else_result);
18131789 }
18141790 } else {
1815 _ = try else_scope.add(.{
1816 .tag = .break_void_node,
1817 .data = .{ .break_void_node = .{
1818 .src_node = wzc.decl.nodeIndexToRelative(else_src),
1819 .block_inst = main_block,
1820 } },
1821 });
1791 _ = try else_scope.addBreakVoid(block_scope, main_block, else_src);
18221792 }
18231793 if (strat.elide_store_to_block_ptr_instructions) {
18241794 try setCondBrPayloadElideBlockStorePtr(condbr, cond, then_scope, else_scope);