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 {...@@ -935,11 +935,11 @@ pub const Scope = struct {
935 break_count: usize = 0,935 break_count: usize = 0,
936 /// Tracks `break :foo bar` instructions so they can possibly be elided later if936 /// Tracks `break :foo bar` instructions so they can possibly be elided later if
937 /// the labeled block ends up not needing a result location pointer.937 /// 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) = .{},
939 /// Tracks `store_to_block_ptr` instructions that correspond to break instructions939 /// Tracks `store_to_block_ptr` instructions that correspond to break instructions
940 /// so they can possibly be elided later if the labeled block ends up not needing940 /// so they can possibly be elided later if the labeled block ends up not needing
941 /// a result location pointer.941 /// 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
944 pub const Label = struct {944 pub const Label = struct {
945 token: ast.TokenIndex,945 token: ast.TokenIndex,
...@@ -1222,6 +1222,35 @@ pub const Scope = struct {...@@ -1222,6 +1222,35 @@ pub const Scope = struct {
1222 });1222 });
1223 }1223 }
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
1225 pub fn addBin(1254 pub fn addBin(
1226 gz: *GenZir,1255 gz: *GenZir,
1227 tag: zir.Inst.Tag,1256 tag: zir.Inst.Tag,
src/astgen.zig+32-62
...@@ -672,62 +672,62 @@ fn breakExpr(...@@ -672,62 +672,62 @@ fn breakExpr(
672 rl: ResultLoc,672 rl: ResultLoc,
673 node: ast.Node.Index,673 node: ast.Node.Index,
674) InnerError!zir.Inst.Ref {674) InnerError!zir.Inst.Ref {
675 if (true) @panic("TODO update for zir-memory-layout");
676 const tree = parent_scope.tree();675 const tree = parent_scope.tree();
677 const node_datas = tree.nodes.items(.data);676 const node_datas = tree.nodes.items(.data);
678 const main_tokens = tree.nodes.items(.main_token);677 const main_tokens = tree.nodes.items(.main_token);
679678
679 const break_token = main_tokens[node];
680 const break_label = node_datas[node].lhs;680 const break_label = node_datas[node].lhs;
681 const rhs = node_datas[node].rhs;681 const rhs = node_datas[node].rhs;
682682
683 const parent_gz = parent_scope.getGenZir();
684
683 // Look for the label in the scope.685 // Look for the label in the scope.
684 var scope = parent_scope;686 var scope = parent_scope;
685 while (true) {687 while (true) {
686 switch (scope.tag) {688 switch (scope.tag) {
687 .gen_zir => {689 .gen_zir => {
688 const gen_zir = scope.cast(Scope.GenZir).?;690 const block_gz = scope.getGenZir();
689691
690 const block_inst = blk: {692 const block_inst = blk: {
691 if (break_label != 0) {693 if (break_label != 0) {
692 if (gen_zir.label) |*label| {694 if (block_gz.label) |*label| {
693 if (try tokenIdentEql(mod, parent_scope, label.token, break_label)) {695 if (try tokenIdentEql(mod, parent_scope, label.token, break_label)) {
694 label.used = true;696 label.used = true;
695 break :blk label.block_inst;697 break :blk label.block_inst;
696 }698 }
697 }699 }
698 } else if (gen_zir.break_block) |inst| {700 } else if (block_gz.break_block != 0) {
699 break :blk inst;701 break :blk block_gz.break_block;
700 }702 }
701 scope = gen_zir.parent;703 scope = block_gz.parent;
702 continue;704 continue;
703 };705 };
704706
705 if (rhs == 0) {707 if (rhs == 0) {
706 const result = try addZirInstTag(mod, parent_scope, src, .break_void, .{708 const result = try parent_gz.addBreakVoid(block_gz, block_inst, node);
707 .block = block_inst,709 return rvalue(mod, parent_scope, rl, result, node);
708 });
709 return rvalue(mod, parent_scope, rl, result);
710 }710 }
711 gen_zir.break_count += 1;711 block_gz.break_count += 1;
712 const prev_rvalue_rl_count = gen_zir.rvalue_rl_count;712 const prev_rvalue_rl_count = block_gz.rvalue_rl_count;
713 const operand = try expr(mod, parent_scope, gen_zir.break_result_loc, rhs);713 const operand = try expr(mod, parent_scope, block_gz.break_result_loc, rhs);
714 const have_store_to_block = gen_zir.rvalue_rl_count != prev_rvalue_rl_count;714 const have_store_to_block = block_gz.rvalue_rl_count != prev_rvalue_rl_count;
715 const br = try addZirInstTag(mod, parent_scope, src, .@"break", .{715
716 .block = block_inst,716 const br = try parent_gz.addBreak(block_inst, operand);
717 .operand = operand,717
718 });718 if (block_gz.break_result_loc == .block_ptr) {
719 if (gen_zir.break_result_loc == .block_ptr) {719 try block_gz.labeled_breaks.append(mod.gpa, br);
720 try gen_zir.labeled_breaks.append(mod.gpa, br.castTag(.@"break").?);
721720
722 if (have_store_to_block) {721 if (have_store_to_block) {
723 const inst_list = parent_scope.getGenZir().instructions.items;722 const zir_tags = parent_gz.zir_code.instructions.items(.tag);
724 const last_inst = inst_list[inst_list.len - 2];723 const zir_datas = parent_gz.zir_code.instructions.items(.data);
725 const store_inst = last_inst.castTag(.store_to_block_ptr).?;724 const last_inst = zir_tags.len - 2;
726 assert(store_inst.positionals.lhs == gen_zir.rl_ptr.?);725 assert(zir_tags[last_inst] == .store_to_block_ptr);
727 try gen_zir.labeled_store_to_block_ptr_list.append(mod.gpa, store_inst);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));
728 }728 }
729 }729 }
730 return rvalue(mod, parent_scope, rl, br);730 return rvalue(mod, parent_scope, rl, br, node);
731 },731 },
732 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,732 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,
733 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,733 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,
...@@ -735,7 +735,7 @@ fn breakExpr(...@@ -735,7 +735,7 @@ fn breakExpr(
735 const label_name = try mod.identifierTokenString(parent_scope, break_label);735 const label_name = try mod.identifierTokenString(parent_scope, break_label);
736 return mod.failTok(parent_scope, break_label, "label not found: '{s}'", .{label_name});736 return mod.failTok(parent_scope, break_label, "label not found: '{s}'", .{label_name});
737 } else {737 } else {
738 return mod.failTok(parent_scope, src, "break expression outside loop", .{});738 return mod.failTok(parent_scope, break_token, "break expression outside loop", .{});
739 },739 },
740 }740 }
741 }741 }
...@@ -1769,23 +1769,11 @@ fn finishThenElseBlock(...@@ -1769,23 +1769,11 @@ fn finishThenElseBlock(
1769 switch (strat.tag) {1769 switch (strat.tag) {
1770 .break_void => {1770 .break_void => {
1771 if (!wzc.refIsNoReturn(then_result)) {1771 if (!wzc.refIsNoReturn(then_result)) {
1772 _ = try then_scope.add(.{1772 _ = try then_scope.addBreakVoid(block_scope, then_break_block, then_src);
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 });
1779 }1773 }
1780 const elide_else = if (else_result != .none) wzc.refIsNoReturn(else_result) else false;1774 const elide_else = if (else_result != .none) wzc.refIsNoReturn(else_result) else false;
1781 if (!elide_else) {1775 if (!elide_else) {
1782 _ = try else_scope.add(.{1776 _ = try else_scope.addBreakVoid(block_scope, main_block, else_src);
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 });
1789 }1777 }
1790 assert(!strat.elide_store_to_block_ptr_instructions);1778 assert(!strat.elide_store_to_block_ptr_instructions);
1791 try setCondBrPayload(condbr, cond, then_scope, else_scope);1779 try setCondBrPayload(condbr, cond, then_scope, else_scope);
...@@ -1793,32 +1781,14 @@ fn finishThenElseBlock(...@@ -1793,32 +1781,14 @@ fn finishThenElseBlock(
1793 },1781 },
1794 .break_operand => {1782 .break_operand => {
1795 if (!wzc.refIsNoReturn(then_result)) {1783 if (!wzc.refIsNoReturn(then_result)) {
1796 _ = try then_scope.add(.{1784 _ = try then_scope.addBreak(then_break_block, then_result);
1797 .tag = .@"break",
1798 .data = .{ .@"break" = .{
1799 .block_inst = then_break_block,
1800 .operand = then_result,
1801 } },
1802 });
1803 }1785 }
1804 if (else_result != .none) {1786 if (else_result != .none) {
1805 if (!wzc.refIsNoReturn(else_result)) {1787 if (!wzc.refIsNoReturn(else_result)) {
1806 _ = try else_scope.add(.{1788 _ = try else_scope.addBreak(main_block, else_result);
1807 .tag = .@"break",
1808 .data = .{ .@"break" = .{
1809 .block_inst = main_block,
1810 .operand = else_result,
1811 } },
1812 });
1813 }1789 }
1814 } else {1790 } else {
1815 _ = try else_scope.add(.{1791 _ = try else_scope.addBreakVoid(block_scope, main_block, else_src);
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 });
1822 }1792 }
1823 if (strat.elide_store_to_block_ptr_instructions) {1793 if (strat.elide_store_to_block_ptr_instructions) {
1824 try setCondBrPayloadElideBlockStorePtr(condbr, cond, then_scope, else_scope);1794 try setCondBrPayloadElideBlockStorePtr(condbr, cond, then_scope, else_scope);