motiejus/zig

fork of https://codeberg.org/ziglang/zig
git clone https://git.jakstys.lt/motiejus/zig.git
Log | Tree | Refs | README | LICENSE

src/print_zir.zig (120739B) - Raw


      1 const std = @import("std");
      2 const mem = std.mem;
      3 const Allocator = std.mem.Allocator;
      4 const assert = std.debug.assert;
      5 const Ast = std.zig.Ast;
      6 const InternPool = @import("InternPool.zig");
      7 
      8 const Zir = std.zig.Zir;
      9 const Zcu = @import("Zcu.zig");
     10 const LazySrcLoc = Zcu.LazySrcLoc;
     11 
     12 /// Write human-readable, debug formatted ZIR code.
     13 pub fn renderAsText(gpa: Allocator, tree: ?Ast, zir: Zir, bw: *std.Io.Writer) !void {
     14     var arena = std.heap.ArenaAllocator.init(gpa);
     15     defer arena.deinit();
     16 
     17     var writer: Writer = .{
     18         .gpa = gpa,
     19         .arena = arena.allocator(),
     20         .tree = tree,
     21         .code = zir,
     22         .indent = 0,
     23         .parent_decl_node = .root,
     24         .recurse_decls = true,
     25         .recurse_blocks = true,
     26     };
     27 
     28     const main_struct_inst: Zir.Inst.Index = .main_struct_inst;
     29     try bw.print("%{d} ", .{@intFromEnum(main_struct_inst)});
     30     try writer.writeInstToStream(bw, main_struct_inst);
     31     try bw.writeAll("\n");
     32     const imports_index = zir.extra[@intFromEnum(Zir.ExtraIndex.imports)];
     33     if (imports_index != 0) {
     34         try bw.writeAll("Imports:\n");
     35 
     36         const extra = zir.extraData(Zir.Inst.Imports, imports_index);
     37         var extra_index = extra.end;
     38 
     39         for (0..extra.data.imports_len) |_| {
     40             const item = zir.extraData(Zir.Inst.Imports.Item, extra_index);
     41             extra_index = item.end;
     42 
     43             const import_path = zir.nullTerminatedString(item.data.name);
     44             try bw.print("  @import(\"{f}\") ", .{
     45                 std.zig.fmtString(import_path),
     46             });
     47             try writer.writeSrcTokAbs(bw, item.data.token);
     48             try bw.writeAll("\n");
     49         }
     50     }
     51 }
     52 
     53 pub fn renderInstructionContext(
     54     gpa: Allocator,
     55     block: []const Zir.Inst.Index,
     56     block_index: usize,
     57     scope_file: *Zcu.File,
     58     parent_decl_node: Ast.Node.Index,
     59     indent: u32,
     60     bw: *std.Io.Writer,
     61 ) !void {
     62     var arena = std.heap.ArenaAllocator.init(gpa);
     63     defer arena.deinit();
     64 
     65     var writer: Writer = .{
     66         .gpa = gpa,
     67         .arena = arena.allocator(),
     68         .tree = scope_file.tree,
     69         .code = scope_file.zir.?,
     70         .indent = if (indent < 2) 2 else indent,
     71         .parent_decl_node = parent_decl_node,
     72         .recurse_decls = false,
     73         .recurse_blocks = true,
     74     };
     75 
     76     try writer.writeBody(bw, block[0..block_index]);
     77     try bw.splatByteAll(' ', writer.indent - 2);
     78     try bw.print("> %{d} ", .{@intFromEnum(block[block_index])});
     79     try writer.writeInstToStream(bw, block[block_index]);
     80     try bw.writeByte('\n');
     81     if (block_index + 1 < block.len) {
     82         try writer.writeBody(bw, block[block_index + 1 ..]);
     83     }
     84 }
     85 
     86 pub fn renderSingleInstruction(
     87     gpa: Allocator,
     88     inst: Zir.Inst.Index,
     89     scope_file: *Zcu.File,
     90     parent_decl_node: Ast.Node.Index,
     91     indent: u32,
     92     bw: *std.Io.Writer,
     93 ) !void {
     94     var arena = std.heap.ArenaAllocator.init(gpa);
     95     defer arena.deinit();
     96 
     97     var writer: Writer = .{
     98         .gpa = gpa,
     99         .arena = arena.allocator(),
    100         .tree = scope_file.tree,
    101         .code = scope_file.zir.?,
    102         .indent = indent,
    103         .parent_decl_node = parent_decl_node,
    104         .recurse_decls = false,
    105         .recurse_blocks = false,
    106     };
    107 
    108     try bw.print("%{d} ", .{@intFromEnum(inst)});
    109     try writer.writeInstToStream(bw, inst);
    110 }
    111 
    112 const Writer = struct {
    113     gpa: Allocator,
    114     arena: Allocator,
    115     tree: ?Ast,
    116     code: Zir,
    117     indent: u32,
    118     parent_decl_node: Ast.Node.Index,
    119     recurse_decls: bool,
    120     recurse_blocks: bool,
    121 
    122     /// Using `std.zig.findLineColumn` whenever we need to resolve a source location makes ZIR
    123     /// printing O(N^2), which can have drastic effects - taking a ZIR dump from a few seconds to
    124     /// many minutes. Since we're usually resolving source locations close to one another,
    125     /// preserving state across source location resolutions speeds things up a lot.
    126     line_col_cursor: struct {
    127         line: usize = 0,
    128         column: usize = 0,
    129         line_start: usize = 0,
    130         off: usize = 0,
    131 
    132         fn find(cur: *@This(), source: []const u8, want_offset: usize) std.zig.Loc {
    133             if (want_offset < cur.off) {
    134                 // Go back to the start of this line
    135                 cur.off = cur.line_start;
    136                 cur.column = 0;
    137 
    138                 while (want_offset < cur.off) {
    139                     // Go back to the newline
    140                     cur.off -= 1;
    141 
    142                     // Seek to the start of the previous line
    143                     while (cur.off > 0 and source[cur.off - 1] != '\n') {
    144                         cur.off -= 1;
    145                     }
    146                     cur.line_start = cur.off;
    147                     cur.line -= 1;
    148                 }
    149             }
    150 
    151             // The cursor is now positioned before `want_offset`.
    152             // Seek forward as in `std.zig.findLineColumn`.
    153 
    154             while (cur.off < want_offset) : (cur.off += 1) {
    155                 switch (source[cur.off]) {
    156                     '\n' => {
    157                         cur.line += 1;
    158                         cur.column = 0;
    159                         cur.line_start = cur.off + 1;
    160                     },
    161                     else => {
    162                         cur.column += 1;
    163                     },
    164                 }
    165             }
    166 
    167             while (cur.off < source.len and source[cur.off] != '\n') {
    168                 cur.off += 1;
    169             }
    170 
    171             return .{
    172                 .line = cur.line,
    173                 .column = cur.column,
    174                 .source_line = source[cur.line_start..cur.off],
    175             };
    176         }
    177     } = .{},
    178 
    179     const Error = std.Io.Writer.Error || Allocator.Error;
    180 
    181     fn writeInstToStream(
    182         self: *Writer,
    183         stream: *std.Io.Writer,
    184         inst: Zir.Inst.Index,
    185     ) Error!void {
    186         const tags = self.code.instructions.items(.tag);
    187         const tag = tags[@intFromEnum(inst)];
    188         try stream.print("= {s}(", .{@tagName(tags[@intFromEnum(inst)])});
    189         switch (tag) {
    190             .alloc,
    191             .alloc_mut,
    192             .alloc_comptime_mut,
    193             .elem_type,
    194             .indexable_ptr_elem_type,
    195             .splat_op_result_ty,
    196             .indexable_ptr_len,
    197             .anyframe_type,
    198             .bit_not,
    199             .bool_not,
    200             .slice_sentinel_ty,
    201             .negate,
    202             .negate_wrap,
    203             .load,
    204             .ensure_result_used,
    205             .ensure_result_non_error,
    206             .ensure_err_union_payload_void,
    207             .ret_node,
    208             .ret_load,
    209             .resolve_inferred_alloc,
    210             .optional_type,
    211             .optional_payload_safe,
    212             .optional_payload_unsafe,
    213             .optional_payload_safe_ptr,
    214             .optional_payload_unsafe_ptr,
    215             .err_union_payload_unsafe,
    216             .err_union_payload_unsafe_ptr,
    217             .err_union_code,
    218             .err_union_code_ptr,
    219             .is_non_null,
    220             .is_non_null_ptr,
    221             .is_non_err,
    222             .is_non_err_ptr,
    223             .ret_is_non_err,
    224             .typeof,
    225             .type_info,
    226             .size_of,
    227             .bit_size_of,
    228             .typeof_log2_int_type,
    229             .int_from_ptr,
    230             .compile_error,
    231             .set_eval_branch_quota,
    232             .int_from_enum,
    233             .align_of,
    234             .int_from_bool,
    235             .embed_file,
    236             .error_name,
    237             .panic,
    238             .set_runtime_safety,
    239             .sqrt,
    240             .sin,
    241             .cos,
    242             .tan,
    243             .exp,
    244             .exp2,
    245             .log,
    246             .log2,
    247             .log10,
    248             .abs,
    249             .floor,
    250             .ceil,
    251             .trunc,
    252             .round,
    253             .tag_name,
    254             .type_name,
    255             .frame_type,
    256             .clz,
    257             .ctz,
    258             .pop_count,
    259             .byte_swap,
    260             .bit_reverse,
    261             .@"resume",
    262             .make_ptr_const,
    263             .validate_deref,
    264             .validate_const,
    265             .check_comptime_control_flow,
    266             .opt_eu_base_ptr_init,
    267             .restore_err_ret_index_unconditional,
    268             .restore_err_ret_index_fn_entry,
    269             => try self.writeUnNode(stream, inst),
    270 
    271             .ref,
    272             .ret_implicit,
    273             .validate_ref_ty,
    274             => try self.writeUnTok(stream, inst),
    275 
    276             .bool_br_and,
    277             .bool_br_or,
    278             => try self.writeBoolBr(stream, inst),
    279 
    280             .validate_destructure => try self.writeValidateDestructure(stream, inst),
    281             .array_type_sentinel => try self.writeArrayTypeSentinel(stream, inst),
    282             .ptr_type => try self.writePtrType(stream, inst),
    283             .int => try self.writeInt(stream, inst),
    284             .int_big => try self.writeIntBig(stream, inst),
    285             .float => try self.writeFloat(stream, inst),
    286             .float128 => try self.writeFloat128(stream, inst),
    287             .str => try self.writeStr(stream, inst),
    288             .int_type => try self.writeIntType(stream, inst),
    289 
    290             .save_err_ret_index => try self.writeSaveErrRetIndex(stream, inst),
    291 
    292             .@"break",
    293             .break_inline,
    294             .switch_continue,
    295             => try self.writeBreak(stream, inst),
    296 
    297             .slice_start => try self.writeSliceStart(stream, inst),
    298             .slice_end => try self.writeSliceEnd(stream, inst),
    299             .slice_sentinel => try self.writeSliceSentinel(stream, inst),
    300             .slice_length => try self.writeSliceLength(stream, inst),
    301 
    302             .union_init => try self.writeUnionInit(stream, inst),
    303 
    304             // Struct inits
    305 
    306             .struct_init_empty,
    307             .struct_init_empty_result,
    308             .struct_init_empty_ref_result,
    309             => try self.writeUnNode(stream, inst),
    310 
    311             .struct_init_anon => try self.writeStructInitAnon(stream, inst),
    312 
    313             .struct_init,
    314             .struct_init_ref,
    315             => try self.writeStructInit(stream, inst),
    316 
    317             .validate_struct_init_ty,
    318             .validate_struct_init_result_ty,
    319             => try self.writeUnNode(stream, inst),
    320 
    321             .validate_ptr_struct_init => try self.writeBlock(stream, inst),
    322             .struct_init_field_type => try self.writeStructInitFieldType(stream, inst),
    323             .struct_init_field_ptr => try self.writePlNodeField(stream, inst),
    324 
    325             // Array inits
    326 
    327             .array_init_anon => try self.writeArrayInitAnon(stream, inst),
    328 
    329             .array_init,
    330             .array_init_ref,
    331             => try self.writeArrayInit(stream, inst),
    332 
    333             .validate_array_init_ty,
    334             .validate_array_init_result_ty,
    335             => try self.writeValidateArrayInitTy(stream, inst),
    336 
    337             .validate_array_init_ref_ty => try self.writeValidateArrayInitRefTy(stream, inst),
    338             .validate_ptr_array_init => try self.writeBlock(stream, inst),
    339             .array_init_elem_type => try self.writeArrayInitElemType(stream, inst),
    340             .array_init_elem_ptr => try self.writeArrayInitElemPtr(stream, inst),
    341 
    342             .atomic_load => try self.writeAtomicLoad(stream, inst),
    343             .atomic_store => try self.writeAtomicStore(stream, inst),
    344             .atomic_rmw => try self.writeAtomicRmw(stream, inst),
    345             .shuffle => try self.writeShuffle(stream, inst),
    346             .mul_add => try self.writeMulAdd(stream, inst),
    347             .builtin_call => try self.writeBuiltinCall(stream, inst),
    348 
    349             .field_type_ref => try self.writeFieldTypeRef(stream, inst),
    350 
    351             .add,
    352             .addwrap,
    353             .add_sat,
    354             .add_unsafe,
    355             .array_cat,
    356             .mul,
    357             .mulwrap,
    358             .mul_sat,
    359             .sub,
    360             .subwrap,
    361             .sub_sat,
    362             .cmp_lt,
    363             .cmp_lte,
    364             .cmp_eq,
    365             .cmp_gte,
    366             .cmp_gt,
    367             .cmp_neq,
    368             .div,
    369             .has_decl,
    370             .has_field,
    371             .mod_rem,
    372             .shl,
    373             .shl_exact,
    374             .shl_sat,
    375             .shr,
    376             .shr_exact,
    377             .xor,
    378             .store_node,
    379             .store_to_inferred_ptr,
    380             .error_union_type,
    381             .merge_error_sets,
    382             .bit_and,
    383             .bit_or,
    384             .int_from_float,
    385             .float_from_int,
    386             .ptr_from_int,
    387             .enum_from_int,
    388             .float_cast,
    389             .int_cast,
    390             .ptr_cast,
    391             .truncate,
    392             .div_exact,
    393             .div_floor,
    394             .div_trunc,
    395             .mod,
    396             .rem,
    397             .bit_offset_of,
    398             .offset_of,
    399             .splat,
    400             .reduce,
    401             .bitcast,
    402             .reify_int,
    403             .vector_type,
    404             .max,
    405             .min,
    406             .memcpy,
    407             .memset,
    408             .memmove,
    409             .elem_ptr_node,
    410             .elem_ptr_load,
    411             .elem_ptr,
    412             .elem_val,
    413             .array_type,
    414             .coerce_ptr_elem_ty,
    415             => try self.writePlNodeBin(stream, inst),
    416 
    417             .for_len => try self.writePlNodeMultiOp(stream, inst),
    418 
    419             .array_mul => try self.writeArrayMul(stream, inst),
    420 
    421             .elem_val_imm => try self.writeElemValImm(stream, inst),
    422 
    423             .@"export" => try self.writePlNodeExport(stream, inst),
    424 
    425             .call => try self.writeCall(stream, inst, .direct),
    426             .field_call => try self.writeCall(stream, inst, .field),
    427 
    428             .block,
    429             .block_inline,
    430             .suspend_block,
    431             .loop,
    432             .c_import,
    433             .typeof_builtin,
    434             => try self.writeBlock(stream, inst),
    435 
    436             .block_comptime => try self.writeBlockComptime(stream, inst),
    437 
    438             .condbr,
    439             .condbr_inline,
    440             => try self.writeCondBr(stream, inst),
    441 
    442             .@"try",
    443             .try_ptr,
    444             => try self.writeTry(stream, inst),
    445 
    446             .error_set_decl => try self.writeErrorSetDecl(stream, inst),
    447 
    448             .switch_block,
    449             .switch_block_ref,
    450             => try self.writeSwitchBlock(stream, inst),
    451 
    452             .switch_block_err_union => try self.writeSwitchBlockErrUnion(stream, inst),
    453 
    454             .field_ptr_load,
    455             .field_ptr,
    456             .decl_literal,
    457             .decl_literal_no_coerce,
    458             => try self.writePlNodeField(stream, inst),
    459 
    460             .field_ptr_named,
    461             .field_ptr_named_load,
    462             => try self.writePlNodeFieldNamed(stream, inst),
    463 
    464             .as_node, .as_shift_operand => try self.writeAs(stream, inst),
    465 
    466             .repeat,
    467             .repeat_inline,
    468             .alloc_inferred,
    469             .alloc_inferred_mut,
    470             .alloc_inferred_comptime,
    471             .alloc_inferred_comptime_mut,
    472             .ret_ptr,
    473             .ret_type,
    474             .trap,
    475             => try self.writeNode(stream, inst),
    476 
    477             .error_value,
    478             .enum_literal,
    479             .decl_ref,
    480             .decl_val,
    481             .ret_err_value,
    482             .ret_err_value_code,
    483             .param_anytype,
    484             .param_anytype_comptime,
    485             => try self.writeStrTok(stream, inst),
    486 
    487             .dbg_var_ptr,
    488             .dbg_var_val,
    489             => try self.writeStrOp(stream, inst),
    490 
    491             .param, .param_comptime => try self.writeParam(stream, inst),
    492 
    493             .func => try self.writeFunc(stream, inst, false),
    494             .func_inferred => try self.writeFunc(stream, inst, true),
    495             .func_fancy => try self.writeFuncFancy(stream, inst),
    496 
    497             .@"unreachable" => try self.writeUnreachable(stream, inst),
    498 
    499             .dbg_stmt => try self.writeDbgStmt(stream, inst),
    500 
    501             .@"defer" => try self.writeDefer(stream, inst),
    502             .defer_err_code => try self.writeDeferErrCode(stream, inst),
    503 
    504             .declaration => try self.writeDeclaration(stream, inst),
    505 
    506             .extended => try self.writeExtended(stream, inst),
    507 
    508             .import => try self.writeImport(stream, inst),
    509         }
    510     }
    511 
    512     fn writeExtended(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
    513         const extended = self.code.instructions.items(.data)[@intFromEnum(inst)].extended;
    514         try stream.print("{s}(", .{@tagName(extended.opcode)});
    515         switch (extended.opcode) {
    516             .this,
    517             .ret_addr,
    518             .error_return_trace,
    519             .frame,
    520             .frame_address,
    521             .breakpoint,
    522             .disable_instrumentation,
    523             .disable_intrinsics,
    524             .c_va_start,
    525             .in_comptime,
    526             .value_placeholder,
    527             => try self.writeExtNode(stream, extended),
    528 
    529             .builtin_src => {
    530                 try stream.writeAll("))");
    531                 const inst_data = self.code.extraData(Zir.Inst.LineColumn, extended.operand).data;
    532                 try stream.print(":{d}:{d}", .{ inst_data.line + 1, inst_data.column + 1 });
    533             },
    534 
    535             .@"asm" => try self.writeAsm(stream, extended, false),
    536             .asm_expr => try self.writeAsm(stream, extended, true),
    537             .alloc => try self.writeAllocExtended(stream, extended),
    538 
    539             .compile_log => try self.writeNodeMultiOp(stream, extended),
    540             .typeof_peer => try self.writeTypeofPeer(stream, extended),
    541             .min_multi => try self.writeNodeMultiOp(stream, extended),
    542             .max_multi => try self.writeNodeMultiOp(stream, extended),
    543 
    544             .select => try self.writeSelect(stream, extended),
    545 
    546             .add_with_overflow,
    547             .sub_with_overflow,
    548             .mul_with_overflow,
    549             .shl_with_overflow,
    550             => try self.writeOverflowArithmetic(stream, extended),
    551 
    552             .struct_decl => try self.writeStructDecl(stream, extended),
    553             .union_decl => try self.writeUnionDecl(stream, extended),
    554             .enum_decl => try self.writeEnumDecl(stream, extended),
    555             .opaque_decl => try self.writeOpaqueDecl(stream, extended),
    556 
    557             .tuple_decl => try self.writeTupleDecl(stream, extended),
    558 
    559             .c_undef,
    560             .c_include,
    561             .set_float_mode,
    562             .wasm_memory_size,
    563             .int_from_error,
    564             .error_from_int,
    565             .c_va_copy,
    566             .c_va_end,
    567             .work_item_id,
    568             .work_group_size,
    569             .work_group_id,
    570             .branch_hint,
    571             .float_op_result_ty,
    572             .reify_tuple,
    573             .reify_pointer_sentinel_ty,
    574             => {
    575                 const inst_data = self.code.extraData(Zir.Inst.UnNode, extended.operand).data;
    576                 try self.writeInstRef(stream, inst_data.operand);
    577                 try stream.writeAll(")) ");
    578                 try self.writeSrcNode(stream, inst_data.node);
    579             },
    580 
    581             .builtin_extern,
    582             .c_define,
    583             .error_cast,
    584             .wasm_memory_grow,
    585             .prefetch,
    586             .c_va_arg,
    587             .reify_enum_value_slice_ty,
    588             => {
    589                 const inst_data = self.code.extraData(Zir.Inst.BinNode, extended.operand).data;
    590                 try self.writeInstRef(stream, inst_data.lhs);
    591                 try stream.writeAll(", ");
    592                 try self.writeInstRef(stream, inst_data.rhs);
    593                 try stream.writeAll(")) ");
    594                 try self.writeSrcNode(stream, inst_data.node);
    595             },
    596 
    597             .reify_slice_arg_ty => {
    598                 const reify_slice_arg_info: Zir.Inst.ReifySliceArgInfo = @enumFromInt(extended.operand);
    599                 const extra = self.code.extraData(Zir.Inst.UnNode, extended.operand).data;
    600                 try stream.print("{t}, ", .{reify_slice_arg_info});
    601                 try self.writeInstRef(stream, extra.operand);
    602                 try stream.writeAll(")) ");
    603                 try self.writeSrcNode(stream, extra.node);
    604             },
    605 
    606             .reify_pointer => {
    607                 const extra = self.code.extraData(Zir.Inst.ReifyPointer, extended.operand).data;
    608                 try self.writeInstRef(stream, extra.size);
    609                 try stream.writeAll(", ");
    610                 try self.writeInstRef(stream, extra.attrs);
    611                 try stream.writeAll(", ");
    612                 try self.writeInstRef(stream, extra.elem_ty);
    613                 try stream.writeAll(", ");
    614                 try self.writeInstRef(stream, extra.sentinel);
    615                 try stream.writeAll(")) ");
    616                 try self.writeSrcNode(stream, extra.node);
    617             },
    618             .reify_fn => {
    619                 const extra = self.code.extraData(Zir.Inst.ReifyFn, extended.operand).data;
    620                 try self.writeInstRef(stream, extra.param_types);
    621                 try stream.writeAll(", ");
    622                 try self.writeInstRef(stream, extra.param_attrs);
    623                 try stream.writeAll(", ");
    624                 try self.writeInstRef(stream, extra.ret_ty);
    625                 try stream.writeAll(", ");
    626                 try self.writeInstRef(stream, extra.fn_attrs);
    627                 try stream.writeAll(")) ");
    628                 try self.writeSrcNode(stream, extra.node);
    629             },
    630             .reify_struct => {
    631                 const extra = self.code.extraData(Zir.Inst.ReifyStruct, extended.operand).data;
    632                 const name_strat: Zir.Inst.NameStrategy = @enumFromInt(extended.small);
    633                 try stream.print("line({d}), {t}, ", .{ extra.src_line, name_strat });
    634                 try self.writeInstRef(stream, extra.layout);
    635                 try stream.writeAll(", ");
    636                 try self.writeInstRef(stream, extra.backing_ty);
    637                 try stream.writeAll(", ");
    638                 try self.writeInstRef(stream, extra.field_names);
    639                 try stream.writeAll(", ");
    640                 try self.writeInstRef(stream, extra.field_types);
    641                 try stream.writeAll(", ");
    642                 try self.writeInstRef(stream, extra.field_attrs);
    643                 try stream.writeAll(")) ");
    644                 const prev_parent_decl_node = self.parent_decl_node;
    645                 self.parent_decl_node = extra.node;
    646                 defer self.parent_decl_node = prev_parent_decl_node;
    647                 try self.writeSrcNode(stream, .zero);
    648             },
    649             .reify_union => {
    650                 const extra = self.code.extraData(Zir.Inst.ReifyUnion, extended.operand).data;
    651                 const name_strat: Zir.Inst.NameStrategy = @enumFromInt(extended.small);
    652                 try stream.print("line({d}), {t}, ", .{ extra.src_line, name_strat });
    653                 try self.writeInstRef(stream, extra.layout);
    654                 try stream.writeAll(", ");
    655                 try self.writeInstRef(stream, extra.arg_ty);
    656                 try stream.writeAll(", ");
    657                 try self.writeInstRef(stream, extra.field_names);
    658                 try stream.writeAll(", ");
    659                 try self.writeInstRef(stream, extra.field_types);
    660                 try stream.writeAll(", ");
    661                 try self.writeInstRef(stream, extra.field_attrs);
    662                 try stream.writeAll(")) ");
    663                 const prev_parent_decl_node = self.parent_decl_node;
    664                 self.parent_decl_node = extra.node;
    665                 defer self.parent_decl_node = prev_parent_decl_node;
    666                 try self.writeSrcNode(stream, .zero);
    667             },
    668             .reify_enum => {
    669                 const extra = self.code.extraData(Zir.Inst.ReifyEnum, extended.operand).data;
    670                 const name_strat: Zir.Inst.NameStrategy = @enumFromInt(extended.small);
    671                 try stream.print("line({d}), {t}, ", .{ extra.src_line, name_strat });
    672                 try self.writeInstRef(stream, extra.tag_ty);
    673                 try stream.writeAll(", ");
    674                 try self.writeInstRef(stream, extra.mode);
    675                 try stream.writeAll(", ");
    676                 try self.writeInstRef(stream, extra.field_names);
    677                 try stream.writeAll(", ");
    678                 try self.writeInstRef(stream, extra.field_values);
    679                 try stream.writeAll(")) ");
    680                 const prev_parent_decl_node = self.parent_decl_node;
    681                 self.parent_decl_node = extra.node;
    682                 defer self.parent_decl_node = prev_parent_decl_node;
    683                 try self.writeSrcNode(stream, .zero);
    684             },
    685 
    686             .cmpxchg => try self.writeCmpxchg(stream, extended),
    687             .ptr_cast_full => try self.writePtrCastFull(stream, extended),
    688             .ptr_cast_no_dest => try self.writePtrCastNoDest(stream, extended),
    689 
    690             .restore_err_ret_index => try self.writeRestoreErrRetIndex(stream, extended),
    691             .closure_get => try self.writeClosureGet(stream, extended),
    692             .field_parent_ptr => try self.writeFieldParentPtr(stream, extended),
    693             .builtin_value => try self.writeBuiltinValue(stream, extended),
    694             .inplace_arith_result_ty => try self.writeInplaceArithResultTy(stream, extended),
    695 
    696             .dbg_empty_stmt => try stream.writeAll("))"),
    697             .astgen_error => try stream.writeAll("))"),
    698         }
    699     }
    700 
    701     fn writeExtNode(self: *Writer, stream: *std.Io.Writer, extended: Zir.Inst.Extended.InstData) !void {
    702         try stream.writeAll(")) ");
    703         const src_node: Ast.Node.Offset = @enumFromInt(@as(i32, @bitCast(extended.operand)));
    704         try self.writeSrcNode(stream, src_node);
    705     }
    706 
    707     fn writeArrayInitElemType(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
    708         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].bin;
    709         try self.writeInstRef(stream, inst_data.lhs);
    710         try stream.print(", {d})", .{@intFromEnum(inst_data.rhs)});
    711     }
    712 
    713     fn writeUnNode(
    714         self: *Writer,
    715         stream: *std.Io.Writer,
    716         inst: Zir.Inst.Index,
    717     ) Error!void {
    718         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
    719         try self.writeInstRef(stream, inst_data.operand);
    720         try stream.writeAll(") ");
    721         try self.writeSrcNode(stream, inst_data.src_node);
    722     }
    723 
    724     fn writeUnTok(
    725         self: *Writer,
    726         stream: *std.Io.Writer,
    727         inst: Zir.Inst.Index,
    728     ) Error!void {
    729         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].un_tok;
    730         try self.writeInstRef(stream, inst_data.operand);
    731         try stream.writeAll(") ");
    732         try self.writeSrcTok(stream, inst_data.src_tok);
    733     }
    734 
    735     fn writeValidateDestructure(
    736         self: *Writer,
    737         stream: *std.Io.Writer,
    738         inst: Zir.Inst.Index,
    739     ) Error!void {
    740         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
    741         const extra = self.code.extraData(Zir.Inst.ValidateDestructure, inst_data.payload_index).data;
    742         try self.writeInstRef(stream, extra.operand);
    743         try stream.print(", {d}) (destructure=", .{extra.expect_len});
    744         try self.writeSrcNode(stream, extra.destructure_node);
    745         try stream.writeAll(") ");
    746         try self.writeSrcNode(stream, inst_data.src_node);
    747     }
    748 
    749     fn writeValidateArrayInitTy(
    750         self: *Writer,
    751         stream: *std.Io.Writer,
    752         inst: Zir.Inst.Index,
    753     ) Error!void {
    754         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
    755         const extra = self.code.extraData(Zir.Inst.ArrayInit, inst_data.payload_index).data;
    756         try self.writeInstRef(stream, extra.ty);
    757         try stream.print(", {d}) ", .{extra.init_count});
    758         try self.writeSrcNode(stream, inst_data.src_node);
    759     }
    760 
    761     fn writeArrayTypeSentinel(
    762         self: *Writer,
    763         stream: *std.Io.Writer,
    764         inst: Zir.Inst.Index,
    765     ) Error!void {
    766         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
    767         const extra = self.code.extraData(Zir.Inst.ArrayTypeSentinel, inst_data.payload_index).data;
    768         try self.writeInstRef(stream, extra.len);
    769         try stream.writeAll(", ");
    770         try self.writeInstRef(stream, extra.sentinel);
    771         try stream.writeAll(", ");
    772         try self.writeInstRef(stream, extra.elem_type);
    773         try stream.writeAll(") ");
    774         try self.writeSrcNode(stream, inst_data.src_node);
    775     }
    776 
    777     fn writePtrType(
    778         self: *Writer,
    779         stream: *std.Io.Writer,
    780         inst: Zir.Inst.Index,
    781     ) Error!void {
    782         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].ptr_type;
    783         const str_allowzero = if (inst_data.flags.is_allowzero) "allowzero, " else "";
    784         const str_const = if (!inst_data.flags.is_mutable) "const, " else "";
    785         const str_volatile = if (inst_data.flags.is_volatile) "volatile, " else "";
    786         const extra = self.code.extraData(Zir.Inst.PtrType, inst_data.payload_index);
    787         try self.writeInstRef(stream, extra.data.elem_type);
    788         try stream.print(", {s}{s}{s}{s}", .{
    789             str_allowzero,
    790             str_const,
    791             str_volatile,
    792             @tagName(inst_data.size),
    793         });
    794         var extra_index = extra.end;
    795         if (inst_data.flags.has_sentinel) {
    796             try stream.writeAll(", ");
    797             try self.writeInstRef(stream, @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index])));
    798             extra_index += 1;
    799         }
    800         if (inst_data.flags.has_align) {
    801             try stream.writeAll(", align(");
    802             try self.writeInstRef(stream, @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index])));
    803             extra_index += 1;
    804             if (inst_data.flags.has_bit_range) {
    805                 const bit_start = extra_index + @intFromBool(inst_data.flags.has_addrspace);
    806                 try stream.writeAll(":");
    807                 try self.writeInstRef(stream, @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[bit_start])));
    808                 try stream.writeAll(":");
    809                 try self.writeInstRef(stream, @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[bit_start + 1])));
    810             }
    811             try stream.writeAll(")");
    812         }
    813         if (inst_data.flags.has_addrspace) {
    814             try stream.writeAll(", addrspace(");
    815             try self.writeInstRef(stream, @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index])));
    816             try stream.writeAll(")");
    817         }
    818         try stream.writeAll(") ");
    819         try self.writeSrcNode(stream, extra.data.src_node);
    820     }
    821 
    822     fn writeInt(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
    823         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].int;
    824         try stream.print("{d})", .{inst_data});
    825     }
    826 
    827     fn writeIntBig(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
    828         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].str;
    829         const byte_count = inst_data.len * @sizeOf(std.math.big.Limb);
    830         const limb_bytes = self.code.string_bytes[@intFromEnum(inst_data.start)..][0..byte_count];
    831         // limb_bytes is not aligned properly; we must allocate and copy the bytes
    832         // in order to accomplish this.
    833         const limbs = try self.gpa.alloc(std.math.big.Limb, inst_data.len);
    834         defer self.gpa.free(limbs);
    835 
    836         @memcpy(mem.sliceAsBytes(limbs), limb_bytes);
    837         const big_int: std.math.big.int.Const = .{
    838             .limbs = limbs,
    839             .positive = true,
    840         };
    841         const as_string = try big_int.toStringAlloc(self.gpa, 10, .lower);
    842         defer self.gpa.free(as_string);
    843         try stream.print("{s})", .{as_string});
    844     }
    845 
    846     fn writeFloat(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
    847         const number = self.code.instructions.items(.data)[@intFromEnum(inst)].float;
    848         try stream.print("{d})", .{number});
    849     }
    850 
    851     fn writeFloat128(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
    852         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
    853         const extra = self.code.extraData(Zir.Inst.Float128, inst_data.payload_index).data;
    854         const number = extra.get();
    855         // TODO improve std.format to be able to print f128 values
    856         try stream.print("{d}) ", .{@as(f64, @floatCast(number))});
    857         try self.writeSrcNode(stream, inst_data.src_node);
    858     }
    859 
    860     fn writeStr(
    861         self: *Writer,
    862         stream: *std.Io.Writer,
    863         inst: Zir.Inst.Index,
    864     ) Error!void {
    865         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].str;
    866         const str = inst_data.get(self.code);
    867         try stream.print("\"{f}\")", .{std.zig.fmtString(str)});
    868     }
    869 
    870     fn writeSliceStart(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
    871         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
    872         const extra = self.code.extraData(Zir.Inst.SliceStart, inst_data.payload_index).data;
    873         try self.writeInstRef(stream, extra.lhs);
    874         try stream.writeAll(", ");
    875         try self.writeInstRef(stream, extra.start);
    876         try stream.writeAll(") ");
    877         try self.writeSrcNode(stream, inst_data.src_node);
    878     }
    879 
    880     fn writeSliceEnd(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
    881         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
    882         const extra = self.code.extraData(Zir.Inst.SliceEnd, inst_data.payload_index).data;
    883         try self.writeInstRef(stream, extra.lhs);
    884         try stream.writeAll(", ");
    885         try self.writeInstRef(stream, extra.start);
    886         try stream.writeAll(", ");
    887         try self.writeInstRef(stream, extra.end);
    888         try stream.writeAll(") ");
    889         try self.writeSrcNode(stream, inst_data.src_node);
    890     }
    891 
    892     fn writeSliceSentinel(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
    893         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
    894         const extra = self.code.extraData(Zir.Inst.SliceSentinel, inst_data.payload_index).data;
    895         try self.writeInstRef(stream, extra.lhs);
    896         try stream.writeAll(", ");
    897         try self.writeInstRef(stream, extra.start);
    898         try stream.writeAll(", ");
    899         try self.writeInstRef(stream, extra.end);
    900         try stream.writeAll(", ");
    901         try self.writeInstRef(stream, extra.sentinel);
    902         try stream.writeAll(") ");
    903         try self.writeSrcNode(stream, inst_data.src_node);
    904     }
    905 
    906     fn writeSliceLength(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
    907         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
    908         const extra = self.code.extraData(Zir.Inst.SliceLength, inst_data.payload_index).data;
    909         try self.writeInstRef(stream, extra.lhs);
    910         try stream.writeAll(", ");
    911         try self.writeInstRef(stream, extra.start);
    912         try stream.writeAll(", ");
    913         try self.writeInstRef(stream, extra.len);
    914         if (extra.sentinel != .none) {
    915             try stream.writeAll(", ");
    916             try self.writeInstRef(stream, extra.sentinel);
    917         }
    918         try stream.writeAll(") ");
    919         try self.writeSrcNode(stream, inst_data.src_node);
    920     }
    921 
    922     fn writeUnionInit(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
    923         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
    924         const extra = self.code.extraData(Zir.Inst.UnionInit, inst_data.payload_index).data;
    925         try self.writeInstRef(stream, extra.union_type);
    926         try stream.writeAll(", ");
    927         try self.writeInstRef(stream, extra.field_name);
    928         try stream.writeAll(", ");
    929         try self.writeInstRef(stream, extra.init);
    930         try stream.writeAll(") ");
    931         try self.writeSrcNode(stream, inst_data.src_node);
    932     }
    933 
    934     fn writeShuffle(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
    935         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
    936         const extra = self.code.extraData(Zir.Inst.Shuffle, inst_data.payload_index).data;
    937         try self.writeInstRef(stream, extra.elem_type);
    938         try stream.writeAll(", ");
    939         try self.writeInstRef(stream, extra.a);
    940         try stream.writeAll(", ");
    941         try self.writeInstRef(stream, extra.b);
    942         try stream.writeAll(", ");
    943         try self.writeInstRef(stream, extra.mask);
    944         try stream.writeAll(") ");
    945         try self.writeSrcNode(stream, inst_data.src_node);
    946     }
    947 
    948     fn writeSelect(self: *Writer, stream: *std.Io.Writer, extended: Zir.Inst.Extended.InstData) !void {
    949         const extra = self.code.extraData(Zir.Inst.Select, extended.operand).data;
    950         try self.writeInstRef(stream, extra.elem_type);
    951         try stream.writeAll(", ");
    952         try self.writeInstRef(stream, extra.pred);
    953         try stream.writeAll(", ");
    954         try self.writeInstRef(stream, extra.a);
    955         try stream.writeAll(", ");
    956         try self.writeInstRef(stream, extra.b);
    957         try stream.writeAll(") ");
    958         try self.writeSrcNode(stream, extra.node);
    959     }
    960 
    961     fn writeMulAdd(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
    962         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
    963         const extra = self.code.extraData(Zir.Inst.MulAdd, inst_data.payload_index).data;
    964         try self.writeInstRef(stream, extra.mulend1);
    965         try stream.writeAll(", ");
    966         try self.writeInstRef(stream, extra.mulend2);
    967         try stream.writeAll(", ");
    968         try self.writeInstRef(stream, extra.addend);
    969         try stream.writeAll(") ");
    970         try self.writeSrcNode(stream, inst_data.src_node);
    971     }
    972 
    973     fn writeBuiltinCall(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
    974         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
    975         const extra = self.code.extraData(Zir.Inst.BuiltinCall, inst_data.payload_index).data;
    976 
    977         try self.writeFlag(stream, "nodiscard ", extra.flags.ensure_result_used);
    978         try self.writeFlag(stream, "nosuspend ", extra.flags.is_nosuspend);
    979 
    980         try self.writeInstRef(stream, extra.modifier);
    981         try stream.writeAll(", ");
    982         try self.writeInstRef(stream, extra.callee);
    983         try stream.writeAll(", ");
    984         try self.writeInstRef(stream, extra.args);
    985         try stream.writeAll(") ");
    986         try self.writeSrcNode(stream, inst_data.src_node);
    987     }
    988 
    989     fn writeFieldParentPtr(self: *Writer, stream: *std.Io.Writer, extended: Zir.Inst.Extended.InstData) !void {
    990         const extra = self.code.extraData(Zir.Inst.FieldParentPtr, extended.operand).data;
    991         const FlagsInt = @typeInfo(Zir.Inst.FullPtrCastFlags).@"struct".backing_integer.?;
    992         const flags: Zir.Inst.FullPtrCastFlags = @bitCast(@as(FlagsInt, @truncate(extended.small)));
    993         if (flags.align_cast) try stream.writeAll("align_cast, ");
    994         if (flags.addrspace_cast) try stream.writeAll("addrspace_cast, ");
    995         if (flags.const_cast) try stream.writeAll("const_cast, ");
    996         if (flags.volatile_cast) try stream.writeAll("volatile_cast, ");
    997         try self.writeInstRef(stream, extra.parent_ptr_type);
    998         try stream.writeAll(", ");
    999         try self.writeInstRef(stream, extra.field_name);
   1000         try stream.writeAll(", ");
   1001         try self.writeInstRef(stream, extra.field_ptr);
   1002         try stream.writeAll(") ");
   1003         try self.writeSrcNode(stream, extra.src_node);
   1004     }
   1005 
   1006     fn writeParam(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
   1007         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_tok;
   1008         const extra = self.code.extraData(Zir.Inst.Param, inst_data.payload_index);
   1009         const body = self.code.bodySlice(extra.end, extra.data.type.body_len);
   1010         try stream.print("\"{f}\", ", .{
   1011             std.zig.fmtString(self.code.nullTerminatedString(extra.data.name)),
   1012         });
   1013 
   1014         if (extra.data.type.is_generic) try stream.writeAll("[generic] ");
   1015 
   1016         try self.writeBracedBody(stream, body);
   1017         try stream.writeAll(") ");
   1018         try self.writeSrcTok(stream, inst_data.src_tok);
   1019     }
   1020 
   1021     fn writePlNodeBin(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
   1022         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
   1023         const extra = self.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
   1024         try self.writeInstRef(stream, extra.lhs);
   1025         try stream.writeAll(", ");
   1026         try self.writeInstRef(stream, extra.rhs);
   1027         try stream.writeAll(") ");
   1028         try self.writeSrcNode(stream, inst_data.src_node);
   1029     }
   1030 
   1031     fn writePlNodeMultiOp(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
   1032         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
   1033         const extra = self.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index);
   1034         const args = self.code.refSlice(extra.end, extra.data.operands_len);
   1035         try stream.writeAll("{");
   1036         for (args, 0..) |arg, i| {
   1037             if (i != 0) try stream.writeAll(", ");
   1038             try self.writeInstRef(stream, arg);
   1039         }
   1040         try stream.writeAll("}) ");
   1041         try self.writeSrcNode(stream, inst_data.src_node);
   1042     }
   1043 
   1044     fn writeArrayMul(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
   1045         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
   1046         const extra = self.code.extraData(Zir.Inst.ArrayMul, inst_data.payload_index).data;
   1047         try self.writeInstRef(stream, extra.res_ty);
   1048         try stream.writeAll(", ");
   1049         try self.writeInstRef(stream, extra.lhs);
   1050         try stream.writeAll(", ");
   1051         try self.writeInstRef(stream, extra.rhs);
   1052         try stream.writeAll(") ");
   1053         try self.writeSrcNode(stream, inst_data.src_node);
   1054     }
   1055 
   1056     fn writeElemValImm(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
   1057         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].elem_val_imm;
   1058         try self.writeInstRef(stream, inst_data.operand);
   1059         try stream.print(", {d})", .{inst_data.idx});
   1060     }
   1061 
   1062     fn writeArrayInitElemPtr(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
   1063         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
   1064         const extra = self.code.extraData(Zir.Inst.ElemPtrImm, inst_data.payload_index).data;
   1065 
   1066         try self.writeInstRef(stream, extra.ptr);
   1067         try stream.print(", {d}) ", .{extra.index});
   1068         try self.writeSrcNode(stream, inst_data.src_node);
   1069     }
   1070 
   1071     fn writePlNodeExport(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
   1072         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
   1073         const extra = self.code.extraData(Zir.Inst.Export, inst_data.payload_index).data;
   1074 
   1075         try self.writeInstRef(stream, extra.exported);
   1076         try stream.writeAll(", ");
   1077         try self.writeInstRef(stream, extra.options);
   1078         try stream.writeAll(") ");
   1079         try self.writeSrcNode(stream, inst_data.src_node);
   1080     }
   1081 
   1082     fn writeValidateArrayInitRefTy(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
   1083         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
   1084         const extra = self.code.extraData(Zir.Inst.ArrayInitRefTy, inst_data.payload_index).data;
   1085 
   1086         try self.writeInstRef(stream, extra.ptr_ty);
   1087         try stream.writeAll(", ");
   1088         try stream.print(", {}) ", .{extra.elem_count});
   1089         try self.writeSrcNode(stream, inst_data.src_node);
   1090     }
   1091 
   1092     fn writeStructInit(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
   1093         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
   1094         const extra = self.code.extraData(Zir.Inst.StructInit, inst_data.payload_index);
   1095         var field_i: u32 = 0;
   1096         var extra_index = extra.end;
   1097 
   1098         while (field_i < extra.data.fields_len) : (field_i += 1) {
   1099             const item = self.code.extraData(Zir.Inst.StructInit.Item, extra_index);
   1100             extra_index = item.end;
   1101 
   1102             if (field_i != 0) {
   1103                 try stream.writeAll(", [");
   1104             } else {
   1105                 try stream.writeAll("[");
   1106             }
   1107             try self.writeInstIndex(stream, item.data.field_type);
   1108             try stream.writeAll(", ");
   1109             try self.writeInstRef(stream, item.data.init);
   1110             try stream.writeAll("]");
   1111         }
   1112         try stream.writeAll(") ");
   1113         try self.writeSrcNode(stream, inst_data.src_node);
   1114     }
   1115 
   1116     fn writeCmpxchg(self: *Writer, stream: *std.Io.Writer, extended: Zir.Inst.Extended.InstData) !void {
   1117         const extra = self.code.extraData(Zir.Inst.Cmpxchg, extended.operand).data;
   1118 
   1119         try self.writeInstRef(stream, extra.ptr);
   1120         try stream.writeAll(", ");
   1121         try self.writeInstRef(stream, extra.expected_value);
   1122         try stream.writeAll(", ");
   1123         try self.writeInstRef(stream, extra.new_value);
   1124         try stream.writeAll(", ");
   1125         try self.writeInstRef(stream, extra.success_order);
   1126         try stream.writeAll(", ");
   1127         try self.writeInstRef(stream, extra.failure_order);
   1128         try stream.writeAll(") ");
   1129         try self.writeSrcNode(stream, extra.node);
   1130     }
   1131 
   1132     fn writePtrCastFull(self: *Writer, stream: *std.Io.Writer, extended: Zir.Inst.Extended.InstData) !void {
   1133         const FlagsInt = @typeInfo(Zir.Inst.FullPtrCastFlags).@"struct".backing_integer.?;
   1134         const flags: Zir.Inst.FullPtrCastFlags = @bitCast(@as(FlagsInt, @truncate(extended.small)));
   1135         const extra = self.code.extraData(Zir.Inst.BinNode, extended.operand).data;
   1136         if (flags.ptr_cast) try stream.writeAll("ptr_cast, ");
   1137         if (flags.align_cast) try stream.writeAll("align_cast, ");
   1138         if (flags.addrspace_cast) try stream.writeAll("addrspace_cast, ");
   1139         if (flags.const_cast) try stream.writeAll("const_cast, ");
   1140         if (flags.volatile_cast) try stream.writeAll("volatile_cast, ");
   1141         try self.writeInstRef(stream, extra.lhs);
   1142         try stream.writeAll(", ");
   1143         try self.writeInstRef(stream, extra.rhs);
   1144         try stream.writeAll(")) ");
   1145         try self.writeSrcNode(stream, extra.node);
   1146     }
   1147 
   1148     fn writePtrCastNoDest(self: *Writer, stream: *std.Io.Writer, extended: Zir.Inst.Extended.InstData) !void {
   1149         const FlagsInt = @typeInfo(Zir.Inst.FullPtrCastFlags).@"struct".backing_integer.?;
   1150         const flags: Zir.Inst.FullPtrCastFlags = @bitCast(@as(FlagsInt, @truncate(extended.small)));
   1151         const extra = self.code.extraData(Zir.Inst.UnNode, extended.operand).data;
   1152         if (flags.const_cast) try stream.writeAll("const_cast, ");
   1153         if (flags.volatile_cast) try stream.writeAll("volatile_cast, ");
   1154         try self.writeInstRef(stream, extra.operand);
   1155         try stream.writeAll(")) ");
   1156         try self.writeSrcNode(stream, extra.node);
   1157     }
   1158 
   1159     fn writeAtomicLoad(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
   1160         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
   1161         const extra = self.code.extraData(Zir.Inst.AtomicLoad, inst_data.payload_index).data;
   1162 
   1163         try self.writeInstRef(stream, extra.elem_type);
   1164         try stream.writeAll(", ");
   1165         try self.writeInstRef(stream, extra.ptr);
   1166         try stream.writeAll(", ");
   1167         try self.writeInstRef(stream, extra.ordering);
   1168         try stream.writeAll(") ");
   1169         try self.writeSrcNode(stream, inst_data.src_node);
   1170     }
   1171 
   1172     fn writeAtomicStore(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
   1173         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
   1174         const extra = self.code.extraData(Zir.Inst.AtomicStore, inst_data.payload_index).data;
   1175 
   1176         try self.writeInstRef(stream, extra.ptr);
   1177         try stream.writeAll(", ");
   1178         try self.writeInstRef(stream, extra.operand);
   1179         try stream.writeAll(", ");
   1180         try self.writeInstRef(stream, extra.ordering);
   1181         try stream.writeAll(") ");
   1182         try self.writeSrcNode(stream, inst_data.src_node);
   1183     }
   1184 
   1185     fn writeAtomicRmw(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
   1186         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
   1187         const extra = self.code.extraData(Zir.Inst.AtomicRmw, inst_data.payload_index).data;
   1188 
   1189         try self.writeInstRef(stream, extra.ptr);
   1190         try stream.writeAll(", ");
   1191         try self.writeInstRef(stream, extra.operation);
   1192         try stream.writeAll(", ");
   1193         try self.writeInstRef(stream, extra.operand);
   1194         try stream.writeAll(", ");
   1195         try self.writeInstRef(stream, extra.ordering);
   1196         try stream.writeAll(") ");
   1197         try self.writeSrcNode(stream, inst_data.src_node);
   1198     }
   1199 
   1200     fn writeStructInitAnon(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
   1201         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
   1202         const extra = self.code.extraData(Zir.Inst.StructInitAnon, inst_data.payload_index);
   1203         var field_i: u32 = 0;
   1204         var extra_index = extra.end;
   1205 
   1206         while (field_i < extra.data.fields_len) : (field_i += 1) {
   1207             const item = self.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index);
   1208             extra_index = item.end;
   1209 
   1210             const field_name = self.code.nullTerminatedString(item.data.field_name);
   1211 
   1212             const prefix = if (field_i != 0) ", [" else "[";
   1213             try stream.print("{s}{s}=", .{ prefix, field_name });
   1214             try self.writeInstRef(stream, item.data.init);
   1215             try stream.writeAll("]");
   1216         }
   1217         try stream.writeAll(") ");
   1218         try self.writeSrcNode(stream, inst_data.src_node);
   1219     }
   1220 
   1221     fn writeStructInitFieldType(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
   1222         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
   1223         const extra = self.code.extraData(Zir.Inst.FieldType, inst_data.payload_index).data;
   1224         try self.writeInstRef(stream, extra.container_type);
   1225         const field_name = self.code.nullTerminatedString(extra.name_start);
   1226         try stream.print(", {s}) ", .{field_name});
   1227         try self.writeSrcNode(stream, inst_data.src_node);
   1228     }
   1229 
   1230     fn writeFieldTypeRef(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
   1231         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
   1232         const extra = self.code.extraData(Zir.Inst.FieldTypeRef, inst_data.payload_index).data;
   1233         try self.writeInstRef(stream, extra.container_type);
   1234         try stream.writeAll(", ");
   1235         try self.writeInstRef(stream, extra.field_name);
   1236         try stream.writeAll(") ");
   1237         try self.writeSrcNode(stream, inst_data.src_node);
   1238     }
   1239 
   1240     fn writeNodeMultiOp(self: *Writer, stream: *std.Io.Writer, extended: Zir.Inst.Extended.InstData) !void {
   1241         const extra = self.code.extraData(Zir.Inst.NodeMultiOp, extended.operand);
   1242         const operands = self.code.refSlice(extra.end, extended.small);
   1243 
   1244         for (operands, 0..) |operand, i| {
   1245             if (i != 0) try stream.writeAll(", ");
   1246             try self.writeInstRef(stream, operand);
   1247         }
   1248         try stream.writeAll(")) ");
   1249         try self.writeSrcNode(stream, extra.data.src_node);
   1250     }
   1251 
   1252     fn writeInstNode(
   1253         self: *Writer,
   1254         stream: *std.Io.Writer,
   1255         inst: Zir.Inst.Index,
   1256     ) Error!void {
   1257         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].inst_node;
   1258         try self.writeInstIndex(stream, inst_data.inst);
   1259         try stream.writeAll(") ");
   1260         try self.writeSrcNode(stream, inst_data.src_node);
   1261     }
   1262 
   1263     fn writeAsm(
   1264         self: *Writer,
   1265         stream: *std.Io.Writer,
   1266         extended: Zir.Inst.Extended.InstData,
   1267         tmpl_is_expr: bool,
   1268     ) !void {
   1269         const extra = self.code.extraData(Zir.Inst.Asm, extended.operand);
   1270         const outputs_len = @as(u5, @truncate(extended.small));
   1271         const inputs_len = @as(u5, @truncate(extended.small >> 5));
   1272         const clobbers_len = @as(u5, @truncate(extended.small >> 10));
   1273         const is_volatile = @as(u1, @truncate(extended.small >> 15)) != 0;
   1274 
   1275         try self.writeFlag(stream, "volatile, ", is_volatile);
   1276         if (tmpl_is_expr) {
   1277             try self.writeInstRef(stream, @enumFromInt(@intFromEnum(extra.data.asm_source)));
   1278             try stream.writeAll(", ");
   1279         } else {
   1280             const asm_source = self.code.nullTerminatedString(extra.data.asm_source);
   1281             try stream.print("\"{f}\", ", .{std.zig.fmtString(asm_source)});
   1282         }
   1283         try stream.writeAll(", ");
   1284 
   1285         var extra_i: usize = extra.end;
   1286         var output_type_bits = extra.data.output_type_bits;
   1287         {
   1288             var i: usize = 0;
   1289             while (i < outputs_len) : (i += 1) {
   1290                 const output = self.code.extraData(Zir.Inst.Asm.Output, extra_i);
   1291                 extra_i = output.end;
   1292 
   1293                 const is_type = @as(u1, @truncate(output_type_bits)) != 0;
   1294                 output_type_bits >>= 1;
   1295 
   1296                 const name = self.code.nullTerminatedString(output.data.name);
   1297                 const constraint = self.code.nullTerminatedString(output.data.constraint);
   1298                 try stream.print("output({f}, \"{f}\", ", .{
   1299                     std.zig.fmtIdP(name), std.zig.fmtString(constraint),
   1300                 });
   1301                 try self.writeFlag(stream, "->", is_type);
   1302                 try self.writeInstRef(stream, output.data.operand);
   1303                 try stream.writeAll(")");
   1304                 if (i + 1 < outputs_len) {
   1305                     try stream.writeAll("), ");
   1306                 }
   1307             }
   1308         }
   1309         {
   1310             var i: usize = 0;
   1311             while (i < inputs_len) : (i += 1) {
   1312                 const input = self.code.extraData(Zir.Inst.Asm.Input, extra_i);
   1313                 extra_i = input.end;
   1314 
   1315                 const name = self.code.nullTerminatedString(input.data.name);
   1316                 const constraint = self.code.nullTerminatedString(input.data.constraint);
   1317                 try stream.print("input({f}, \"{f}\", ", .{
   1318                     std.zig.fmtIdP(name), std.zig.fmtString(constraint),
   1319                 });
   1320                 try self.writeInstRef(stream, input.data.operand);
   1321                 try stream.writeAll(")");
   1322                 if (i + 1 < inputs_len) {
   1323                     try stream.writeAll(", ");
   1324                 }
   1325             }
   1326         }
   1327         {
   1328             var i: usize = 0;
   1329             while (i < clobbers_len) : (i += 1) {
   1330                 const str_index = self.code.extra[extra_i];
   1331                 extra_i += 1;
   1332                 const clobber = self.code.nullTerminatedString(@enumFromInt(str_index));
   1333                 try stream.print("{f}", .{std.zig.fmtIdP(clobber)});
   1334                 if (i + 1 < clobbers_len) {
   1335                     try stream.writeAll(", ");
   1336                 }
   1337             }
   1338         }
   1339         try stream.writeAll(")) ");
   1340         try self.writeSrcNode(stream, extra.data.src_node);
   1341     }
   1342 
   1343     fn writeOverflowArithmetic(self: *Writer, stream: *std.Io.Writer, extended: Zir.Inst.Extended.InstData) !void {
   1344         const extra = self.code.extraData(Zir.Inst.BinNode, extended.operand).data;
   1345 
   1346         try self.writeInstRef(stream, extra.lhs);
   1347         try stream.writeAll(", ");
   1348         try self.writeInstRef(stream, extra.rhs);
   1349         try stream.writeAll(")) ");
   1350         try self.writeSrcNode(stream, extra.node);
   1351     }
   1352 
   1353     fn writeCall(
   1354         self: *Writer,
   1355         stream: *std.Io.Writer,
   1356         inst: Zir.Inst.Index,
   1357         comptime kind: enum { direct, field },
   1358     ) !void {
   1359         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
   1360         const ExtraType = switch (kind) {
   1361             .direct => Zir.Inst.Call,
   1362             .field => Zir.Inst.FieldCall,
   1363         };
   1364         const extra = self.code.extraData(ExtraType, inst_data.payload_index);
   1365         const args_len = extra.data.flags.args_len;
   1366         const body = self.code.extra[extra.end..];
   1367 
   1368         if (extra.data.flags.ensure_result_used) {
   1369             try stream.writeAll("nodiscard ");
   1370         }
   1371         try stream.print(".{s}, ", .{@tagName(@as(std.builtin.CallModifier, @enumFromInt(extra.data.flags.packed_modifier)))});
   1372         switch (kind) {
   1373             .direct => try self.writeInstRef(stream, extra.data.callee),
   1374             .field => {
   1375                 const field_name = self.code.nullTerminatedString(extra.data.field_name_start);
   1376                 try self.writeInstRef(stream, extra.data.obj_ptr);
   1377                 try stream.print(", \"{f}\"", .{std.zig.fmtString(field_name)});
   1378             },
   1379         }
   1380         try stream.writeAll(", [");
   1381 
   1382         self.indent += 2;
   1383         if (args_len != 0) {
   1384             try stream.writeAll("\n");
   1385         }
   1386         var i: usize = 0;
   1387         var arg_start: u32 = args_len;
   1388         while (i < args_len) : (i += 1) {
   1389             try stream.splatByteAll(' ', self.indent);
   1390             const arg_end = self.code.extra[extra.end + i];
   1391             defer arg_start = arg_end;
   1392             const arg_body = body[arg_start..arg_end];
   1393             try self.writeBracedBody(stream, @ptrCast(arg_body));
   1394 
   1395             try stream.writeAll(",\n");
   1396         }
   1397         self.indent -= 2;
   1398         if (args_len != 0) {
   1399             try stream.splatByteAll(' ', self.indent);
   1400         }
   1401 
   1402         try stream.writeAll("]) ");
   1403         try self.writeSrcNode(stream, inst_data.src_node);
   1404     }
   1405 
   1406     fn writeBlock(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
   1407         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
   1408         const extra = self.code.extraData(Zir.Inst.Block, inst_data.payload_index);
   1409         const body = self.code.bodySlice(extra.end, extra.data.body_len);
   1410         try self.writeBracedBody(stream, body);
   1411         try stream.writeAll(") ");
   1412         try self.writeSrcNode(stream, inst_data.src_node);
   1413     }
   1414 
   1415     fn writeBlockComptime(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
   1416         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
   1417         const extra = self.code.extraData(Zir.Inst.BlockComptime, inst_data.payload_index);
   1418         const body = self.code.bodySlice(extra.end, extra.data.body_len);
   1419         try stream.print("reason={s}, ", .{@tagName(extra.data.reason)});
   1420         try self.writeBracedBody(stream, body);
   1421         try stream.writeAll(") ");
   1422         try self.writeSrcNode(stream, inst_data.src_node);
   1423     }
   1424 
   1425     fn writeCondBr(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
   1426         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
   1427         const extra = self.code.extraData(Zir.Inst.CondBr, inst_data.payload_index);
   1428         const then_body = self.code.bodySlice(extra.end, extra.data.then_body_len);
   1429         const else_body = self.code.bodySlice(extra.end + then_body.len, extra.data.else_body_len);
   1430         try self.writeInstRef(stream, extra.data.condition);
   1431         try stream.writeAll(", ");
   1432         try self.writeBracedBody(stream, then_body);
   1433         try stream.writeAll(", ");
   1434         try self.writeBracedBody(stream, else_body);
   1435         try stream.writeAll(") ");
   1436         try self.writeSrcNode(stream, inst_data.src_node);
   1437     }
   1438 
   1439     fn writeTry(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
   1440         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
   1441         const extra = self.code.extraData(Zir.Inst.Try, inst_data.payload_index);
   1442         const body = self.code.bodySlice(extra.end, extra.data.body_len);
   1443         try self.writeInstRef(stream, extra.data.operand);
   1444         try stream.writeAll(", ");
   1445         try self.writeBracedBody(stream, body);
   1446         try stream.writeAll(") ");
   1447         try self.writeSrcNode(stream, inst_data.src_node);
   1448     }
   1449 
   1450     fn writeStructDecl(self: *Writer, stream: *std.Io.Writer, extended: Zir.Inst.Extended.InstData) !void {
   1451         const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
   1452 
   1453         const extra = self.code.extraData(Zir.Inst.StructDecl, extended.operand);
   1454 
   1455         const prev_parent_decl_node = self.parent_decl_node;
   1456         self.parent_decl_node = extra.data.src_node;
   1457         defer self.parent_decl_node = prev_parent_decl_node;
   1458 
   1459         const fields_hash: std.zig.SrcHash = @bitCast([4]u32{
   1460             extra.data.fields_hash_0,
   1461             extra.data.fields_hash_1,
   1462             extra.data.fields_hash_2,
   1463             extra.data.fields_hash_3,
   1464         });
   1465 
   1466         try stream.print("hash({x}) ", .{&fields_hash});
   1467 
   1468         var extra_index: usize = extra.end;
   1469 
   1470         const captures_len = if (small.has_captures_len) blk: {
   1471             const captures_len = self.code.extra[extra_index];
   1472             extra_index += 1;
   1473             break :blk captures_len;
   1474         } else 0;
   1475 
   1476         const fields_len = if (small.has_fields_len) blk: {
   1477             const fields_len = self.code.extra[extra_index];
   1478             extra_index += 1;
   1479             break :blk fields_len;
   1480         } else 0;
   1481 
   1482         const decls_len = if (small.has_decls_len) blk: {
   1483             const decls_len = self.code.extra[extra_index];
   1484             extra_index += 1;
   1485             break :blk decls_len;
   1486         } else 0;
   1487 
   1488         try self.writeFlag(stream, "known_non_opv, ", small.known_non_opv);
   1489         try self.writeFlag(stream, "known_comptime_only, ", small.known_comptime_only);
   1490 
   1491         try stream.print("{s}, ", .{@tagName(small.name_strategy)});
   1492 
   1493         extra_index = try self.writeCaptures(stream, extra_index, captures_len);
   1494         try stream.writeAll(", ");
   1495 
   1496         if (small.has_backing_int) {
   1497             const backing_int_body_len = self.code.extra[extra_index];
   1498             extra_index += 1;
   1499             try stream.writeAll("packed(");
   1500             if (backing_int_body_len == 0) {
   1501                 const backing_int_ref: Zir.Inst.Ref = @enumFromInt(self.code.extra[extra_index]);
   1502                 extra_index += 1;
   1503                 try self.writeInstRef(stream, backing_int_ref);
   1504             } else {
   1505                 const body = self.code.bodySlice(extra_index, backing_int_body_len);
   1506                 extra_index += backing_int_body_len;
   1507                 self.indent += 2;
   1508                 try self.writeBracedDecl(stream, body);
   1509                 self.indent -= 2;
   1510             }
   1511             try stream.writeAll("), ");
   1512         } else {
   1513             try stream.print("{s}, ", .{@tagName(small.layout)});
   1514         }
   1515 
   1516         if (decls_len == 0) {
   1517             try stream.writeAll("{}, ");
   1518         } else {
   1519             try stream.writeAll("{\n");
   1520             self.indent += 2;
   1521             try self.writeBody(stream, self.code.bodySlice(extra_index, decls_len));
   1522             self.indent -= 2;
   1523             extra_index += decls_len;
   1524             try stream.splatByteAll(' ', self.indent);
   1525             try stream.writeAll("}, ");
   1526         }
   1527 
   1528         if (fields_len == 0) {
   1529             try stream.writeAll("{}, {}) ");
   1530         } else {
   1531             const bits_per_field = 4;
   1532             const fields_per_u32 = 32 / bits_per_field;
   1533             const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
   1534             const Field = struct {
   1535                 type_len: u32 = 0,
   1536                 align_len: u32 = 0,
   1537                 init_len: u32 = 0,
   1538                 type: Zir.Inst.Ref = .none,
   1539                 name: Zir.NullTerminatedString,
   1540                 is_comptime: bool,
   1541             };
   1542             const fields = try self.arena.alloc(Field, fields_len);
   1543             {
   1544                 var bit_bag_index: usize = extra_index;
   1545                 extra_index += bit_bags_count;
   1546                 var cur_bit_bag: u32 = undefined;
   1547                 var field_i: u32 = 0;
   1548                 while (field_i < fields_len) : (field_i += 1) {
   1549                     if (field_i % fields_per_u32 == 0) {
   1550                         cur_bit_bag = self.code.extra[bit_bag_index];
   1551                         bit_bag_index += 1;
   1552                     }
   1553                     const has_align = @as(u1, @truncate(cur_bit_bag)) != 0;
   1554                     cur_bit_bag >>= 1;
   1555                     const has_default = @as(u1, @truncate(cur_bit_bag)) != 0;
   1556                     cur_bit_bag >>= 1;
   1557                     const is_comptime = @as(u1, @truncate(cur_bit_bag)) != 0;
   1558                     cur_bit_bag >>= 1;
   1559                     const has_type_body = @as(u1, @truncate(cur_bit_bag)) != 0;
   1560                     cur_bit_bag >>= 1;
   1561 
   1562                     const field_name_index: Zir.NullTerminatedString = @enumFromInt(self.code.extra[extra_index]);
   1563                     extra_index += 1;
   1564 
   1565                     fields[field_i] = .{
   1566                         .is_comptime = is_comptime,
   1567                         .name = field_name_index,
   1568                     };
   1569 
   1570                     if (has_type_body) {
   1571                         fields[field_i].type_len = self.code.extra[extra_index];
   1572                     } else {
   1573                         fields[field_i].type = @enumFromInt(self.code.extra[extra_index]);
   1574                     }
   1575                     extra_index += 1;
   1576 
   1577                     if (has_align) {
   1578                         fields[field_i].align_len = self.code.extra[extra_index];
   1579                         extra_index += 1;
   1580                     }
   1581 
   1582                     if (has_default) {
   1583                         fields[field_i].init_len = self.code.extra[extra_index];
   1584                         extra_index += 1;
   1585                     }
   1586                 }
   1587             }
   1588 
   1589             try stream.writeAll("{\n");
   1590             self.indent += 2;
   1591 
   1592             for (fields, 0..) |field, i| {
   1593                 try stream.splatByteAll(' ', self.indent);
   1594                 try self.writeFlag(stream, "comptime ", field.is_comptime);
   1595                 if (field.name != .empty) {
   1596                     const field_name = self.code.nullTerminatedString(field.name);
   1597                     try stream.print("{f}: ", .{std.zig.fmtIdP(field_name)});
   1598                 } else {
   1599                     try stream.print("@\"{d}\": ", .{i});
   1600                 }
   1601                 if (field.type != .none) {
   1602                     try self.writeInstRef(stream, field.type);
   1603                 }
   1604 
   1605                 if (field.type_len > 0) {
   1606                     const body = self.code.bodySlice(extra_index, field.type_len);
   1607                     extra_index += body.len;
   1608                     self.indent += 2;
   1609                     try self.writeBracedDecl(stream, body);
   1610                     self.indent -= 2;
   1611                 }
   1612 
   1613                 if (field.align_len > 0) {
   1614                     const body = self.code.bodySlice(extra_index, field.align_len);
   1615                     extra_index += body.len;
   1616                     self.indent += 2;
   1617                     try stream.writeAll(" align(");
   1618                     try self.writeBracedDecl(stream, body);
   1619                     try stream.writeAll(")");
   1620                     self.indent -= 2;
   1621                 }
   1622 
   1623                 if (field.init_len > 0) {
   1624                     const body = self.code.bodySlice(extra_index, field.init_len);
   1625                     extra_index += body.len;
   1626                     self.indent += 2;
   1627                     try stream.writeAll(" = ");
   1628                     try self.writeBracedDecl(stream, body);
   1629                     self.indent -= 2;
   1630                 }
   1631 
   1632                 try stream.writeAll(",\n");
   1633             }
   1634 
   1635             self.indent -= 2;
   1636             try stream.splatByteAll(' ', self.indent);
   1637             try stream.writeAll("}) ");
   1638         }
   1639         try self.writeSrcNode(stream, .zero);
   1640     }
   1641 
   1642     fn writeUnionDecl(self: *Writer, stream: *std.Io.Writer, extended: Zir.Inst.Extended.InstData) !void {
   1643         const small = @as(Zir.Inst.UnionDecl.Small, @bitCast(extended.small));
   1644 
   1645         const extra = self.code.extraData(Zir.Inst.UnionDecl, extended.operand);
   1646 
   1647         const prev_parent_decl_node = self.parent_decl_node;
   1648         self.parent_decl_node = extra.data.src_node;
   1649         defer self.parent_decl_node = prev_parent_decl_node;
   1650 
   1651         const fields_hash: std.zig.SrcHash = @bitCast([4]u32{
   1652             extra.data.fields_hash_0,
   1653             extra.data.fields_hash_1,
   1654             extra.data.fields_hash_2,
   1655             extra.data.fields_hash_3,
   1656         });
   1657 
   1658         try stream.print("hash({x}) ", .{&fields_hash});
   1659 
   1660         var extra_index: usize = extra.end;
   1661 
   1662         const tag_type_ref = if (small.has_tag_type) blk: {
   1663             const tag_type_ref = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
   1664             extra_index += 1;
   1665             break :blk tag_type_ref;
   1666         } else .none;
   1667 
   1668         const captures_len = if (small.has_captures_len) blk: {
   1669             const captures_len = self.code.extra[extra_index];
   1670             extra_index += 1;
   1671             break :blk captures_len;
   1672         } else 0;
   1673 
   1674         const body_len = if (small.has_body_len) blk: {
   1675             const body_len = self.code.extra[extra_index];
   1676             extra_index += 1;
   1677             break :blk body_len;
   1678         } else 0;
   1679 
   1680         const fields_len = if (small.has_fields_len) blk: {
   1681             const fields_len = self.code.extra[extra_index];
   1682             extra_index += 1;
   1683             break :blk fields_len;
   1684         } else 0;
   1685 
   1686         const decls_len = if (small.has_decls_len) blk: {
   1687             const decls_len = self.code.extra[extra_index];
   1688             extra_index += 1;
   1689             break :blk decls_len;
   1690         } else 0;
   1691 
   1692         try stream.print("{s}, {s}, ", .{
   1693             @tagName(small.name_strategy), @tagName(small.layout),
   1694         });
   1695         try self.writeFlag(stream, "autoenum, ", small.auto_enum_tag);
   1696 
   1697         extra_index = try self.writeCaptures(stream, extra_index, captures_len);
   1698         try stream.writeAll(", ");
   1699 
   1700         if (decls_len == 0) {
   1701             try stream.writeAll("{}");
   1702         } else {
   1703             try stream.writeAll("{\n");
   1704             self.indent += 2;
   1705             try self.writeBody(stream, self.code.bodySlice(extra_index, decls_len));
   1706             self.indent -= 2;
   1707             extra_index += decls_len;
   1708             try stream.splatByteAll(' ', self.indent);
   1709             try stream.writeAll("}");
   1710         }
   1711 
   1712         if (tag_type_ref != .none) {
   1713             try stream.writeAll(", ");
   1714             try self.writeInstRef(stream, tag_type_ref);
   1715         }
   1716 
   1717         if (fields_len == 0) {
   1718             try stream.writeAll("}) ");
   1719             try self.writeSrcNode(stream, .zero);
   1720             return;
   1721         }
   1722         try stream.writeAll(", ");
   1723 
   1724         const body = self.code.bodySlice(extra_index, body_len);
   1725         extra_index += body.len;
   1726 
   1727         try self.writeBracedDecl(stream, body);
   1728         try stream.writeAll(", {\n");
   1729 
   1730         self.indent += 2;
   1731         const bits_per_field = 4;
   1732         const fields_per_u32 = 32 / bits_per_field;
   1733         const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
   1734         const body_end = extra_index;
   1735         extra_index += bit_bags_count;
   1736         var bit_bag_index: usize = body_end;
   1737         var cur_bit_bag: u32 = undefined;
   1738         var field_i: u32 = 0;
   1739         while (field_i < fields_len) : (field_i += 1) {
   1740             if (field_i % fields_per_u32 == 0) {
   1741                 cur_bit_bag = self.code.extra[bit_bag_index];
   1742                 bit_bag_index += 1;
   1743             }
   1744             const has_type = @as(u1, @truncate(cur_bit_bag)) != 0;
   1745             cur_bit_bag >>= 1;
   1746             const has_align = @as(u1, @truncate(cur_bit_bag)) != 0;
   1747             cur_bit_bag >>= 1;
   1748             const has_value = @as(u1, @truncate(cur_bit_bag)) != 0;
   1749             cur_bit_bag >>= 1;
   1750             const unused = @as(u1, @truncate(cur_bit_bag)) != 0;
   1751             cur_bit_bag >>= 1;
   1752 
   1753             _ = unused;
   1754 
   1755             const field_name_index: Zir.NullTerminatedString = @enumFromInt(self.code.extra[extra_index]);
   1756             const field_name = self.code.nullTerminatedString(field_name_index);
   1757             extra_index += 1;
   1758 
   1759             try stream.splatByteAll(' ', self.indent);
   1760             try stream.print("{f}", .{std.zig.fmtIdP(field_name)});
   1761 
   1762             if (has_type) {
   1763                 const field_type = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
   1764                 extra_index += 1;
   1765 
   1766                 try stream.writeAll(": ");
   1767                 try self.writeInstRef(stream, field_type);
   1768             }
   1769             if (has_align) {
   1770                 const align_ref = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
   1771                 extra_index += 1;
   1772 
   1773                 try stream.writeAll(" align(");
   1774                 try self.writeInstRef(stream, align_ref);
   1775                 try stream.writeAll(")");
   1776             }
   1777             if (has_value) {
   1778                 const default_ref = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
   1779                 extra_index += 1;
   1780 
   1781                 try stream.writeAll(" = ");
   1782                 try self.writeInstRef(stream, default_ref);
   1783             }
   1784             try stream.writeAll(",\n");
   1785         }
   1786 
   1787         self.indent -= 2;
   1788         try stream.splatByteAll(' ', self.indent);
   1789         try stream.writeAll("}) ");
   1790         try self.writeSrcNode(stream, .zero);
   1791     }
   1792 
   1793     fn writeEnumDecl(self: *Writer, stream: *std.Io.Writer, extended: Zir.Inst.Extended.InstData) !void {
   1794         const small = @as(Zir.Inst.EnumDecl.Small, @bitCast(extended.small));
   1795 
   1796         const extra = self.code.extraData(Zir.Inst.EnumDecl, extended.operand);
   1797 
   1798         const prev_parent_decl_node = self.parent_decl_node;
   1799         self.parent_decl_node = extra.data.src_node;
   1800         defer self.parent_decl_node = prev_parent_decl_node;
   1801 
   1802         const fields_hash: std.zig.SrcHash = @bitCast([4]u32{
   1803             extra.data.fields_hash_0,
   1804             extra.data.fields_hash_1,
   1805             extra.data.fields_hash_2,
   1806             extra.data.fields_hash_3,
   1807         });
   1808 
   1809         try stream.print("hash({x}) ", .{&fields_hash});
   1810 
   1811         var extra_index: usize = extra.end;
   1812 
   1813         const tag_type_ref = if (small.has_tag_type) blk: {
   1814             const tag_type_ref = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
   1815             extra_index += 1;
   1816             break :blk tag_type_ref;
   1817         } else .none;
   1818 
   1819         const captures_len = if (small.has_captures_len) blk: {
   1820             const captures_len = self.code.extra[extra_index];
   1821             extra_index += 1;
   1822             break :blk captures_len;
   1823         } else 0;
   1824 
   1825         const body_len = if (small.has_body_len) blk: {
   1826             const body_len = self.code.extra[extra_index];
   1827             extra_index += 1;
   1828             break :blk body_len;
   1829         } else 0;
   1830 
   1831         const fields_len = if (small.has_fields_len) blk: {
   1832             const fields_len = self.code.extra[extra_index];
   1833             extra_index += 1;
   1834             break :blk fields_len;
   1835         } else 0;
   1836 
   1837         const decls_len = if (small.has_decls_len) blk: {
   1838             const decls_len = self.code.extra[extra_index];
   1839             extra_index += 1;
   1840             break :blk decls_len;
   1841         } else 0;
   1842 
   1843         try stream.print("{s}, ", .{@tagName(small.name_strategy)});
   1844         try self.writeFlag(stream, "nonexhaustive, ", small.nonexhaustive);
   1845 
   1846         extra_index = try self.writeCaptures(stream, extra_index, captures_len);
   1847         try stream.writeAll(", ");
   1848 
   1849         if (decls_len == 0) {
   1850             try stream.writeAll("{}, ");
   1851         } else {
   1852             try stream.writeAll("{\n");
   1853             self.indent += 2;
   1854             try self.writeBody(stream, self.code.bodySlice(extra_index, decls_len));
   1855             self.indent -= 2;
   1856             extra_index += decls_len;
   1857             try stream.splatByteAll(' ', self.indent);
   1858             try stream.writeAll("}, ");
   1859         }
   1860 
   1861         if (tag_type_ref != .none) {
   1862             try self.writeInstRef(stream, tag_type_ref);
   1863             try stream.writeAll(", ");
   1864         }
   1865 
   1866         const body = self.code.bodySlice(extra_index, body_len);
   1867         extra_index += body.len;
   1868 
   1869         try self.writeBracedDecl(stream, body);
   1870         if (fields_len == 0) {
   1871             try stream.writeAll(", {}) ");
   1872         } else {
   1873             try stream.writeAll(", {\n");
   1874 
   1875             self.indent += 2;
   1876             const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable;
   1877             const body_end = extra_index;
   1878             extra_index += bit_bags_count;
   1879             var bit_bag_index: usize = body_end;
   1880             var cur_bit_bag: u32 = undefined;
   1881             var field_i: u32 = 0;
   1882             while (field_i < fields_len) : (field_i += 1) {
   1883                 if (field_i % 32 == 0) {
   1884                     cur_bit_bag = self.code.extra[bit_bag_index];
   1885                     bit_bag_index += 1;
   1886                 }
   1887                 const has_tag_value = @as(u1, @truncate(cur_bit_bag)) != 0;
   1888                 cur_bit_bag >>= 1;
   1889 
   1890                 const field_name = self.code.nullTerminatedString(@enumFromInt(self.code.extra[extra_index]));
   1891                 extra_index += 1;
   1892 
   1893                 try stream.splatByteAll(' ', self.indent);
   1894                 try stream.print("{f}", .{std.zig.fmtIdP(field_name)});
   1895 
   1896                 if (has_tag_value) {
   1897                     const tag_value_ref = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
   1898                     extra_index += 1;
   1899 
   1900                     try stream.writeAll(" = ");
   1901                     try self.writeInstRef(stream, tag_value_ref);
   1902                 }
   1903                 try stream.writeAll(",\n");
   1904             }
   1905             self.indent -= 2;
   1906             try stream.splatByteAll(' ', self.indent);
   1907             try stream.writeAll("}) ");
   1908         }
   1909         try self.writeSrcNode(stream, .zero);
   1910     }
   1911 
   1912     fn writeOpaqueDecl(
   1913         self: *Writer,
   1914         stream: *std.Io.Writer,
   1915         extended: Zir.Inst.Extended.InstData,
   1916     ) !void {
   1917         const small = @as(Zir.Inst.OpaqueDecl.Small, @bitCast(extended.small));
   1918         const extra = self.code.extraData(Zir.Inst.OpaqueDecl, extended.operand);
   1919 
   1920         const prev_parent_decl_node = self.parent_decl_node;
   1921         self.parent_decl_node = extra.data.src_node;
   1922         defer self.parent_decl_node = prev_parent_decl_node;
   1923 
   1924         var extra_index: usize = extra.end;
   1925 
   1926         const captures_len = if (small.has_captures_len) blk: {
   1927             const captures_len = self.code.extra[extra_index];
   1928             extra_index += 1;
   1929             break :blk captures_len;
   1930         } else 0;
   1931 
   1932         const decls_len = if (small.has_decls_len) blk: {
   1933             const decls_len = self.code.extra[extra_index];
   1934             extra_index += 1;
   1935             break :blk decls_len;
   1936         } else 0;
   1937 
   1938         try stream.print("{s}, ", .{@tagName(small.name_strategy)});
   1939 
   1940         extra_index = try self.writeCaptures(stream, extra_index, captures_len);
   1941         try stream.writeAll(", ");
   1942 
   1943         if (decls_len == 0) {
   1944             try stream.writeAll("{}) ");
   1945         } else {
   1946             try stream.writeAll("{\n");
   1947             self.indent += 2;
   1948             try self.writeBody(stream, self.code.bodySlice(extra_index, decls_len));
   1949             self.indent -= 2;
   1950             try stream.splatByteAll(' ', self.indent);
   1951             try stream.writeAll("}) ");
   1952         }
   1953         try self.writeSrcNode(stream, .zero);
   1954     }
   1955 
   1956     fn writeTupleDecl(self: *Writer, stream: *std.Io.Writer, extended: Zir.Inst.Extended.InstData) !void {
   1957         const fields_len = extended.small;
   1958         assert(fields_len != 0);
   1959         const extra = self.code.extraData(Zir.Inst.TupleDecl, extended.operand);
   1960 
   1961         var extra_index = extra.end;
   1962 
   1963         try stream.writeAll("{ ");
   1964 
   1965         for (0..fields_len) |field_idx| {
   1966             if (field_idx != 0) try stream.writeAll(", ");
   1967 
   1968             const field_ty, const field_init = self.code.extra[extra_index..][0..2].*;
   1969             extra_index += 2;
   1970 
   1971             try stream.print("@\"{d}\": ", .{field_idx});
   1972             try self.writeInstRef(stream, @enumFromInt(field_ty));
   1973             try stream.writeAll(" = ");
   1974             try self.writeInstRef(stream, @enumFromInt(field_init));
   1975         }
   1976 
   1977         try stream.writeAll(" }) ");
   1978 
   1979         try self.writeSrcNode(stream, extra.data.src_node);
   1980     }
   1981 
   1982     fn writeErrorSetDecl(
   1983         self: *Writer,
   1984         stream: *std.Io.Writer,
   1985         inst: Zir.Inst.Index,
   1986     ) !void {
   1987         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
   1988         const extra = self.code.extraData(Zir.Inst.ErrorSetDecl, inst_data.payload_index);
   1989 
   1990         try stream.writeAll("{\n");
   1991         self.indent += 2;
   1992 
   1993         var extra_index = @as(u32, @intCast(extra.end));
   1994         const extra_index_end = extra_index + extra.data.fields_len;
   1995         while (extra_index < extra_index_end) : (extra_index += 1) {
   1996             const name_index: Zir.NullTerminatedString = @enumFromInt(self.code.extra[extra_index]);
   1997             const name = self.code.nullTerminatedString(name_index);
   1998             try stream.splatByteAll(' ', self.indent);
   1999             try stream.print("{f},\n", .{std.zig.fmtIdP(name)});
   2000         }
   2001 
   2002         self.indent -= 2;
   2003         try stream.splatByteAll(' ', self.indent);
   2004         try stream.writeAll("}) ");
   2005 
   2006         try self.writeSrcNode(stream, inst_data.src_node);
   2007     }
   2008 
   2009     fn writeSwitchBlockErrUnion(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
   2010         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
   2011         const extra = self.code.extraData(Zir.Inst.SwitchBlockErrUnion, inst_data.payload_index);
   2012 
   2013         var extra_index: usize = extra.end;
   2014 
   2015         const multi_cases_len = if (extra.data.bits.has_multi_cases) blk: {
   2016             const multi_cases_len = self.code.extra[extra_index];
   2017             extra_index += 1;
   2018             break :blk multi_cases_len;
   2019         } else 0;
   2020 
   2021         const err_capture_inst: Zir.Inst.Index = if (extra.data.bits.any_uses_err_capture) blk: {
   2022             const tag_capture_inst = self.code.extra[extra_index];
   2023             extra_index += 1;
   2024             break :blk @enumFromInt(tag_capture_inst);
   2025         } else undefined;
   2026 
   2027         try self.writeInstRef(stream, extra.data.operand);
   2028 
   2029         if (extra.data.bits.any_uses_err_capture) {
   2030             try stream.writeAll(", err_capture=");
   2031             try self.writeInstIndex(stream, err_capture_inst);
   2032         }
   2033 
   2034         self.indent += 2;
   2035 
   2036         {
   2037             const info = @as(Zir.Inst.SwitchBlock.ProngInfo, @bitCast(self.code.extra[extra_index]));
   2038             extra_index += 1;
   2039 
   2040             assert(!info.is_inline);
   2041             const body = self.code.bodySlice(extra_index, info.body_len);
   2042             extra_index += body.len;
   2043 
   2044             try stream.writeAll(",\n");
   2045             try stream.splatByteAll(' ', self.indent);
   2046             try stream.writeAll("non_err => ");
   2047             try self.writeBracedBody(stream, body);
   2048         }
   2049 
   2050         if (extra.data.bits.has_else) {
   2051             const info = @as(Zir.Inst.SwitchBlock.ProngInfo, @bitCast(self.code.extra[extra_index]));
   2052             extra_index += 1;
   2053             const capture_text = switch (info.capture) {
   2054                 .none => "",
   2055                 .by_val => "by_val ",
   2056                 .by_ref => "by_ref ",
   2057             };
   2058             const inline_text = if (info.is_inline) "inline " else "";
   2059             const body = self.code.bodySlice(extra_index, info.body_len);
   2060             extra_index += body.len;
   2061 
   2062             try stream.writeAll(",\n");
   2063             try stream.splatByteAll(' ', self.indent);
   2064             try stream.print("{s}{s}else => ", .{ capture_text, inline_text });
   2065             try self.writeBracedBody(stream, body);
   2066         }
   2067 
   2068         {
   2069             const scalar_cases_len = extra.data.bits.scalar_cases_len;
   2070             var scalar_i: usize = 0;
   2071             while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
   2072                 const item_ref = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
   2073                 extra_index += 1;
   2074                 const info = @as(Zir.Inst.SwitchBlock.ProngInfo, @bitCast(self.code.extra[extra_index]));
   2075                 extra_index += 1;
   2076                 const body = self.code.bodySlice(extra_index, info.body_len);
   2077                 extra_index += info.body_len;
   2078 
   2079                 try stream.writeAll(",\n");
   2080                 try stream.splatByteAll(' ', self.indent);
   2081                 switch (info.capture) {
   2082                     .none => {},
   2083                     .by_val => try stream.writeAll("by_val "),
   2084                     .by_ref => try stream.writeAll("by_ref "),
   2085                 }
   2086                 if (info.is_inline) try stream.writeAll("inline ");
   2087                 try self.writeInstRef(stream, item_ref);
   2088                 try stream.writeAll(" => ");
   2089                 try self.writeBracedBody(stream, body);
   2090             }
   2091         }
   2092         {
   2093             var multi_i: usize = 0;
   2094             while (multi_i < multi_cases_len) : (multi_i += 1) {
   2095                 const items_len = self.code.extra[extra_index];
   2096                 extra_index += 1;
   2097                 const ranges_len = self.code.extra[extra_index];
   2098                 extra_index += 1;
   2099                 const info = @as(Zir.Inst.SwitchBlock.ProngInfo, @bitCast(self.code.extra[extra_index]));
   2100                 extra_index += 1;
   2101                 const items = self.code.refSlice(extra_index, items_len);
   2102                 extra_index += items_len;
   2103 
   2104                 try stream.writeAll(",\n");
   2105                 try stream.splatByteAll(' ', self.indent);
   2106                 switch (info.capture) {
   2107                     .none => {},
   2108                     .by_val => try stream.writeAll("by_val "),
   2109                     .by_ref => try stream.writeAll("by_ref "),
   2110                 }
   2111                 if (info.is_inline) try stream.writeAll("inline ");
   2112 
   2113                 for (items, 0..) |item_ref, item_i| {
   2114                     if (item_i != 0) try stream.writeAll(", ");
   2115                     try self.writeInstRef(stream, item_ref);
   2116                 }
   2117 
   2118                 var range_i: usize = 0;
   2119                 while (range_i < ranges_len) : (range_i += 1) {
   2120                     const item_first = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
   2121                     extra_index += 1;
   2122                     const item_last = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
   2123                     extra_index += 1;
   2124 
   2125                     if (range_i != 0 or items.len != 0) {
   2126                         try stream.writeAll(", ");
   2127                     }
   2128                     try self.writeInstRef(stream, item_first);
   2129                     try stream.writeAll("...");
   2130                     try self.writeInstRef(stream, item_last);
   2131                 }
   2132 
   2133                 const body = self.code.bodySlice(extra_index, info.body_len);
   2134                 extra_index += info.body_len;
   2135                 try stream.writeAll(" => ");
   2136                 try self.writeBracedBody(stream, body);
   2137             }
   2138         }
   2139 
   2140         self.indent -= 2;
   2141 
   2142         try stream.writeAll(") ");
   2143         try self.writeSrcNode(stream, inst_data.src_node);
   2144     }
   2145 
   2146     fn writeSwitchBlock(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
   2147         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
   2148         const extra = self.code.extraData(Zir.Inst.SwitchBlock, inst_data.payload_index);
   2149 
   2150         var extra_index: usize = extra.end;
   2151 
   2152         const multi_cases_len = if (extra.data.bits.has_multi_cases) blk: {
   2153             const multi_cases_len = self.code.extra[extra_index];
   2154             extra_index += 1;
   2155             break :blk multi_cases_len;
   2156         } else 0;
   2157 
   2158         const tag_capture_inst: Zir.Inst.Index = if (extra.data.bits.any_has_tag_capture) blk: {
   2159             const tag_capture_inst = self.code.extra[extra_index];
   2160             extra_index += 1;
   2161             break :blk @enumFromInt(tag_capture_inst);
   2162         } else undefined;
   2163 
   2164         try self.writeInstRef(stream, extra.data.operand);
   2165 
   2166         if (extra.data.bits.any_has_tag_capture) {
   2167             try stream.writeAll(", tag_capture=");
   2168             try self.writeInstIndex(stream, tag_capture_inst);
   2169         }
   2170 
   2171         self.indent += 2;
   2172 
   2173         const special_prongs = extra.data.bits.special_prongs;
   2174 
   2175         if (special_prongs.hasElse()) {
   2176             const info: Zir.Inst.SwitchBlock.ProngInfo = @bitCast(self.code.extra[extra_index]);
   2177             const capture_text = switch (info.capture) {
   2178                 .none => "",
   2179                 .by_val => "by_val ",
   2180                 .by_ref => "by_ref ",
   2181             };
   2182             const inline_text = if (info.is_inline) "inline " else "";
   2183             extra_index += 1;
   2184             const body = self.code.bodySlice(extra_index, info.body_len);
   2185             extra_index += body.len;
   2186 
   2187             try stream.writeAll(",\n");
   2188             try stream.splatByteAll(' ', self.indent);
   2189             try stream.print("{s}{s}else => ", .{ capture_text, inline_text });
   2190             try self.writeBracedBody(stream, body);
   2191         }
   2192 
   2193         if (special_prongs.hasUnder()) {
   2194             var single_item_ref: Zir.Inst.Ref = .none;
   2195             var items_len: u32 = 0;
   2196             var ranges_len: u32 = 0;
   2197             if (special_prongs.hasOneAdditionalItem()) {
   2198                 single_item_ref = @enumFromInt(self.code.extra[extra_index]);
   2199                 extra_index += 1;
   2200             } else if (special_prongs.hasManyAdditionalItems()) {
   2201                 items_len = self.code.extra[extra_index];
   2202                 extra_index += 1;
   2203                 ranges_len = self.code.extra[extra_index];
   2204                 extra_index += 1;
   2205             }
   2206             const info: Zir.Inst.SwitchBlock.ProngInfo = @bitCast(self.code.extra[extra_index]);
   2207             extra_index += 1;
   2208             const items = self.code.refSlice(extra_index, items_len);
   2209             extra_index += items_len;
   2210 
   2211             try stream.writeAll(",\n");
   2212             try stream.splatByteAll(' ', self.indent);
   2213             switch (info.capture) {
   2214                 .none => {},
   2215                 .by_val => try stream.writeAll("by_val "),
   2216                 .by_ref => try stream.writeAll("by_ref "),
   2217             }
   2218             if (info.is_inline) try stream.writeAll("inline ");
   2219 
   2220             try stream.writeAll("_");
   2221             if (single_item_ref != .none) {
   2222                 try stream.writeAll(", ");
   2223                 try self.writeInstRef(stream, single_item_ref);
   2224             }
   2225             for (items) |item_ref| {
   2226                 try stream.writeAll(", ");
   2227                 try self.writeInstRef(stream, item_ref);
   2228             }
   2229 
   2230             var range_i: usize = 0;
   2231             while (range_i < ranges_len) : (range_i += 1) {
   2232                 const item_first: Zir.Inst.Ref = @enumFromInt(self.code.extra[extra_index]);
   2233                 extra_index += 1;
   2234                 const item_last: Zir.Inst.Ref = @enumFromInt(self.code.extra[extra_index]);
   2235                 extra_index += 1;
   2236 
   2237                 try stream.writeAll(", ");
   2238                 try self.writeInstRef(stream, item_first);
   2239                 try stream.writeAll("...");
   2240                 try self.writeInstRef(stream, item_last);
   2241             }
   2242 
   2243             const body = self.code.bodySlice(extra_index, info.body_len);
   2244             extra_index += info.body_len;
   2245             try stream.writeAll(" => ");
   2246             try self.writeBracedBody(stream, body);
   2247         }
   2248 
   2249         {
   2250             const scalar_cases_len = extra.data.bits.scalar_cases_len;
   2251             var scalar_i: usize = 0;
   2252             while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
   2253                 const item_ref: Zir.Inst.Ref = @enumFromInt(self.code.extra[extra_index]);
   2254                 extra_index += 1;
   2255                 const info: Zir.Inst.SwitchBlock.ProngInfo = @bitCast(self.code.extra[extra_index]);
   2256                 extra_index += 1;
   2257                 const body = self.code.bodySlice(extra_index, info.body_len);
   2258                 extra_index += info.body_len;
   2259 
   2260                 try stream.writeAll(",\n");
   2261                 try stream.splatByteAll(' ', self.indent);
   2262                 switch (info.capture) {
   2263                     .none => {},
   2264                     .by_val => try stream.writeAll("by_val "),
   2265                     .by_ref => try stream.writeAll("by_ref "),
   2266                 }
   2267                 if (info.is_inline) try stream.writeAll("inline ");
   2268                 try self.writeInstRef(stream, item_ref);
   2269                 try stream.writeAll(" => ");
   2270                 try self.writeBracedBody(stream, body);
   2271             }
   2272         }
   2273         {
   2274             var multi_i: usize = 0;
   2275             while (multi_i < multi_cases_len) : (multi_i += 1) {
   2276                 const items_len = self.code.extra[extra_index];
   2277                 extra_index += 1;
   2278                 const ranges_len = self.code.extra[extra_index];
   2279                 extra_index += 1;
   2280                 const info: Zir.Inst.SwitchBlock.ProngInfo = @bitCast(self.code.extra[extra_index]);
   2281                 extra_index += 1;
   2282                 const items = self.code.refSlice(extra_index, items_len);
   2283                 extra_index += items_len;
   2284 
   2285                 try stream.writeAll(",\n");
   2286                 try stream.splatByteAll(' ', self.indent);
   2287                 switch (info.capture) {
   2288                     .none => {},
   2289                     .by_val => try stream.writeAll("by_val "),
   2290                     .by_ref => try stream.writeAll("by_ref "),
   2291                 }
   2292                 if (info.is_inline) try stream.writeAll("inline ");
   2293 
   2294                 for (items, 0..) |item_ref, item_i| {
   2295                     if (item_i != 0) try stream.writeAll(", ");
   2296                     try self.writeInstRef(stream, item_ref);
   2297                 }
   2298 
   2299                 var range_i: usize = 0;
   2300                 while (range_i < ranges_len) : (range_i += 1) {
   2301                     const item_first: Zir.Inst.Ref = @enumFromInt(self.code.extra[extra_index]);
   2302                     extra_index += 1;
   2303                     const item_last: Zir.Inst.Ref = @enumFromInt(self.code.extra[extra_index]);
   2304                     extra_index += 1;
   2305 
   2306                     if (range_i != 0 or items.len != 0) {
   2307                         try stream.writeAll(", ");
   2308                     }
   2309                     try self.writeInstRef(stream, item_first);
   2310                     try stream.writeAll("...");
   2311                     try self.writeInstRef(stream, item_last);
   2312                 }
   2313 
   2314                 const body = self.code.bodySlice(extra_index, info.body_len);
   2315                 extra_index += info.body_len;
   2316                 try stream.writeAll(" => ");
   2317                 try self.writeBracedBody(stream, body);
   2318             }
   2319         }
   2320 
   2321         self.indent -= 2;
   2322 
   2323         try stream.writeAll(") ");
   2324         try self.writeSrcNode(stream, inst_data.src_node);
   2325     }
   2326 
   2327     fn writePlNodeField(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
   2328         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
   2329         const extra = self.code.extraData(Zir.Inst.Field, inst_data.payload_index).data;
   2330         const name = self.code.nullTerminatedString(extra.field_name_start);
   2331         try self.writeInstRef(stream, extra.lhs);
   2332         try stream.print(", \"{f}\") ", .{std.zig.fmtString(name)});
   2333         try self.writeSrcNode(stream, inst_data.src_node);
   2334     }
   2335 
   2336     fn writePlNodeFieldNamed(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
   2337         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
   2338         const extra = self.code.extraData(Zir.Inst.FieldNamed, inst_data.payload_index).data;
   2339         try self.writeInstRef(stream, extra.lhs);
   2340         try stream.writeAll(", ");
   2341         try self.writeInstRef(stream, extra.field_name);
   2342         try stream.writeAll(") ");
   2343         try self.writeSrcNode(stream, inst_data.src_node);
   2344     }
   2345 
   2346     fn writeAs(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
   2347         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
   2348         const extra = self.code.extraData(Zir.Inst.As, inst_data.payload_index).data;
   2349         try self.writeInstRef(stream, extra.dest_type);
   2350         try stream.writeAll(", ");
   2351         try self.writeInstRef(stream, extra.operand);
   2352         try stream.writeAll(") ");
   2353         try self.writeSrcNode(stream, inst_data.src_node);
   2354     }
   2355 
   2356     fn writeNode(
   2357         self: *Writer,
   2358         stream: *std.Io.Writer,
   2359         inst: Zir.Inst.Index,
   2360     ) Error!void {
   2361         const src_node = self.code.instructions.items(.data)[@intFromEnum(inst)].node;
   2362         try stream.writeAll(") ");
   2363         try self.writeSrcNode(stream, src_node);
   2364     }
   2365 
   2366     fn writeStrTok(
   2367         self: *Writer,
   2368         stream: *std.Io.Writer,
   2369         inst: Zir.Inst.Index,
   2370     ) Error!void {
   2371         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].str_tok;
   2372         const str = inst_data.get(self.code);
   2373         try stream.print("\"{f}\") ", .{std.zig.fmtString(str)});
   2374         try self.writeSrcTok(stream, inst_data.src_tok);
   2375     }
   2376 
   2377     fn writeStrOp(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
   2378         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].str_op;
   2379         const str = inst_data.getStr(self.code);
   2380         try self.writeInstRef(stream, inst_data.operand);
   2381         try stream.print(", \"{f}\")", .{std.zig.fmtString(str)});
   2382     }
   2383 
   2384     fn writeFunc(
   2385         self: *Writer,
   2386         stream: *std.Io.Writer,
   2387         inst: Zir.Inst.Index,
   2388         inferred_error_set: bool,
   2389     ) !void {
   2390         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
   2391         const extra = self.code.extraData(Zir.Inst.Func, inst_data.payload_index);
   2392 
   2393         var extra_index = extra.end;
   2394         var ret_ty_ref: Zir.Inst.Ref = .none;
   2395         var ret_ty_body: []const Zir.Inst.Index = &.{};
   2396 
   2397         switch (extra.data.ret_ty.body_len) {
   2398             0 => {
   2399                 ret_ty_ref = .void_type;
   2400             },
   2401             1 => {
   2402                 ret_ty_ref = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
   2403                 extra_index += 1;
   2404             },
   2405             else => {
   2406                 ret_ty_body = self.code.bodySlice(extra_index, extra.data.ret_ty.body_len);
   2407                 extra_index += ret_ty_body.len;
   2408             },
   2409         }
   2410 
   2411         const body = self.code.bodySlice(extra_index, extra.data.body_len);
   2412         extra_index += body.len;
   2413 
   2414         var src_locs: Zir.Inst.Func.SrcLocs = undefined;
   2415         if (body.len != 0) {
   2416             src_locs = self.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data;
   2417         }
   2418         return self.writeFuncCommon(
   2419             stream,
   2420             inferred_error_set,
   2421             false,
   2422             false,
   2423 
   2424             .none,
   2425             &.{},
   2426             ret_ty_ref,
   2427             ret_ty_body,
   2428             extra.data.ret_ty.is_generic,
   2429 
   2430             body,
   2431             inst_data.src_node,
   2432             src_locs,
   2433             0,
   2434         );
   2435     }
   2436 
   2437     fn writeFuncFancy(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
   2438         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
   2439         const extra = self.code.extraData(Zir.Inst.FuncFancy, inst_data.payload_index);
   2440 
   2441         var extra_index: usize = extra.end;
   2442         var cc_ref: Zir.Inst.Ref = .none;
   2443         var cc_body: []const Zir.Inst.Index = &.{};
   2444         var ret_ty_ref: Zir.Inst.Ref = .none;
   2445         var ret_ty_body: []const Zir.Inst.Index = &.{};
   2446 
   2447         if (extra.data.bits.has_cc_body) {
   2448             const body_len = self.code.extra[extra_index];
   2449             extra_index += 1;
   2450             cc_body = self.code.bodySlice(extra_index, body_len);
   2451             extra_index += cc_body.len;
   2452         } else if (extra.data.bits.has_cc_ref) {
   2453             cc_ref = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
   2454             extra_index += 1;
   2455         }
   2456         if (extra.data.bits.has_ret_ty_body) {
   2457             const body_len = self.code.extra[extra_index];
   2458             extra_index += 1;
   2459             ret_ty_body = self.code.bodySlice(extra_index, body_len);
   2460             extra_index += ret_ty_body.len;
   2461         } else if (extra.data.bits.has_ret_ty_ref) {
   2462             ret_ty_ref = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
   2463             extra_index += 1;
   2464         }
   2465 
   2466         const noalias_bits: u32 = if (extra.data.bits.has_any_noalias) blk: {
   2467             const x = self.code.extra[extra_index];
   2468             extra_index += 1;
   2469             break :blk x;
   2470         } else 0;
   2471 
   2472         const body = self.code.bodySlice(extra_index, extra.data.body_len);
   2473         extra_index += body.len;
   2474 
   2475         var src_locs: Zir.Inst.Func.SrcLocs = undefined;
   2476         if (body.len != 0) {
   2477             src_locs = self.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data;
   2478         }
   2479         return self.writeFuncCommon(
   2480             stream,
   2481             extra.data.bits.is_inferred_error,
   2482             extra.data.bits.is_var_args,
   2483             extra.data.bits.is_noinline,
   2484             cc_ref,
   2485             cc_body,
   2486             ret_ty_ref,
   2487             ret_ty_body,
   2488             extra.data.bits.ret_ty_is_generic,
   2489             body,
   2490             inst_data.src_node,
   2491             src_locs,
   2492             noalias_bits,
   2493         );
   2494     }
   2495 
   2496     fn writeAllocExtended(self: *Writer, stream: *std.Io.Writer, extended: Zir.Inst.Extended.InstData) !void {
   2497         const extra = self.code.extraData(Zir.Inst.AllocExtended, extended.operand);
   2498         const small = @as(Zir.Inst.AllocExtended.Small, @bitCast(extended.small));
   2499 
   2500         var extra_index: usize = extra.end;
   2501         const type_inst: Zir.Inst.Ref = if (!small.has_type) .none else blk: {
   2502             const type_inst = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
   2503             extra_index += 1;
   2504             break :blk type_inst;
   2505         };
   2506         const align_inst: Zir.Inst.Ref = if (!small.has_align) .none else blk: {
   2507             const align_inst = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
   2508             extra_index += 1;
   2509             break :blk align_inst;
   2510         };
   2511         try self.writeFlag(stream, ",is_const", small.is_const);
   2512         try self.writeFlag(stream, ",is_comptime", small.is_comptime);
   2513         try self.writeOptionalInstRef(stream, ",ty=", type_inst);
   2514         try self.writeOptionalInstRef(stream, ",align=", align_inst);
   2515         try stream.writeAll(")) ");
   2516         try self.writeSrcNode(stream, extra.data.src_node);
   2517     }
   2518 
   2519     fn writeTypeofPeer(self: *Writer, stream: *std.Io.Writer, extended: Zir.Inst.Extended.InstData) !void {
   2520         const extra = self.code.extraData(Zir.Inst.TypeOfPeer, extended.operand);
   2521         const body = self.code.bodySlice(extra.data.body_index, extra.data.body_len);
   2522         try self.writeBracedBody(stream, body);
   2523         try stream.writeAll(",[");
   2524         const args = self.code.refSlice(extra.end, extended.small);
   2525         for (args, 0..) |arg, i| {
   2526             if (i != 0) try stream.writeAll(", ");
   2527             try self.writeInstRef(stream, arg);
   2528         }
   2529         try stream.writeAll("])");
   2530     }
   2531 
   2532     fn writeBoolBr(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
   2533         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
   2534         const extra = self.code.extraData(Zir.Inst.BoolBr, inst_data.payload_index);
   2535         const body = self.code.bodySlice(extra.end, extra.data.body_len);
   2536         try self.writeInstRef(stream, extra.data.lhs);
   2537         try stream.writeAll(", ");
   2538         try self.writeBracedBody(stream, body);
   2539         try stream.writeAll(") ");
   2540         try self.writeSrcNode(stream, inst_data.src_node);
   2541     }
   2542 
   2543     fn writeIntType(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
   2544         const int_type = self.code.instructions.items(.data)[@intFromEnum(inst)].int_type;
   2545         const prefix: u8 = switch (int_type.signedness) {
   2546             .signed => 'i',
   2547             .unsigned => 'u',
   2548         };
   2549         try stream.print("{c}{d}) ", .{ prefix, int_type.bit_count });
   2550         try self.writeSrcNode(stream, int_type.src_node);
   2551     }
   2552 
   2553     fn writeSaveErrRetIndex(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
   2554         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].save_err_ret_index;
   2555 
   2556         try self.writeInstRef(stream, inst_data.operand);
   2557 
   2558         try stream.writeAll(")");
   2559     }
   2560 
   2561     fn writeRestoreErrRetIndex(self: *Writer, stream: *std.Io.Writer, extended: Zir.Inst.Extended.InstData) !void {
   2562         const extra = self.code.extraData(Zir.Inst.RestoreErrRetIndex, extended.operand).data;
   2563 
   2564         try self.writeInstRef(stream, extra.block);
   2565         try self.writeInstRef(stream, extra.operand);
   2566 
   2567         try stream.writeAll(") ");
   2568         try self.writeSrcNode(stream, extra.src_node);
   2569     }
   2570 
   2571     fn writeBreak(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
   2572         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].@"break";
   2573         const extra = self.code.extraData(Zir.Inst.Break, inst_data.payload_index).data;
   2574 
   2575         try self.writeInstIndex(stream, extra.block_inst);
   2576         try stream.writeAll(", ");
   2577         try self.writeInstRef(stream, inst_data.operand);
   2578         try stream.writeAll(")");
   2579     }
   2580 
   2581     fn writeArrayInit(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
   2582         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
   2583 
   2584         const extra = self.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index);
   2585         const args = self.code.refSlice(extra.end, extra.data.operands_len);
   2586 
   2587         try self.writeInstRef(stream, args[0]);
   2588         try stream.writeAll("{");
   2589         for (args[1..], 0..) |arg, i| {
   2590             if (i != 0) try stream.writeAll(", ");
   2591             try self.writeInstRef(stream, arg);
   2592         }
   2593         try stream.writeAll("}) ");
   2594         try self.writeSrcNode(stream, inst_data.src_node);
   2595     }
   2596 
   2597     fn writeArrayInitAnon(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
   2598         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
   2599 
   2600         const extra = self.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index);
   2601         const args = self.code.refSlice(extra.end, extra.data.operands_len);
   2602 
   2603         try stream.writeAll("{");
   2604         for (args, 0..) |arg, i| {
   2605             if (i != 0) try stream.writeAll(", ");
   2606             try self.writeInstRef(stream, arg);
   2607         }
   2608         try stream.writeAll("}) ");
   2609         try self.writeSrcNode(stream, inst_data.src_node);
   2610     }
   2611 
   2612     fn writeArrayInitSent(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
   2613         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
   2614 
   2615         const extra = self.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index);
   2616         const args = self.code.refSlice(extra.end, extra.data.operands_len);
   2617         const sent = args[args.len - 1];
   2618         const elems = args[0 .. args.len - 1];
   2619 
   2620         try self.writeInstRef(stream, sent);
   2621         try stream.writeAll(", ");
   2622 
   2623         try stream.writeAll(".{");
   2624         for (elems, 0..) |elem, i| {
   2625             if (i != 0) try stream.writeAll(", ");
   2626             try self.writeInstRef(stream, elem);
   2627         }
   2628         try stream.writeAll("}) ");
   2629         try self.writeSrcNode(stream, inst_data.src_node);
   2630     }
   2631 
   2632     fn writeUnreachable(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
   2633         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].@"unreachable";
   2634         try stream.writeAll(") ");
   2635         try self.writeSrcNode(stream, inst_data.src_node);
   2636     }
   2637 
   2638     fn writeFuncCommon(
   2639         self: *Writer,
   2640         stream: *std.Io.Writer,
   2641         inferred_error_set: bool,
   2642         var_args: bool,
   2643         is_noinline: bool,
   2644         cc_ref: Zir.Inst.Ref,
   2645         cc_body: []const Zir.Inst.Index,
   2646         ret_ty_ref: Zir.Inst.Ref,
   2647         ret_ty_body: []const Zir.Inst.Index,
   2648         ret_ty_is_generic: bool,
   2649         body: []const Zir.Inst.Index,
   2650         src_node: Ast.Node.Offset,
   2651         src_locs: Zir.Inst.Func.SrcLocs,
   2652         noalias_bits: u32,
   2653     ) !void {
   2654         try self.writeOptionalInstRefOrBody(stream, "cc=", cc_ref, cc_body);
   2655         if (ret_ty_is_generic) try stream.writeAll("[generic] ");
   2656         try self.writeOptionalInstRefOrBody(stream, "ret_ty=", ret_ty_ref, ret_ty_body);
   2657         try self.writeFlag(stream, "vargs, ", var_args);
   2658         try self.writeFlag(stream, "inferror, ", inferred_error_set);
   2659         try self.writeFlag(stream, "noinline, ", is_noinline);
   2660 
   2661         if (noalias_bits != 0) {
   2662             try stream.print("noalias=0b{b}, ", .{noalias_bits});
   2663         }
   2664 
   2665         try stream.writeAll("body=");
   2666         try self.writeBracedBody(stream, body);
   2667         try stream.writeAll(") ");
   2668         if (body.len != 0) {
   2669             try stream.print("(lbrace={d}:{d},rbrace={d}:{d}) ", .{
   2670                 src_locs.lbrace_line + 1, @as(u16, @truncate(src_locs.columns)) + 1,
   2671                 src_locs.rbrace_line + 1, @as(u16, @truncate(src_locs.columns >> 16)) + 1,
   2672             });
   2673         }
   2674         try self.writeSrcNode(stream, src_node);
   2675     }
   2676 
   2677     fn writeDbgStmt(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
   2678         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].dbg_stmt;
   2679         try stream.print("{d}, {d})", .{ inst_data.line + 1, inst_data.column + 1 });
   2680     }
   2681 
   2682     fn writeDefer(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
   2683         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].@"defer";
   2684         const body = self.code.bodySlice(inst_data.index, inst_data.len);
   2685         try self.writeBracedBody(stream, body);
   2686         try stream.writeByte(')');
   2687     }
   2688 
   2689     fn writeDeferErrCode(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
   2690         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].defer_err_code;
   2691         const extra = self.code.extraData(Zir.Inst.DeferErrCode, inst_data.payload_index).data;
   2692 
   2693         try self.writeInstRef(stream, extra.remapped_err_code.toRef());
   2694         try stream.writeAll(" = ");
   2695         try self.writeInstRef(stream, inst_data.err_code);
   2696         try stream.writeAll(", ");
   2697         const body = self.code.bodySlice(extra.index, extra.len);
   2698         try self.writeBracedBody(stream, body);
   2699         try stream.writeByte(')');
   2700     }
   2701 
   2702     fn writeDeclaration(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
   2703         const decl = self.code.getDeclaration(inst);
   2704 
   2705         const prev_parent_decl_node = self.parent_decl_node;
   2706         defer self.parent_decl_node = prev_parent_decl_node;
   2707         self.parent_decl_node = decl.src_node;
   2708 
   2709         if (decl.is_pub) try stream.writeAll("pub ");
   2710         switch (decl.linkage) {
   2711             .normal => {},
   2712             .@"export" => try stream.writeAll("export "),
   2713             .@"extern" => try stream.writeAll("extern "),
   2714         }
   2715         switch (decl.kind) {
   2716             .@"comptime" => try stream.writeAll("comptime"),
   2717             .unnamed_test => try stream.writeAll("test"),
   2718             .@"test", .decltest, .@"const", .@"var" => {
   2719                 try stream.print("{s} '{s}'", .{ @tagName(decl.kind), self.code.nullTerminatedString(decl.name) });
   2720             },
   2721         }
   2722         const src_hash = self.code.getAssociatedSrcHash(inst).?;
   2723         try stream.print(" line({d}) column({d}) hash({x})", .{
   2724             decl.src_line, decl.src_column, &src_hash,
   2725         });
   2726 
   2727         {
   2728             if (decl.type_body) |b| {
   2729                 try stream.writeAll(" type=");
   2730                 try self.writeBracedDecl(stream, b);
   2731             }
   2732 
   2733             if (decl.align_body) |b| {
   2734                 try stream.writeAll(" align=");
   2735                 try self.writeBracedDecl(stream, b);
   2736             }
   2737 
   2738             if (decl.linksection_body) |b| {
   2739                 try stream.writeAll(" linksection=");
   2740                 try self.writeBracedDecl(stream, b);
   2741             }
   2742 
   2743             if (decl.addrspace_body) |b| {
   2744                 try stream.writeAll(" addrspace=");
   2745                 try self.writeBracedDecl(stream, b);
   2746             }
   2747 
   2748             if (decl.value_body) |b| {
   2749                 try stream.writeAll(" value=");
   2750                 try self.writeBracedDecl(stream, b);
   2751             }
   2752         }
   2753 
   2754         try stream.writeAll(") ");
   2755         try self.writeSrcNode(stream, .zero);
   2756     }
   2757 
   2758     fn writeClosureGet(self: *Writer, stream: *std.Io.Writer, extended: Zir.Inst.Extended.InstData) !void {
   2759         try stream.print("{d})) ", .{extended.small});
   2760         const src_node: Ast.Node.Offset = @enumFromInt(@as(i32, @bitCast(extended.operand)));
   2761         try self.writeSrcNode(stream, src_node);
   2762     }
   2763 
   2764     fn writeBuiltinValue(self: *Writer, stream: *std.Io.Writer, extended: Zir.Inst.Extended.InstData) !void {
   2765         const val: Zir.Inst.BuiltinValue = @enumFromInt(extended.small);
   2766         try stream.print("{s})) ", .{@tagName(val)});
   2767         const src_node: Ast.Node.Offset = @enumFromInt(@as(i32, @bitCast(extended.operand)));
   2768         try self.writeSrcNode(stream, src_node);
   2769     }
   2770 
   2771     fn writeInplaceArithResultTy(self: *Writer, stream: *std.Io.Writer, extended: Zir.Inst.Extended.InstData) !void {
   2772         const op: Zir.Inst.InplaceOp = @enumFromInt(extended.small);
   2773         try self.writeInstRef(stream, @enumFromInt(extended.operand));
   2774         try stream.print(", {s}))", .{@tagName(op)});
   2775     }
   2776 
   2777     fn writeInstRef(self: *Writer, stream: *std.Io.Writer, ref: Zir.Inst.Ref) !void {
   2778         if (ref == .none) {
   2779             return stream.writeAll(".none");
   2780         } else if (ref.toIndex()) |i| {
   2781             return self.writeInstIndex(stream, i);
   2782         } else {
   2783             const val: InternPool.Index = @enumFromInt(@intFromEnum(ref));
   2784             return stream.print("@{s}", .{@tagName(val)});
   2785         }
   2786     }
   2787 
   2788     fn writeInstIndex(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
   2789         _ = self;
   2790         return stream.print("%{d}", .{@intFromEnum(inst)});
   2791     }
   2792 
   2793     fn writeCaptures(self: *Writer, stream: *std.Io.Writer, extra_index: usize, captures_len: u32) !usize {
   2794         if (captures_len == 0) {
   2795             try stream.writeAll("{}");
   2796             return extra_index;
   2797         }
   2798 
   2799         const captures: []const Zir.Inst.Capture = @ptrCast(self.code.extra[extra_index..][0..captures_len]);
   2800         const capture_names: []const Zir.NullTerminatedString = @ptrCast(self.code.extra[extra_index + captures_len ..][0..captures_len]);
   2801         for (captures, capture_names) |capture, name| {
   2802             try stream.writeAll("{ ");
   2803             if (name != .empty) {
   2804                 const name_slice = self.code.nullTerminatedString(name);
   2805                 try stream.print("{s} = ", .{name_slice});
   2806             }
   2807             try self.writeCapture(stream, capture);
   2808         }
   2809 
   2810         return extra_index + 2 * captures_len;
   2811     }
   2812 
   2813     fn writeCapture(self: *Writer, stream: *std.Io.Writer, capture: Zir.Inst.Capture) !void {
   2814         switch (capture.unwrap()) {
   2815             .nested => |i| return stream.print("[{d}]", .{i}),
   2816             .instruction => |inst| return self.writeInstIndex(stream, inst),
   2817             .instruction_load => |ptr_inst| {
   2818                 try stream.writeAll("load ");
   2819                 try self.writeInstIndex(stream, ptr_inst);
   2820             },
   2821             .decl_val => |str| try stream.print("decl_val \"{f}\"", .{
   2822                 std.zig.fmtString(self.code.nullTerminatedString(str)),
   2823             }),
   2824             .decl_ref => |str| try stream.print("decl_ref \"{f}\"", .{
   2825                 std.zig.fmtString(self.code.nullTerminatedString(str)),
   2826             }),
   2827         }
   2828     }
   2829 
   2830     fn writeOptionalInstRef(
   2831         self: *Writer,
   2832         stream: *std.Io.Writer,
   2833         prefix: []const u8,
   2834         inst: Zir.Inst.Ref,
   2835     ) !void {
   2836         if (inst == .none) return;
   2837         try stream.writeAll(prefix);
   2838         try self.writeInstRef(stream, inst);
   2839     }
   2840 
   2841     fn writeOptionalInstRefOrBody(
   2842         self: *Writer,
   2843         stream: *std.Io.Writer,
   2844         prefix: []const u8,
   2845         ref: Zir.Inst.Ref,
   2846         body: []const Zir.Inst.Index,
   2847     ) !void {
   2848         if (body.len != 0) {
   2849             try stream.writeAll(prefix);
   2850             try self.writeBracedBody(stream, body);
   2851             try stream.writeAll(", ");
   2852         } else if (ref != .none) {
   2853             try stream.writeAll(prefix);
   2854             try self.writeInstRef(stream, ref);
   2855             try stream.writeAll(", ");
   2856         }
   2857     }
   2858 
   2859     fn writeFlag(
   2860         self: *Writer,
   2861         stream: *std.Io.Writer,
   2862         name: []const u8,
   2863         flag: bool,
   2864     ) !void {
   2865         _ = self;
   2866         if (!flag) return;
   2867         try stream.writeAll(name);
   2868     }
   2869 
   2870     fn writeSrcNode(self: *Writer, stream: *std.Io.Writer, src_node: Ast.Node.Offset) !void {
   2871         const tree = self.tree orelse return;
   2872         const abs_node = src_node.toAbsolute(self.parent_decl_node);
   2873         const src_span = tree.nodeToSpan(abs_node);
   2874         const start = self.line_col_cursor.find(tree.source, src_span.start);
   2875         const end = self.line_col_cursor.find(tree.source, src_span.end);
   2876         try stream.print("node_offset:{d}:{d} to :{d}:{d}", .{
   2877             start.line + 1, start.column + 1,
   2878             end.line + 1,   end.column + 1,
   2879         });
   2880     }
   2881 
   2882     fn writeSrcTok(self: *Writer, stream: *std.Io.Writer, src_tok: Ast.TokenOffset) !void {
   2883         const tree = self.tree orelse return;
   2884         const abs_tok = src_tok.toAbsolute(tree.firstToken(self.parent_decl_node));
   2885         const span_start = tree.tokenStart(abs_tok);
   2886         const span_end = span_start + @as(u32, @intCast(tree.tokenSlice(abs_tok).len));
   2887         const start = self.line_col_cursor.find(tree.source, span_start);
   2888         const end = self.line_col_cursor.find(tree.source, span_end);
   2889         try stream.print("token_offset:{d}:{d} to :{d}:{d}", .{
   2890             start.line + 1, start.column + 1,
   2891             end.line + 1,   end.column + 1,
   2892         });
   2893     }
   2894 
   2895     fn writeSrcTokAbs(self: *Writer, stream: *std.Io.Writer, src_tok: Ast.TokenIndex) !void {
   2896         const tree = self.tree orelse return;
   2897         const span_start = tree.tokenStart(src_tok);
   2898         const span_end = span_start + @as(u32, @intCast(tree.tokenSlice(src_tok).len));
   2899         const start = self.line_col_cursor.find(tree.source, span_start);
   2900         const end = self.line_col_cursor.find(tree.source, span_end);
   2901         try stream.print("token_abs:{d}:{d} to :{d}:{d}", .{
   2902             start.line + 1, start.column + 1,
   2903             end.line + 1,   end.column + 1,
   2904         });
   2905     }
   2906 
   2907     fn writeBracedDecl(self: *Writer, stream: *std.Io.Writer, body: []const Zir.Inst.Index) !void {
   2908         try self.writeBracedBodyConditional(stream, body, self.recurse_decls);
   2909     }
   2910 
   2911     fn writeBracedBody(self: *Writer, stream: *std.Io.Writer, body: []const Zir.Inst.Index) !void {
   2912         try self.writeBracedBodyConditional(stream, body, self.recurse_blocks);
   2913     }
   2914 
   2915     fn writeBracedBodyConditional(self: *Writer, stream: *std.Io.Writer, body: []const Zir.Inst.Index, enabled: bool) !void {
   2916         if (body.len == 0) {
   2917             try stream.writeAll("{}");
   2918         } else if (enabled) {
   2919             try stream.writeAll("{\n");
   2920             self.indent += 2;
   2921             try self.writeBody(stream, body);
   2922             self.indent -= 2;
   2923             try stream.splatByteAll(' ', self.indent);
   2924             try stream.writeAll("}");
   2925         } else if (body.len == 1) {
   2926             try stream.writeByte('{');
   2927             try self.writeInstIndex(stream, body[0]);
   2928             try stream.writeByte('}');
   2929         } else if (body.len == 2) {
   2930             try stream.writeByte('{');
   2931             try self.writeInstIndex(stream, body[0]);
   2932             try stream.writeAll(", ");
   2933             try self.writeInstIndex(stream, body[1]);
   2934             try stream.writeByte('}');
   2935         } else {
   2936             try stream.writeByte('{');
   2937             try self.writeInstIndex(stream, body[0]);
   2938             try stream.writeAll("..");
   2939             try self.writeInstIndex(stream, body[body.len - 1]);
   2940             try stream.writeByte('}');
   2941         }
   2942     }
   2943 
   2944     fn writeBody(self: *Writer, stream: *std.Io.Writer, body: []const Zir.Inst.Index) !void {
   2945         for (body) |inst| {
   2946             try stream.splatByteAll(' ', self.indent);
   2947             try stream.print("%{d} ", .{@intFromEnum(inst)});
   2948             try self.writeInstToStream(stream, inst);
   2949             try stream.writeByte('\n');
   2950         }
   2951     }
   2952 
   2953     fn writeImport(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
   2954         const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_tok;
   2955         const extra = self.code.extraData(Zir.Inst.Import, inst_data.payload_index).data;
   2956         try self.writeInstRef(stream, extra.res_ty);
   2957         const import_path = self.code.nullTerminatedString(extra.path);
   2958         try stream.print(", \"{f}\") ", .{std.zig.fmtString(import_path)});
   2959         try self.writeSrcTok(stream, inst_data.src_tok);
   2960     }
   2961 };