authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2023-05-27 13:50:50+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2023-06-13 12:55:15+01:00
log85e94fed1e058720460560823ac09d7b64e49b97
treedf28ab8360a7cbdf32005532349b72e4713ef097
parent39510cc7d1f6035e16aaa4f97991abbaddef463c
signaturelock-open Commit is signed but in an unrecognized format.

Eliminate switch_cond[_ref] ZIR tags

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.

5 files changed, 40 insertions(+), 91 deletions(-)

src/AstGen.zig+6-8
...@@ -2610,8 +2610,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As...@@ -2610,8 +2610,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
2610 .slice_length,2610 .slice_length,
2611 .import,2611 .import,
2612 .switch_block,2612 .switch_block,
2613 .switch_cond,2613 .switch_block_ref,
2614 .switch_cond_ref,
2615 .struct_init_empty,2614 .struct_init_empty,
2616 .struct_init,2615 .struct_init,
2617 .struct_init_ref,2616 .struct_init_ref,
...@@ -6835,10 +6834,6 @@ fn switchExpr(...@@ -6835,10 +6834,6 @@ fn switchExpr(
6835 const operand_lc = LineColumn{ astgen.source_line - parent_gz.decl_line, astgen.source_column };6834 const operand_lc = LineColumn{ astgen.source_line - parent_gz.decl_line, astgen.source_column };
68366835
6837 const raw_operand = try expr(parent_gz, scope, operand_ri, operand_node);6836 const raw_operand = try expr(parent_gz, scope, operand_ri, operand_node);
6838 const cond_tag: Zir.Inst.Tag = if (any_payload_is_ref) .switch_cond_ref else .switch_cond;
6839 const cond = try parent_gz.addUnNode(cond_tag, raw_operand, operand_node);
6840 // Sema expects a dbg_stmt immediately after switch_cond(_ref)
6841 try emitDbgStmt(parent_gz, operand_lc);
6842 const item_ri: ResultInfo = .{ .rl = .none };6837 const item_ri: ResultInfo = .{ .rl = .none };
68436838
6844 // This contains the data that goes into the `extra` array for the SwitchBlock/SwitchBlockMulti,6839 // This contains the data that goes into the `extra` array for the SwitchBlock/SwitchBlockMulti,
...@@ -6858,8 +6853,11 @@ fn switchExpr(...@@ -6858,8 +6853,11 @@ fn switchExpr(
6858 block_scope.instructions_top = GenZir.unstacked_top;6853 block_scope.instructions_top = GenZir.unstacked_top;
6859 block_scope.setBreakResultInfo(ri);6854 block_scope.setBreakResultInfo(ri);
68606855
6856 // Sema expects a dbg_stmt immediately before switch_block(_ref)
6857 try emitDbgStmt(parent_gz, operand_lc);
6861 // This gets added to the parent block later, after the item expressions.6858 // This gets added to the parent block later, after the item expressions.
6862 const switch_block = try parent_gz.makeBlockInst(.switch_block, switch_node);6859 const switch_tag: Zir.Inst.Tag = if (any_payload_is_ref) .switch_block_ref else .switch_block;
6860 const switch_block = try parent_gz.makeBlockInst(switch_tag, switch_node);
68636861
6864 // We re-use this same scope for all cases, including the special prong, if any.6862 // We re-use this same scope for all cases, including the special prong, if any.
6865 var case_scope = parent_gz.makeSubBlock(&block_scope.base);6863 var case_scope = parent_gz.makeSubBlock(&block_scope.base);
...@@ -7076,7 +7074,7 @@ fn switchExpr(...@@ -7076,7 +7074,7 @@ fn switchExpr(
7076 payloads.items.len - case_table_end);7074 payloads.items.len - case_table_end);
70777075
7078 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.SwitchBlock{7076 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.SwitchBlock{
7079 .operand = cond,7077 .operand = raw_operand,
7080 .bits = Zir.Inst.SwitchBlock.Bits{7078 .bits = Zir.Inst.SwitchBlock.Bits{
7081 .has_multi_cases = multi_cases_len != 0,7079 .has_multi_cases = multi_cases_len != 0,
7082 .has_else = special_prong == .@"else",7080 .has_else = special_prong == .@"else",
src/Autodoc.zig-25
...@@ -1993,31 +1993,6 @@ fn walkInstruction(...@@ -1993,31 +1993,6 @@ fn walkInstruction(
1993 .expr = .{ .switchIndex = switch_index },1993 .expr = .{ .switchIndex = switch_index },
1994 };1994 };
1995 },1995 },
1996 .switch_cond => {
1997 const un_node = data[inst_index].un_node;
1998 const operand = try self.walkRef(
1999 file,
2000 parent_scope,
2001 parent_src,
2002 un_node.operand,
2003 need_type,
2004 );
2005 const operand_index = self.exprs.items.len;
2006 try self.exprs.append(self.arena, operand.expr);
2007
2008 // const ast_index = self.ast_nodes.items.len;
2009 // const sep = "=" ** 200;
2010 // log.debug("{s}", .{sep});
2011 // log.debug("SWITCH COND", .{});
2012 // log.debug("ast index = {}", .{ast_index});
2013 // log.debug("ast previous = {}", .{self.ast_nodes.items[ast_index - 1]});
2014 // log.debug("{s}", .{sep});
2015
2016 return DocData.WalkResult{
2017 .typeRef = operand.typeRef,
2018 .expr = .{ .typeOf = operand_index },
2019 };
2020 },
20211996
2022 .typeof => {1997 .typeof => {
2023 const un_node = data[inst_index].un_node;1998 const un_node = data[inst_index].un_node;
src/Sema.zig+21-33
...@@ -1007,9 +1007,8 @@ fn analyzeBodyInner(...@@ -1007,9 +1007,8 @@ fn analyzeBodyInner(
1007 .slice_start => try sema.zirSliceStart(block, inst),1007 .slice_start => try sema.zirSliceStart(block, inst),
1008 .slice_length => try sema.zirSliceLength(block, inst),1008 .slice_length => try sema.zirSliceLength(block, inst),
1009 .str => try sema.zirStr(block, inst),1009 .str => try sema.zirStr(block, inst),
1010 .switch_block => try sema.zirSwitchBlock(block, inst),1010 .switch_block => try sema.zirSwitchBlock(block, inst, false),
1011 .switch_cond => try sema.zirSwitchCond(block, inst, false),1011 .switch_block_ref => try sema.zirSwitchBlock(block, inst, true),
1012 .switch_cond_ref => try sema.zirSwitchCond(block, inst, true),
1013 .type_info => try sema.zirTypeInfo(block, inst),1012 .type_info => try sema.zirTypeInfo(block, inst),
1014 .size_of => try sema.zirSizeOf(block, inst),1013 .size_of => try sema.zirSizeOf(block, inst),
1015 .bit_size_of => try sema.zirBitSizeOf(block, inst),1014 .bit_size_of => try sema.zirBitSizeOf(block, inst),
...@@ -10411,23 +10410,14 @@ const SwitchProngAnalysis = struct {...@@ -10411,23 +10410,14 @@ const SwitchProngAnalysis = struct {
10411 }10410 }
10412};10411};
1041310412
10414fn zirSwitchCond(10413fn switchCond(
10415 sema: *Sema,10414 sema: *Sema,
10416 block: *Block,10415 block: *Block,
10417 inst: Zir.Inst.Index,10416 src: LazySrcLoc,
10418 is_ref: bool,10417 operand: Air.Inst.Ref,
10419) CompileError!Air.Inst.Ref {10418) CompileError!Air.Inst.Ref {
10420 const mod = sema.mod;10419 const mod = sema.mod;
10421 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
10422 const src = inst_data.src();
10423 const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = inst_data.src_node };
10424 const operand_ptr = try sema.resolveInst(inst_data.operand);
10425 const operand = if (is_ref)
10426 try sema.analyzeLoad(block, src, operand_ptr, operand_src)
10427 else
10428 operand_ptr;
10429 const operand_ty = sema.typeOf(operand);10420 const operand_ty = sema.typeOf(operand);
10430
10431 switch (operand_ty.zigTypeTag(mod)) {10421 switch (operand_ty.zigTypeTag(mod)) {
10432 .Type,10422 .Type,
10433 .Void,10423 .Void,
...@@ -10484,7 +10474,7 @@ fn zirSwitchCond(...@@ -10484,7 +10474,7 @@ fn zirSwitchCond(
1048410474
10485const SwitchErrorSet = std.AutoHashMap(InternPool.NullTerminatedString, Module.SwitchProngSrc);10475const SwitchErrorSet = std.AutoHashMap(InternPool.NullTerminatedString, Module.SwitchProngSrc);
1048610476
10487fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {10477fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_ref: bool) CompileError!Air.Inst.Ref {
10488 const tracy = trace(@src());10478 const tracy = trace(@src());
10489 defer tracy.end();10479 defer tracy.end();
1049010480
...@@ -10498,10 +10488,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -10498,10 +10488,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
10498 const special_prong_src: LazySrcLoc = .{ .node_offset_switch_special_prong = src_node_offset };10488 const special_prong_src: LazySrcLoc = .{ .node_offset_switch_special_prong = src_node_offset };
10499 const extra = sema.code.extraData(Zir.Inst.SwitchBlock, inst_data.payload_index);10489 const extra = sema.code.extraData(Zir.Inst.SwitchBlock, inst_data.payload_index);
1050010490
10501 const operand = try sema.resolveInst(extra.data.operand);10491 const raw_operand: struct { val: Air.Inst.Ref, ptr: Air.Inst.Ref } = blk: {
10502 // AstGen guarantees that the instruction immediately following10492 const maybe_ptr = try sema.resolveInst(extra.data.operand);
10503 // switch_cond(_ref) is a dbg_stmt10493 if (operand_is_ref) {
10504 const cond_dbg_node_index = Zir.refToIndex(extra.data.operand).? + 1;10494 const val = try sema.analyzeLoad(block, src, maybe_ptr, operand_src);
10495 break :blk .{ .val = val, .ptr = maybe_ptr };
10496 } else {
10497 break :blk .{ .val = maybe_ptr, .ptr = undefined };
10498 }
10499 };
10500
10501 const operand = try sema.switchCond(block, src, raw_operand.val);
10502
10503 // AstGen guarantees that the instruction immediately preceding
10504 // switch_block(_ref) is a dbg_stmt
10505 const cond_dbg_node_index = inst - 1;
1050510506
10506 var header_extra_index: usize = extra.end;10507 var header_extra_index: usize = extra.end;
1050710508
...@@ -10555,19 +10556,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -10555,19 +10556,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
10555 },10556 },
10556 };10557 };
1055710558
10558 const raw_operand: struct { val: Air.Inst.Ref, ptr: Air.Inst.Ref } = blk: {
10559 const zir_tags = sema.code.instructions.items(.tag);
10560 const zir_data = sema.code.instructions.items(.data);
10561 const cond_index = Zir.refToIndex(extra.data.operand).?;
10562 const raw = sema.resolveInst(zir_data[cond_index].un_node.operand) catch unreachable;
10563 if (zir_tags[cond_index] == .switch_cond_ref) {
10564 const val = try sema.analyzeLoad(block, src, raw, operand_src);
10565 break :blk .{ .val = val, .ptr = raw };
10566 } else {
10567 break :blk .{ .val = raw, .ptr = undefined };
10568 }
10569 };
10570
10571 const maybe_union_ty = sema.typeOf(raw_operand.val);10559 const maybe_union_ty = sema.typeOf(raw_operand.val);
10572 const union_originally = maybe_union_ty.zigTypeTag(mod) == .Union;10560 const union_originally = maybe_union_ty.zigTypeTag(mod) == .Union;
1057310561
src/Zir.zig+10-22
...@@ -667,15 +667,9 @@ pub const Inst = struct {...@@ -667,15 +667,9 @@ pub const Inst = struct {
667 /// A switch expression. Uses the `pl_node` union field.667 /// A switch expression. Uses the `pl_node` union field.
668 /// AST node is the switch, payload is `SwitchBlock`.668 /// AST node is the switch, payload is `SwitchBlock`.
669 switch_block,669 switch_block,
670 /// Produces the value that will be switched on. For example, for670 /// A switch expression. Uses the `pl_node` union field.
671 /// integers, it returns the integer with no modifications. For tagged unions, it671 /// AST node is the switch, payload is `SwitchBlock`. Operand is a pointer.
672 /// returns the active enum tag.672 switch_block_ref,
673 /// Uses the `un_node` union field.
674 switch_cond,
675 /// Same as `switch_cond`, except the input operand is a pointer to
676 /// what will be switched on.
677 /// Uses the `un_node` union field.
678 switch_cond_ref,
679 /// Given a673 /// Given a
680 /// *A returns *A674 /// *A returns *A
681 /// *E!A returns *A675 /// *E!A returns *A
...@@ -1122,8 +1116,7 @@ pub const Inst = struct {...@@ -1122,8 +1116,7 @@ pub const Inst = struct {
1122 .resolve_inferred_alloc,1116 .resolve_inferred_alloc,
1123 .set_eval_branch_quota,1117 .set_eval_branch_quota,
1124 .switch_block,1118 .switch_block,
1125 .switch_cond,1119 .switch_block_ref,
1126 .switch_cond_ref,
1127 .array_base_ptr,1120 .array_base_ptr,
1128 .field_base_ptr,1121 .field_base_ptr,
1129 .validate_array_init_ty,1122 .validate_array_init_ty,
...@@ -1411,8 +1404,7 @@ pub const Inst = struct {...@@ -1411,8 +1404,7 @@ pub const Inst = struct {
1411 .import,1404 .import,
1412 .typeof_log2_int_type,1405 .typeof_log2_int_type,
1413 .switch_block,1406 .switch_block,
1414 .switch_cond,1407 .switch_block_ref,
1415 .switch_cond_ref,
1416 .array_base_ptr,1408 .array_base_ptr,
1417 .field_base_ptr,1409 .field_base_ptr,
1418 .struct_init_empty,1410 .struct_init_empty,
...@@ -1663,8 +1655,7 @@ pub const Inst = struct {...@@ -1663,8 +1655,7 @@ pub const Inst = struct {
1663 .err_union_code_ptr = .un_node,1655 .err_union_code_ptr = .un_node,
1664 .enum_literal = .str_tok,1656 .enum_literal = .str_tok,
1665 .switch_block = .pl_node,1657 .switch_block = .pl_node,
1666 .switch_cond = .un_node,1658 .switch_block_ref = .pl_node,
1667 .switch_cond_ref = .un_node,
1668 .array_base_ptr = .un_node,1659 .array_base_ptr = .un_node,
1669 .field_base_ptr = .un_node,1660 .field_base_ptr = .un_node,
1670 .validate_array_init_ty = .pl_node,1661 .validate_array_init_ty = .pl_node,
...@@ -2665,13 +2656,10 @@ pub const Inst = struct {...@@ -2665,13 +2656,10 @@ pub const Inst = struct {
2665 /// captured payload. Whether this is captured by reference or by value2656 /// captured payload. Whether this is captured by reference or by value
2666 /// depends on whether the `byref` bit is set for the corresponding body.2657 /// depends on whether the `byref` bit is set for the corresponding body.
2667 pub const SwitchBlock = struct {2658 pub const SwitchBlock = struct {
2668 /// This is always a `switch_cond` or `switch_cond_ref` instruction.2659 /// The operand passed to the `switch` expression. If this is a
2669 /// If it is a `switch_cond_ref` instruction, bits.is_ref is always true.2660 /// `switch_block`, this is the operand value; if `switch_block_ref` it
2670 /// If it is a `switch_cond` instruction, bits.is_ref is always false.2661 /// is a pointer to the operand. `switch_block_ref` is always used if
2671 /// Both `switch_cond` and `switch_cond_ref` return a value, not a pointer,2662 /// any prong has a byref capture.
2672 /// that is useful for the case items, but cannot be used for capture values.
2673 /// For the capture values, Sema is expected to find the operand of this operand
2674 /// and use that.
2675 operand: Ref,2663 operand: Ref,
2676 bits: Bits,2664 bits: Bits,
26772665
src/print_zir.zig+3-3
...@@ -222,8 +222,6 @@ const Writer = struct {...@@ -222,8 +222,6 @@ const Writer = struct {
222 .bit_reverse,222 .bit_reverse,
223 .@"resume",223 .@"resume",
224 .@"await",224 .@"await",
225 .switch_cond,
226 .switch_cond_ref,
227 .array_base_ptr,225 .array_base_ptr,
228 .field_base_ptr,226 .field_base_ptr,
229 .validate_struct_init_ty,227 .validate_struct_init_ty,
...@@ -388,7 +386,9 @@ const Writer = struct {...@@ -388,7 +386,9 @@ const Writer = struct {
388 .error_set_decl_anon => try self.writeErrorSetDecl(stream, inst, .anon),386 .error_set_decl_anon => try self.writeErrorSetDecl(stream, inst, .anon),
389 .error_set_decl_func => try self.writeErrorSetDecl(stream, inst, .func),387 .error_set_decl_func => try self.writeErrorSetDecl(stream, inst, .func),
390388
391 .switch_block => try self.writeSwitchBlock(stream, inst),389 .switch_block,
390 .switch_block_ref,
391 => try self.writeSwitchBlock(stream, inst),
392392
393 .field_ptr,393 .field_ptr,
394 .field_ptr_init,394 .field_ptr_init,