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};