Skip to content

Commit

Permalink
Eliminate switch_cond[_ref] ZIR tags
Browse files Browse the repository at this point in the history
This finishes the process of consolidating switch expressions in ZIR
into as simple and compact a representation as is possible. There are
now just two ZIR tags dedicated to switch expressions: switch_block and
switch_block_ref, with the latter being for an operand passed by
reference.
  • Loading branch information
mlugg committed May 30, 2023
1 parent a0631e7 commit 0170b12
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 91 deletions.
14 changes: 6 additions & 8 deletions src/AstGen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2610,8 +2610,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
.slice_length,
.import,
.switch_block,
.switch_cond,
.switch_cond_ref,
.switch_block_ref,
.struct_init_empty,
.struct_init,
.struct_init_ref,
Expand Down Expand Up @@ -6819,10 +6818,6 @@ fn switchExpr(
const operand_lc = LineColumn{ astgen.source_line - parent_gz.decl_line, astgen.source_column };

const raw_operand = try expr(parent_gz, scope, operand_ri, operand_node);
const cond_tag: Zir.Inst.Tag = if (any_payload_is_ref) .switch_cond_ref else .switch_cond;
const cond = try parent_gz.addUnNode(cond_tag, raw_operand, operand_node);
// Sema expects a dbg_stmt immediately after switch_cond(_ref)
try emitDbgStmt(parent_gz, operand_lc);
const item_ri: ResultInfo = .{ .rl = .none };

// This contains the data that goes into the `extra` array for the SwitchBlock/SwitchBlockMulti,
Expand All @@ -6842,8 +6837,11 @@ fn switchExpr(
block_scope.instructions_top = GenZir.unstacked_top;
block_scope.setBreakResultInfo(ri);

// Sema expects a dbg_stmt immediately before switch_block(_ref)
try emitDbgStmt(parent_gz, operand_lc);
// This gets added to the parent block later, after the item expressions.
const switch_block = try parent_gz.makeBlockInst(.switch_block, switch_node);
const switch_tag: Zir.Inst.Tag = if (any_payload_is_ref) .switch_block_ref else .switch_block;
const switch_block = try parent_gz.makeBlockInst(switch_tag, switch_node);

// We re-use this same scope for all cases, including the special prong, if any.
var case_scope = parent_gz.makeSubBlock(&block_scope.base);
Expand Down Expand Up @@ -7060,7 +7058,7 @@ fn switchExpr(
payloads.items.len - case_table_end);

const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.SwitchBlock{
.operand = cond,
.operand = raw_operand,
.bits = Zir.Inst.SwitchBlock.Bits{
.has_multi_cases = multi_cases_len != 0,
.has_else = special_prong == .@"else",
Expand Down
25 changes: 0 additions & 25 deletions src/Autodoc.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1992,31 +1992,6 @@ fn walkInstruction(
.expr = .{ .switchIndex = switch_index },
};
},
.switch_cond => {
const un_node = data[inst_index].un_node;
const operand = try self.walkRef(
file,
parent_scope,
parent_src,
un_node.operand,
need_type,
);
const operand_index = self.exprs.items.len;
try self.exprs.append(self.arena, operand.expr);

// const ast_index = self.ast_nodes.items.len;
// const sep = "=" ** 200;
// log.debug("{s}", .{sep});
// log.debug("SWITCH COND", .{});
// log.debug("ast index = {}", .{ast_index});
// log.debug("ast previous = {}", .{self.ast_nodes.items[ast_index - 1]});
// log.debug("{s}", .{sep});

return DocData.WalkResult{
.typeRef = operand.typeRef,
.expr = .{ .typeOf = operand_index },
};
},

.typeof => {
const un_node = data[inst_index].un_node;
Expand Down
54 changes: 21 additions & 33 deletions src/Sema.zig
Original file line number Diff line number Diff line change
Expand Up @@ -979,9 +979,8 @@ fn analyzeBodyInner(
.slice_start => try sema.zirSliceStart(block, inst),
.slice_length => try sema.zirSliceLength(block, inst),
.str => try sema.zirStr(block, inst),
.switch_block => try sema.zirSwitchBlock(block, inst),
.switch_cond => try sema.zirSwitchCond(block, inst, false),
.switch_cond_ref => try sema.zirSwitchCond(block, inst, true),
.switch_block => try sema.zirSwitchBlock(block, inst, false),
.switch_block_ref => try sema.zirSwitchBlock(block, inst, true),
.type_info => try sema.zirTypeInfo(block, inst),
.size_of => try sema.zirSizeOf(block, inst),
.bit_size_of => try sema.zirBitSizeOf(block, inst),
Expand Down Expand Up @@ -10384,22 +10383,13 @@ const SwitchProngAnalysis = struct {
}
};

fn zirSwitchCond(
fn switchCond(
sema: *Sema,
block: *Block,
inst: Zir.Inst.Index,
is_ref: bool,
src: LazySrcLoc,
operand: Air.Inst.Ref,
) CompileError!Air.Inst.Ref {
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const src = inst_data.src();
const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = inst_data.src_node };
const operand_ptr = try sema.resolveInst(inst_data.operand);
const operand = if (is_ref)
try sema.analyzeLoad(block, src, operand_ptr, operand_src)
else
operand_ptr;
const operand_ty = sema.typeOf(operand);

switch (operand_ty.zigTypeTag()) {
.Type,
.Void,
Expand Down Expand Up @@ -10456,7 +10446,7 @@ fn zirSwitchCond(

const SwitchErrorSet = std.StringHashMap(Module.SwitchProngSrc);

fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_ref: bool) CompileError!Air.Inst.Ref {
const tracy = trace(@src());
defer tracy.end();

Expand All @@ -10468,10 +10458,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
const special_prong_src: LazySrcLoc = .{ .node_offset_switch_special_prong = src_node_offset };
const extra = sema.code.extraData(Zir.Inst.SwitchBlock, inst_data.payload_index);

const operand = try sema.resolveInst(extra.data.operand);
// AstGen guarantees that the instruction immediately following
// switch_cond(_ref) is a dbg_stmt
const cond_dbg_node_index = Zir.refToIndex(extra.data.operand).? + 1;
const raw_operand: struct { val: Air.Inst.Ref, ptr: Air.Inst.Ref } = blk: {
const maybe_ptr = try sema.resolveInst(extra.data.operand);
if (operand_is_ref) {
const val = try sema.analyzeLoad(block, src, maybe_ptr, operand_src);
break :blk .{ .val = val, .ptr = maybe_ptr };
} else {
break :blk .{ .val = maybe_ptr, .ptr = undefined };
}
};

const operand = try sema.switchCond(block, src, raw_operand.val);

// AstGen guarantees that the instruction immediately preceding
// switch_block(_ref) is a dbg_stmt
const cond_dbg_node_index = inst - 1;

var header_extra_index: usize = extra.end;

Expand Down Expand Up @@ -10525,19 +10526,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
},
};

const raw_operand: struct { val: Air.Inst.Ref, ptr: Air.Inst.Ref } = blk: {
const zir_tags = sema.code.instructions.items(.tag);
const zir_data = sema.code.instructions.items(.data);
const cond_index = Zir.refToIndex(extra.data.operand).?;
const raw = sema.resolveInst(zir_data[cond_index].un_node.operand) catch unreachable;
if (zir_tags[cond_index] == .switch_cond_ref) {
const val = try sema.analyzeLoad(block, src, raw, operand_src);
break :blk .{ .val = val, .ptr = raw };
} else {
break :blk .{ .val = raw, .ptr = undefined };
}
};

const maybe_union_ty = sema.typeOf(raw_operand.val);
const union_originally = maybe_union_ty.zigTypeTag() == .Union;

Expand Down
32 changes: 10 additions & 22 deletions src/Zir.zig
Original file line number Diff line number Diff line change
Expand Up @@ -666,15 +666,9 @@ pub const Inst = struct {
/// A switch expression. Uses the `pl_node` union field.
/// AST node is the switch, payload is `SwitchBlock`.
switch_block,
/// Produces the value that will be switched on. For example, for
/// integers, it returns the integer with no modifications. For tagged unions, it
/// returns the active enum tag.
/// Uses the `un_node` union field.
switch_cond,
/// Same as `switch_cond`, except the input operand is a pointer to
/// what will be switched on.
/// Uses the `un_node` union field.
switch_cond_ref,
/// A switch expression. Uses the `pl_node` union field.
/// AST node is the switch, payload is `SwitchBlock`. Operand is a pointer.
switch_block_ref,
/// Given a
/// *A returns *A
/// *E!A returns *A
Expand Down Expand Up @@ -1121,8 +1115,7 @@ pub const Inst = struct {
.resolve_inferred_alloc,
.set_eval_branch_quota,
.switch_block,
.switch_cond,
.switch_cond_ref,
.switch_block_ref,
.array_base_ptr,
.field_base_ptr,
.validate_array_init_ty,
Expand Down Expand Up @@ -1410,8 +1403,7 @@ pub const Inst = struct {
.import,
.typeof_log2_int_type,
.switch_block,
.switch_cond,
.switch_cond_ref,
.switch_block_ref,
.array_base_ptr,
.field_base_ptr,
.struct_init_empty,
Expand Down Expand Up @@ -1662,8 +1654,7 @@ pub const Inst = struct {
.err_union_code_ptr = .un_node,
.enum_literal = .str_tok,
.switch_block = .pl_node,
.switch_cond = .un_node,
.switch_cond_ref = .un_node,
.switch_block_ref = .pl_node,
.array_base_ptr = .un_node,
.field_base_ptr = .un_node,
.validate_array_init_ty = .pl_node,
Expand Down Expand Up @@ -3009,13 +3000,10 @@ pub const Inst = struct {
/// captured payload. Whether this is captured by reference or by value
/// depends on whether the `byref` bit is set for the corresponding body.
pub const SwitchBlock = struct {
/// This is always a `switch_cond` or `switch_cond_ref` instruction.
/// If it is a `switch_cond_ref` instruction, bits.is_ref is always true.
/// If it is a `switch_cond` instruction, bits.is_ref is always false.
/// Both `switch_cond` and `switch_cond_ref` return a value, not a pointer,
/// that is useful for the case items, but cannot be used for capture values.
/// For the capture values, Sema is expected to find the operand of this operand
/// and use that.
/// The operand passed to the `switch` expression. If this is a
/// `switch_block`, this is the operand value; if `switch_block_ref` it
/// is a pointer to the operand. `switch_block_ref` is always used if
/// any prong has a byref capture.
operand: Ref,
bits: Bits,

Expand Down
6 changes: 3 additions & 3 deletions src/print_zir.zig
Original file line number Diff line number Diff line change
Expand Up @@ -221,8 +221,6 @@ const Writer = struct {
.bit_reverse,
.@"resume",
.@"await",
.switch_cond,
.switch_cond_ref,
.array_base_ptr,
.field_base_ptr,
.validate_struct_init_ty,
Expand Down Expand Up @@ -387,7 +385,9 @@ const Writer = struct {
.error_set_decl_anon => try self.writeErrorSetDecl(stream, inst, .anon),
.error_set_decl_func => try self.writeErrorSetDecl(stream, inst, .func),

.switch_block => try self.writeSwitchBlock(stream, inst),
.switch_block,
.switch_block_ref,
=> try self.writeSwitchBlock(stream, inst),

.field_ptr,
.field_ptr_init,
Expand Down

0 comments on commit 0170b12

Please sign in to comment.