aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimon Kruiper <timonkruiper@gmail.com>2021-03-24 15:26:09 +0100
committerAndrew Kelley <andrew@ziglang.org>2021-03-24 19:54:03 -0700
commit522707622e95ef17b94c7a3d78ca81cadde5274d (patch)
treef7518af54081f2e46b43ee5b324f1e7e303a25fe
parentd73a4940e0d907e017ce60d0a7183cd1618b3b39 (diff)
downloadzig-522707622e95ef17b94c7a3d78ca81cadde5274d.tar.gz
zig-522707622e95ef17b94c7a3d78ca81cadde5274d.zip
astgen: implement breaking from a block
-rw-r--r--src/Module.zig33
-rw-r--r--src/astgen.zig94
2 files changed, 63 insertions, 64 deletions
diff --git a/src/Module.zig b/src/Module.zig
index a97ba364ab..e3e8fa813b 100644
--- a/src/Module.zig
+++ b/src/Module.zig
@@ -935,11 +935,11 @@ pub const Scope = struct {
break_count: usize = 0,
/// Tracks `break :foo bar` instructions so they can possibly be elided later if
/// the labeled block ends up not needing a result location pointer.
- labeled_breaks: std.ArrayListUnmanaged(zir.Inst.Index) = .{},
+ labeled_breaks: std.ArrayListUnmanaged(zir.Inst.Ref) = .{},
/// Tracks `store_to_block_ptr` instructions that correspond to break instructions
/// so they can possibly be elided later if the labeled block ends up not needing
/// a result location pointer.
- labeled_store_to_block_ptr_list: std.ArrayListUnmanaged(zir.Inst.Index) = .{},
+ labeled_store_to_block_ptr_list: std.ArrayListUnmanaged(zir.Inst.Ref) = .{},
pub const Label = struct {
token: ast.TokenIndex,
@@ -1222,6 +1222,35 @@ pub const Scope = struct {
});
}
+ pub fn addBreak(
+ gz: *GenZir,
+ break_block: zir.Inst.Index,
+ operand: zir.Inst.Ref,
+ ) !zir.Inst.Ref {
+ return try gz.add(.{
+ .tag = .@"break",
+ .data = .{ .@"break" = .{
+ .block_inst = break_block,
+ .operand = operand,
+ } },
+ });
+ }
+
+ pub fn addBreakVoid(
+ inner_gz: *GenZir,
+ block_gz: *GenZir,
+ break_block: zir.Inst.Index,
+ node_index: ast.Node.Index,
+ ) !zir.Inst.Ref {
+ return try inner_gz.add(.{
+ .tag = .break_void_node,
+ .data = .{ .break_void_node = .{
+ .src_node = block_gz.zir_code.decl.nodeIndexToRelative(node_index),
+ .block_inst = break_block,
+ } },
+ });
+ }
+
pub fn addBin(
gz: *GenZir,
tag: zir.Inst.Tag,
diff --git a/src/astgen.zig b/src/astgen.zig
index ab97e000c6..cbaa965dc5 100644
--- a/src/astgen.zig
+++ b/src/astgen.zig
@@ -672,62 +672,62 @@ fn breakExpr(
rl: ResultLoc,
node: ast.Node.Index,
) InnerError!zir.Inst.Ref {
- if (true) @panic("TODO update for zir-memory-layout");
const tree = parent_scope.tree();
const node_datas = tree.nodes.items(.data);
const main_tokens = tree.nodes.items(.main_token);
+ const break_token = main_tokens[node];
const break_label = node_datas[node].lhs;
const rhs = node_datas[node].rhs;
+ const parent_gz = parent_scope.getGenZir();
+
// Look for the label in the scope.
var scope = parent_scope;
while (true) {
switch (scope.tag) {
.gen_zir => {
- const gen_zir = scope.cast(Scope.GenZir).?;
+ const block_gz = scope.getGenZir();
const block_inst = blk: {
if (break_label != 0) {
- if (gen_zir.label) |*label| {
+ if (block_gz.label) |*label| {
if (try tokenIdentEql(mod, parent_scope, label.token, break_label)) {
label.used = true;
break :blk label.block_inst;
}
}
- } else if (gen_zir.break_block) |inst| {
- break :blk inst;
+ } else if (block_gz.break_block != 0) {
+ break :blk block_gz.break_block;
}
- scope = gen_zir.parent;
+ scope = block_gz.parent;
continue;
};
if (rhs == 0) {
- const result = try addZirInstTag(mod, parent_scope, src, .break_void, .{
- .block = block_inst,
- });
- return rvalue(mod, parent_scope, rl, result);
+ const result = try parent_gz.addBreakVoid(block_gz, block_inst, node);
+ return rvalue(mod, parent_scope, rl, result, node);
}
- gen_zir.break_count += 1;
- const prev_rvalue_rl_count = gen_zir.rvalue_rl_count;
- const operand = try expr(mod, parent_scope, gen_zir.break_result_loc, rhs);
- const have_store_to_block = gen_zir.rvalue_rl_count != prev_rvalue_rl_count;
- const br = try addZirInstTag(mod, parent_scope, src, .@"break", .{
- .block = block_inst,
- .operand = operand,
- });
- if (gen_zir.break_result_loc == .block_ptr) {
- try gen_zir.labeled_breaks.append(mod.gpa, br.castTag(.@"break").?);
+ block_gz.break_count += 1;
+ const prev_rvalue_rl_count = block_gz.rvalue_rl_count;
+ const operand = try expr(mod, parent_scope, block_gz.break_result_loc, rhs);
+ const have_store_to_block = block_gz.rvalue_rl_count != prev_rvalue_rl_count;
+
+ const br = try parent_gz.addBreak(block_inst, operand);
+
+ if (block_gz.break_result_loc == .block_ptr) {
+ try block_gz.labeled_breaks.append(mod.gpa, br);
if (have_store_to_block) {
- const inst_list = parent_scope.getGenZir().instructions.items;
- const last_inst = inst_list[inst_list.len - 2];
- const store_inst = last_inst.castTag(.store_to_block_ptr).?;
- assert(store_inst.positionals.lhs == gen_zir.rl_ptr.?);
- try gen_zir.labeled_store_to_block_ptr_list.append(mod.gpa, store_inst);
+ const zir_tags = parent_gz.zir_code.instructions.items(.tag);
+ const zir_datas = parent_gz.zir_code.instructions.items(.data);
+ const last_inst = zir_tags.len - 2;
+ assert(zir_tags[last_inst] == .store_to_block_ptr);
+ assert(zir_datas[last_inst].bin.lhs == block_gz.rl_ptr);
+ try block_gz.labeled_store_to_block_ptr_list.append(mod.gpa, @intCast(zir.Inst.Ref, last_inst));
}
}
- return rvalue(mod, parent_scope, rl, br);
+ return rvalue(mod, parent_scope, rl, br, node);
},
.local_val => scope = scope.cast(Scope.LocalVal).?.parent,
.local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,
@@ -735,7 +735,7 @@ fn breakExpr(
const label_name = try mod.identifierTokenString(parent_scope, break_label);
return mod.failTok(parent_scope, break_label, "label not found: '{s}'", .{label_name});
} else {
- return mod.failTok(parent_scope, src, "break expression outside loop", .{});
+ return mod.failTok(parent_scope, break_token, "break expression outside loop", .{});
},
}
}
@@ -1769,23 +1769,11 @@ fn finishThenElseBlock(
switch (strat.tag) {
.break_void => {
if (!wzc.refIsNoReturn(then_result)) {
- _ = try then_scope.add(.{
- .tag = .break_void_node,
- .data = .{ .break_void_node = .{
- .src_node = wzc.decl.nodeIndexToRelative(then_src),
- .block_inst = then_break_block,
- } },
- });
+ _ = try then_scope.addBreakVoid(block_scope, then_break_block, then_src);
}
const elide_else = if (else_result != .none) wzc.refIsNoReturn(else_result) else false;
if (!elide_else) {
- _ = try else_scope.add(.{
- .tag = .break_void_node,
- .data = .{ .break_void_node = .{
- .src_node = wzc.decl.nodeIndexToRelative(else_src),
- .block_inst = main_block,
- } },
- });
+ _ = try else_scope.addBreakVoid(block_scope, main_block, else_src);
}
assert(!strat.elide_store_to_block_ptr_instructions);
try setCondBrPayload(condbr, cond, then_scope, else_scope);
@@ -1793,32 +1781,14 @@ fn finishThenElseBlock(
},
.break_operand => {
if (!wzc.refIsNoReturn(then_result)) {
- _ = try then_scope.add(.{
- .tag = .@"break",
- .data = .{ .@"break" = .{
- .block_inst = then_break_block,
- .operand = then_result,
- } },
- });
+ _ = try then_scope.addBreak(then_break_block, then_result);
}
if (else_result != .none) {
if (!wzc.refIsNoReturn(else_result)) {
- _ = try else_scope.add(.{
- .tag = .@"break",
- .data = .{ .@"break" = .{
- .block_inst = main_block,
- .operand = else_result,
- } },
- });
+ _ = try else_scope.addBreak(main_block, else_result);
}
} else {
- _ = try else_scope.add(.{
- .tag = .break_void_node,
- .data = .{ .break_void_node = .{
- .src_node = wzc.decl.nodeIndexToRelative(else_src),
- .block_inst = main_block,
- } },
- });
+ _ = try else_scope.addBreakVoid(block_scope, main_block, else_src);
}
if (strat.elide_store_to_block_ptr_instructions) {
try setCondBrPayloadElideBlockStorePtr(condbr, cond, then_scope, else_scope);