| author | |
| committer | |
| log | 85e94fed1e058720460560823ac09d7b64e49b97 |
| tree | df28ab8360a7cbdf32005532349b72e4713ef097 |
| parent | 39510cc7d1f6035e16aaa4f97991abbaddef463c |
| signature | Commit is signed but in an unrecognized format. |
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 }; |
| 6836 | 6835 | ||
| 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 }; |
| 6843 | 6838 | ||
| 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); |
| 6860 | 6855 | ||
| 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); | ||
| 6863 | 6861 | ||
| 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); |
| 7077 | 7075 | ||
| 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 | }, | ||
| 2021 | 1996 | ||
| 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 | }; |
| 10413 | 10412 | ||
| 10414 | fn zirSwitchCond( | 10413 | fn 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( |
| 10484 | 10474 | ||
| 10485 | const SwitchErrorSet = std.AutoHashMap(InternPool.NullTerminatedString, Module.SwitchProngSrc); | 10475 | const SwitchErrorSet = std.AutoHashMap(InternPool.NullTerminatedString, Module.SwitchProngSrc); |
| 10486 | 10476 | ||
| 10487 | fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 10477 | fn 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(); |
| 10490 | 10480 | ||
| ... | @@ -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); |
| 10500 | 10490 | ||
| 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 following | 10492 | const maybe_ptr = try sema.resolveInst(extra.data.operand); |
| 10503 | // switch_cond(_ref) is a dbg_stmt | 10493 | 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; | ||
| 10505 | 10506 | ||
| 10506 | var header_extra_index: usize = extra.end; | 10507 | var header_extra_index: usize = extra.end; |
| 10507 | 10508 | ||
| ... | @@ -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 | }; |
| 10557 | 10558 | ||
| 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; |
| 10573 | 10561 |
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, for | 670 | /// A switch expression. Uses the `pl_node` union field. |
| 671 | /// integers, it returns the integer with no modifications. For tagged unions, it | 671 | /// 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 a | 673 | /// Given a |
| 680 | /// *A returns *A | 674 | /// *A returns *A |
| 681 | /// *E!A returns *A | 675 | /// *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 value | 2656 | /// 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, |
| 2677 | 2665 |
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), |
| 390 | 388 | ||
| 391 | .switch_block => try self.writeSwitchBlock(stream, inst), | 389 | .switch_block, |
| 390 | .switch_block_ref, | ||
| 391 | => try self.writeSwitchBlock(stream, inst), | ||
| 392 | 392 | ||
| 393 | .field_ptr, | 393 | .field_ptr, |
| 394 | .field_ptr_init, | 394 | .field_ptr_init, |