1const std = @import("std"); 2const mem = std.mem; 3const Allocator = std.mem.Allocator; 4const assert = std.debug.assert; 5const Ast = std.zig.Ast; 6 7const Zir = @import("Zir.zig"); 8const Module = @import("Module.zig"); 9const LazySrcLoc = Module.LazySrcLoc; 10 11/// Write human-readable, debug formatted ZIR code to a file. 12pub fn renderAsTextToFile( 13 gpa: Allocator, 14 scope_file: *Module.File, 15 fs_file: std.fs.File, 16) !void { 17 var arena = std.heap.ArenaAllocator.init(gpa); 18 defer arena.deinit(); 19 20 var writer: Writer = .{ 21 .gpa = gpa, 22 .arena = arena.allocator(), 23 .file = scope_file, 24 .code = scope_file.zir, 25 .indent = 0, 26 .parent_decl_node = 0, 27 .recurse_decls = true, 28 .recurse_blocks = true, 29 }; 30 31 var raw_stream = std.io.bufferedWriter(fs_file.writer()); 32 const stream = raw_stream.writer(); 33 34 const main_struct_inst = Zir.main_struct_inst; 35 try stream.print("%{d} ", .{main_struct_inst}); 36 try writer.writeInstToStream(stream, main_struct_inst); 37 try stream.writeAll("\n"); 38 const imports_index = scope_file.zir.extra[@enumToInt(Zir.ExtraIndex.imports)]; 39 if (imports_index != 0) { 40 try stream.writeAll("Imports:\n"); 41 42 const extra = scope_file.zir.extraData(Zir.Inst.Imports, imports_index); 43 var import_i: u32 = 0; 44 var extra_index = extra.end; 45 46 while (import_i < extra.data.imports_len) : (import_i += 1) { 47 const item = scope_file.zir.extraData(Zir.Inst.Imports.Item, extra_index); 48 extra_index = item.end; 49 50 const src: LazySrcLoc = .{ .token_abs = item.data.token }; 51 const import_path = scope_file.zir.nullTerminatedString(item.data.name); 52 try stream.print(" @import(\"{}\") ", .{ 53 std.zig.fmtEscapes(import_path), 54 }); 55 try writer.writeSrc(stream, src); 56 try stream.writeAll("\n"); 57 } 58 } 59 60 try raw_stream.flush(); 61} 62 63pub fn renderInstructionContext( 64 gpa: Allocator, 65 block: []const Zir.Inst.Index, 66 block_index: usize, 67 scope_file: *Module.File, 68 parent_decl_node: Ast.Node.Index, 69 indent: u32, 70 stream: anytype, 71) !void { 72 var arena = std.heap.ArenaAllocator.init(gpa); 73 defer arena.deinit(); 74 75 var writer: Writer = .{ 76 .gpa = gpa, 77 .arena = arena.allocator(), 78 .file = scope_file, 79 .code = scope_file.zir, 80 .indent = if (indent < 2) 2 else indent, 81 .parent_decl_node = parent_decl_node, 82 .recurse_decls = false, 83 .recurse_blocks = true, 84 }; 85 86 try writer.writeBody(stream, block[0..block_index]); 87 try stream.writeByteNTimes(' ', writer.indent - 2); 88 try stream.print("> %{d} ", .{block[block_index]}); 89 try writer.writeInstToStream(stream, block[block_index]); 90 try stream.writeByte('\n'); 91 if (block_index + 1 < block.len) { 92 try writer.writeBody(stream, block[block_index + 1 ..]); 93 } 94} 95 96pub fn renderSingleInstruction( 97 gpa: Allocator, 98 inst: Zir.Inst.Index, 99 scope_file: *Module.File, 100 parent_decl_node: Ast.Node.Index, 101 indent: u32, 102 stream: anytype, 103) !void { 104 var arena = std.heap.ArenaAllocator.init(gpa); 105 defer arena.deinit(); 106 107 var writer: Writer = .{ 108 .gpa = gpa, 109 .arena = arena.allocator(), 110 .file = scope_file, 111 .code = scope_file.zir, 112 .indent = indent, 113 .parent_decl_node = parent_decl_node, 114 .recurse_decls = false, 115 .recurse_blocks = false, 116 }; 117 118 try stream.print("%{d} ", .{inst}); 119 try writer.writeInstToStream(stream, inst); 120} 121 122const Writer = struct { 123 gpa: Allocator, 124 arena: Allocator, 125 file: *Module.File, 126 code: Zir, 127 indent: u32, 128 parent_decl_node: Ast.Node.Index, 129 recurse_decls: bool, 130 recurse_blocks: bool, 131 132 fn relativeToNodeIndex(self: *Writer, offset: i32) Ast.Node.Index { 133 return @bitCast(Ast.Node.Index, offset + @bitCast(i32, self.parent_decl_node)); 134 } 135 136 fn writeInstToStream( 137 self: *Writer, 138 stream: anytype, 139 inst: Zir.Inst.Index, 140 ) (@TypeOf(stream).Error || error{OutOfMemory})!void { 141 const tags = self.code.instructions.items(.tag); 142 const tag = tags[inst]; 143 try stream.print("= {s}(", .{@tagName(tags[inst])}); 144 switch (tag) { 145 .array_type, 146 .as, 147 .coerce_result_ptr, 148 .elem_ptr, 149 .elem_val, 150 .store, 151 .store_to_block_ptr, 152 .store_to_inferred_ptr, 153 .field_ptr_type, 154 => try self.writeBin(stream, inst), 155 156 .alloc, 157 .alloc_mut, 158 .alloc_comptime, 159 .indexable_ptr_len, 160 .anyframe_type, 161 .bit_not, 162 .bool_not, 163 .negate, 164 .negate_wrap, 165 .load, 166 .ensure_result_used, 167 .ensure_result_non_error, 168 .ret_node, 169 .ret_load, 170 .resolve_inferred_alloc, 171 .optional_type, 172 .optional_payload_safe, 173 .optional_payload_unsafe, 174 .optional_payload_safe_ptr, 175 .optional_payload_unsafe_ptr, 176 .err_union_payload_safe, 177 .err_union_payload_unsafe, 178 .err_union_payload_safe_ptr, 179 .err_union_payload_unsafe_ptr, 180 .err_union_code, 181 .err_union_code_ptr, 182 .is_non_null, 183 .is_non_null_ptr, 184 .is_non_err, 185 .is_non_err_ptr, 186 .typeof, 187 .struct_init_empty, 188 .type_info, 189 .size_of, 190 .bit_size_of, 191 .typeof_log2_int_type, 192 .log2_int_type, 193 .ptr_to_int, 194 .error_to_int, 195 .int_to_error, 196 .compile_error, 197 .set_eval_branch_quota, 198 .enum_to_int, 199 .align_of, 200 .bool_to_int, 201 .embed_file, 202 .error_name, 203 .panic, 204 .set_align_stack, 205 .set_cold, 206 .set_float_mode, 207 .set_runtime_safety, 208 .sqrt, 209 .sin, 210 .cos, 211 .exp, 212 .exp2, 213 .log, 214 .log2, 215 .log10, 216 .fabs, 217 .floor, 218 .ceil, 219 .trunc, 220 .round, 221 .tag_name, 222 .reify, 223 .type_name, 224 .frame_type, 225 .frame_size, 226 .clz, 227 .ctz, 228 .pop_count, 229 .byte_swap, 230 .bit_reverse, 231 .elem_type, 232 .@"resume", 233 .@"await", 234 .await_nosuspend, 235 .fence, 236 .switch_cond, 237 .switch_cond_ref, 238 => try self.writeUnNode(stream, inst), 239 240 .ref, 241 .ret_coerce, 242 .ensure_err_payload_void, 243 .closure_capture, 244 => try self.writeUnTok(stream, inst), 245 246 .bool_br_and, 247 .bool_br_or, 248 => try self.writeBoolBr(stream, inst), 249 250 .array_type_sentinel => try self.writeArrayTypeSentinel(stream, inst), 251 .ptr_type_simple => try self.writePtrTypeSimple(stream, inst), 252 .ptr_type => try self.writePtrType(stream, inst), 253 .int => try self.writeInt(stream, inst), 254 .int_big => try self.writeIntBig(stream, inst), 255 .float => try self.writeFloat(stream, inst), 256 .float128 => try self.writeFloat128(stream, inst), 257 .str => try self.writeStr(stream, inst), 258 .int_type => try self.writeIntType(stream, inst), 259 260 .@"break", 261 .break_inline, 262 => try self.writeBreak(stream, inst), 263 .array_init, 264 .array_init_ref, 265 .array_init_anon, 266 .array_init_anon_ref, 267 => try self.writeArrayInit(stream, inst), 268 269 .slice_start => try self.writeSliceStart(stream, inst), 270 .slice_end => try self.writeSliceEnd(stream, inst), 271 .slice_sentinel => try self.writeSliceSentinel(stream, inst), 272 273 .union_init_ptr => try self.writeUnionInitPtr(stream, inst), 274 275 .struct_init, 276 .struct_init_ref, 277 => try self.writeStructInit(stream, inst), 278 279 .cmpxchg_strong, .cmpxchg_weak => try self.writeCmpxchg(stream, inst), 280 .atomic_store => try self.writeAtomicStore(stream, inst), 281 .atomic_rmw => try self.writeAtomicRmw(stream, inst), 282 .memcpy => try self.writeMemcpy(stream, inst), 283 .memset => try self.writeMemset(stream, inst), 284 .shuffle => try self.writeShuffle(stream, inst), 285 .select => try self.writeSelect(stream, inst), 286 .mul_add => try self.writeMulAdd(stream, inst), 287 .field_parent_ptr => try self.writeFieldParentPtr(stream, inst), 288 .builtin_call => try self.writeBuiltinCall(stream, inst), 289 .builtin_async_call => try self.writeBuiltinAsyncCall(stream, inst), 290 291 .struct_init_anon, 292 .struct_init_anon_ref, 293 => try self.writeStructInitAnon(stream, inst), 294 295 .field_type => try self.writeFieldType(stream, inst), 296 .field_type_ref => try self.writeFieldTypeRef(stream, inst), 297 298 .add, 299 .addwrap, 300 .add_sat, 301 .array_cat, 302 .array_mul, 303 .mul, 304 .mulwrap, 305 .mul_sat, 306 .sub, 307 .subwrap, 308 .sub_sat, 309 .cmp_lt, 310 .cmp_lte, 311 .cmp_eq, 312 .cmp_gte, 313 .cmp_gt, 314 .cmp_neq, 315 .div, 316 .has_decl, 317 .has_field, 318 .mod_rem, 319 .shl, 320 .shl_exact, 321 .shl_sat, 322 .shr, 323 .shr_exact, 324 .xor, 325 .store_node, 326 .error_union_type, 327 .merge_error_sets, 328 .bit_and, 329 .bit_or, 330 .float_to_int, 331 .int_to_float, 332 .int_to_ptr, 333 .int_to_enum, 334 .float_cast, 335 .int_cast, 336 .err_set_cast, 337 .ptr_cast, 338 .truncate, 339 .align_cast, 340 .div_exact, 341 .div_floor, 342 .div_trunc, 343 .mod, 344 .rem, 345 .bit_offset_of, 346 .offset_of, 347 .splat, 348 .reduce, 349 .atomic_load, 350 .bitcast, 351 .vector_type, 352 .maximum, 353 .minimum, 354 .elem_ptr_node, 355 .elem_val_node, 356 => try self.writePlNodeBin(stream, inst), 357 358 .elem_ptr_imm => try self.writeElemPtrImm(stream, inst), 359 360 .@"export" => try self.writePlNodeExport(stream, inst), 361 .export_value => try self.writePlNodeExportValue(stream, inst), 362 363 .call => try self.writePlNodeCall(stream, inst), 364 365 .block, 366 .block_inline, 367 .suspend_block, 368 .loop, 369 .validate_struct_init, 370 .validate_array_init, 371 .c_import, 372 => try self.writePlNodeBlock(stream, inst), 373 374 .condbr, 375 .condbr_inline, 376 => try self.writePlNodeCondBr(stream, inst), 377 378 .error_set_decl => try self.writeErrorSetDecl(stream, inst, .parent), 379 .error_set_decl_anon => try self.writeErrorSetDecl(stream, inst, .anon), 380 .error_set_decl_func => try self.writeErrorSetDecl(stream, inst, .func), 381 382 .switch_block => try self.writePlNodeSwitchBlock(stream, inst), 383 384 .field_ptr, 385 .field_val, 386 .field_call_bind, 387 => try self.writePlNodeField(stream, inst), 388 389 .field_ptr_named, 390 .field_val_named, 391 .field_call_bind_named, 392 => try self.writePlNodeFieldNamed(stream, inst), 393 394 .as_node => try self.writeAs(stream, inst), 395 396 .breakpoint, 397 .repeat, 398 .repeat_inline, 399 .alloc_inferred, 400 .alloc_inferred_mut, 401 .alloc_inferred_comptime, 402 => try self.writeNode(stream, inst), 403 404 .error_value, 405 .enum_literal, 406 .decl_ref, 407 .decl_val, 408 .import, 409 .ret_err_value, 410 .ret_err_value_code, 411 .param_anytype, 412 .param_anytype_comptime, 413 => try self.writeStrTok(stream, inst), 414 415 .param, .param_comptime => try self.writeParam(stream, inst), 416 417 .func => try self.writeFunc(stream, inst, false), 418 .func_inferred => try self.writeFunc(stream, inst, true), 419 420 .@"unreachable" => try self.writeUnreachable(stream, inst), 421 422 .switch_capture, 423 .switch_capture_ref, 424 .switch_capture_multi, 425 .switch_capture_multi_ref, 426 .switch_capture_else, 427 .switch_capture_else_ref, 428 => try self.writeSwitchCapture(stream, inst), 429 430 .dbg_stmt => try self.writeDbgStmt(stream, inst), 431 432 .closure_get => try self.writeInstNode(stream, inst), 433 434 .extended => try self.writeExtended(stream, inst), 435 } 436 } 437 438 fn writeExtended(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { 439 const extended = self.code.instructions.items(.data)[inst].extended; 440 try stream.print("{s}(", .{@tagName(extended.opcode)}); 441 switch (extended.opcode) { 442 .ret_ptr, 443 .ret_type, 444 .this, 445 .ret_addr, 446 .error_return_trace, 447 .frame, 448 .frame_address, 449 .builtin_src, 450 => try self.writeExtNode(stream, extended), 451 452 .@"asm" => try self.writeAsm(stream, extended), 453 .func => try self.writeFuncExtended(stream, extended), 454 .variable => try self.writeVarExtended(stream, extended), 455 .alloc => try self.writeAllocExtended(stream, extended), 456 457 .compile_log, 458 .typeof_peer, 459 => try self.writeNodeMultiOp(stream, extended), 460 461 .add_with_overflow, 462 .sub_with_overflow, 463 .mul_with_overflow, 464 .shl_with_overflow, 465 => try self.writeOverflowArithmetic(stream, extended), 466 467 .struct_decl => try self.writeStructDecl(stream, extended), 468 .union_decl => try self.writeUnionDecl(stream, extended), 469 .enum_decl => try self.writeEnumDecl(stream, extended), 470 .opaque_decl => try self.writeOpaqueDecl(stream, extended), 471 472 .c_undef, .c_include, .wasm_memory_size => { 473 const inst_data = self.code.extraData(Zir.Inst.UnNode, extended.operand).data; 474 const src: LazySrcLoc = .{ .node_offset = inst_data.node }; 475 try self.writeInstRef(stream, inst_data.operand); 476 try stream.writeAll(")) "); 477 try self.writeSrc(stream, src); 478 }, 479 480 .builtin_extern, .c_define, .wasm_memory_grow, .prefetch => { 481 const inst_data = self.code.extraData(Zir.Inst.BinNode, extended.operand).data; 482 const src: LazySrcLoc = .{ .node_offset = inst_data.node }; 483 try self.writeInstRef(stream, inst_data.lhs); 484 try stream.writeAll(", "); 485 try self.writeInstRef(stream, inst_data.rhs); 486 try stream.writeAll(")) "); 487 try self.writeSrc(stream, src); 488 }, 489 } 490 } 491 492 fn writeExtNode(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void { 493 const src: LazySrcLoc = .{ .node_offset = @bitCast(i32, extended.operand) }; 494 try stream.writeAll(")) "); 495 try self.writeSrc(stream, src); 496 } 497 498 fn writeBin(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { 499 const inst_data = self.code.instructions.items(.data)[inst].bin; 500 try self.writeInstRef(stream, inst_data.lhs); 501 try stream.writeAll(", "); 502 try self.writeInstRef(stream, inst_data.rhs); 503 try stream.writeByte(')'); 504 } 505 506 fn writeUnNode( 507 self: *Writer, 508 stream: anytype, 509 inst: Zir.Inst.Index, 510 ) (@TypeOf(stream).Error || error{OutOfMemory})!void { 511 const inst_data = self.code.instructions.items(.data)[inst].un_node; 512 try self.writeInstRef(stream, inst_data.operand); 513 try stream.writeAll(") "); 514 try self.writeSrc(stream, inst_data.src()); 515 } 516 517 fn writeUnTok( 518 self: *Writer, 519 stream: anytype, 520 inst: Zir.Inst.Index, 521 ) (@TypeOf(stream).Error || error{OutOfMemory})!void { 522 const inst_data = self.code.instructions.items(.data)[inst].un_tok; 523 try self.writeInstRef(stream, inst_data.operand); 524 try stream.writeAll(") "); 525 try self.writeSrc(stream, inst_data.src()); 526 } 527 528 fn writeArrayTypeSentinel( 529 self: *Writer, 530 stream: anytype, 531 inst: Zir.Inst.Index, 532 ) (@TypeOf(stream).Error || error{OutOfMemory})!void { 533 const inst_data = self.code.instructions.items(.data)[inst].pl_node; 534 const extra = self.code.extraData(Zir.Inst.ArrayTypeSentinel, inst_data.payload_index).data; 535 try self.writeInstRef(stream, extra.len); 536 try stream.writeAll(", "); 537 try self.writeInstRef(stream, extra.sentinel); 538 try stream.writeAll(", "); 539 try self.writeInstRef(stream, extra.elem_type); 540 try stream.writeAll(") "); 541 try self.writeSrc(stream, inst_data.src()); 542 } 543 544 fn writePtrTypeSimple( 545 self: *Writer, 546 stream: anytype, 547 inst: Zir.Inst.Index, 548 ) (@TypeOf(stream).Error || error{OutOfMemory})!void { 549 const inst_data = self.code.instructions.items(.data)[inst].ptr_type_simple; 550 const str_allowzero = if (inst_data.is_allowzero) "allowzero, " else ""; 551 const str_const = if (!inst_data.is_mutable) "const, " else ""; 552 const str_volatile = if (inst_data.is_volatile) "volatile, " else ""; 553 try self.writeInstRef(stream, inst_data.elem_type); 554 try stream.print(", {s}{s}{s}{s})", .{ 555 str_allowzero, 556 str_const, 557 str_volatile, 558 @tagName(inst_data.size), 559 }); 560 } 561 562 fn writePtrType( 563 self: *Writer, 564 stream: anytype, 565 inst: Zir.Inst.Index, 566 ) (@TypeOf(stream).Error || error{OutOfMemory})!void { 567 const inst_data = self.code.instructions.items(.data)[inst].ptr_type; 568 const str_allowzero = if (inst_data.flags.is_allowzero) "allowzero, " else ""; 569 const str_const = if (!inst_data.flags.is_mutable) "const, " else ""; 570 const str_volatile = if (inst_data.flags.is_volatile) "volatile, " else ""; 571 const extra = self.code.extraData(Zir.Inst.PtrType, inst_data.payload_index); 572 try self.writeInstRef(stream, extra.data.elem_type); 573 try stream.print(", {s}{s}{s}{s}", .{ 574 str_allowzero, 575 str_const, 576 str_volatile, 577 @tagName(inst_data.size), 578 }); 579 var extra_index = extra.end; 580 if (inst_data.flags.has_sentinel) { 581 try stream.writeAll(", "); 582 try self.writeInstRef(stream, @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index])); 583 extra_index += 1; 584 } 585 if (inst_data.flags.has_align) { 586 try stream.writeAll(", align("); 587 try self.writeInstRef(stream, @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index])); 588 extra_index += 1; 589 if (inst_data.flags.has_bit_range) { 590 const bit_start = extra_index + @boolToInt(inst_data.flags.has_addrspace); 591 try stream.writeAll(":"); 592 try self.writeInstRef(stream, @intToEnum(Zir.Inst.Ref, self.code.extra[bit_start])); 593 try stream.writeAll(":"); 594 try self.writeInstRef(stream, @intToEnum(Zir.Inst.Ref, self.code.extra[bit_start + 1])); 595 } 596 try stream.writeAll(")"); 597 } 598 if (inst_data.flags.has_addrspace) { 599 try stream.writeAll(", addrspace("); 600 try self.writeInstRef(stream, @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index])); 601 try stream.writeAll(")"); 602 } 603 try stream.writeAll(")"); 604 } 605 606 fn writeInt(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { 607 const inst_data = self.code.instructions.items(.data)[inst].int; 608 try stream.print("{d})", .{inst_data}); 609 } 610 611 fn writeIntBig(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { 612 const inst_data = self.code.instructions.items(.data)[inst].str; 613 const byte_count = inst_data.len * @sizeOf(std.math.big.Limb); 614 const limb_bytes = self.code.string_bytes[inst_data.start..][0..byte_count]; 615 // limb_bytes is not aligned properly; we must allocate and copy the bytes 616 // in order to accomplish this. 617 const limbs = try self.gpa.alloc(std.math.big.Limb, inst_data.len); 618 defer self.gpa.free(limbs); 619 620 mem.copy(u8, mem.sliceAsBytes(limbs), limb_bytes); 621 const big_int: std.math.big.int.Const = .{ 622 .limbs = limbs, 623 .positive = true, 624 }; 625 const as_string = try big_int.toStringAlloc(self.gpa, 10, .lower); 626 defer self.gpa.free(as_string); 627 try stream.print("{s})", .{as_string}); 628 } 629 630 fn writeFloat(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { 631 const number = self.code.instructions.items(.data)[inst].float; 632 try stream.print("{d})", .{number}); 633 } 634 635 fn writeFloat128(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { 636 const inst_data = self.code.instructions.items(.data)[inst].pl_node; 637 const extra = self.code.extraData(Zir.Inst.Float128, inst_data.payload_index).data; 638 const src = inst_data.src(); 639 const number = extra.get(); 640 // TODO improve std.format to be able to print f128 values 641 try stream.print("{d}) ", .{@floatCast(f64, number)}); 642 try self.writeSrc(stream, src); 643 } 644 645 fn writeStr( 646 self: *Writer, 647 stream: anytype, 648 inst: Zir.Inst.Index, 649 ) (@TypeOf(stream).Error || error{OutOfMemory})!void { 650 const inst_data = self.code.instructions.items(.data)[inst].str; 651 const str = inst_data.get(self.code); 652 try stream.print("\"{}\")", .{std.zig.fmtEscapes(str)}); 653 } 654 655 fn writeSliceStart(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { 656 const inst_data = self.code.instructions.items(.data)[inst].pl_node; 657 const extra = self.code.extraData(Zir.Inst.SliceStart, inst_data.payload_index).data; 658 try self.writeInstRef(stream, extra.lhs); 659 try stream.writeAll(", "); 660 try self.writeInstRef(stream, extra.start); 661 try stream.writeAll(") "); 662 try self.writeSrc(stream, inst_data.src()); 663 } 664 665 fn writeSliceEnd(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { 666 const inst_data = self.code.instructions.items(.data)[inst].pl_node; 667 const extra = self.code.extraData(Zir.Inst.SliceEnd, inst_data.payload_index).data; 668 try self.writeInstRef(stream, extra.lhs); 669 try stream.writeAll(", "); 670 try self.writeInstRef(stream, extra.start); 671 try stream.writeAll(", "); 672 try self.writeInstRef(stream, extra.end); 673 try stream.writeAll(") "); 674 try self.writeSrc(stream, inst_data.src()); 675 } 676 677 fn writeSliceSentinel(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { 678 const inst_data = self.code.instructions.items(.data)[inst].pl_node; 679 const extra = self.code.extraData(Zir.Inst.SliceSentinel, inst_data.payload_index).data; 680 try self.writeInstRef(stream, extra.lhs); 681 try stream.writeAll(", "); 682 try self.writeInstRef(stream, extra.start); 683 try stream.writeAll(", "); 684 try self.writeInstRef(stream, extra.end); 685 try stream.writeAll(", "); 686 try self.writeInstRef(stream, extra.sentinel); 687 try stream.writeAll(") "); 688 try self.writeSrc(stream, inst_data.src()); 689 } 690 691 fn writeUnionInitPtr(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { 692 const inst_data = self.code.instructions.items(.data)[inst].pl_node; 693 const extra = self.code.extraData(Zir.Inst.UnionInitPtr, inst_data.payload_index).data; 694 try self.writeInstRef(stream, extra.result_ptr); 695 try stream.writeAll(", "); 696 try self.writeInstRef(stream, extra.union_type); 697 try stream.writeAll(", "); 698 try self.writeInstRef(stream, extra.field_name); 699 try stream.writeAll(") "); 700 try self.writeSrc(stream, inst_data.src()); 701 } 702 703 fn writeShuffle(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { 704 const inst_data = self.code.instructions.items(.data)[inst].pl_node; 705 const extra = self.code.extraData(Zir.Inst.Shuffle, inst_data.payload_index).data; 706 try self.writeInstRef(stream, extra.elem_type); 707 try stream.writeAll(", "); 708 try self.writeInstRef(stream, extra.a); 709 try stream.writeAll(", "); 710 try self.writeInstRef(stream, extra.b); 711 try stream.writeAll(", "); 712 try self.writeInstRef(stream, extra.mask); 713 try stream.writeAll(") "); 714 try self.writeSrc(stream, inst_data.src()); 715 } 716 717 fn writeSelect(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { 718 const inst_data = self.code.instructions.items(.data)[inst].pl_node; 719 const extra = self.code.extraData(Zir.Inst.Select, inst_data.payload_index).data; 720 try self.writeInstRef(stream, extra.elem_type); 721 try stream.writeAll(", "); 722 try self.writeInstRef(stream, extra.pred); 723 try stream.writeAll(", "); 724 try self.writeInstRef(stream, extra.a); 725 try stream.writeAll(", "); 726 try self.writeInstRef(stream, extra.b); 727 try stream.writeAll(") "); 728 try self.writeSrc(stream, inst_data.src()); 729 } 730 731 fn writeMulAdd(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { 732 const inst_data = self.code.instructions.items(.data)[inst].pl_node; 733 const extra = self.code.extraData(Zir.Inst.MulAdd, inst_data.payload_index).data; 734 try self.writeInstRef(stream, extra.mulend1); 735 try stream.writeAll(", "); 736 try self.writeInstRef(stream, extra.mulend2); 737 try stream.writeAll(", "); 738 try self.writeInstRef(stream, extra.addend); 739 try stream.writeAll(") "); 740 try self.writeSrc(stream, inst_data.src()); 741 } 742 743 fn writeBuiltinCall(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { 744 const inst_data = self.code.instructions.items(.data)[inst].pl_node; 745 const extra = self.code.extraData(Zir.Inst.BuiltinCall, inst_data.payload_index).data; 746 try self.writeInstRef(stream, extra.options); 747 try stream.writeAll(", "); 748 try self.writeInstRef(stream, extra.callee); 749 try stream.writeAll(", "); 750 try self.writeInstRef(stream, extra.args); 751 try stream.writeAll(") "); 752 try self.writeSrc(stream, inst_data.src()); 753 } 754 755 fn writeFieldParentPtr(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { 756 const inst_data = self.code.instructions.items(.data)[inst].pl_node; 757 const extra = self.code.extraData(Zir.Inst.FieldParentPtr, inst_data.payload_index).data; 758 try self.writeInstRef(stream, extra.parent_type); 759 try stream.writeAll(", "); 760 try self.writeInstRef(stream, extra.field_name); 761 try stream.writeAll(", "); 762 try self.writeInstRef(stream, extra.field_ptr); 763 try stream.writeAll(") "); 764 try self.writeSrc(stream, inst_data.src()); 765 } 766 767 fn writeBuiltinAsyncCall(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { 768 const inst_data = self.code.instructions.items(.data)[inst].pl_node; 769 const extra = self.code.extraData(Zir.Inst.AsyncCall, inst_data.payload_index).data; 770 try self.writeInstRef(stream, extra.frame_buffer); 771 try stream.writeAll(", "); 772 try self.writeInstRef(stream, extra.result_ptr); 773 try stream.writeAll(", "); 774 try self.writeInstRef(stream, extra.fn_ptr); 775 try stream.writeAll(", "); 776 try self.writeInstRef(stream, extra.args); 777 try stream.writeAll(") "); 778 try self.writeSrc(stream, inst_data.src()); 779 } 780 781 fn writeParam(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { 782 const inst_data = self.code.instructions.items(.data)[inst].pl_tok; 783 const extra = self.code.extraData(Zir.Inst.Param, inst_data.payload_index); 784 const body = self.code.extra[extra.end..][0..extra.data.body_len]; 785 try stream.print("\"{}\", ", .{ 786 std.zig.fmtEscapes(self.code.nullTerminatedString(extra.data.name)), 787 }); 788 try self.writeBracedBody(stream, body); 789 try stream.writeAll(") "); 790 try self.writeSrc(stream, inst_data.src()); 791 } 792 793 fn writePlNodeBin(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { 794 const inst_data = self.code.instructions.items(.data)[inst].pl_node; 795 const extra = self.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 796 try self.writeInstRef(stream, extra.lhs); 797 try stream.writeAll(", "); 798 try self.writeInstRef(stream, extra.rhs); 799 try stream.writeAll(") "); 800 try self.writeSrc(stream, inst_data.src()); 801 } 802 803 fn writeElemPtrImm(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { 804 const inst_data = self.code.instructions.items(.data)[inst].pl_node; 805 const extra = self.code.extraData(Zir.Inst.ElemPtrImm, inst_data.payload_index).data; 806 807 try self.writeInstRef(stream, extra.ptr); 808 try stream.print(", {d}) ", .{extra.index}); 809 try self.writeSrc(stream, inst_data.src()); 810 } 811 812 fn writePlNodeExport(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { 813 const inst_data = self.code.instructions.items(.data)[inst].pl_node; 814 const extra = self.code.extraData(Zir.Inst.Export, inst_data.payload_index).data; 815 const decl_name = self.code.nullTerminatedString(extra.decl_name); 816 817 try self.writeInstRef(stream, extra.namespace); 818 try stream.print(", {}, ", .{std.zig.fmtId(decl_name)}); 819 try self.writeInstRef(stream, extra.options); 820 try stream.writeAll(") "); 821 try self.writeSrc(stream, inst_data.src()); 822 } 823 824 fn writePlNodeExportValue(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { 825 const inst_data = self.code.instructions.items(.data)[inst].pl_node; 826 const extra = self.code.extraData(Zir.Inst.ExportValue, inst_data.payload_index).data; 827 828 try self.writeInstRef(stream, extra.operand); 829 try stream.writeAll(", "); 830 try self.writeInstRef(stream, extra.options); 831 try stream.writeAll(") "); 832 try self.writeSrc(stream, inst_data.src()); 833 } 834 835 fn writeStructInit(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { 836 const inst_data = self.code.instructions.items(.data)[inst].pl_node; 837 const extra = self.code.extraData(Zir.Inst.StructInit, inst_data.payload_index); 838 var field_i: u32 = 0; 839 var extra_index = extra.end; 840 841 while (field_i < extra.data.fields_len) : (field_i += 1) { 842 const item = self.code.extraData(Zir.Inst.StructInit.Item, extra_index); 843 extra_index = item.end; 844 845 if (field_i != 0) { 846 try stream.writeAll(", ["); 847 } else { 848 try stream.writeAll("["); 849 } 850 try self.writeInstIndex(stream, item.data.field_type); 851 try stream.writeAll(", "); 852 try self.writeInstRef(stream, item.data.init); 853 try stream.writeAll("]"); 854 } 855 try stream.writeAll(") "); 856 try self.writeSrc(stream, inst_data.src()); 857 } 858 859 fn writeCmpxchg(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { 860 const inst_data = self.code.instructions.items(.data)[inst].pl_node; 861 const extra = self.code.extraData(Zir.Inst.Cmpxchg, inst_data.payload_index).data; 862 863 try self.writeInstRef(stream, extra.ptr); 864 try stream.writeAll(", "); 865 try self.writeInstRef(stream, extra.expected_value); 866 try stream.writeAll(", "); 867 try self.writeInstRef(stream, extra.new_value); 868 try stream.writeAll(", "); 869 try self.writeInstRef(stream, extra.success_order); 870 try stream.writeAll(", "); 871 try self.writeInstRef(stream, extra.failure_order); 872 try stream.writeAll(") "); 873 try self.writeSrc(stream, inst_data.src()); 874 } 875 876 fn writeAtomicStore(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { 877 const inst_data = self.code.instructions.items(.data)[inst].pl_node; 878 const extra = self.code.extraData(Zir.Inst.AtomicStore, inst_data.payload_index).data; 879 880 try self.writeInstRef(stream, extra.ptr); 881 try stream.writeAll(", "); 882 try self.writeInstRef(stream, extra.operand); 883 try stream.writeAll(", "); 884 try self.writeInstRef(stream, extra.ordering); 885 try stream.writeAll(") "); 886 try self.writeSrc(stream, inst_data.src()); 887 } 888 889 fn writeAtomicRmw(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { 890 const inst_data = self.code.instructions.items(.data)[inst].pl_node; 891 const extra = self.code.extraData(Zir.Inst.AtomicRmw, inst_data.payload_index).data; 892 893 try self.writeInstRef(stream, extra.ptr); 894 try stream.writeAll(", "); 895 try self.writeInstRef(stream, extra.operation); 896 try stream.writeAll(", "); 897 try self.writeInstRef(stream, extra.operand); 898 try stream.writeAll(", "); 899 try self.writeInstRef(stream, extra.ordering); 900 try stream.writeAll(") "); 901 try self.writeSrc(stream, inst_data.src()); 902 } 903 904 fn writeMemcpy(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { 905 const inst_data = self.code.instructions.items(.data)[inst].pl_node; 906 const extra = self.code.extraData(Zir.Inst.Memcpy, inst_data.payload_index).data; 907 908 try self.writeInstRef(stream, extra.dest); 909 try stream.writeAll(", "); 910 try self.writeInstRef(stream, extra.source); 911 try stream.writeAll(", "); 912 try self.writeInstRef(stream, extra.byte_count); 913 try stream.writeAll(") "); 914 try self.writeSrc(stream, inst_data.src()); 915 } 916 917 fn writeMemset(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { 918 const inst_data = self.code.instructions.items(.data)[inst].pl_node; 919 const extra = self.code.extraData(Zir.Inst.Memset, inst_data.payload_index).data; 920 921 try self.writeInstRef(stream, extra.dest); 922 try stream.writeAll(", "); 923 try self.writeInstRef(stream, extra.byte); 924 try stream.writeAll(", "); 925 try self.writeInstRef(stream, extra.byte_count); 926 try stream.writeAll(") "); 927 try self.writeSrc(stream, inst_data.src()); 928 } 929 930 fn writeStructInitAnon(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { 931 const inst_data = self.code.instructions.items(.data)[inst].pl_node; 932 const extra = self.code.extraData(Zir.Inst.StructInitAnon, inst_data.payload_index); 933 var field_i: u32 = 0; 934 var extra_index = extra.end; 935 936 while (field_i < extra.data.fields_len) : (field_i += 1) { 937 const item = self.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index); 938 extra_index = item.end; 939 940 const field_name = self.code.nullTerminatedString(item.data.field_name); 941 942 const prefix = if (field_i != 0) ", [" else "["; 943 try stream.print("{s}{s}=", .{ prefix, field_name }); 944 try self.writeInstRef(stream, item.data.init); 945 try stream.writeAll("]"); 946 } 947 try stream.writeAll(") "); 948 try self.writeSrc(stream, inst_data.src()); 949 } 950 951 fn writeFieldType(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { 952 const inst_data = self.code.instructions.items(.data)[inst].pl_node; 953 const extra = self.code.extraData(Zir.Inst.FieldType, inst_data.payload_index).data; 954 try self.writeInstRef(stream, extra.container_type); 955 const field_name = self.code.nullTerminatedString(extra.name_start); 956 try stream.print(", {s}) ", .{field_name}); 957 try self.writeSrc(stream, inst_data.src()); 958 } 959 960 fn writeFieldTypeRef(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { 961 const inst_data = self.code.instructions.items(.data)[inst].pl_node; 962 const extra = self.code.extraData(Zir.Inst.FieldTypeRef, inst_data.payload_index).data; 963 try self.writeInstRef(stream, extra.container_type); 964 try stream.writeAll(", "); 965 try self.writeInstRef(stream, extra.field_name); 966 try stream.writeAll(") "); 967 try self.writeSrc(stream, inst_data.src()); 968 } 969 970 fn writeNodeMultiOp(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void { 971 const extra = self.code.extraData(Zir.Inst.NodeMultiOp, extended.operand); 972 const src: LazySrcLoc = .{ .node_offset = extra.data.src_node }; 973 const operands = self.code.refSlice(extra.end, extended.small); 974 975 for (operands) |operand, i| { 976 if (i != 0) try stream.writeAll(", "); 977 try self.writeInstRef(stream, operand); 978 } 979 try stream.writeAll(")) "); 980 try self.writeSrc(stream, src); 981 } 982 983 fn writeInstNode( 984 self: *Writer, 985 stream: anytype, 986 inst: Zir.Inst.Index, 987 ) (@TypeOf(stream).Error || error{OutOfMemory})!void { 988 const inst_data = self.code.instructions.items(.data)[inst].inst_node; 989 try self.writeInstIndex(stream, inst_data.inst); 990 try stream.writeAll(") "); 991 try self.writeSrc(stream, inst_data.src()); 992 } 993 994 fn writeAsm(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void { 995 const extra = self.code.extraData(Zir.Inst.Asm, extended.operand); 996 const src: LazySrcLoc = .{ .node_offset = extra.data.src_node }; 997 const outputs_len = @truncate(u5, extended.small); 998 const inputs_len = @truncate(u5, extended.small >> 5); 999 const clobbers_len = @truncate(u5, extended.small >> 10); 1000 const is_volatile = @truncate(u1, extended.small >> 15) != 0; 1001 const asm_source = self.code.nullTerminatedString(extra.data.asm_source); 1002 1003 try self.writeFlag(stream, "volatile, ", is_volatile); 1004 try stream.print("\"{}\", ", .{std.zig.fmtEscapes(asm_source)}); 1005 try stream.writeAll(", "); 1006 1007 var extra_i: usize = extra.end; 1008 var output_type_bits = extra.data.output_type_bits; 1009 { 1010 var i: usize = 0; 1011 while (i < outputs_len) : (i += 1) { 1012 const output = self.code.extraData(Zir.Inst.Asm.Output, extra_i); 1013 extra_i = output.end; 1014 1015 const is_type = @truncate(u1, output_type_bits) != 0; 1016 output_type_bits >>= 1; 1017 1018 const name = self.code.nullTerminatedString(output.data.name); 1019 const constraint = self.code.nullTerminatedString(output.data.constraint); 1020 try stream.print("output({}, \"{}\", ", .{ 1021 std.zig.fmtId(name), std.zig.fmtEscapes(constraint), 1022 }); 1023 try self.writeFlag(stream, "->", is_type); 1024 try self.writeInstRef(stream, output.data.operand); 1025 try stream.writeAll(")"); 1026 if (i + 1 < outputs_len) { 1027 try stream.writeAll("), "); 1028 } 1029 } 1030 } 1031 { 1032 var i: usize = 0; 1033 while (i < inputs_len) : (i += 1) { 1034 const input = self.code.extraData(Zir.Inst.Asm.Input, extra_i); 1035 extra_i = input.end; 1036 1037 const name = self.code.nullTerminatedString(input.data.name); 1038 const constraint = self.code.nullTerminatedString(input.data.constraint); 1039 try stream.print("input({}, \"{}\", ", .{ 1040 std.zig.fmtId(name), std.zig.fmtEscapes(constraint), 1041 }); 1042 try self.writeInstRef(stream, input.data.operand); 1043 try stream.writeAll(")"); 1044 if (i + 1 < inputs_len) { 1045 try stream.writeAll(", "); 1046 } 1047 } 1048 } 1049 { 1050 var i: usize = 0; 1051 while (i < clobbers_len) : (i += 1) { 1052 const str_index = self.code.extra[extra_i]; 1053 extra_i += 1; 1054 const clobber = self.code.nullTerminatedString(str_index); 1055 try stream.print("{}", .{std.zig.fmtId(clobber)}); 1056 if (i + 1 < clobbers_len) { 1057 try stream.writeAll(", "); 1058 } 1059 } 1060 } 1061 try stream.writeAll(")) "); 1062 try self.writeSrc(stream, src); 1063 } 1064 1065 fn writeOverflowArithmetic(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void { 1066 const extra = self.code.extraData(Zir.Inst.OverflowArithmetic, extended.operand).data; 1067 const src: LazySrcLoc = .{ .node_offset = extra.node }; 1068 1069 try self.writeInstRef(stream, extra.lhs); 1070 try stream.writeAll(", "); 1071 try self.writeInstRef(stream, extra.rhs); 1072 try stream.writeAll(", "); 1073 try self.writeInstRef(stream, extra.ptr); 1074 try stream.writeAll(")) "); 1075 try self.writeSrc(stream, src); 1076 } 1077 1078 fn writePlNodeCall(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { 1079 const inst_data = self.code.instructions.items(.data)[inst].pl_node; 1080 const extra = self.code.extraData(Zir.Inst.Call, inst_data.payload_index); 1081 const args = self.code.refSlice(extra.end, extra.data.flags.args_len); 1082 1083 if (extra.data.flags.ensure_result_used) { 1084 try stream.writeAll("nodiscard "); 1085 } 1086 try stream.print(".{s}, ", .{@tagName(@intToEnum(std.builtin.CallOptions.Modifier, extra.data.flags.packed_modifier))}); 1087 try self.writeInstRef(stream, extra.data.callee); 1088 try stream.writeAll(", ["); 1089 for (args) |arg, i| { 1090 if (i != 0) try stream.writeAll(", "); 1091 try self.writeInstRef(stream, arg); 1092 } 1093 try stream.writeAll("]) "); 1094 try self.writeSrc(stream, inst_data.src()); 1095 } 1096 1097 fn writePlNodeBlock(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { 1098 const inst_data = self.code.instructions.items(.data)[inst].pl_node; 1099 try self.writePlNodeBlockWithoutSrc(stream, inst); 1100 try self.writeSrc(stream, inst_data.src()); 1101 } 1102 1103 fn writePlNodeBlockWithoutSrc(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { 1104 const inst_data = self.code.instructions.items(.data)[inst].pl_node; 1105 const extra = self.code.extraData(Zir.Inst.Block, inst_data.payload_index); 1106 const body = self.code.extra[extra.end..][0..extra.data.body_len]; 1107 try self.writeBracedBody(stream, body); 1108 try stream.writeAll(") "); 1109 } 1110 1111 fn writePlNodeCondBr(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { 1112 const inst_data = self.code.instructions.items(.data)[inst].pl_node; 1113 const extra = self.code.extraData(Zir.Inst.CondBr, inst_data.payload_index); 1114 const then_body = self.code.extra[extra.end..][0..extra.data.then_body_len]; 1115 const else_body = self.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len]; 1116 try self.writeInstRef(stream, extra.data.condition); 1117 try stream.writeAll(", "); 1118 try self.writeBracedBody(stream, then_body); 1119 try stream.writeAll(", "); 1120 try self.writeBracedBody(stream, else_body); 1121 try stream.writeAll(") "); 1122 try self.writeSrc(stream, inst_data.src()); 1123 } 1124 1125 fn writeStructDecl(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void { 1126 const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small); 1127 1128 var extra_index: usize = extended.operand; 1129 1130 const src_node: ?i32 = if (small.has_src_node) blk: { 1131 const src_node = @bitCast(i32, self.code.extra[extra_index]); 1132 extra_index += 1; 1133 break :blk src_node; 1134 } else null; 1135 1136 const body_len = if (small.has_body_len) blk: { 1137 const body_len = self.code.extra[extra_index]; 1138 extra_index += 1; 1139 break :blk body_len; 1140 } else 0; 1141 1142 const fields_len = if (small.has_fields_len) blk: { 1143 const fields_len = self.code.extra[extra_index]; 1144 extra_index += 1; 1145 break :blk fields_len; 1146 } else 0; 1147 1148 const decls_len = if (small.has_decls_len) blk: { 1149 const decls_len = self.code.extra[extra_index]; 1150 extra_index += 1; 1151 break :blk decls_len; 1152 } else 0; 1153 1154 try self.writeFlag(stream, "known_has_bits, ", small.known_has_bits); 1155 try stream.print("{s}, {s}, ", .{ 1156 @tagName(small.name_strategy), @tagName(small.layout), 1157 }); 1158 1159 if (decls_len == 0) { 1160 try stream.writeAll("{}, "); 1161 } else { 1162 try stream.writeAll("{\n"); 1163 self.indent += 2; 1164 extra_index = try self.writeDecls(stream, decls_len, extra_index); 1165 self.indent -= 2; 1166 try stream.writeByteNTimes(' ', self.indent); 1167 try stream.writeAll("}, "); 1168 } 1169 1170 const body = self.code.extra[extra_index..][0..body_len]; 1171 extra_index += body.len; 1172 1173 if (fields_len == 0) { 1174 assert(body.len == 0); 1175 try stream.writeAll("{}, {})"); 1176 } else { 1177 const prev_parent_decl_node = self.parent_decl_node; 1178 if (src_node) |off| self.parent_decl_node = self.relativeToNodeIndex(off); 1179 try self.writeBracedDecl(stream, body); 1180 try stream.writeAll(", {\n"); 1181 1182 self.indent += 2; 1183 const bits_per_field = 4; 1184 const fields_per_u32 = 32 / bits_per_field; 1185 const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable; 1186 var bit_bag_index: usize = extra_index; 1187 extra_index += bit_bags_count; 1188 var cur_bit_bag: u32 = undefined; 1189 var field_i: u32 = 0; 1190 while (field_i < fields_len) : (field_i += 1) { 1191 if (field_i % fields_per_u32 == 0) { 1192 cur_bit_bag = self.code.extra[bit_bag_index]; 1193 bit_bag_index += 1; 1194 } 1195 const has_align = @truncate(u1, cur_bit_bag) != 0; 1196 cur_bit_bag >>= 1; 1197 const has_default = @truncate(u1, cur_bit_bag) != 0; 1198 cur_bit_bag >>= 1; 1199 const is_comptime = @truncate(u1, cur_bit_bag) != 0; 1200 cur_bit_bag >>= 1; 1201 const unused = @truncate(u1, cur_bit_bag) != 0; 1202 cur_bit_bag >>= 1; 1203 1204 _ = unused; 1205 1206 const field_name = self.code.nullTerminatedString(self.code.extra[extra_index]); 1207 extra_index += 1; 1208 const field_type = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); 1209 extra_index += 1; 1210 1211 try stream.writeByteNTimes(' ', self.indent); 1212 try self.writeFlag(stream, "comptime ", is_comptime); 1213 try stream.print("{}: ", .{std.zig.fmtId(field_name)}); 1214 try self.writeInstRef(stream, field_type); 1215 1216 if (has_align) { 1217 const align_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); 1218 extra_index += 1; 1219 1220 try stream.writeAll(" align("); 1221 try self.writeInstRef(stream, align_ref); 1222 try stream.writeAll(")"); 1223 } 1224 if (has_default) { 1225 const default_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); 1226 extra_index += 1; 1227 1228 try stream.writeAll(" = "); 1229 try self.writeInstRef(stream, default_ref); 1230 } 1231 try stream.writeAll(",\n"); 1232 } 1233 1234 self.parent_decl_node = prev_parent_decl_node; 1235 self.indent -= 2; 1236 try stream.writeByteNTimes(' ', self.indent); 1237 try stream.writeAll("})"); 1238 } 1239 try self.writeSrcNode(stream, src_node); 1240 } 1241 1242 fn writeUnionDecl(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void { 1243 const small = @bitCast(Zir.Inst.UnionDecl.Small, extended.small); 1244 1245 var extra_index: usize = extended.operand; 1246 1247 const src_node: ?i32 = if (small.has_src_node) blk: { 1248 const src_node = @bitCast(i32, self.code.extra[extra_index]); 1249 extra_index += 1; 1250 break :blk src_node; 1251 } else null; 1252 1253 const tag_type_ref = if (small.has_tag_type) blk: { 1254 const tag_type_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); 1255 extra_index += 1; 1256 break :blk tag_type_ref; 1257 } else .none; 1258 1259 const body_len = if (small.has_body_len) blk: { 1260 const body_len = self.code.extra[extra_index]; 1261 extra_index += 1; 1262 break :blk body_len; 1263 } else 0; 1264 1265 const fields_len = if (small.has_fields_len) blk: { 1266 const fields_len = self.code.extra[extra_index]; 1267 extra_index += 1; 1268 break :blk fields_len; 1269 } else 0; 1270 1271 const decls_len = if (small.has_decls_len) blk: { 1272 const decls_len = self.code.extra[extra_index]; 1273 extra_index += 1; 1274 break :blk decls_len; 1275 } else 0; 1276 1277 try stream.print("{s}, {s}, ", .{ 1278 @tagName(small.name_strategy), @tagName(small.layout), 1279 }); 1280 try self.writeFlag(stream, "autoenum, ", small.auto_enum_tag); 1281 1282 if (decls_len == 0) { 1283 try stream.writeAll("{}, "); 1284 } else { 1285 try stream.writeAll("{\n"); 1286 self.indent += 2; 1287 extra_index = try self.writeDecls(stream, decls_len, extra_index); 1288 self.indent -= 2; 1289 try stream.writeByteNTimes(' ', self.indent); 1290 try stream.writeAll("}, "); 1291 } 1292 1293 assert(fields_len != 0); 1294 1295 if (tag_type_ref != .none) { 1296 try self.writeInstRef(stream, tag_type_ref); 1297 try stream.writeAll(", "); 1298 } 1299 1300 const body = self.code.extra[extra_index..][0..body_len]; 1301 extra_index += body.len; 1302 1303 const prev_parent_decl_node = self.parent_decl_node; 1304 if (src_node) |off| self.parent_decl_node = self.relativeToNodeIndex(off); 1305 try self.writeBracedDecl(stream, body); 1306 try stream.writeAll(", {\n"); 1307 1308 self.indent += 2; 1309 const bits_per_field = 4; 1310 const fields_per_u32 = 32 / bits_per_field; 1311 const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable; 1312 const body_end = extra_index; 1313 extra_index += bit_bags_count; 1314 var bit_bag_index: usize = body_end; 1315 var cur_bit_bag: u32 = undefined; 1316 var field_i: u32 = 0; 1317 while (field_i < fields_len) : (field_i += 1) { 1318 if (field_i % fields_per_u32 == 0) { 1319 cur_bit_bag = self.code.extra[bit_bag_index]; 1320 bit_bag_index += 1; 1321 } 1322 const has_type = @truncate(u1, cur_bit_bag) != 0; 1323 cur_bit_bag >>= 1; 1324 const has_align = @truncate(u1, cur_bit_bag) != 0; 1325 cur_bit_bag >>= 1; 1326 const has_value = @truncate(u1, cur_bit_bag) != 0; 1327 cur_bit_bag >>= 1; 1328 const unused = @truncate(u1, cur_bit_bag) != 0; 1329 cur_bit_bag >>= 1; 1330 1331 _ = unused; 1332 1333 const field_name = self.code.nullTerminatedString(self.code.extra[extra_index]); 1334 extra_index += 1; 1335 try stream.writeByteNTimes(' ', self.indent); 1336 try stream.print("{}", .{std.zig.fmtId(field_name)}); 1337 1338 if (has_type) { 1339 const field_type = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); 1340 extra_index += 1; 1341 1342 try stream.writeAll(": "); 1343 try self.writeInstRef(stream, field_type); 1344 } 1345 if (has_align) { 1346 const align_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); 1347 extra_index += 1; 1348 1349 try stream.writeAll(" align("); 1350 try self.writeInstRef(stream, align_ref); 1351 try stream.writeAll(")"); 1352 } 1353 if (has_value) { 1354 const default_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); 1355 extra_index += 1; 1356 1357 try stream.writeAll(" = "); 1358 try self.writeInstRef(stream, default_ref); 1359 } 1360 try stream.writeAll(",\n"); 1361 } 1362 1363 self.parent_decl_node = prev_parent_decl_node; 1364 self.indent -= 2; 1365 try stream.writeByteNTimes(' ', self.indent); 1366 try stream.writeAll("})"); 1367 try self.writeSrcNode(stream, src_node); 1368 } 1369 1370 fn writeDecls(self: *Writer, stream: anytype, decls_len: u32, extra_start: usize) !usize { 1371 const parent_decl_node = self.parent_decl_node; 1372 const bit_bags_count = std.math.divCeil(usize, decls_len, 8) catch unreachable; 1373 var extra_index = extra_start + bit_bags_count; 1374 var bit_bag_index: usize = extra_start; 1375 var cur_bit_bag: u32 = undefined; 1376 var decl_i: u32 = 0; 1377 while (decl_i < decls_len) : (decl_i += 1) { 1378 if (decl_i % 8 == 0) { 1379 cur_bit_bag = self.code.extra[bit_bag_index]; 1380 bit_bag_index += 1; 1381 } 1382 const is_pub = @truncate(u1, cur_bit_bag) != 0; 1383 cur_bit_bag >>= 1; 1384 const is_exported = @truncate(u1, cur_bit_bag) != 0; 1385 cur_bit_bag >>= 1; 1386 const has_align = @truncate(u1, cur_bit_bag) != 0; 1387 cur_bit_bag >>= 1; 1388 const has_section_or_addrspace = @truncate(u1, cur_bit_bag) != 0; 1389 cur_bit_bag >>= 1; 1390 1391 const sub_index = extra_index; 1392 1393 const hash_u32s = self.code.extra[extra_index..][0..4]; 1394 extra_index += 4; 1395 const line = self.code.extra[extra_index]; 1396 extra_index += 1; 1397 const decl_name_index = self.code.extra[extra_index]; 1398 extra_index += 1; 1399 const decl_index = self.code.extra[extra_index]; 1400 extra_index += 1; 1401 const align_inst: Zir.Inst.Ref = if (!has_align) .none else inst: { 1402 const inst = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); 1403 extra_index += 1; 1404 break :inst inst; 1405 }; 1406 const section_inst: Zir.Inst.Ref = if (!has_section_or_addrspace) .none else inst: { 1407 const inst = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); 1408 extra_index += 1; 1409 break :inst inst; 1410 }; 1411 const addrspace_inst: Zir.Inst.Ref = if (!has_section_or_addrspace) .none else inst: { 1412 const inst = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); 1413 extra_index += 1; 1414 break :inst inst; 1415 }; 1416 1417 const pub_str = if (is_pub) "pub " else ""; 1418 const hash_bytes = @bitCast([16]u8, hash_u32s.*); 1419 try stream.writeByteNTimes(' ', self.indent); 1420 if (decl_name_index == 0) { 1421 const name = if (is_exported) "usingnamespace" else "comptime"; 1422 try stream.writeAll(pub_str); 1423 try stream.writeAll(name); 1424 } else if (decl_name_index == 1) { 1425 try stream.writeAll("test"); 1426 } else { 1427 const raw_decl_name = self.code.nullTerminatedString(decl_name_index); 1428 const decl_name = if (raw_decl_name.len == 0) 1429 self.code.nullTerminatedString(decl_name_index + 1) 1430 else 1431 raw_decl_name; 1432 const test_str = if (raw_decl_name.len == 0) "test " else ""; 1433 const export_str = if (is_exported) "export " else ""; 1434 try stream.print("[{d}] {s}{s}{s}{}", .{ 1435 sub_index, pub_str, test_str, export_str, std.zig.fmtId(decl_name), 1436 }); 1437 if (align_inst != .none) { 1438 try stream.writeAll(" align("); 1439 try self.writeInstRef(stream, align_inst); 1440 try stream.writeAll(")"); 1441 } 1442 if (addrspace_inst != .none) { 1443 try stream.writeAll(" addrspace("); 1444 try self.writeInstRef(stream, addrspace_inst); 1445 try stream.writeAll(")"); 1446 } 1447 if (section_inst != .none) { 1448 try stream.writeAll(" linksection("); 1449 try self.writeInstRef(stream, section_inst); 1450 try stream.writeAll(")"); 1451 } 1452 } 1453 1454 if (self.recurse_decls) { 1455 const tag = self.code.instructions.items(.tag)[decl_index]; 1456 try stream.print(" line({d}) hash({}): %{d} = {s}(", .{ 1457 line, std.fmt.fmtSliceHexLower(&hash_bytes), decl_index, @tagName(tag), 1458 }); 1459 1460 const decl_block_inst_data = self.code.instructions.items(.data)[decl_index].pl_node; 1461 const sub_decl_node_off = decl_block_inst_data.src_node; 1462 self.parent_decl_node = self.relativeToNodeIndex(sub_decl_node_off); 1463 try self.writePlNodeBlockWithoutSrc(stream, decl_index); 1464 self.parent_decl_node = parent_decl_node; 1465 try self.writeSrc(stream, decl_block_inst_data.src()); 1466 try stream.writeAll("\n"); 1467 } else { 1468 try stream.print(" line({d}) hash({}): %{d} = ...\n", .{ 1469 line, std.fmt.fmtSliceHexLower(&hash_bytes), decl_index, 1470 }); 1471 } 1472 } 1473 return extra_index; 1474 } 1475 1476 fn writeEnumDecl(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void { 1477 const small = @bitCast(Zir.Inst.EnumDecl.Small, extended.small); 1478 var extra_index: usize = extended.operand; 1479 1480 const src_node: ?i32 = if (small.has_src_node) blk: { 1481 const src_node = @bitCast(i32, self.code.extra[extra_index]); 1482 extra_index += 1; 1483 break :blk src_node; 1484 } else null; 1485 1486 const tag_type_ref = if (small.has_tag_type) blk: { 1487 const tag_type_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); 1488 extra_index += 1; 1489 break :blk tag_type_ref; 1490 } else .none; 1491 1492 const body_len = if (small.has_body_len) blk: { 1493 const body_len = self.code.extra[extra_index]; 1494 extra_index += 1; 1495 break :blk body_len; 1496 } else 0; 1497 1498 const fields_len = if (small.has_fields_len) blk: { 1499 const fields_len = self.code.extra[extra_index]; 1500 extra_index += 1; 1501 break :blk fields_len; 1502 } else 0; 1503 1504 const decls_len = if (small.has_decls_len) blk: { 1505 const decls_len = self.code.extra[extra_index]; 1506 extra_index += 1; 1507 break :blk decls_len; 1508 } else 0; 1509 1510 try stream.print("{s}, ", .{@tagName(small.name_strategy)}); 1511 try self.writeFlag(stream, "nonexhaustive, ", small.nonexhaustive); 1512 1513 if (decls_len == 0) { 1514 try stream.writeAll("{}, "); 1515 } else { 1516 try stream.writeAll("{\n"); 1517 self.indent += 2; 1518 extra_index = try self.writeDecls(stream, decls_len, extra_index); 1519 self.indent -= 2; 1520 try stream.writeByteNTimes(' ', self.indent); 1521 try stream.writeAll("}, "); 1522 } 1523 1524 if (tag_type_ref != .none) { 1525 try self.writeInstRef(stream, tag_type_ref); 1526 try stream.writeAll(", "); 1527 } 1528 1529 const body = self.code.extra[extra_index..][0..body_len]; 1530 extra_index += body.len; 1531 1532 if (fields_len == 0) { 1533 assert(body.len == 0); 1534 try stream.writeAll("{}, {})"); 1535 } else { 1536 const prev_parent_decl_node = self.parent_decl_node; 1537 if (src_node) |off| self.parent_decl_node = self.relativeToNodeIndex(off); 1538 try self.writeBracedDecl(stream, body); 1539 try stream.writeAll(", {\n"); 1540 1541 self.indent += 2; 1542 const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable; 1543 const body_end = extra_index; 1544 extra_index += bit_bags_count; 1545 var bit_bag_index: usize = body_end; 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 % 32 == 0) { 1550 cur_bit_bag = self.code.extra[bit_bag_index]; 1551 bit_bag_index += 1; 1552 } 1553 const has_tag_value = @truncate(u1, cur_bit_bag) != 0; 1554 cur_bit_bag >>= 1; 1555 1556 const field_name = self.code.nullTerminatedString(self.code.extra[extra_index]); 1557 extra_index += 1; 1558 1559 try stream.writeByteNTimes(' ', self.indent); 1560 try stream.print("{}", .{std.zig.fmtId(field_name)}); 1561 1562 if (has_tag_value) { 1563 const tag_value_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); 1564 extra_index += 1; 1565 1566 try stream.writeAll(" = "); 1567 try self.writeInstRef(stream, tag_value_ref); 1568 } 1569 try stream.writeAll(",\n"); 1570 } 1571 self.parent_decl_node = prev_parent_decl_node; 1572 self.indent -= 2; 1573 try stream.writeByteNTimes(' ', self.indent); 1574 try stream.writeAll("})"); 1575 } 1576 try self.writeSrcNode(stream, src_node); 1577 } 1578 1579 fn writeOpaqueDecl( 1580 self: *Writer, 1581 stream: anytype, 1582 extended: Zir.Inst.Extended.InstData, 1583 ) !void { 1584 const small = @bitCast(Zir.Inst.OpaqueDecl.Small, extended.small); 1585 var extra_index: usize = extended.operand; 1586 1587 const src_node: ?i32 = if (small.has_src_node) blk: { 1588 const src_node = @bitCast(i32, self.code.extra[extra_index]); 1589 extra_index += 1; 1590 break :blk src_node; 1591 } else null; 1592 1593 const decls_len = if (small.has_decls_len) blk: { 1594 const decls_len = self.code.extra[extra_index]; 1595 extra_index += 1; 1596 break :blk decls_len; 1597 } else 0; 1598 1599 try stream.print("{s}, ", .{@tagName(small.name_strategy)}); 1600 1601 if (decls_len == 0) { 1602 try stream.writeAll("{})"); 1603 } else { 1604 try stream.writeAll("{\n"); 1605 self.indent += 2; 1606 _ = try self.writeDecls(stream, decls_len, extra_index); 1607 self.indent -= 2; 1608 try stream.writeByteNTimes(' ', self.indent); 1609 try stream.writeAll("})"); 1610 } 1611 try self.writeSrcNode(stream, src_node); 1612 } 1613 1614 fn writeErrorSetDecl( 1615 self: *Writer, 1616 stream: anytype, 1617 inst: Zir.Inst.Index, 1618 name_strategy: Zir.Inst.NameStrategy, 1619 ) !void { 1620 const inst_data = self.code.instructions.items(.data)[inst].pl_node; 1621 const extra = self.code.extraData(Zir.Inst.ErrorSetDecl, inst_data.payload_index); 1622 const fields = self.code.extra[extra.end..][0..extra.data.fields_len]; 1623 1624 try stream.print("{s}, ", .{@tagName(name_strategy)}); 1625 1626 try stream.writeAll("{\n"); 1627 self.indent += 2; 1628 for (fields) |str_index| { 1629 const name = self.code.nullTerminatedString(str_index); 1630 try stream.writeByteNTimes(' ', self.indent); 1631 try stream.print("{},\n", .{std.zig.fmtId(name)}); 1632 } 1633 self.indent -= 2; 1634 try stream.writeByteNTimes(' ', self.indent); 1635 try stream.writeAll("}) "); 1636 1637 try self.writeSrc(stream, inst_data.src()); 1638 } 1639 1640 fn writePlNodeSwitchBlock(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { 1641 const inst_data = self.code.instructions.items(.data)[inst].pl_node; 1642 const extra = self.code.extraData(Zir.Inst.SwitchBlock, inst_data.payload_index); 1643 1644 var extra_index: usize = extra.end; 1645 1646 const multi_cases_len = if (extra.data.bits.has_multi_cases) blk: { 1647 const multi_cases_len = self.code.extra[extra_index]; 1648 extra_index += 1; 1649 break :blk multi_cases_len; 1650 } else 0; 1651 1652 try self.writeInstRef(stream, extra.data.operand); 1653 try self.writeFlag(stream, ", ref", extra.data.bits.is_ref); 1654 1655 self.indent += 2; 1656 1657 else_prong: { 1658 const special_prong = extra.data.bits.specialProng(); 1659 const prong_name = switch (special_prong) { 1660 .@"else" => "else", 1661 .under => "_", 1662 else => break :else_prong, 1663 }; 1664 1665 const body_len = self.code.extra[extra_index]; 1666 extra_index += 1; 1667 const body = self.code.extra[extra_index..][0..body_len]; 1668 extra_index += body.len; 1669 1670 try stream.writeAll(",\n"); 1671 try stream.writeByteNTimes(' ', self.indent); 1672 try stream.print("{s} => ", .{prong_name}); 1673 try self.writeBracedBody(stream, body); 1674 } 1675 1676 { 1677 const scalar_cases_len = extra.data.bits.scalar_cases_len; 1678 var scalar_i: usize = 0; 1679 while (scalar_i < scalar_cases_len) : (scalar_i += 1) { 1680 const item_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); 1681 extra_index += 1; 1682 const body_len = self.code.extra[extra_index]; 1683 extra_index += 1; 1684 const body = self.code.extra[extra_index..][0..body_len]; 1685 extra_index += body_len; 1686 1687 try stream.writeAll(",\n"); 1688 try stream.writeByteNTimes(' ', self.indent); 1689 try self.writeInstRef(stream, item_ref); 1690 try stream.writeAll(" => "); 1691 try self.writeBracedBody(stream, body); 1692 } 1693 } 1694 { 1695 var multi_i: usize = 0; 1696 while (multi_i < multi_cases_len) : (multi_i += 1) { 1697 const items_len = self.code.extra[extra_index]; 1698 extra_index += 1; 1699 const ranges_len = self.code.extra[extra_index]; 1700 extra_index += 1; 1701 const body_len = self.code.extra[extra_index]; 1702 extra_index += 1; 1703 const items = self.code.refSlice(extra_index, items_len); 1704 extra_index += items_len; 1705 1706 try stream.writeAll(",\n"); 1707 try stream.writeByteNTimes(' ', self.indent); 1708 1709 for (items) |item_ref, item_i| { 1710 if (item_i != 0) try stream.writeAll(", "); 1711 try self.writeInstRef(stream, item_ref); 1712 } 1713 1714 var range_i: usize = 0; 1715 while (range_i < ranges_len) : (range_i += 1) { 1716 const item_first = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); 1717 extra_index += 1; 1718 const item_last = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); 1719 extra_index += 1; 1720 1721 if (range_i != 0 or items.len != 0) { 1722 try stream.writeAll(", "); 1723 } 1724 try self.writeInstRef(stream, item_first); 1725 try stream.writeAll("..."); 1726 try self.writeInstRef(stream, item_last); 1727 } 1728 1729 const body = self.code.extra[extra_index..][0..body_len]; 1730 extra_index += body_len; 1731 try stream.writeAll(" => "); 1732 try self.writeBracedBody(stream, body); 1733 } 1734 } 1735 1736 self.indent -= 2; 1737 1738 try stream.writeAll(") "); 1739 try self.writeSrc(stream, inst_data.src()); 1740 } 1741 1742 fn writePlNodeField(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { 1743 const inst_data = self.code.instructions.items(.data)[inst].pl_node; 1744 const extra = self.code.extraData(Zir.Inst.Field, inst_data.payload_index).data; 1745 const name = self.code.nullTerminatedString(extra.field_name_start); 1746 try self.writeInstRef(stream, extra.lhs); 1747 try stream.print(", \"{}\") ", .{std.zig.fmtEscapes(name)}); 1748 try self.writeSrc(stream, inst_data.src()); 1749 } 1750 1751 fn writePlNodeFieldNamed(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { 1752 const inst_data = self.code.instructions.items(.data)[inst].pl_node; 1753 const extra = self.code.extraData(Zir.Inst.FieldNamed, inst_data.payload_index).data; 1754 try self.writeInstRef(stream, extra.lhs); 1755 try stream.writeAll(", "); 1756 try self.writeInstRef(stream, extra.field_name); 1757 try stream.writeAll(") "); 1758 try self.writeSrc(stream, inst_data.src()); 1759 } 1760 1761 fn writeAs(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { 1762 const inst_data = self.code.instructions.items(.data)[inst].pl_node; 1763 const extra = self.code.extraData(Zir.Inst.As, inst_data.payload_index).data; 1764 try self.writeInstRef(stream, extra.dest_type); 1765 try stream.writeAll(", "); 1766 try self.writeInstRef(stream, extra.operand); 1767 try stream.writeAll(") "); 1768 try self.writeSrc(stream, inst_data.src()); 1769 } 1770 1771 fn writeNode( 1772 self: *Writer, 1773 stream: anytype, 1774 inst: Zir.Inst.Index, 1775 ) (@TypeOf(stream).Error || error{OutOfMemory})!void { 1776 const src_node = self.code.instructions.items(.data)[inst].node; 1777 const src: LazySrcLoc = .{ .node_offset = src_node }; 1778 try stream.writeAll(") "); 1779 try self.writeSrc(stream, src); 1780 } 1781 1782 fn writeStrTok( 1783 self: *Writer, 1784 stream: anytype, 1785 inst: Zir.Inst.Index, 1786 ) (@TypeOf(stream).Error || error{OutOfMemory})!void { 1787 const inst_data = self.code.instructions.items(.data)[inst].str_tok; 1788 const str = inst_data.get(self.code); 1789 try stream.print("\"{}\") ", .{std.zig.fmtEscapes(str)}); 1790 try self.writeSrc(stream, inst_data.src()); 1791 } 1792 1793 fn writeFunc( 1794 self: *Writer, 1795 stream: anytype, 1796 inst: Zir.Inst.Index, 1797 inferred_error_set: bool, 1798 ) !void { 1799 const inst_data = self.code.instructions.items(.data)[inst].pl_node; 1800 const src = inst_data.src(); 1801 const extra = self.code.extraData(Zir.Inst.Func, inst_data.payload_index); 1802 var extra_index = extra.end; 1803 1804 const ret_ty_body = self.code.extra[extra_index..][0..extra.data.ret_body_len]; 1805 extra_index += ret_ty_body.len; 1806 1807 const body = self.code.extra[extra_index..][0..extra.data.body_len]; 1808 extra_index += body.len; 1809 1810 var src_locs: Zir.Inst.Func.SrcLocs = undefined; 1811 if (body.len != 0) { 1812 src_locs = self.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data; 1813 } 1814 return self.writeFuncCommon( 1815 stream, 1816 ret_ty_body, 1817 inferred_error_set, 1818 false, 1819 false, 1820 .none, 1821 .none, 1822 body, 1823 src, 1824 src_locs, 1825 ); 1826 } 1827 1828 fn writeFuncExtended(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void { 1829 const extra = self.code.extraData(Zir.Inst.ExtendedFunc, extended.operand); 1830 const src: LazySrcLoc = .{ .node_offset = extra.data.src_node }; 1831 const small = @bitCast(Zir.Inst.ExtendedFunc.Small, extended.small); 1832 1833 var extra_index: usize = extra.end; 1834 if (small.has_lib_name) { 1835 const lib_name = self.code.nullTerminatedString(self.code.extra[extra_index]); 1836 extra_index += 1; 1837 try stream.print("lib_name=\"{}\", ", .{std.zig.fmtEscapes(lib_name)}); 1838 } 1839 try self.writeFlag(stream, "test, ", small.is_test); 1840 const cc: Zir.Inst.Ref = if (!small.has_cc) .none else blk: { 1841 const cc = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); 1842 extra_index += 1; 1843 break :blk cc; 1844 }; 1845 const align_inst: Zir.Inst.Ref = if (!small.has_align) .none else blk: { 1846 const align_inst = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); 1847 extra_index += 1; 1848 break :blk align_inst; 1849 }; 1850 1851 const ret_ty_body = self.code.extra[extra_index..][0..extra.data.ret_body_len]; 1852 extra_index += ret_ty_body.len; 1853 1854 const body = self.code.extra[extra_index..][0..extra.data.body_len]; 1855 extra_index += body.len; 1856 1857 var src_locs: Zir.Inst.Func.SrcLocs = undefined; 1858 if (body.len != 0) { 1859 src_locs = self.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data; 1860 } 1861 return self.writeFuncCommon( 1862 stream, 1863 ret_ty_body, 1864 small.is_inferred_error, 1865 small.is_var_args, 1866 small.is_extern, 1867 cc, 1868 align_inst, 1869 body, 1870 src, 1871 src_locs, 1872 ); 1873 } 1874 1875 fn writeVarExtended(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void { 1876 const extra = self.code.extraData(Zir.Inst.ExtendedVar, extended.operand); 1877 const small = @bitCast(Zir.Inst.ExtendedVar.Small, extended.small); 1878 1879 try self.writeInstRef(stream, extra.data.var_type); 1880 1881 var extra_index: usize = extra.end; 1882 if (small.has_lib_name) { 1883 const lib_name = self.code.nullTerminatedString(self.code.extra[extra_index]); 1884 extra_index += 1; 1885 try stream.print(", lib_name=\"{}\"", .{std.zig.fmtEscapes(lib_name)}); 1886 } 1887 const align_inst: Zir.Inst.Ref = if (!small.has_align) .none else blk: { 1888 const align_inst = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); 1889 extra_index += 1; 1890 break :blk align_inst; 1891 }; 1892 const init_inst: Zir.Inst.Ref = if (!small.has_init) .none else blk: { 1893 const init_inst = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); 1894 extra_index += 1; 1895 break :blk init_inst; 1896 }; 1897 try self.writeFlag(stream, ", is_extern", small.is_extern); 1898 try self.writeOptionalInstRef(stream, ", align=", align_inst); 1899 try self.writeOptionalInstRef(stream, ", init=", init_inst); 1900 try stream.writeAll("))"); 1901 } 1902 1903 fn writeAllocExtended(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void { 1904 const extra = self.code.extraData(Zir.Inst.AllocExtended, extended.operand); 1905 const small = @bitCast(Zir.Inst.AllocExtended.Small, extended.small); 1906 const src: LazySrcLoc = .{ .node_offset = extra.data.src_node }; 1907 1908 var extra_index: usize = extra.end; 1909 const type_inst: Zir.Inst.Ref = if (!small.has_type) .none else blk: { 1910 const type_inst = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); 1911 extra_index += 1; 1912 break :blk type_inst; 1913 }; 1914 const align_inst: Zir.Inst.Ref = if (!small.has_align) .none else blk: { 1915 const align_inst = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); 1916 extra_index += 1; 1917 break :blk align_inst; 1918 }; 1919 try self.writeFlag(stream, ",is_const", small.is_const); 1920 try self.writeFlag(stream, ",is_comptime", small.is_comptime); 1921 try self.writeOptionalInstRef(stream, ",ty=", type_inst); 1922 try self.writeOptionalInstRef(stream, ",align=", align_inst); 1923 try stream.writeAll(")) "); 1924 try self.writeSrc(stream, src); 1925 } 1926 1927 fn writeBoolBr(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { 1928 const inst_data = self.code.instructions.items(.data)[inst].bool_br; 1929 const extra = self.code.extraData(Zir.Inst.Block, inst_data.payload_index); 1930 const body = self.code.extra[extra.end..][0..extra.data.body_len]; 1931 try self.writeInstRef(stream, inst_data.lhs); 1932 try stream.writeAll(", "); 1933 try self.writeBracedBody(stream, body); 1934 } 1935 1936 fn writeIntType(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { 1937 const int_type = self.code.instructions.items(.data)[inst].int_type; 1938 const prefix: u8 = switch (int_type.signedness) { 1939 .signed => 'i', 1940 .unsigned => 'u', 1941 }; 1942 try stream.print("{c}{d}) ", .{ prefix, int_type.bit_count }); 1943 try self.writeSrc(stream, int_type.src()); 1944 } 1945 1946 fn writeBreak(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { 1947 const inst_data = self.code.instructions.items(.data)[inst].@"break"; 1948 1949 try self.writeInstIndex(stream, inst_data.block_inst); 1950 try stream.writeAll(", "); 1951 try self.writeInstRef(stream, inst_data.operand); 1952 try stream.writeAll(")"); 1953 } 1954 1955 fn writeArrayInit(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { 1956 const inst_data = self.code.instructions.items(.data)[inst].pl_node; 1957 1958 const extra = self.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index); 1959 const args = self.code.refSlice(extra.end, extra.data.operands_len); 1960 1961 try stream.writeAll(".{"); 1962 for (args) |arg, i| { 1963 if (i != 0) try stream.writeAll(", "); 1964 try self.writeInstRef(stream, arg); 1965 } 1966 try stream.writeAll("})"); 1967 } 1968 1969 fn writeUnreachable(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { 1970 const inst_data = self.code.instructions.items(.data)[inst].@"unreachable"; 1971 const safety_str = if (inst_data.safety) "safe" else "unsafe"; 1972 try stream.print("{s}) ", .{safety_str}); 1973 try self.writeSrc(stream, inst_data.src()); 1974 } 1975 1976 fn writeFuncCommon( 1977 self: *Writer, 1978 stream: anytype, 1979 ret_ty_body: []const Zir.Inst.Index, 1980 inferred_error_set: bool, 1981 var_args: bool, 1982 is_extern: bool, 1983 cc: Zir.Inst.Ref, 1984 align_inst: Zir.Inst.Ref, 1985 body: []const Zir.Inst.Index, 1986 src: LazySrcLoc, 1987 src_locs: Zir.Inst.Func.SrcLocs, 1988 ) !void { 1989 if (ret_ty_body.len == 0) { 1990 try stream.writeAll("ret_ty=void"); 1991 } else { 1992 try stream.writeAll("ret_ty="); 1993 try self.writeBracedBody(stream, ret_ty_body); 1994 } 1995 1996 try self.writeOptionalInstRef(stream, ", cc=", cc); 1997 try self.writeOptionalInstRef(stream, ", align=", align_inst); 1998 try self.writeFlag(stream, ", vargs", var_args); 1999 try self.writeFlag(stream, ", extern", is_extern); 2000 try self.writeFlag(stream, ", inferror", inferred_error_set); 2001 2002 try stream.writeAll(", body="); 2003 try self.writeBracedBody(stream, body); 2004 try stream.writeAll(") "); 2005 if (body.len != 0) { 2006 try stream.print("(lbrace={d}:{d},rbrace={d}:{d}) ", .{ 2007 src_locs.lbrace_line + 1, @truncate(u16, src_locs.columns) + 1, 2008 src_locs.rbrace_line + 1, @truncate(u16, src_locs.columns >> 16) + 1, 2009 }); 2010 } 2011 try self.writeSrc(stream, src); 2012 } 2013 2014 fn writeSwitchCapture(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { 2015 const inst_data = self.code.instructions.items(.data)[inst].switch_capture; 2016 try self.writeInstIndex(stream, inst_data.switch_inst); 2017 try stream.print(", {d})", .{inst_data.prong_index}); 2018 } 2019 2020 fn writeDbgStmt(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { 2021 const inst_data = self.code.instructions.items(.data)[inst].dbg_stmt; 2022 try stream.print("{d}, {d})", .{ inst_data.line + 1, inst_data.column + 1 }); 2023 } 2024 2025 fn writeInstRef(self: *Writer, stream: anytype, ref: Zir.Inst.Ref) !void { 2026 var i: usize = @enumToInt(ref); 2027 2028 if (i < Zir.Inst.Ref.typed_value_map.len) { 2029 return stream.print("@{}", .{ref}); 2030 } 2031 i -= Zir.Inst.Ref.typed_value_map.len; 2032 2033 return self.writeInstIndex(stream, @intCast(Zir.Inst.Index, i)); 2034 } 2035 2036 fn writeInstIndex(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { 2037 _ = self; 2038 return stream.print("%{d}", .{inst}); 2039 } 2040 2041 fn writeOptionalInstRef( 2042 self: *Writer, 2043 stream: anytype, 2044 prefix: []const u8, 2045 inst: Zir.Inst.Ref, 2046 ) !void { 2047 if (inst == .none) return; 2048 try stream.writeAll(prefix); 2049 try self.writeInstRef(stream, inst); 2050 } 2051 2052 fn writeFlag( 2053 self: *Writer, 2054 stream: anytype, 2055 name: []const u8, 2056 flag: bool, 2057 ) !void { 2058 _ = self; 2059 if (!flag) return; 2060 try stream.writeAll(name); 2061 } 2062 2063 fn writeSrc(self: *Writer, stream: anytype, src: LazySrcLoc) !void { 2064 if (self.file.tree_loaded) { 2065 const tree = self.file.tree; 2066 const src_loc: Module.SrcLoc = .{ 2067 .file_scope = self.file, 2068 .parent_decl_node = self.parent_decl_node, 2069 .lazy = src, 2070 }; 2071 const abs_byte_off = src_loc.byteOffset(self.gpa) catch unreachable; 2072 const delta_line = std.zig.findLineColumn(tree.source, abs_byte_off); 2073 try stream.print("{s}:{d}:{d}", .{ 2074 @tagName(src), delta_line.line + 1, delta_line.column + 1, 2075 }); 2076 } 2077 } 2078 2079 fn writeSrcNode(self: *Writer, stream: anytype, src_node: ?i32) !void { 2080 const node_offset = src_node orelse return; 2081 const src: LazySrcLoc = .{ .node_offset = node_offset }; 2082 try stream.writeAll(" "); 2083 return self.writeSrc(stream, src); 2084 } 2085 2086 fn writeBracedDecl(self: *Writer, stream: anytype, body: []const Zir.Inst.Index) !void { 2087 try self.writeBracedBodyConditional(stream, body, self.recurse_decls); 2088 } 2089 2090 fn writeBracedBody(self: *Writer, stream: anytype, body: []const Zir.Inst.Index) !void { 2091 try self.writeBracedBodyConditional(stream, body, self.recurse_blocks); 2092 } 2093 2094 fn writeBracedBodyConditional(self: *Writer, stream: anytype, body: []const Zir.Inst.Index, enabled: bool) !void { 2095 if (body.len == 0) { 2096 try stream.writeAll("{}"); 2097 } else if (enabled) { 2098 try stream.writeAll("{\n"); 2099 self.indent += 2; 2100 try self.writeBody(stream, body); 2101 self.indent -= 2; 2102 try stream.writeByteNTimes(' ', self.indent); 2103 try stream.writeAll("}"); 2104 } else if (body.len == 1) { 2105 try stream.writeByte('{'); 2106 try self.writeInstIndex(stream, body[0]); 2107 try stream.writeByte('}'); 2108 } else if (body.len == 2) { 2109 try stream.writeByte('{'); 2110 try self.writeInstIndex(stream, body[0]); 2111 try stream.writeAll(", "); 2112 try self.writeInstIndex(stream, body[1]); 2113 try stream.writeByte('}'); 2114 } else { 2115 try stream.writeByte('{'); 2116 try self.writeInstIndex(stream, body[0]); 2117 try stream.writeAll(".."); 2118 try self.writeInstIndex(stream, body[body.len - 1]); 2119 try stream.writeByte('}'); 2120 } 2121 } 2122 2123 fn writeBody(self: *Writer, stream: anytype, body: []const Zir.Inst.Index) !void { 2124 for (body) |inst| { 2125 try stream.writeByteNTimes(' ', self.indent); 2126 try stream.print("%{d} ", .{inst}); 2127 try self.writeInstToStream(stream, inst); 2128 try stream.writeByte('\n'); 2129 } 2130 } 2131}; 2132