master
   1const std = @import("std");
   2const mem = std.mem;
   3const Allocator = std.mem.Allocator;
   4const assert = std.debug.assert;
   5const Ast = std.zig.Ast;
   6const InternPool = @import("InternPool.zig");
   7
   8const Zir = std.zig.Zir;
   9const Zcu = @import("Zcu.zig");
  10const LazySrcLoc = Zcu.LazySrcLoc;
  11
  12/// Write human-readable, debug formatted ZIR code.
  13pub 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
  53pub 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
  86pub 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
 112const 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.small);
 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};