Skip to content

Commit

Permalink
Eliminate switch_capture_tag ZIR instruction
Browse files Browse the repository at this point in the history
This is a follow-up to a previous commit which eliminated switch_capture
and switch_capture_ref. All captures are now handled directly by
`switch_block`, which has also eliminated some unnecessary Block data in
Sema.
  • Loading branch information
mlugg committed May 30, 2023
1 parent c55296c commit a0631e7
Show file tree
Hide file tree
Showing 4 changed files with 195 additions and 92 deletions.
62 changes: 47 additions & 15 deletions src/AstGen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2612,7 +2612,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
.switch_block,
.switch_cond,
.switch_cond_ref,
.switch_capture_tag,
.struct_init_empty,
.struct_init,
.struct_init_ref,
Expand Down Expand Up @@ -2956,7 +2955,7 @@ fn deferStmt(
try gz.astgen.instructions.append(gz.astgen.gpa, .{
.tag = .extended,
.data = .{ .extended = .{
.opcode = .errdefer_err_code,
.opcode = .value_placeholder,
.small = undefined,
.operand = undefined,
} },
Expand Down Expand Up @@ -6695,6 +6694,7 @@ fn switchExpr(
// for the following variables, make note of the special prong AST node index,
// and bail out with a compile error if there are multiple special prongs present.
var any_payload_is_ref = false;
var any_has_tag_capture = false;
var scalar_cases_len: u32 = 0;
var multi_cases_len: u32 = 0;
var inline_cases_len: u32 = 0;
Expand All @@ -6705,8 +6705,12 @@ fn switchExpr(
for (case_nodes) |case_node| {
const case = tree.fullSwitchCase(case_node).?;
if (case.payload_token) |payload_token| {
if (token_tags[payload_token] == .asterisk) {
const ident = if (token_tags[payload_token] == .asterisk) blk: {
any_payload_is_ref = true;
break :blk payload_token + 1;
} else payload_token;
if (token_tags[ident + 1] == .comma) {
any_has_tag_capture = true;
}
}
// Check for else/`_` prong.
Expand Down Expand Up @@ -6845,6 +6849,20 @@ fn switchExpr(
var case_scope = parent_gz.makeSubBlock(&block_scope.base);
case_scope.instructions_top = GenZir.unstacked_top;

// If any prong has an inline tag capture, allocate a shared dummy instruction for it
const tag_inst = if (any_has_tag_capture) tag_inst: {
const inst = @intCast(Zir.Inst.Index, astgen.instructions.len);
try astgen.instructions.append(astgen.gpa, .{
.tag = .extended,
.data = .{ .extended = .{
.opcode = .value_placeholder,
.small = undefined,
.operand = undefined,
} }, // TODO rename opcode
});
break :tag_inst inst;
} else undefined;

// In this pass we generate all the item and prong expressions.
var multi_case_index: u32 = 0;
var scalar_case_index: u32 = 0;
Expand All @@ -6858,7 +6876,7 @@ fn switchExpr(
var dbg_var_inst: Zir.Inst.Ref = undefined;
var dbg_var_tag_name: ?u32 = null;
var dbg_var_tag_inst: Zir.Inst.Ref = undefined;
var tag_inst: Zir.Inst.Index = 0;
var has_tag_capture = false;
var capture_val_scope: Scope.LocalVal = undefined;
var tag_scope: Scope.LocalVal = undefined;

Expand Down Expand Up @@ -6909,14 +6927,9 @@ fn switchExpr(
}
const tag_name = try astgen.identAsString(tag_token);
try astgen.detectLocalShadowing(payload_sub_scope, tag_name, tag_token, tag_slice, .@"switch tag capture");
tag_inst = @intCast(Zir.Inst.Index, astgen.instructions.len);
try astgen.instructions.append(gpa, .{
.tag = .switch_capture_tag,
.data = .{ .un_tok = .{
.operand = cond,
.src_tok = case_scope.tokenIndexToRelative(tag_token),
} },
});

assert(any_has_tag_capture);
has_tag_capture = true;

tag_scope = .{
.parent = payload_sub_scope,
Expand Down Expand Up @@ -6982,7 +6995,6 @@ fn switchExpr(
case_scope.instructions_top = parent_gz.instructions.items.len;
defer case_scope.unstack();

if (tag_inst != 0) try case_scope.instructions.append(gpa, tag_inst);
try case_scope.addDbgBlockBegin();
if (dbg_var_name) |some| {
try case_scope.addDbgVar(.dbg_var_val, some, dbg_var_inst);
Expand All @@ -7002,26 +7014,40 @@ fn switchExpr(
const case_slice = case_scope.instructionsSlice();
// Since we use the switch_block instruction itself to refer to the
// capture, which will not be added to the child block, we need to
// handle ref_table manually.
// handle ref_table manually, and the same for the inline tag
// capture instruction.
const refs_len = refs: {
var n: usize = 0;
var check_inst = switch_block;
while (astgen.ref_table.get(check_inst)) |ref_inst| {
n += 1;
check_inst = ref_inst;
}
if (has_tag_capture) {
check_inst = tag_inst;
while (astgen.ref_table.get(check_inst)) |ref_inst| {
n += 1;
check_inst = ref_inst;
}
}
break :refs n;
};
const body_len = refs_len + astgen.countBodyLenAfterFixups(case_slice);
try payloads.ensureUnusedCapacity(gpa, body_len);
payloads.items[body_len_index] = @bitCast(u32, Zir.Inst.SwitchBlock.ProngInfo{
.body_len = @intCast(u29, body_len),
.body_len = @intCast(u28, body_len),
.capture = capture,
.is_inline = case.inline_token != null,
.has_tag_capture = has_tag_capture,
});
if (astgen.ref_table.fetchRemove(switch_block)) |kv| {
appendPossiblyRefdBodyInst(astgen, payloads, kv.value);
}
if (has_tag_capture) {
if (astgen.ref_table.fetchRemove(tag_inst)) |kv| {
appendPossiblyRefdBodyInst(astgen, payloads, kv.value);
}
}
appendBodyWithFixupsArrayList(astgen, payloads, case_slice);
}
}
Expand All @@ -7030,6 +7056,7 @@ fn switchExpr(

try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.SwitchBlock).Struct.fields.len +
@boolToInt(multi_cases_len != 0) +
@boolToInt(any_has_tag_capture) +
payloads.items.len - case_table_end);

const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.SwitchBlock{
Expand All @@ -7038,6 +7065,7 @@ fn switchExpr(
.has_multi_cases = multi_cases_len != 0,
.has_else = special_prong == .@"else",
.has_under = special_prong == .under,
.any_has_tag_capture = any_has_tag_capture,
.scalar_cases_len = @intCast(Zir.Inst.SwitchBlock.Bits.ScalarCasesLen, scalar_cases_len),
},
});
Expand All @@ -7046,6 +7074,10 @@ fn switchExpr(
astgen.extra.appendAssumeCapacity(multi_cases_len);
}

if (any_has_tag_capture) {
astgen.extra.appendAssumeCapacity(tag_inst);
}

const zir_datas = astgen.instructions.items(.data);
const zir_tags = astgen.instructions.items(.tag);

Expand Down
Loading

0 comments on commit a0631e7

Please sign in to comment.