diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2021-09-20 14:45:40 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2021-09-20 14:45:40 -0700 |
| commit | f3147de7a28767a27406355fd2d93d1bbcec9437 (patch) | |
| tree | 3fa1ffc2140e0781959e5f25753beb9c958fad35 /src | |
| parent | b9d3527e0ed53c4796ab64b4df7daf0909739807 (diff) | |
| download | zig-f3147de7a28767a27406355fd2d93d1bbcec9437.tar.gz zig-f3147de7a28767a27406355fd2d93d1bbcec9437.zip | |
stage2: extract ZIR printing code into print_zir.zig
also implement textual printing of the ZIR instruction `atomic_rmw`.
Diffstat (limited to 'src')
| -rw-r--r-- | src/Zir.zig | 1844 | ||||
| -rw-r--r-- | src/main.zig | 2 | ||||
| -rw-r--r-- | src/print_zir.zig | 1868 |
3 files changed, 1869 insertions, 1845 deletions
diff --git a/src/Zir.zig b/src/Zir.zig index f8dbef2534..f4c3e58eb0 100644 --- a/src/Zir.zig +++ b/src/Zir.zig @@ -112,51 +112,6 @@ pub fn deinit(code: *Zir, gpa: *Allocator) void { code.* = undefined; } -/// Write human-readable, debug formatted ZIR code to a file. -pub fn renderAsTextToFile( - gpa: *Allocator, - scope_file: *Module.Scope.File, - fs_file: std.fs.File, -) !void { - var arena = std.heap.ArenaAllocator.init(gpa); - defer arena.deinit(); - - var writer: Writer = .{ - .gpa = gpa, - .arena = &arena.allocator, - .file = scope_file, - .code = scope_file.zir, - .indent = 0, - .parent_decl_node = 0, - }; - - const main_struct_inst = scope_file.zir.getMainStruct(); - try fs_file.writer().print("%{d} ", .{main_struct_inst}); - try writer.writeInstToStream(fs_file.writer(), main_struct_inst); - try fs_file.writeAll("\n"); - const imports_index = scope_file.zir.extra[@enumToInt(ExtraIndex.imports)]; - if (imports_index != 0) { - try fs_file.writeAll("Imports:\n"); - - const extra = scope_file.zir.extraData(Inst.Imports, imports_index); - var import_i: u32 = 0; - var extra_index = extra.end; - - while (import_i < extra.data.imports_len) : (import_i += 1) { - const item = scope_file.zir.extraData(Inst.Imports.Item, extra_index); - extra_index = item.end; - - const src: LazySrcLoc = .{ .token_abs = item.data.token }; - const import_path = scope_file.zir.nullTerminatedString(item.data.name); - try fs_file.writer().print(" @import(\"{}\") ", .{ - std.zig.fmtEscapes(import_path), - }); - try writer.writeSrc(fs_file.writer(), src); - try fs_file.writer().writeAll("\n"); - } - } -} - /// These are untyped instructions generated from an Abstract Syntax Tree. /// The data here is immutable because it is possible to have multiple /// analyses on the same ZIR happening at the same time. @@ -2904,1805 +2859,6 @@ pub const Inst = struct { pub const SpecialProng = enum { none, @"else", under }; -const Writer = struct { - gpa: *Allocator, - arena: *Allocator, - file: *Module.Scope.File, - code: Zir, - indent: u32, - parent_decl_node: u32, - - fn relativeToNodeIndex(self: *Writer, offset: i32) Ast.Node.Index { - return @bitCast(Ast.Node.Index, offset + @bitCast(i32, self.parent_decl_node)); - } - - fn writeInstToStream( - self: *Writer, - stream: anytype, - inst: Inst.Index, - ) (@TypeOf(stream).Error || error{OutOfMemory})!void { - const tags = self.code.instructions.items(.tag); - const tag = tags[inst]; - try stream.print("= {s}(", .{@tagName(tags[inst])}); - switch (tag) { - .array_type, - .as, - .coerce_result_ptr, - .elem_ptr, - .elem_val, - .store, - .store_to_block_ptr, - .store_to_inferred_ptr, - .field_ptr_type, - => try self.writeBin(stream, inst), - - .alloc, - .alloc_mut, - .alloc_comptime, - .indexable_ptr_len, - .anyframe_type, - .bit_not, - .bool_not, - .negate, - .negate_wrap, - .load, - .ensure_result_used, - .ensure_result_non_error, - .ret_node, - .ret_load, - .resolve_inferred_alloc, - .optional_type, - .optional_payload_safe, - .optional_payload_unsafe, - .optional_payload_safe_ptr, - .optional_payload_unsafe_ptr, - .err_union_payload_safe, - .err_union_payload_unsafe, - .err_union_payload_safe_ptr, - .err_union_payload_unsafe_ptr, - .err_union_code, - .err_union_code_ptr, - .is_non_null, - .is_non_null_ptr, - .is_non_err, - .is_non_err_ptr, - .typeof, - .typeof_elem, - .struct_init_empty, - .type_info, - .size_of, - .bit_size_of, - .typeof_log2_int_type, - .log2_int_type, - .ptr_to_int, - .error_to_int, - .int_to_error, - .compile_error, - .set_eval_branch_quota, - .enum_to_int, - .align_of, - .bool_to_int, - .embed_file, - .error_name, - .panic, - .set_align_stack, - .set_cold, - .set_float_mode, - .set_runtime_safety, - .sqrt, - .sin, - .cos, - .exp, - .exp2, - .log, - .log2, - .log10, - .fabs, - .floor, - .ceil, - .trunc, - .round, - .tag_name, - .reify, - .type_name, - .frame_type, - .frame_size, - .clz, - .ctz, - .pop_count, - .byte_swap, - .bit_reverse, - .elem_type, - .@"resume", - .@"await", - .await_nosuspend, - .fence, - => try self.writeUnNode(stream, inst), - - .ref, - .ret_coerce, - .ensure_err_payload_void, - => try self.writeUnTok(stream, inst), - - .bool_br_and, - .bool_br_or, - => try self.writeBoolBr(stream, inst), - - .array_type_sentinel => try self.writeArrayTypeSentinel(stream, inst), - .param_type => try self.writeParamType(stream, inst), - .ptr_type_simple => try self.writePtrTypeSimple(stream, inst), - .ptr_type => try self.writePtrType(stream, inst), - .int => try self.writeInt(stream, inst), - .int_big => try self.writeIntBig(stream, inst), - .float => try self.writeFloat(stream, inst), - .float128 => try self.writeFloat128(stream, inst), - .str => try self.writeStr(stream, inst), - .int_type => try self.writeIntType(stream, inst), - - .@"break", - .break_inline, - => try self.writeBreak(stream, inst), - - .elem_ptr_node, - .elem_val_node, - .field_ptr_named, - .field_val_named, - .slice_start, - .slice_end, - .slice_sentinel, - .array_init, - .array_init_anon, - .array_init_ref, - .array_init_anon_ref, - .union_init_ptr, - .shuffle, - .select, - .atomic_rmw, - .mul_add, - .builtin_call, - .field_parent_ptr, - .memcpy, - .memset, - .builtin_async_call, - => try self.writePlNode(stream, inst), - - .struct_init, - .struct_init_ref, - => try self.writeStructInit(stream, inst), - - .cmpxchg_strong, .cmpxchg_weak => try self.writeCmpxchg(stream, inst), - .atomic_store => try self.writeAtomicStore(stream, inst), - - .struct_init_anon, - .struct_init_anon_ref, - => try self.writeStructInitAnon(stream, inst), - - .field_type => try self.writeFieldType(stream, inst), - .field_type_ref => try self.writeFieldTypeRef(stream, inst), - - .add, - .addwrap, - .array_cat, - .array_mul, - .mul, - .mulwrap, - .sub, - .subwrap, - .cmp_lt, - .cmp_lte, - .cmp_eq, - .cmp_gte, - .cmp_gt, - .cmp_neq, - .div, - .has_decl, - .has_field, - .mod_rem, - .shl, - .shl_exact, - .shr, - .shr_exact, - .xor, - .store_node, - .error_union_type, - .merge_error_sets, - .bit_and, - .bit_or, - .float_to_int, - .int_to_float, - .int_to_ptr, - .int_to_enum, - .float_cast, - .int_cast, - .err_set_cast, - .ptr_cast, - .truncate, - .align_cast, - .div_exact, - .div_floor, - .div_trunc, - .mod, - .rem, - .bit_offset_of, - .offset_of, - .splat, - .reduce, - .atomic_load, - .bitcast, - .bitcast_result_ptr, - .vector_type, - .maximum, - .minimum, - => try self.writePlNodeBin(stream, inst), - - .@"export" => try self.writePlNodeExport(stream, inst), - - .call, - .call_chkused, - .call_compile_time, - .call_nosuspend, - .call_async, - => try self.writePlNodeCall(stream, inst), - - .block, - .block_inline, - .suspend_block, - .loop, - .validate_struct_init_ptr, - .validate_array_init_ptr, - .c_import, - => try self.writePlNodeBlock(stream, inst), - - .condbr, - .condbr_inline, - => try self.writePlNodeCondBr(stream, inst), - - .opaque_decl => try self.writeOpaqueDecl(stream, inst, .parent), - .opaque_decl_anon => try self.writeOpaqueDecl(stream, inst, .anon), - .opaque_decl_func => try self.writeOpaqueDecl(stream, inst, .func), - - .error_set_decl => try self.writeErrorSetDecl(stream, inst, .parent), - .error_set_decl_anon => try self.writeErrorSetDecl(stream, inst, .anon), - .error_set_decl_func => try self.writeErrorSetDecl(stream, inst, .func), - - .switch_block => try self.writePlNodeSwitchBr(stream, inst, .none), - .switch_block_else => try self.writePlNodeSwitchBr(stream, inst, .@"else"), - .switch_block_under => try self.writePlNodeSwitchBr(stream, inst, .under), - .switch_block_ref => try self.writePlNodeSwitchBr(stream, inst, .none), - .switch_block_ref_else => try self.writePlNodeSwitchBr(stream, inst, .@"else"), - .switch_block_ref_under => try self.writePlNodeSwitchBr(stream, inst, .under), - - .switch_block_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .none), - .switch_block_else_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .@"else"), - .switch_block_under_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .under), - .switch_block_ref_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .none), - .switch_block_ref_else_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .@"else"), - .switch_block_ref_under_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .under), - - .field_ptr, - .field_val, - => try self.writePlNodeField(stream, inst), - - .as_node => try self.writeAs(stream, inst), - - .breakpoint, - .repeat, - .repeat_inline, - .alloc_inferred, - .alloc_inferred_mut, - .alloc_inferred_comptime, - => try self.writeNode(stream, inst), - - .error_value, - .enum_literal, - .decl_ref, - .decl_val, - .import, - .ret_err_value, - .ret_err_value_code, - .param_anytype, - .param_anytype_comptime, - => try self.writeStrTok(stream, inst), - - .param, .param_comptime => try self.writeParam(stream, inst), - - .func => try self.writeFunc(stream, inst, false), - .func_inferred => try self.writeFunc(stream, inst, true), - - .@"unreachable" => try self.writeUnreachable(stream, inst), - - .switch_capture, - .switch_capture_ref, - .switch_capture_multi, - .switch_capture_multi_ref, - .switch_capture_else, - .switch_capture_else_ref, - => try self.writeSwitchCapture(stream, inst), - - .dbg_stmt => try self.writeDbgStmt(stream, inst), - - .extended => try self.writeExtended(stream, inst), - } - } - - fn writeExtended(self: *Writer, stream: anytype, inst: Inst.Index) !void { - const extended = self.code.instructions.items(.data)[inst].extended; - try stream.print("{s}(", .{@tagName(extended.opcode)}); - switch (extended.opcode) { - .ret_ptr, - .ret_type, - .this, - .ret_addr, - .error_return_trace, - .frame, - .frame_address, - .builtin_src, - => try self.writeExtNode(stream, extended), - - .@"asm" => try self.writeAsm(stream, extended), - .func => try self.writeFuncExtended(stream, extended), - .variable => try self.writeVarExtended(stream, extended), - - .compile_log, - .typeof_peer, - => try self.writeNodeMultiOp(stream, extended), - - .add_with_overflow, - .sub_with_overflow, - .mul_with_overflow, - .shl_with_overflow, - => try self.writeOverflowArithmetic(stream, extended), - - .add_with_saturation, - .sub_with_saturation, - .mul_with_saturation, - .shl_with_saturation, - => try self.writeSaturatingArithmetic(stream, extended), - .struct_decl => try self.writeStructDecl(stream, extended), - .union_decl => try self.writeUnionDecl(stream, extended), - .enum_decl => try self.writeEnumDecl(stream, extended), - - .alloc, - .builtin_extern, - .c_undef, - .c_include, - .c_define, - .wasm_memory_size, - .wasm_memory_grow, - => try stream.writeAll("TODO))"), - } - } - - fn writeExtNode(self: *Writer, stream: anytype, extended: Inst.Extended.InstData) !void { - const src: LazySrcLoc = .{ .node_offset = @bitCast(i32, extended.operand) }; - try stream.writeAll(")) "); - try self.writeSrc(stream, src); - } - - fn writeBin(self: *Writer, stream: anytype, inst: Inst.Index) !void { - const inst_data = self.code.instructions.items(.data)[inst].bin; - try self.writeInstRef(stream, inst_data.lhs); - try stream.writeAll(", "); - try self.writeInstRef(stream, inst_data.rhs); - try stream.writeByte(')'); - } - - fn writeUnNode( - self: *Writer, - stream: anytype, - inst: Inst.Index, - ) (@TypeOf(stream).Error || error{OutOfMemory})!void { - const inst_data = self.code.instructions.items(.data)[inst].un_node; - try self.writeInstRef(stream, inst_data.operand); - try stream.writeAll(") "); - try self.writeSrc(stream, inst_data.src()); - } - - fn writeUnTok( - self: *Writer, - stream: anytype, - inst: Inst.Index, - ) (@TypeOf(stream).Error || error{OutOfMemory})!void { - const inst_data = self.code.instructions.items(.data)[inst].un_tok; - try self.writeInstRef(stream, inst_data.operand); - try stream.writeAll(") "); - try self.writeSrc(stream, inst_data.src()); - } - - fn writeArrayTypeSentinel( - self: *Writer, - stream: anytype, - inst: Inst.Index, - ) (@TypeOf(stream).Error || error{OutOfMemory})!void { - const inst_data = self.code.instructions.items(.data)[inst].array_type_sentinel; - _ = inst_data; - try stream.writeAll("TODO)"); - } - - fn writeParamType( - self: *Writer, - stream: anytype, - inst: Inst.Index, - ) (@TypeOf(stream).Error || error{OutOfMemory})!void { - const inst_data = self.code.instructions.items(.data)[inst].param_type; - try self.writeInstRef(stream, inst_data.callee); - try stream.print(", {d})", .{inst_data.param_index}); - } - - fn writePtrTypeSimple( - self: *Writer, - stream: anytype, - inst: Inst.Index, - ) (@TypeOf(stream).Error || error{OutOfMemory})!void { - const inst_data = self.code.instructions.items(.data)[inst].ptr_type_simple; - const str_allowzero = if (inst_data.is_allowzero) "allowzero, " else ""; - const str_const = if (!inst_data.is_mutable) "const, " else ""; - const str_volatile = if (inst_data.is_volatile) "volatile, " else ""; - try self.writeInstRef(stream, inst_data.elem_type); - try stream.print(", {s}{s}{s}{s})", .{ - str_allowzero, - str_const, - str_volatile, - @tagName(inst_data.size), - }); - } - - fn writePtrType( - self: *Writer, - stream: anytype, - inst: Inst.Index, - ) (@TypeOf(stream).Error || error{OutOfMemory})!void { - const inst_data = self.code.instructions.items(.data)[inst].ptr_type; - _ = inst_data; - try stream.writeAll("TODO)"); - } - - fn writeInt(self: *Writer, stream: anytype, inst: Inst.Index) !void { - const inst_data = self.code.instructions.items(.data)[inst].int; - try stream.print("{d})", .{inst_data}); - } - - fn writeIntBig(self: *Writer, stream: anytype, inst: Inst.Index) !void { - const inst_data = self.code.instructions.items(.data)[inst].str; - const byte_count = inst_data.len * @sizeOf(std.math.big.Limb); - const limb_bytes = self.code.string_bytes[inst_data.start..][0..byte_count]; - // limb_bytes is not aligned properly; we must allocate and copy the bytes - // in order to accomplish this. - const limbs = try self.gpa.alloc(std.math.big.Limb, inst_data.len); - defer self.gpa.free(limbs); - - mem.copy(u8, mem.sliceAsBytes(limbs), limb_bytes); - const big_int: std.math.big.int.Const = .{ - .limbs = limbs, - .positive = true, - }; - const as_string = try big_int.toStringAlloc(self.gpa, 10, .lower); - defer self.gpa.free(as_string); - try stream.print("{s})", .{as_string}); - } - - fn writeFloat(self: *Writer, stream: anytype, inst: Inst.Index) !void { - const number = self.code.instructions.items(.data)[inst].float; - try stream.print("{d})", .{number}); - } - - fn writeFloat128(self: *Writer, stream: anytype, inst: Inst.Index) !void { - const inst_data = self.code.instructions.items(.data)[inst].pl_node; - const extra = self.code.extraData(Inst.Float128, inst_data.payload_index).data; - const src = inst_data.src(); - const number = extra.get(); - // TODO improve std.format to be able to print f128 values - try stream.print("{d}) ", .{@floatCast(f64, number)}); - try self.writeSrc(stream, src); - } - - fn writeStr( - self: *Writer, - stream: anytype, - inst: Inst.Index, - ) (@TypeOf(stream).Error || error{OutOfMemory})!void { - const inst_data = self.code.instructions.items(.data)[inst].str; - const str = inst_data.get(self.code); - try stream.print("\"{}\")", .{std.zig.fmtEscapes(str)}); - } - - fn writePlNode(self: *Writer, stream: anytype, inst: Inst.Index) !void { - const inst_data = self.code.instructions.items(.data)[inst].pl_node; - try stream.writeAll("TODO) "); - try self.writeSrc(stream, inst_data.src()); - } - - fn writeParam(self: *Writer, stream: anytype, inst: Inst.Index) !void { - const inst_data = self.code.instructions.items(.data)[inst].pl_tok; - const extra = self.code.extraData(Inst.Param, inst_data.payload_index); - const body = self.code.extra[extra.end..][0..extra.data.body_len]; - try stream.print("\"{}\", ", .{ - std.zig.fmtEscapes(self.code.nullTerminatedString(extra.data.name)), - }); - try stream.writeAll("{\n"); - self.indent += 2; - try self.writeBody(stream, body); - self.indent -= 2; - try stream.writeByteNTimes(' ', self.indent); - try stream.writeAll("}) "); - try self.writeSrc(stream, inst_data.src()); - } - - fn writePlNodeBin(self: *Writer, stream: anytype, inst: Inst.Index) !void { - const inst_data = self.code.instructions.items(.data)[inst].pl_node; - const extra = self.code.extraData(Inst.Bin, inst_data.payload_index).data; - try self.writeInstRef(stream, extra.lhs); - try stream.writeAll(", "); - try self.writeInstRef(stream, extra.rhs); - try stream.writeAll(") "); - try self.writeSrc(stream, inst_data.src()); - } - - fn writePlNodeExport(self: *Writer, stream: anytype, inst: Inst.Index) !void { - const inst_data = self.code.instructions.items(.data)[inst].pl_node; - const extra = self.code.extraData(Inst.Export, inst_data.payload_index).data; - const decl_name = self.code.nullTerminatedString(extra.decl_name); - - try self.writeInstRef(stream, extra.namespace); - try stream.print(", {}, ", .{std.zig.fmtId(decl_name)}); - try self.writeInstRef(stream, extra.options); - try stream.writeAll(") "); - try self.writeSrc(stream, inst_data.src()); - } - - fn writeStructInit(self: *Writer, stream: anytype, inst: Inst.Index) !void { - const inst_data = self.code.instructions.items(.data)[inst].pl_node; - const extra = self.code.extraData(Inst.StructInit, inst_data.payload_index); - var field_i: u32 = 0; - var extra_index = extra.end; - - while (field_i < extra.data.fields_len) : (field_i += 1) { - const item = self.code.extraData(Inst.StructInit.Item, extra_index); - extra_index = item.end; - - if (field_i != 0) { - try stream.writeAll(", ["); - } else { - try stream.writeAll("["); - } - try self.writeInstIndex(stream, item.data.field_type); - try stream.writeAll(", "); - try self.writeInstRef(stream, item.data.init); - try stream.writeAll("]"); - } - try stream.writeAll(") "); - try self.writeSrc(stream, inst_data.src()); - } - - fn writeCmpxchg(self: *Writer, stream: anytype, inst: Inst.Index) !void { - const inst_data = self.code.instructions.items(.data)[inst].pl_node; - const extra = self.code.extraData(Inst.Cmpxchg, inst_data.payload_index).data; - - try self.writeInstRef(stream, extra.ptr); - try stream.writeAll(", "); - try self.writeInstRef(stream, extra.expected_value); - try stream.writeAll(", "); - try self.writeInstRef(stream, extra.new_value); - try stream.writeAll(", "); - try self.writeInstRef(stream, extra.success_order); - try stream.writeAll(", "); - try self.writeInstRef(stream, extra.failure_order); - try stream.writeAll(") "); - try self.writeSrc(stream, inst_data.src()); - } - - fn writeAtomicStore(self: *Writer, stream: anytype, inst: Inst.Index) !void { - const inst_data = self.code.instructions.items(.data)[inst].pl_node; - const extra = self.code.extraData(Inst.AtomicStore, inst_data.payload_index).data; - - try self.writeInstRef(stream, extra.ptr); - try stream.writeAll(", "); - try self.writeInstRef(stream, extra.operand); - try stream.writeAll(", "); - try self.writeInstRef(stream, extra.ordering); - try stream.writeAll(") "); - try self.writeSrc(stream, inst_data.src()); - } - - fn writeStructInitAnon(self: *Writer, stream: anytype, inst: Inst.Index) !void { - const inst_data = self.code.instructions.items(.data)[inst].pl_node; - const extra = self.code.extraData(Inst.StructInitAnon, inst_data.payload_index); - var field_i: u32 = 0; - var extra_index = extra.end; - - while (field_i < extra.data.fields_len) : (field_i += 1) { - const item = self.code.extraData(Inst.StructInitAnon.Item, extra_index); - extra_index = item.end; - - const field_name = self.code.nullTerminatedString(item.data.field_name); - - const prefix = if (field_i != 0) ", [" else "["; - try stream.print("{s}[{s}=", .{ prefix, field_name }); - try self.writeInstRef(stream, item.data.init); - try stream.writeAll("]"); - } - try stream.writeAll(") "); - try self.writeSrc(stream, inst_data.src()); - } - - fn writeFieldType(self: *Writer, stream: anytype, inst: Inst.Index) !void { - const inst_data = self.code.instructions.items(.data)[inst].pl_node; - const extra = self.code.extraData(Inst.FieldType, inst_data.payload_index).data; - try self.writeInstRef(stream, extra.container_type); - const field_name = self.code.nullTerminatedString(extra.name_start); - try stream.print(", {s}) ", .{field_name}); - try self.writeSrc(stream, inst_data.src()); - } - - fn writeFieldTypeRef(self: *Writer, stream: anytype, inst: Inst.Index) !void { - const inst_data = self.code.instructions.items(.data)[inst].pl_node; - const extra = self.code.extraData(Inst.FieldTypeRef, inst_data.payload_index).data; - try self.writeInstRef(stream, extra.container_type); - try stream.writeAll(", "); - try self.writeInstRef(stream, extra.field_name); - try stream.writeAll(") "); - try self.writeSrc(stream, inst_data.src()); - } - - fn writeNodeMultiOp(self: *Writer, stream: anytype, extended: Inst.Extended.InstData) !void { - const extra = self.code.extraData(Inst.NodeMultiOp, extended.operand); - const src: LazySrcLoc = .{ .node_offset = extra.data.src_node }; - const operands = self.code.refSlice(extra.end, extended.small); - - for (operands) |operand, i| { - if (i != 0) try stream.writeAll(", "); - try self.writeInstRef(stream, operand); - } - try stream.writeAll(")) "); - try self.writeSrc(stream, src); - } - - fn writeAsm(self: *Writer, stream: anytype, extended: Inst.Extended.InstData) !void { - const extra = self.code.extraData(Inst.Asm, extended.operand); - const src: LazySrcLoc = .{ .node_offset = extra.data.src_node }; - const outputs_len = @truncate(u5, extended.small); - const inputs_len = @truncate(u5, extended.small >> 5); - const clobbers_len = @truncate(u5, extended.small >> 10); - const is_volatile = @truncate(u1, extended.small >> 15) != 0; - const asm_source = self.code.nullTerminatedString(extra.data.asm_source); - - try self.writeFlag(stream, "volatile, ", is_volatile); - try stream.print("\"{}\", ", .{std.zig.fmtEscapes(asm_source)}); - try stream.writeAll(", "); - - var extra_i: usize = extra.end; - var output_type_bits = extra.data.output_type_bits; - { - var i: usize = 0; - while (i < outputs_len) : (i += 1) { - const output = self.code.extraData(Inst.Asm.Output, extra_i); - extra_i = output.end; - - const is_type = @truncate(u1, output_type_bits) != 0; - output_type_bits >>= 1; - - const name = self.code.nullTerminatedString(output.data.name); - const constraint = self.code.nullTerminatedString(output.data.constraint); - try stream.print("output({}, \"{}\", ", .{ - std.zig.fmtId(name), std.zig.fmtEscapes(constraint), - }); - try self.writeFlag(stream, "->", is_type); - try self.writeInstRef(stream, output.data.operand); - try stream.writeAll(")"); - if (i + 1 < outputs_len) { - try stream.writeAll("), "); - } - } - } - { - var i: usize = 0; - while (i < inputs_len) : (i += 1) { - const input = self.code.extraData(Inst.Asm.Input, extra_i); - extra_i = input.end; - - const name = self.code.nullTerminatedString(input.data.name); - const constraint = self.code.nullTerminatedString(input.data.constraint); - try stream.print("input({}, \"{}\", ", .{ - std.zig.fmtId(name), std.zig.fmtEscapes(constraint), - }); - try self.writeInstRef(stream, input.data.operand); - try stream.writeAll(")"); - if (i + 1 < inputs_len) { - try stream.writeAll(", "); - } - } - } - { - var i: usize = 0; - while (i < clobbers_len) : (i += 1) { - const str_index = self.code.extra[extra_i]; - extra_i += 1; - const clobber = self.code.nullTerminatedString(str_index); - try stream.print("{}", .{std.zig.fmtId(clobber)}); - if (i + 1 < clobbers_len) { - try stream.writeAll(", "); - } - } - } - try stream.writeAll(")) "); - try self.writeSrc(stream, src); - } - - fn writeOverflowArithmetic(self: *Writer, stream: anytype, extended: Inst.Extended.InstData) !void { - const extra = self.code.extraData(Zir.Inst.OverflowArithmetic, extended.operand).data; - const src: LazySrcLoc = .{ .node_offset = extra.node }; - - try self.writeInstRef(stream, extra.lhs); - try stream.writeAll(", "); - try self.writeInstRef(stream, extra.rhs); - try stream.writeAll(", "); - try self.writeInstRef(stream, extra.ptr); - try stream.writeAll(")) "); - try self.writeSrc(stream, src); - } - - fn writeSaturatingArithmetic(self: *Writer, stream: anytype, extended: Inst.Extended.InstData) !void { - const extra = self.code.extraData(Zir.Inst.SaturatingArithmetic, extended.operand).data; - const src: LazySrcLoc = .{ .node_offset = extra.node }; - - try self.writeInstRef(stream, extra.lhs); - try stream.writeAll(", "); - try self.writeInstRef(stream, extra.rhs); - try stream.writeAll(", "); - try stream.writeAll(") "); - try self.writeSrc(stream, src); - } - - fn writePlNodeCall(self: *Writer, stream: anytype, inst: Inst.Index) !void { - const inst_data = self.code.instructions.items(.data)[inst].pl_node; - const extra = self.code.extraData(Inst.Call, inst_data.payload_index); - const args = self.code.refSlice(extra.end, extra.data.args_len); - - try self.writeInstRef(stream, extra.data.callee); - try stream.writeAll(", ["); - for (args) |arg, i| { - if (i != 0) try stream.writeAll(", "); - try self.writeInstRef(stream, arg); - } - try stream.writeAll("]) "); - try self.writeSrc(stream, inst_data.src()); - } - - fn writePlNodeBlock(self: *Writer, stream: anytype, inst: Inst.Index) !void { - const inst_data = self.code.instructions.items(.data)[inst].pl_node; - try self.writePlNodeBlockWithoutSrc(stream, inst); - try self.writeSrc(stream, inst_data.src()); - } - - fn writePlNodeBlockWithoutSrc(self: *Writer, stream: anytype, inst: Inst.Index) !void { - const inst_data = self.code.instructions.items(.data)[inst].pl_node; - const extra = self.code.extraData(Inst.Block, inst_data.payload_index); - const body = self.code.extra[extra.end..][0..extra.data.body_len]; - try stream.writeAll("{\n"); - self.indent += 2; - try self.writeBody(stream, body); - self.indent -= 2; - try stream.writeByteNTimes(' ', self.indent); - try stream.writeAll("}) "); - } - - fn writePlNodeCondBr(self: *Writer, stream: anytype, inst: Inst.Index) !void { - const inst_data = self.code.instructions.items(.data)[inst].pl_node; - const extra = self.code.extraData(Inst.CondBr, inst_data.payload_index); - const then_body = self.code.extra[extra.end..][0..extra.data.then_body_len]; - const else_body = self.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len]; - try self.writeInstRef(stream, extra.data.condition); - try stream.writeAll(", {\n"); - self.indent += 2; - try self.writeBody(stream, then_body); - self.indent -= 2; - try stream.writeByteNTimes(' ', self.indent); - try stream.writeAll("}, {\n"); - self.indent += 2; - try self.writeBody(stream, else_body); - self.indent -= 2; - try stream.writeByteNTimes(' ', self.indent); - try stream.writeAll("}) "); - try self.writeSrc(stream, inst_data.src()); - } - - fn writeStructDecl(self: *Writer, stream: anytype, extended: Inst.Extended.InstData) !void { - const small = @bitCast(Inst.StructDecl.Small, extended.small); - - var extra_index: usize = extended.operand; - - const src_node: ?i32 = if (small.has_src_node) blk: { - const src_node = @bitCast(i32, self.code.extra[extra_index]); - extra_index += 1; - break :blk src_node; - } else null; - - const body_len = if (small.has_body_len) blk: { - const body_len = self.code.extra[extra_index]; - extra_index += 1; - break :blk body_len; - } else 0; - - const fields_len = if (small.has_fields_len) blk: { - const fields_len = self.code.extra[extra_index]; - extra_index += 1; - break :blk fields_len; - } else 0; - - const decls_len = if (small.has_decls_len) blk: { - const decls_len = self.code.extra[extra_index]; - extra_index += 1; - break :blk decls_len; - } else 0; - - try self.writeFlag(stream, "known_has_bits, ", small.known_has_bits); - try stream.print("{s}, {s}, ", .{ - @tagName(small.name_strategy), @tagName(small.layout), - }); - - if (decls_len == 0) { - try stream.writeAll("{}, "); - } else { - try stream.writeAll("{\n"); - self.indent += 2; - extra_index = try self.writeDecls(stream, decls_len, extra_index); - self.indent -= 2; - try stream.writeByteNTimes(' ', self.indent); - try stream.writeAll("}, "); - } - - const body = self.code.extra[extra_index..][0..body_len]; - extra_index += body.len; - - if (fields_len == 0) { - assert(body.len == 0); - try stream.writeAll("{}, {})"); - } else { - const prev_parent_decl_node = self.parent_decl_node; - if (src_node) |off| self.parent_decl_node = self.relativeToNodeIndex(off); - self.indent += 2; - if (body.len == 0) { - try stream.writeAll("{}, {\n"); - } else { - try stream.writeAll("{\n"); - try self.writeBody(stream, body); - - try stream.writeByteNTimes(' ', self.indent - 2); - try stream.writeAll("}, {\n"); - } - - const bits_per_field = 4; - const fields_per_u32 = 32 / bits_per_field; - const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable; - var bit_bag_index: usize = extra_index; - extra_index += bit_bags_count; - var cur_bit_bag: u32 = undefined; - var field_i: u32 = 0; - while (field_i < fields_len) : (field_i += 1) { - if (field_i % fields_per_u32 == 0) { - cur_bit_bag = self.code.extra[bit_bag_index]; - bit_bag_index += 1; - } - const has_align = @truncate(u1, cur_bit_bag) != 0; - cur_bit_bag >>= 1; - const has_default = @truncate(u1, cur_bit_bag) != 0; - cur_bit_bag >>= 1; - const is_comptime = @truncate(u1, cur_bit_bag) != 0; - cur_bit_bag >>= 1; - const unused = @truncate(u1, cur_bit_bag) != 0; - cur_bit_bag >>= 1; - - _ = unused; - - const field_name = self.code.nullTerminatedString(self.code.extra[extra_index]); - extra_index += 1; - const field_type = @intToEnum(Inst.Ref, self.code.extra[extra_index]); - extra_index += 1; - - try stream.writeByteNTimes(' ', self.indent); - try self.writeFlag(stream, "comptime ", is_comptime); - try stream.print("{}: ", .{std.zig.fmtId(field_name)}); - try self.writeInstRef(stream, field_type); - - if (has_align) { - const align_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]); - extra_index += 1; - - try stream.writeAll(" align("); - try self.writeInstRef(stream, align_ref); - try stream.writeAll(")"); - } - if (has_default) { - const default_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]); - extra_index += 1; - - try stream.writeAll(" = "); - try self.writeInstRef(stream, default_ref); - } - try stream.writeAll(",\n"); - } - - self.parent_decl_node = prev_parent_decl_node; - self.indent -= 2; - try stream.writeByteNTimes(' ', self.indent); - try stream.writeAll("})"); - } - try self.writeSrcNode(stream, src_node); - } - - fn writeUnionDecl(self: *Writer, stream: anytype, extended: Inst.Extended.InstData) !void { - const small = @bitCast(Inst.UnionDecl.Small, extended.small); - - var extra_index: usize = extended.operand; - - const src_node: ?i32 = if (small.has_src_node) blk: { - const src_node = @bitCast(i32, self.code.extra[extra_index]); - extra_index += 1; - break :blk src_node; - } else null; - - const tag_type_ref = if (small.has_tag_type) blk: { - const tag_type_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); - extra_index += 1; - break :blk tag_type_ref; - } else .none; - - const body_len = if (small.has_body_len) blk: { - const body_len = self.code.extra[extra_index]; - extra_index += 1; - break :blk body_len; - } else 0; - - const fields_len = if (small.has_fields_len) blk: { - const fields_len = self.code.extra[extra_index]; - extra_index += 1; - break :blk fields_len; - } else 0; - - const decls_len = if (small.has_decls_len) blk: { - const decls_len = self.code.extra[extra_index]; - extra_index += 1; - break :blk decls_len; - } else 0; - - try stream.print("{s}, {s}, ", .{ - @tagName(small.name_strategy), @tagName(small.layout), - }); - try self.writeFlag(stream, "autoenum, ", small.auto_enum_tag); - - if (decls_len == 0) { - try stream.writeAll("{}, "); - } else { - try stream.writeAll("{\n"); - self.indent += 2; - extra_index = try self.writeDecls(stream, decls_len, extra_index); - self.indent -= 2; - try stream.writeByteNTimes(' ', self.indent); - try stream.writeAll("}, "); - } - - assert(fields_len != 0); - - if (tag_type_ref != .none) { - try self.writeInstRef(stream, tag_type_ref); - try stream.writeAll(", "); - } - - const body = self.code.extra[extra_index..][0..body_len]; - extra_index += body.len; - - const prev_parent_decl_node = self.parent_decl_node; - if (src_node) |off| self.parent_decl_node = self.relativeToNodeIndex(off); - self.indent += 2; - if (body.len == 0) { - try stream.writeAll("{}, {\n"); - } else { - try stream.writeAll("{\n"); - try self.writeBody(stream, body); - - try stream.writeByteNTimes(' ', self.indent - 2); - try stream.writeAll("}, {\n"); - } - - const bits_per_field = 4; - const fields_per_u32 = 32 / bits_per_field; - const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable; - const body_end = extra_index; - extra_index += bit_bags_count; - var bit_bag_index: usize = body_end; - var cur_bit_bag: u32 = undefined; - var field_i: u32 = 0; - while (field_i < fields_len) : (field_i += 1) { - if (field_i % fields_per_u32 == 0) { - cur_bit_bag = self.code.extra[bit_bag_index]; - bit_bag_index += 1; - } - const has_type = @truncate(u1, cur_bit_bag) != 0; - cur_bit_bag >>= 1; - const has_align = @truncate(u1, cur_bit_bag) != 0; - cur_bit_bag >>= 1; - const has_value = @truncate(u1, cur_bit_bag) != 0; - cur_bit_bag >>= 1; - const unused = @truncate(u1, cur_bit_bag) != 0; - cur_bit_bag >>= 1; - - _ = unused; - - const field_name = self.code.nullTerminatedString(self.code.extra[extra_index]); - extra_index += 1; - try stream.writeByteNTimes(' ', self.indent); - try stream.print("{}", .{std.zig.fmtId(field_name)}); - - if (has_type) { - const field_type = @intToEnum(Inst.Ref, self.code.extra[extra_index]); - extra_index += 1; - - try stream.writeAll(": "); - try self.writeInstRef(stream, field_type); - } - if (has_align) { - const align_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]); - extra_index += 1; - - try stream.writeAll(" align("); - try self.writeInstRef(stream, align_ref); - try stream.writeAll(")"); - } - if (has_value) { - const default_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]); - extra_index += 1; - - try stream.writeAll(" = "); - try self.writeInstRef(stream, default_ref); - } - try stream.writeAll(",\n"); - } - - self.parent_decl_node = prev_parent_decl_node; - self.indent -= 2; - try stream.writeByteNTimes(' ', self.indent); - try stream.writeAll("})"); - try self.writeSrcNode(stream, src_node); - } - - fn writeDecls(self: *Writer, stream: anytype, decls_len: u32, extra_start: usize) !usize { - const parent_decl_node = self.parent_decl_node; - const bit_bags_count = std.math.divCeil(usize, decls_len, 8) catch unreachable; - var extra_index = extra_start + bit_bags_count; - var bit_bag_index: usize = extra_start; - var cur_bit_bag: u32 = undefined; - var decl_i: u32 = 0; - while (decl_i < decls_len) : (decl_i += 1) { - if (decl_i % 8 == 0) { - cur_bit_bag = self.code.extra[bit_bag_index]; - bit_bag_index += 1; - } - const is_pub = @truncate(u1, cur_bit_bag) != 0; - cur_bit_bag >>= 1; - const is_exported = @truncate(u1, cur_bit_bag) != 0; - cur_bit_bag >>= 1; - const has_align = @truncate(u1, cur_bit_bag) != 0; - cur_bit_bag >>= 1; - const has_section = @truncate(u1, cur_bit_bag) != 0; - cur_bit_bag >>= 1; - - const sub_index = extra_index; - - const hash_u32s = self.code.extra[extra_index..][0..4]; - extra_index += 4; - const line = self.code.extra[extra_index]; - extra_index += 1; - const decl_name_index = self.code.extra[extra_index]; - extra_index += 1; - const decl_index = self.code.extra[extra_index]; - extra_index += 1; - const align_inst: Inst.Ref = if (!has_align) .none else inst: { - const inst = @intToEnum(Inst.Ref, self.code.extra[extra_index]); - extra_index += 1; - break :inst inst; - }; - const section_inst: Inst.Ref = if (!has_section) .none else inst: { - const inst = @intToEnum(Inst.Ref, self.code.extra[extra_index]); - extra_index += 1; - break :inst inst; - }; - - const pub_str = if (is_pub) "pub " else ""; - const hash_bytes = @bitCast([16]u8, hash_u32s.*); - try stream.writeByteNTimes(' ', self.indent); - if (decl_name_index == 0) { - const name = if (is_exported) "usingnamespace" else "comptime"; - try stream.writeAll(pub_str); - try stream.writeAll(name); - } else if (decl_name_index == 1) { - try stream.writeAll("test"); - } else { - const raw_decl_name = self.code.nullTerminatedString(decl_name_index); - const decl_name = if (raw_decl_name.len == 0) - self.code.nullTerminatedString(decl_name_index + 1) - else - raw_decl_name; - const test_str = if (raw_decl_name.len == 0) "test " else ""; - const export_str = if (is_exported) "export " else ""; - try stream.print("[{d}] {s}{s}{s}{}", .{ - sub_index, pub_str, test_str, export_str, std.zig.fmtId(decl_name), - }); - if (align_inst != .none) { - try stream.writeAll(" align("); - try self.writeInstRef(stream, align_inst); - try stream.writeAll(")"); - } - if (section_inst != .none) { - try stream.writeAll(" linksection("); - try self.writeInstRef(stream, section_inst); - try stream.writeAll(")"); - } - } - const tag = self.code.instructions.items(.tag)[decl_index]; - try stream.print(" line({d}) hash({}): %{d} = {s}(", .{ - line, std.fmt.fmtSliceHexLower(&hash_bytes), decl_index, @tagName(tag), - }); - - const decl_block_inst_data = self.code.instructions.items(.data)[decl_index].pl_node; - const sub_decl_node_off = decl_block_inst_data.src_node; - self.parent_decl_node = self.relativeToNodeIndex(sub_decl_node_off); - try self.writePlNodeBlockWithoutSrc(stream, decl_index); - self.parent_decl_node = parent_decl_node; - try self.writeSrc(stream, decl_block_inst_data.src()); - try stream.writeAll("\n"); - } - return extra_index; - } - - fn writeEnumDecl(self: *Writer, stream: anytype, extended: Inst.Extended.InstData) !void { - const small = @bitCast(Inst.EnumDecl.Small, extended.small); - var extra_index: usize = extended.operand; - - const src_node: ?i32 = if (small.has_src_node) blk: { - const src_node = @bitCast(i32, self.code.extra[extra_index]); - extra_index += 1; - break :blk src_node; - } else null; - - const tag_type_ref = if (small.has_tag_type) blk: { - const tag_type_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); - extra_index += 1; - break :blk tag_type_ref; - } else .none; - - const body_len = if (small.has_body_len) blk: { - const body_len = self.code.extra[extra_index]; - extra_index += 1; - break :blk body_len; - } else 0; - - const fields_len = if (small.has_fields_len) blk: { - const fields_len = self.code.extra[extra_index]; - extra_index += 1; - break :blk fields_len; - } else 0; - - const decls_len = if (small.has_decls_len) blk: { - const decls_len = self.code.extra[extra_index]; - extra_index += 1; - break :blk decls_len; - } else 0; - - try stream.print("{s}, ", .{@tagName(small.name_strategy)}); - try self.writeFlag(stream, "nonexhaustive, ", small.nonexhaustive); - - if (decls_len == 0) { - try stream.writeAll("{}, "); - } else { - try stream.writeAll("{\n"); - self.indent += 2; - extra_index = try self.writeDecls(stream, decls_len, extra_index); - self.indent -= 2; - try stream.writeByteNTimes(' ', self.indent); - try stream.writeAll("}, "); - } - - if (tag_type_ref != .none) { - try self.writeInstRef(stream, tag_type_ref); - try stream.writeAll(", "); - } - - const body = self.code.extra[extra_index..][0..body_len]; - extra_index += body.len; - - if (fields_len == 0) { - assert(body.len == 0); - try stream.writeAll("{}, {})"); - } else { - const prev_parent_decl_node = self.parent_decl_node; - if (src_node) |off| self.parent_decl_node = self.relativeToNodeIndex(off); - self.indent += 2; - if (body.len == 0) { - try stream.writeAll("{}, {\n"); - } else { - try stream.writeAll("{\n"); - try self.writeBody(stream, body); - - try stream.writeByteNTimes(' ', self.indent - 2); - try stream.writeAll("}, {\n"); - } - - const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable; - const body_end = extra_index; - extra_index += bit_bags_count; - var bit_bag_index: usize = body_end; - var cur_bit_bag: u32 = undefined; - var field_i: u32 = 0; - while (field_i < fields_len) : (field_i += 1) { - if (field_i % 32 == 0) { - cur_bit_bag = self.code.extra[bit_bag_index]; - bit_bag_index += 1; - } - const has_tag_value = @truncate(u1, cur_bit_bag) != 0; - cur_bit_bag >>= 1; - - const field_name = self.code.nullTerminatedString(self.code.extra[extra_index]); - extra_index += 1; - - try stream.writeByteNTimes(' ', self.indent); - try stream.print("{}", .{std.zig.fmtId(field_name)}); - - if (has_tag_value) { - const tag_value_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]); - extra_index += 1; - - try stream.writeAll(" = "); - try self.writeInstRef(stream, tag_value_ref); - } - try stream.writeAll(",\n"); - } - self.parent_decl_node = prev_parent_decl_node; - self.indent -= 2; - try stream.writeByteNTimes(' ', self.indent); - try stream.writeAll("})"); - } - try self.writeSrcNode(stream, src_node); - } - - fn writeOpaqueDecl( - self: *Writer, - stream: anytype, - inst: Inst.Index, - name_strategy: Inst.NameStrategy, - ) !void { - const inst_data = self.code.instructions.items(.data)[inst].pl_node; - const extra = self.code.extraData(Inst.OpaqueDecl, inst_data.payload_index); - const decls_len = extra.data.decls_len; - - try stream.print("{s}, ", .{@tagName(name_strategy)}); - - if (decls_len == 0) { - try stream.writeAll("}) "); - } else { - try stream.writeAll("\n"); - self.indent += 2; - _ = try self.writeDecls(stream, decls_len, extra.end); - self.indent -= 2; - try stream.writeByteNTimes(' ', self.indent); - try stream.writeAll("}) "); - } - try self.writeSrc(stream, inst_data.src()); - } - - fn writeErrorSetDecl( - self: *Writer, - stream: anytype, - inst: Inst.Index, - name_strategy: Inst.NameStrategy, - ) !void { - const inst_data = self.code.instructions.items(.data)[inst].pl_node; - const extra = self.code.extraData(Inst.ErrorSetDecl, inst_data.payload_index); - const fields = self.code.extra[extra.end..][0..extra.data.fields_len]; - - try stream.print("{s}, ", .{@tagName(name_strategy)}); - - try stream.writeAll("{\n"); - self.indent += 2; - for (fields) |str_index| { - const name = self.code.nullTerminatedString(str_index); - try stream.writeByteNTimes(' ', self.indent); - try stream.print("{},\n", .{std.zig.fmtId(name)}); - } - self.indent -= 2; - try stream.writeByteNTimes(' ', self.indent); - try stream.writeAll("}) "); - - try self.writeSrc(stream, inst_data.src()); - } - - fn writePlNodeSwitchBr( - self: *Writer, - stream: anytype, - inst: Inst.Index, - special_prong: SpecialProng, - ) !void { - const inst_data = self.code.instructions.items(.data)[inst].pl_node; - const extra = self.code.extraData(Inst.SwitchBlock, inst_data.payload_index); - const special: struct { - body: []const Inst.Index, - end: usize, - } = switch (special_prong) { - .none => .{ .body = &.{}, .end = extra.end }, - .under, .@"else" => blk: { - const body_len = self.code.extra[extra.end]; - const extra_body_start = extra.end + 1; - break :blk .{ - .body = self.code.extra[extra_body_start..][0..body_len], - .end = extra_body_start + body_len, - }; - }, - }; - - try self.writeInstRef(stream, extra.data.operand); - - if (special.body.len != 0) { - const prong_name = switch (special_prong) { - .@"else" => "else", - .under => "_", - else => unreachable, - }; - try stream.print(", {s} => {{\n", .{prong_name}); - self.indent += 2; - try self.writeBody(stream, special.body); - self.indent -= 2; - try stream.writeByteNTimes(' ', self.indent); - try stream.writeAll("}"); - } - - var extra_index: usize = special.end; - { - var scalar_i: usize = 0; - while (scalar_i < extra.data.cases_len) : (scalar_i += 1) { - const item_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]); - extra_index += 1; - const body_len = self.code.extra[extra_index]; - extra_index += 1; - const body = self.code.extra[extra_index..][0..body_len]; - extra_index += body_len; - - try stream.writeAll(", "); - try self.writeInstRef(stream, item_ref); - try stream.writeAll(" => {\n"); - self.indent += 2; - try self.writeBody(stream, body); - self.indent -= 2; - try stream.writeByteNTimes(' ', self.indent); - try stream.writeAll("}"); - } - } - try stream.writeAll(") "); - try self.writeSrc(stream, inst_data.src()); - } - - fn writePlNodeSwitchBlockMulti( - self: *Writer, - stream: anytype, - inst: Inst.Index, - special_prong: SpecialProng, - ) !void { - const inst_data = self.code.instructions.items(.data)[inst].pl_node; - const extra = self.code.extraData(Inst.SwitchBlockMulti, inst_data.payload_index); - const special: struct { - body: []const Inst.Index, - end: usize, - } = switch (special_prong) { - .none => .{ .body = &.{}, .end = extra.end }, - .under, .@"else" => blk: { - const body_len = self.code.extra[extra.end]; - const extra_body_start = extra.end + 1; - break :blk .{ - .body = self.code.extra[extra_body_start..][0..body_len], - .end = extra_body_start + body_len, - }; - }, - }; - - try self.writeInstRef(stream, extra.data.operand); - - if (special.body.len != 0) { - const prong_name = switch (special_prong) { - .@"else" => "else", - .under => "_", - else => unreachable, - }; - try stream.print(", {s} => {{\n", .{prong_name}); - self.indent += 2; - try self.writeBody(stream, special.body); - self.indent -= 2; - try stream.writeByteNTimes(' ', self.indent); - try stream.writeAll("}"); - } - - var extra_index: usize = special.end; - { - var scalar_i: usize = 0; - while (scalar_i < extra.data.scalar_cases_len) : (scalar_i += 1) { - const item_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]); - extra_index += 1; - const body_len = self.code.extra[extra_index]; - extra_index += 1; - const body = self.code.extra[extra_index..][0..body_len]; - extra_index += body_len; - - try stream.writeAll(", "); - try self.writeInstRef(stream, item_ref); - try stream.writeAll(" => {\n"); - self.indent += 2; - try self.writeBody(stream, body); - self.indent -= 2; - try stream.writeByteNTimes(' ', self.indent); - try stream.writeAll("}"); - } - } - { - var multi_i: usize = 0; - while (multi_i < extra.data.multi_cases_len) : (multi_i += 1) { - const items_len = self.code.extra[extra_index]; - extra_index += 1; - const ranges_len = self.code.extra[extra_index]; - extra_index += 1; - const body_len = self.code.extra[extra_index]; - extra_index += 1; - const items = self.code.refSlice(extra_index, items_len); - extra_index += items_len; - - for (items) |item_ref| { - try stream.writeAll(", "); - try self.writeInstRef(stream, item_ref); - } - - var range_i: usize = 0; - while (range_i < ranges_len) : (range_i += 1) { - const item_first = @intToEnum(Inst.Ref, self.code.extra[extra_index]); - extra_index += 1; - const item_last = @intToEnum(Inst.Ref, self.code.extra[extra_index]); - extra_index += 1; - - try stream.writeAll(", "); - try self.writeInstRef(stream, item_first); - try stream.writeAll("..."); - try self.writeInstRef(stream, item_last); - } - - const body = self.code.extra[extra_index..][0..body_len]; - extra_index += body_len; - try stream.writeAll(" => {\n"); - self.indent += 2; - try self.writeBody(stream, body); - self.indent -= 2; - try stream.writeByteNTimes(' ', self.indent); - try stream.writeAll("}"); - } - } - try stream.writeAll(") "); - try self.writeSrc(stream, inst_data.src()); - } - - fn writePlNodeField(self: *Writer, stream: anytype, inst: Inst.Index) !void { - const inst_data = self.code.instructions.items(.data)[inst].pl_node; - const extra = self.code.extraData(Inst.Field, inst_data.payload_index).data; - const name = self.code.nullTerminatedString(extra.field_name_start); - try self.writeInstRef(stream, extra.lhs); - try stream.print(", \"{}\") ", .{std.zig.fmtEscapes(name)}); - try self.writeSrc(stream, inst_data.src()); - } - - fn writeAs(self: *Writer, stream: anytype, inst: Inst.Index) !void { - const inst_data = self.code.instructions.items(.data)[inst].pl_node; - const extra = self.code.extraData(Inst.As, inst_data.payload_index).data; - try self.writeInstRef(stream, extra.dest_type); - try stream.writeAll(", "); - try self.writeInstRef(stream, extra.operand); - try stream.writeAll(") "); - try self.writeSrc(stream, inst_data.src()); - } - - fn writeNode( - self: *Writer, - stream: anytype, - inst: Inst.Index, - ) (@TypeOf(stream).Error || error{OutOfMemory})!void { - const src_node = self.code.instructions.items(.data)[inst].node; - const src: LazySrcLoc = .{ .node_offset = src_node }; - try stream.writeAll(") "); - try self.writeSrc(stream, src); - } - - fn writeStrTok( - self: *Writer, - stream: anytype, - inst: Inst.Index, - ) (@TypeOf(stream).Error || error{OutOfMemory})!void { - const inst_data = self.code.instructions.items(.data)[inst].str_tok; - const str = inst_data.get(self.code); - try stream.print("\"{}\") ", .{std.zig.fmtEscapes(str)}); - try self.writeSrc(stream, inst_data.src()); - } - - fn writeFunc( - self: *Writer, - stream: anytype, - inst: Inst.Index, - inferred_error_set: bool, - ) !void { - const inst_data = self.code.instructions.items(.data)[inst].pl_node; - const src = inst_data.src(); - const extra = self.code.extraData(Inst.Func, inst_data.payload_index); - var extra_index = extra.end; - - const ret_ty_body = self.code.extra[extra_index..][0..extra.data.ret_body_len]; - extra_index += ret_ty_body.len; - - const body = self.code.extra[extra_index..][0..extra.data.body_len]; - extra_index += body.len; - - var src_locs: Zir.Inst.Func.SrcLocs = undefined; - if (body.len != 0) { - src_locs = self.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data; - } - return self.writeFuncCommon( - stream, - ret_ty_body, - inferred_error_set, - false, - false, - .none, - .none, - body, - src, - src_locs, - ); - } - - fn writeFuncExtended(self: *Writer, stream: anytype, extended: Inst.Extended.InstData) !void { - const extra = self.code.extraData(Inst.ExtendedFunc, extended.operand); - const src: LazySrcLoc = .{ .node_offset = extra.data.src_node }; - const small = @bitCast(Inst.ExtendedFunc.Small, extended.small); - - var extra_index: usize = extra.end; - if (small.has_lib_name) { - const lib_name = self.code.nullTerminatedString(self.code.extra[extra_index]); - extra_index += 1; - try stream.print("lib_name=\"{}\", ", .{std.zig.fmtEscapes(lib_name)}); - } - try self.writeFlag(stream, "test, ", small.is_test); - const cc: Inst.Ref = if (!small.has_cc) .none else blk: { - const cc = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); - extra_index += 1; - break :blk cc; - }; - const align_inst: Inst.Ref = if (!small.has_align) .none else blk: { - const align_inst = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); - extra_index += 1; - break :blk align_inst; - }; - - const ret_ty_body = self.code.extra[extra_index..][0..extra.data.ret_body_len]; - extra_index += ret_ty_body.len; - - const body = self.code.extra[extra_index..][0..extra.data.body_len]; - extra_index += body.len; - - var src_locs: Zir.Inst.Func.SrcLocs = undefined; - if (body.len != 0) { - src_locs = self.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data; - } - return self.writeFuncCommon( - stream, - ret_ty_body, - small.is_inferred_error, - small.is_var_args, - small.is_extern, - cc, - align_inst, - body, - src, - src_locs, - ); - } - - fn writeVarExtended(self: *Writer, stream: anytype, extended: Inst.Extended.InstData) !void { - const extra = self.code.extraData(Inst.ExtendedVar, extended.operand); - const small = @bitCast(Inst.ExtendedVar.Small, extended.small); - - try self.writeInstRef(stream, extra.data.var_type); - - var extra_index: usize = extra.end; - if (small.has_lib_name) { - const lib_name = self.code.nullTerminatedString(self.code.extra[extra_index]); - extra_index += 1; - try stream.print(", lib_name=\"{}\"", .{std.zig.fmtEscapes(lib_name)}); - } - const align_inst: Inst.Ref = if (!small.has_align) .none else blk: { - const align_inst = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); - extra_index += 1; - break :blk align_inst; - }; - const init_inst: Inst.Ref = if (!small.has_init) .none else blk: { - const init_inst = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); - extra_index += 1; - break :blk init_inst; - }; - try self.writeFlag(stream, ", is_extern", small.is_extern); - try self.writeOptionalInstRef(stream, ", align=", align_inst); - try self.writeOptionalInstRef(stream, ", init=", init_inst); - try stream.writeAll("))"); - } - - fn writeBoolBr(self: *Writer, stream: anytype, inst: Inst.Index) !void { - const inst_data = self.code.instructions.items(.data)[inst].bool_br; - const extra = self.code.extraData(Inst.Block, inst_data.payload_index); - const body = self.code.extra[extra.end..][0..extra.data.body_len]; - try self.writeInstRef(stream, inst_data.lhs); - try stream.writeAll(", {\n"); - self.indent += 2; - try self.writeBody(stream, body); - self.indent -= 2; - try stream.writeByteNTimes(' ', self.indent); - try stream.writeAll("})"); - } - - fn writeIntType(self: *Writer, stream: anytype, inst: Inst.Index) !void { - const int_type = self.code.instructions.items(.data)[inst].int_type; - const prefix: u8 = switch (int_type.signedness) { - .signed => 'i', - .unsigned => 'u', - }; - try stream.print("{c}{d}) ", .{ prefix, int_type.bit_count }); - try self.writeSrc(stream, int_type.src()); - } - - fn writeBreak(self: *Writer, stream: anytype, inst: Inst.Index) !void { - const inst_data = self.code.instructions.items(.data)[inst].@"break"; - - try self.writeInstIndex(stream, inst_data.block_inst); - try stream.writeAll(", "); - try self.writeInstRef(stream, inst_data.operand); - try stream.writeAll(")"); - } - - fn writeUnreachable(self: *Writer, stream: anytype, inst: Inst.Index) !void { - const inst_data = self.code.instructions.items(.data)[inst].@"unreachable"; - const safety_str = if (inst_data.safety) "safe" else "unsafe"; - try stream.print("{s}) ", .{safety_str}); - try self.writeSrc(stream, inst_data.src()); - } - - fn writeFuncCommon( - self: *Writer, - stream: anytype, - ret_ty_body: []const Inst.Index, - inferred_error_set: bool, - var_args: bool, - is_extern: bool, - cc: Inst.Ref, - align_inst: Inst.Ref, - body: []const Inst.Index, - src: LazySrcLoc, - src_locs: Zir.Inst.Func.SrcLocs, - ) !void { - if (ret_ty_body.len == 0) { - try stream.writeAll("ret_ty=void"); - } else { - try stream.writeAll("ret_ty={\n"); - self.indent += 2; - try self.writeBody(stream, ret_ty_body); - self.indent -= 2; - try stream.writeByteNTimes(' ', self.indent); - try stream.writeAll("}"); - } - - try self.writeOptionalInstRef(stream, ", cc=", cc); - try self.writeOptionalInstRef(stream, ", align=", align_inst); - try self.writeFlag(stream, ", vargs", var_args); - try self.writeFlag(stream, ", extern", is_extern); - try self.writeFlag(stream, ", inferror", inferred_error_set); - - if (body.len == 0) { - try stream.writeAll(", body={}) "); - } else { - try stream.writeAll(", body={\n"); - self.indent += 2; - try self.writeBody(stream, body); - self.indent -= 2; - try stream.writeByteNTimes(' ', self.indent); - try stream.writeAll("}) "); - } - if (body.len != 0) { - try stream.print("(lbrace={d}:{d},rbrace={d}:{d}) ", .{ - src_locs.lbrace_line, @truncate(u16, src_locs.columns), - src_locs.rbrace_line, @truncate(u16, src_locs.columns >> 16), - }); - } - try self.writeSrc(stream, src); - } - - fn writeSwitchCapture(self: *Writer, stream: anytype, inst: Inst.Index) !void { - const inst_data = self.code.instructions.items(.data)[inst].switch_capture; - try self.writeInstIndex(stream, inst_data.switch_inst); - try stream.print(", {d})", .{inst_data.prong_index}); - } - - fn writeDbgStmt(self: *Writer, stream: anytype, inst: Inst.Index) !void { - const inst_data = self.code.instructions.items(.data)[inst].dbg_stmt; - try stream.print("{d}, {d})", .{ inst_data.line, inst_data.column }); - } - - fn writeInstRef(self: *Writer, stream: anytype, ref: Inst.Ref) !void { - var i: usize = @enumToInt(ref); - - if (i < Inst.Ref.typed_value_map.len) { - return stream.print("@{}", .{ref}); - } - i -= Inst.Ref.typed_value_map.len; - - return self.writeInstIndex(stream, @intCast(Inst.Index, i)); - } - - fn writeInstIndex(self: *Writer, stream: anytype, inst: Inst.Index) !void { - _ = self; - return stream.print("%{d}", .{inst}); - } - - fn writeOptionalInstRef( - self: *Writer, - stream: anytype, - prefix: []const u8, - inst: Inst.Ref, - ) !void { - if (inst == .none) return; - try stream.writeAll(prefix); - try self.writeInstRef(stream, inst); - } - - fn writeFlag( - self: *Writer, - stream: anytype, - name: []const u8, - flag: bool, - ) !void { - _ = self; - if (!flag) return; - try stream.writeAll(name); - } - - fn writeSrc(self: *Writer, stream: anytype, src: LazySrcLoc) !void { - const tree = self.file.tree; - const src_loc: Module.SrcLoc = .{ - .file_scope = self.file, - .parent_decl_node = self.parent_decl_node, - .lazy = src, - }; - // Caller must ensure AST tree is loaded. - const abs_byte_off = src_loc.byteOffset(self.gpa) catch unreachable; - const delta_line = std.zig.findLineColumn(tree.source, abs_byte_off); - try stream.print("{s}:{d}:{d}", .{ - @tagName(src), delta_line.line + 1, delta_line.column + 1, - }); - } - - fn writeSrcNode(self: *Writer, stream: anytype, src_node: ?i32) !void { - const node_offset = src_node orelse return; - const src: LazySrcLoc = .{ .node_offset = node_offset }; - try stream.writeAll(" "); - return self.writeSrc(stream, src); - } - - fn writeBody(self: *Writer, stream: anytype, body: []const Inst.Index) !void { - for (body) |inst| { - try stream.writeByteNTimes(' ', self.indent); - try stream.print("%{d} ", .{inst}); - try self.writeInstToStream(stream, inst); - try stream.writeByte('\n'); - } - } -}; - pub const DeclIterator = struct { extra_index: usize, bit_bag_index: usize, diff --git a/src/main.zig b/src/main.zig index b7b5d06264..74bf45b62c 100644 --- a/src/main.zig +++ b/src/main.zig @@ -4132,7 +4132,7 @@ pub fn cmdAstCheck( // zig fmt: on } - return Zir.renderAsTextToFile(gpa, &file, io.getStdOut()); + return @import("print_zir.zig").renderAsTextToFile(gpa, &file, io.getStdOut()); } /// This is only enabled for debug builds. diff --git a/src/print_zir.zig b/src/print_zir.zig new file mode 100644 index 0000000000..911cf05baf --- /dev/null +++ b/src/print_zir.zig @@ -0,0 +1,1868 @@ +const std = @import("std"); +const mem = std.mem; +const Allocator = std.mem.Allocator; +const assert = std.debug.assert; +const Ast = std.zig.Ast; + +const Zir = @import("Zir.zig"); +const Module = @import("Module.zig"); +const LazySrcLoc = Module.LazySrcLoc; + +/// Write human-readable, debug formatted ZIR code to a file. +pub fn renderAsTextToFile( + gpa: *Allocator, + scope_file: *Module.Scope.File, + fs_file: std.fs.File, +) !void { + var arena = std.heap.ArenaAllocator.init(gpa); + defer arena.deinit(); + + var writer: Writer = .{ + .gpa = gpa, + .arena = &arena.allocator, + .file = scope_file, + .code = scope_file.zir, + .indent = 0, + .parent_decl_node = 0, + }; + + const main_struct_inst = scope_file.zir.getMainStruct(); + try fs_file.writer().print("%{d} ", .{main_struct_inst}); + try writer.writeInstToStream(fs_file.writer(), main_struct_inst); + try fs_file.writeAll("\n"); + const imports_index = scope_file.zir.extra[@enumToInt(Zir.ExtraIndex.imports)]; + if (imports_index != 0) { + try fs_file.writeAll("Imports:\n"); + + const extra = scope_file.zir.extraData(Zir.Inst.Imports, imports_index); + var import_i: u32 = 0; + var extra_index = extra.end; + + while (import_i < extra.data.imports_len) : (import_i += 1) { + const item = scope_file.zir.extraData(Zir.Inst.Imports.Item, extra_index); + extra_index = item.end; + + const src: LazySrcLoc = .{ .token_abs = item.data.token }; + const import_path = scope_file.zir.nullTerminatedString(item.data.name); + try fs_file.writer().print(" @import(\"{}\") ", .{ + std.zig.fmtEscapes(import_path), + }); + try writer.writeSrc(fs_file.writer(), src); + try fs_file.writer().writeAll("\n"); + } + } +} + +const Writer = struct { + gpa: *Allocator, + arena: *Allocator, + file: *Module.Scope.File, + code: Zir, + indent: u32, + parent_decl_node: u32, + + fn relativeToNodeIndex(self: *Writer, offset: i32) Ast.Node.Index { + return @bitCast(Ast.Node.Index, offset + @bitCast(i32, self.parent_decl_node)); + } + + fn writeInstToStream( + self: *Writer, + stream: anytype, + inst: Zir.Inst.Index, + ) (@TypeOf(stream).Error || error{OutOfMemory})!void { + const tags = self.code.instructions.items(.tag); + const tag = tags[inst]; + try stream.print("= {s}(", .{@tagName(tags[inst])}); + switch (tag) { + .array_type, + .as, + .coerce_result_ptr, + .elem_ptr, + .elem_val, + .store, + .store_to_block_ptr, + .store_to_inferred_ptr, + .field_ptr_type, + => try self.writeBin(stream, inst), + + .alloc, + .alloc_mut, + .alloc_comptime, + .indexable_ptr_len, + .anyframe_type, + .bit_not, + .bool_not, + .negate, + .negate_wrap, + .load, + .ensure_result_used, + .ensure_result_non_error, + .ret_node, + .ret_load, + .resolve_inferred_alloc, + .optional_type, + .optional_payload_safe, + .optional_payload_unsafe, + .optional_payload_safe_ptr, + .optional_payload_unsafe_ptr, + .err_union_payload_safe, + .err_union_payload_unsafe, + .err_union_payload_safe_ptr, + .err_union_payload_unsafe_ptr, + .err_union_code, + .err_union_code_ptr, + .is_non_null, + .is_non_null_ptr, + .is_non_err, + .is_non_err_ptr, + .typeof, + .typeof_elem, + .struct_init_empty, + .type_info, + .size_of, + .bit_size_of, + .typeof_log2_int_type, + .log2_int_type, + .ptr_to_int, + .error_to_int, + .int_to_error, + .compile_error, + .set_eval_branch_quota, + .enum_to_int, + .align_of, + .bool_to_int, + .embed_file, + .error_name, + .panic, + .set_align_stack, + .set_cold, + .set_float_mode, + .set_runtime_safety, + .sqrt, + .sin, + .cos, + .exp, + .exp2, + .log, + .log2, + .log10, + .fabs, + .floor, + .ceil, + .trunc, + .round, + .tag_name, + .reify, + .type_name, + .frame_type, + .frame_size, + .clz, + .ctz, + .pop_count, + .byte_swap, + .bit_reverse, + .elem_type, + .@"resume", + .@"await", + .await_nosuspend, + .fence, + => try self.writeUnNode(stream, inst), + + .ref, + .ret_coerce, + .ensure_err_payload_void, + => try self.writeUnTok(stream, inst), + + .bool_br_and, + .bool_br_or, + => try self.writeBoolBr(stream, inst), + + .array_type_sentinel => try self.writeArrayTypeSentinel(stream, inst), + .param_type => try self.writeParamType(stream, inst), + .ptr_type_simple => try self.writePtrTypeSimple(stream, inst), + .ptr_type => try self.writePtrType(stream, inst), + .int => try self.writeInt(stream, inst), + .int_big => try self.writeIntBig(stream, inst), + .float => try self.writeFloat(stream, inst), + .float128 => try self.writeFloat128(stream, inst), + .str => try self.writeStr(stream, inst), + .int_type => try self.writeIntType(stream, inst), + + .@"break", + .break_inline, + => try self.writeBreak(stream, inst), + + .elem_ptr_node, + .elem_val_node, + .field_ptr_named, + .field_val_named, + .slice_start, + .slice_end, + .slice_sentinel, + .array_init, + .array_init_anon, + .array_init_ref, + .array_init_anon_ref, + .union_init_ptr, + .shuffle, + .select, + .mul_add, + .builtin_call, + .field_parent_ptr, + .memcpy, + .memset, + .builtin_async_call, + => try self.writePlNode(stream, inst), + + .struct_init, + .struct_init_ref, + => try self.writeStructInit(stream, inst), + + .cmpxchg_strong, .cmpxchg_weak => try self.writeCmpxchg(stream, inst), + .atomic_store => try self.writeAtomicStore(stream, inst), + .atomic_rmw => try self.writeAtomicRmw(stream, inst), + + .struct_init_anon, + .struct_init_anon_ref, + => try self.writeStructInitAnon(stream, inst), + + .field_type => try self.writeFieldType(stream, inst), + .field_type_ref => try self.writeFieldTypeRef(stream, inst), + + .add, + .addwrap, + .array_cat, + .array_mul, + .mul, + .mulwrap, + .sub, + .subwrap, + .cmp_lt, + .cmp_lte, + .cmp_eq, + .cmp_gte, + .cmp_gt, + .cmp_neq, + .div, + .has_decl, + .has_field, + .mod_rem, + .shl, + .shl_exact, + .shr, + .shr_exact, + .xor, + .store_node, + .error_union_type, + .merge_error_sets, + .bit_and, + .bit_or, + .float_to_int, + .int_to_float, + .int_to_ptr, + .int_to_enum, + .float_cast, + .int_cast, + .err_set_cast, + .ptr_cast, + .truncate, + .align_cast, + .div_exact, + .div_floor, + .div_trunc, + .mod, + .rem, + .bit_offset_of, + .offset_of, + .splat, + .reduce, + .atomic_load, + .bitcast, + .bitcast_result_ptr, + .vector_type, + .maximum, + .minimum, + => try self.writePlNodeBin(stream, inst), + + .@"export" => try self.writePlNodeExport(stream, inst), + + .call, + .call_chkused, + .call_compile_time, + .call_nosuspend, + .call_async, + => try self.writePlNodeCall(stream, inst), + + .block, + .block_inline, + .suspend_block, + .loop, + .validate_struct_init_ptr, + .validate_array_init_ptr, + .c_import, + => try self.writePlNodeBlock(stream, inst), + + .condbr, + .condbr_inline, + => try self.writePlNodeCondBr(stream, inst), + + .opaque_decl => try self.writeOpaqueDecl(stream, inst, .parent), + .opaque_decl_anon => try self.writeOpaqueDecl(stream, inst, .anon), + .opaque_decl_func => try self.writeOpaqueDecl(stream, inst, .func), + + .error_set_decl => try self.writeErrorSetDecl(stream, inst, .parent), + .error_set_decl_anon => try self.writeErrorSetDecl(stream, inst, .anon), + .error_set_decl_func => try self.writeErrorSetDecl(stream, inst, .func), + + .switch_block => try self.writePlNodeSwitchBr(stream, inst, .none), + .switch_block_else => try self.writePlNodeSwitchBr(stream, inst, .@"else"), + .switch_block_under => try self.writePlNodeSwitchBr(stream, inst, .under), + .switch_block_ref => try self.writePlNodeSwitchBr(stream, inst, .none), + .switch_block_ref_else => try self.writePlNodeSwitchBr(stream, inst, .@"else"), + .switch_block_ref_under => try self.writePlNodeSwitchBr(stream, inst, .under), + + .switch_block_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .none), + .switch_block_else_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .@"else"), + .switch_block_under_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .under), + .switch_block_ref_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .none), + .switch_block_ref_else_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .@"else"), + .switch_block_ref_under_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .under), + + .field_ptr, + .field_val, + => try self.writePlNodeField(stream, inst), + + .as_node => try self.writeAs(stream, inst), + + .breakpoint, + .repeat, + .repeat_inline, + .alloc_inferred, + .alloc_inferred_mut, + .alloc_inferred_comptime, + => try self.writeNode(stream, inst), + + .error_value, + .enum_literal, + .decl_ref, + .decl_val, + .import, + .ret_err_value, + .ret_err_value_code, + .param_anytype, + .param_anytype_comptime, + => try self.writeStrTok(stream, inst), + + .param, .param_comptime => try self.writeParam(stream, inst), + + .func => try self.writeFunc(stream, inst, false), + .func_inferred => try self.writeFunc(stream, inst, true), + + .@"unreachable" => try self.writeUnreachable(stream, inst), + + .switch_capture, + .switch_capture_ref, + .switch_capture_multi, + .switch_capture_multi_ref, + .switch_capture_else, + .switch_capture_else_ref, + => try self.writeSwitchCapture(stream, inst), + + .dbg_stmt => try self.writeDbgStmt(stream, inst), + + .extended => try self.writeExtended(stream, inst), + } + } + + fn writeExtended(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { + const extended = self.code.instructions.items(.data)[inst].extended; + try stream.print("{s}(", .{@tagName(extended.opcode)}); + switch (extended.opcode) { + .ret_ptr, + .ret_type, + .this, + .ret_addr, + .error_return_trace, + .frame, + .frame_address, + .builtin_src, + => try self.writeExtNode(stream, extended), + + .@"asm" => try self.writeAsm(stream, extended), + .func => try self.writeFuncExtended(stream, extended), + .variable => try self.writeVarExtended(stream, extended), + + .compile_log, + .typeof_peer, + => try self.writeNodeMultiOp(stream, extended), + + .add_with_overflow, + .sub_with_overflow, + .mul_with_overflow, + .shl_with_overflow, + => try self.writeOverflowArithmetic(stream, extended), + + .add_with_saturation, + .sub_with_saturation, + .mul_with_saturation, + .shl_with_saturation, + => try self.writeSaturatingArithmetic(stream, extended), + .struct_decl => try self.writeStructDecl(stream, extended), + .union_decl => try self.writeUnionDecl(stream, extended), + .enum_decl => try self.writeEnumDecl(stream, extended), + + .alloc, + .builtin_extern, + .c_undef, + .c_include, + .c_define, + .wasm_memory_size, + .wasm_memory_grow, + => try stream.writeAll("TODO))"), + } + } + + fn writeExtNode(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void { + const src: LazySrcLoc = .{ .node_offset = @bitCast(i32, extended.operand) }; + try stream.writeAll(")) "); + try self.writeSrc(stream, src); + } + + fn writeBin(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { + const inst_data = self.code.instructions.items(.data)[inst].bin; + try self.writeInstRef(stream, inst_data.lhs); + try stream.writeAll(", "); + try self.writeInstRef(stream, inst_data.rhs); + try stream.writeByte(')'); + } + + fn writeUnNode( + self: *Writer, + stream: anytype, + inst: Zir.Inst.Index, + ) (@TypeOf(stream).Error || error{OutOfMemory})!void { + const inst_data = self.code.instructions.items(.data)[inst].un_node; + try self.writeInstRef(stream, inst_data.operand); + try stream.writeAll(") "); + try self.writeSrc(stream, inst_data.src()); + } + + fn writeUnTok( + self: *Writer, + stream: anytype, + inst: Zir.Inst.Index, + ) (@TypeOf(stream).Error || error{OutOfMemory})!void { + const inst_data = self.code.instructions.items(.data)[inst].un_tok; + try self.writeInstRef(stream, inst_data.operand); + try stream.writeAll(") "); + try self.writeSrc(stream, inst_data.src()); + } + + fn writeArrayTypeSentinel( + self: *Writer, + stream: anytype, + inst: Zir.Inst.Index, + ) (@TypeOf(stream).Error || error{OutOfMemory})!void { + const inst_data = self.code.instructions.items(.data)[inst].array_type_sentinel; + _ = inst_data; + try stream.writeAll("TODO)"); + } + + fn writeParamType( + self: *Writer, + stream: anytype, + inst: Zir.Inst.Index, + ) (@TypeOf(stream).Error || error{OutOfMemory})!void { + const inst_data = self.code.instructions.items(.data)[inst].param_type; + try self.writeInstRef(stream, inst_data.callee); + try stream.print(", {d})", .{inst_data.param_index}); + } + + fn writePtrTypeSimple( + self: *Writer, + stream: anytype, + inst: Zir.Inst.Index, + ) (@TypeOf(stream).Error || error{OutOfMemory})!void { + const inst_data = self.code.instructions.items(.data)[inst].ptr_type_simple; + const str_allowzero = if (inst_data.is_allowzero) "allowzero, " else ""; + const str_const = if (!inst_data.is_mutable) "const, " else ""; + const str_volatile = if (inst_data.is_volatile) "volatile, " else ""; + try self.writeInstRef(stream, inst_data.elem_type); + try stream.print(", {s}{s}{s}{s})", .{ + str_allowzero, + str_const, + str_volatile, + @tagName(inst_data.size), + }); + } + + fn writePtrType( + self: *Writer, + stream: anytype, + inst: Zir.Inst.Index, + ) (@TypeOf(stream).Error || error{OutOfMemory})!void { + const inst_data = self.code.instructions.items(.data)[inst].ptr_type; + _ = inst_data; + try stream.writeAll("TODO)"); + } + + fn writeInt(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { + const inst_data = self.code.instructions.items(.data)[inst].int; + try stream.print("{d})", .{inst_data}); + } + + fn writeIntBig(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { + const inst_data = self.code.instructions.items(.data)[inst].str; + const byte_count = inst_data.len * @sizeOf(std.math.big.Limb); + const limb_bytes = self.code.string_bytes[inst_data.start..][0..byte_count]; + // limb_bytes is not aligned properly; we must allocate and copy the bytes + // in order to accomplish this. + const limbs = try self.gpa.alloc(std.math.big.Limb, inst_data.len); + defer self.gpa.free(limbs); + + mem.copy(u8, mem.sliceAsBytes(limbs), limb_bytes); + const big_int: std.math.big.int.Const = .{ + .limbs = limbs, + .positive = true, + }; + const as_string = try big_int.toStringAlloc(self.gpa, 10, .lower); + defer self.gpa.free(as_string); + try stream.print("{s})", .{as_string}); + } + + fn writeFloat(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { + const number = self.code.instructions.items(.data)[inst].float; + try stream.print("{d})", .{number}); + } + + fn writeFloat128(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { + const inst_data = self.code.instructions.items(.data)[inst].pl_node; + const extra = self.code.extraData(Zir.Inst.Float128, inst_data.payload_index).data; + const src = inst_data.src(); + const number = extra.get(); + // TODO improve std.format to be able to print f128 values + try stream.print("{d}) ", .{@floatCast(f64, number)}); + try self.writeSrc(stream, src); + } + + fn writeStr( + self: *Writer, + stream: anytype, + inst: Zir.Inst.Index, + ) (@TypeOf(stream).Error || error{OutOfMemory})!void { + const inst_data = self.code.instructions.items(.data)[inst].str; + const str = inst_data.get(self.code); + try stream.print("\"{}\")", .{std.zig.fmtEscapes(str)}); + } + + fn writePlNode(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { + const inst_data = self.code.instructions.items(.data)[inst].pl_node; + try stream.writeAll("TODO) "); + try self.writeSrc(stream, inst_data.src()); + } + + fn writeParam(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { + const inst_data = self.code.instructions.items(.data)[inst].pl_tok; + const extra = self.code.extraData(Zir.Inst.Param, inst_data.payload_index); + const body = self.code.extra[extra.end..][0..extra.data.body_len]; + try stream.print("\"{}\", ", .{ + std.zig.fmtEscapes(self.code.nullTerminatedString(extra.data.name)), + }); + try stream.writeAll("{\n"); + self.indent += 2; + try self.writeBody(stream, body); + self.indent -= 2; + try stream.writeByteNTimes(' ', self.indent); + try stream.writeAll("}) "); + try self.writeSrc(stream, inst_data.src()); + } + + fn writePlNodeBin(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { + const inst_data = self.code.instructions.items(.data)[inst].pl_node; + const extra = self.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; + try self.writeInstRef(stream, extra.lhs); + try stream.writeAll(", "); + try self.writeInstRef(stream, extra.rhs); + try stream.writeAll(") "); + try self.writeSrc(stream, inst_data.src()); + } + + fn writePlNodeExport(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { + const inst_data = self.code.instructions.items(.data)[inst].pl_node; + const extra = self.code.extraData(Zir.Inst.Export, inst_data.payload_index).data; + const decl_name = self.code.nullTerminatedString(extra.decl_name); + + try self.writeInstRef(stream, extra.namespace); + try stream.print(", {}, ", .{std.zig.fmtId(decl_name)}); + try self.writeInstRef(stream, extra.options); + try stream.writeAll(") "); + try self.writeSrc(stream, inst_data.src()); + } + + fn writeStructInit(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { + const inst_data = self.code.instructions.items(.data)[inst].pl_node; + const extra = self.code.extraData(Zir.Inst.StructInit, inst_data.payload_index); + var field_i: u32 = 0; + var extra_index = extra.end; + + while (field_i < extra.data.fields_len) : (field_i += 1) { + const item = self.code.extraData(Zir.Inst.StructInit.Item, extra_index); + extra_index = item.end; + + if (field_i != 0) { + try stream.writeAll(", ["); + } else { + try stream.writeAll("["); + } + try self.writeInstIndex(stream, item.data.field_type); + try stream.writeAll(", "); + try self.writeInstRef(stream, item.data.init); + try stream.writeAll("]"); + } + try stream.writeAll(") "); + try self.writeSrc(stream, inst_data.src()); + } + + fn writeCmpxchg(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { + const inst_data = self.code.instructions.items(.data)[inst].pl_node; + const extra = self.code.extraData(Zir.Inst.Cmpxchg, inst_data.payload_index).data; + + try self.writeInstRef(stream, extra.ptr); + try stream.writeAll(", "); + try self.writeInstRef(stream, extra.expected_value); + try stream.writeAll(", "); + try self.writeInstRef(stream, extra.new_value); + try stream.writeAll(", "); + try self.writeInstRef(stream, extra.success_order); + try stream.writeAll(", "); + try self.writeInstRef(stream, extra.failure_order); + try stream.writeAll(") "); + try self.writeSrc(stream, inst_data.src()); + } + + fn writeAtomicStore(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { + const inst_data = self.code.instructions.items(.data)[inst].pl_node; + const extra = self.code.extraData(Zir.Inst.AtomicStore, inst_data.payload_index).data; + + try self.writeInstRef(stream, extra.ptr); + try stream.writeAll(", "); + try self.writeInstRef(stream, extra.operand); + try stream.writeAll(", "); + try self.writeInstRef(stream, extra.ordering); + try stream.writeAll(") "); + try self.writeSrc(stream, inst_data.src()); + } + + fn writeAtomicRmw(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { + const inst_data = self.code.instructions.items(.data)[inst].pl_node; + const extra = self.code.extraData(Zir.Inst.AtomicRmw, inst_data.payload_index).data; + + try self.writeInstRef(stream, extra.ptr); + try stream.writeAll(", "); + try self.writeInstRef(stream, extra.operation); + try stream.writeAll(", "); + try self.writeInstRef(stream, extra.operand); + try stream.writeAll(", "); + try self.writeInstRef(stream, extra.ordering); + try stream.writeAll(") "); + try self.writeSrc(stream, inst_data.src()); + } + + fn writeStructInitAnon(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { + const inst_data = self.code.instructions.items(.data)[inst].pl_node; + const extra = self.code.extraData(Zir.Inst.StructInitAnon, inst_data.payload_index); + var field_i: u32 = 0; + var extra_index = extra.end; + + while (field_i < extra.data.fields_len) : (field_i += 1) { + const item = self.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index); + extra_index = item.end; + + const field_name = self.code.nullTerminatedString(item.data.field_name); + + const prefix = if (field_i != 0) ", [" else "["; + try stream.print("{s}[{s}=", .{ prefix, field_name }); + try self.writeInstRef(stream, item.data.init); + try stream.writeAll("]"); + } + try stream.writeAll(") "); + try self.writeSrc(stream, inst_data.src()); + } + + fn writeFieldType(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { + const inst_data = self.code.instructions.items(.data)[inst].pl_node; + const extra = self.code.extraData(Zir.Inst.FieldType, inst_data.payload_index).data; + try self.writeInstRef(stream, extra.container_type); + const field_name = self.code.nullTerminatedString(extra.name_start); + try stream.print(", {s}) ", .{field_name}); + try self.writeSrc(stream, inst_data.src()); + } + + fn writeFieldTypeRef(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { + const inst_data = self.code.instructions.items(.data)[inst].pl_node; + const extra = self.code.extraData(Zir.Inst.FieldTypeRef, inst_data.payload_index).data; + try self.writeInstRef(stream, extra.container_type); + try stream.writeAll(", "); + try self.writeInstRef(stream, extra.field_name); + try stream.writeAll(") "); + try self.writeSrc(stream, inst_data.src()); + } + + fn writeNodeMultiOp(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void { + const extra = self.code.extraData(Zir.Inst.NodeMultiOp, extended.operand); + const src: LazySrcLoc = .{ .node_offset = extra.data.src_node }; + const operands = self.code.refSlice(extra.end, extended.small); + + for (operands) |operand, i| { + if (i != 0) try stream.writeAll(", "); + try self.writeInstRef(stream, operand); + } + try stream.writeAll(")) "); + try self.writeSrc(stream, src); + } + + fn writeAsm(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void { + const extra = self.code.extraData(Zir.Inst.Asm, extended.operand); + const src: LazySrcLoc = .{ .node_offset = extra.data.src_node }; + const outputs_len = @truncate(u5, extended.small); + const inputs_len = @truncate(u5, extended.small >> 5); + const clobbers_len = @truncate(u5, extended.small >> 10); + const is_volatile = @truncate(u1, extended.small >> 15) != 0; + const asm_source = self.code.nullTerminatedString(extra.data.asm_source); + + try self.writeFlag(stream, "volatile, ", is_volatile); + try stream.print("\"{}\", ", .{std.zig.fmtEscapes(asm_source)}); + try stream.writeAll(", "); + + var extra_i: usize = extra.end; + var output_type_bits = extra.data.output_type_bits; + { + var i: usize = 0; + while (i < outputs_len) : (i += 1) { + const output = self.code.extraData(Zir.Inst.Asm.Output, extra_i); + extra_i = output.end; + + const is_type = @truncate(u1, output_type_bits) != 0; + output_type_bits >>= 1; + + const name = self.code.nullTerminatedString(output.data.name); + const constraint = self.code.nullTerminatedString(output.data.constraint); + try stream.print("output({}, \"{}\", ", .{ + std.zig.fmtId(name), std.zig.fmtEscapes(constraint), + }); + try self.writeFlag(stream, "->", is_type); + try self.writeInstRef(stream, output.data.operand); + try stream.writeAll(")"); + if (i + 1 < outputs_len) { + try stream.writeAll("), "); + } + } + } + { + var i: usize = 0; + while (i < inputs_len) : (i += 1) { + const input = self.code.extraData(Zir.Inst.Asm.Input, extra_i); + extra_i = input.end; + + const name = self.code.nullTerminatedString(input.data.name); + const constraint = self.code.nullTerminatedString(input.data.constraint); + try stream.print("input({}, \"{}\", ", .{ + std.zig.fmtId(name), std.zig.fmtEscapes(constraint), + }); + try self.writeInstRef(stream, input.data.operand); + try stream.writeAll(")"); + if (i + 1 < inputs_len) { + try stream.writeAll(", "); + } + } + } + { + var i: usize = 0; + while (i < clobbers_len) : (i += 1) { + const str_index = self.code.extra[extra_i]; + extra_i += 1; + const clobber = self.code.nullTerminatedString(str_index); + try stream.print("{}", .{std.zig.fmtId(clobber)}); + if (i + 1 < clobbers_len) { + try stream.writeAll(", "); + } + } + } + try stream.writeAll(")) "); + try self.writeSrc(stream, src); + } + + fn writeOverflowArithmetic(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void { + const extra = self.code.extraData(Zir.Inst.OverflowArithmetic, extended.operand).data; + const src: LazySrcLoc = .{ .node_offset = extra.node }; + + try self.writeInstRef(stream, extra.lhs); + try stream.writeAll(", "); + try self.writeInstRef(stream, extra.rhs); + try stream.writeAll(", "); + try self.writeInstRef(stream, extra.ptr); + try stream.writeAll(")) "); + try self.writeSrc(stream, src); + } + + fn writeSaturatingArithmetic(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void { + const extra = self.code.extraData(Zir.Inst.SaturatingArithmetic, extended.operand).data; + const src: LazySrcLoc = .{ .node_offset = extra.node }; + + try self.writeInstRef(stream, extra.lhs); + try stream.writeAll(", "); + try self.writeInstRef(stream, extra.rhs); + try stream.writeAll(", "); + try stream.writeAll(") "); + try self.writeSrc(stream, src); + } + + fn writePlNodeCall(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { + const inst_data = self.code.instructions.items(.data)[inst].pl_node; + const extra = self.code.extraData(Zir.Inst.Call, inst_data.payload_index); + const args = self.code.refSlice(extra.end, extra.data.args_len); + + try self.writeInstRef(stream, extra.data.callee); + try stream.writeAll(", ["); + for (args) |arg, i| { + if (i != 0) try stream.writeAll(", "); + try self.writeInstRef(stream, arg); + } + try stream.writeAll("]) "); + try self.writeSrc(stream, inst_data.src()); + } + + fn writePlNodeBlock(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { + const inst_data = self.code.instructions.items(.data)[inst].pl_node; + try self.writePlNodeBlockWithoutSrc(stream, inst); + try self.writeSrc(stream, inst_data.src()); + } + + fn writePlNodeBlockWithoutSrc(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { + const inst_data = self.code.instructions.items(.data)[inst].pl_node; + const extra = self.code.extraData(Zir.Inst.Block, inst_data.payload_index); + const body = self.code.extra[extra.end..][0..extra.data.body_len]; + try stream.writeAll("{\n"); + self.indent += 2; + try self.writeBody(stream, body); + self.indent -= 2; + try stream.writeByteNTimes(' ', self.indent); + try stream.writeAll("}) "); + } + + fn writePlNodeCondBr(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { + const inst_data = self.code.instructions.items(.data)[inst].pl_node; + const extra = self.code.extraData(Zir.Inst.CondBr, inst_data.payload_index); + const then_body = self.code.extra[extra.end..][0..extra.data.then_body_len]; + const else_body = self.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len]; + try self.writeInstRef(stream, extra.data.condition); + try stream.writeAll(", {\n"); + self.indent += 2; + try self.writeBody(stream, then_body); + self.indent -= 2; + try stream.writeByteNTimes(' ', self.indent); + try stream.writeAll("}, {\n"); + self.indent += 2; + try self.writeBody(stream, else_body); + self.indent -= 2; + try stream.writeByteNTimes(' ', self.indent); + try stream.writeAll("}) "); + try self.writeSrc(stream, inst_data.src()); + } + + fn writeStructDecl(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void { + const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small); + + var extra_index: usize = extended.operand; + + const src_node: ?i32 = if (small.has_src_node) blk: { + const src_node = @bitCast(i32, self.code.extra[extra_index]); + extra_index += 1; + break :blk src_node; + } else null; + + const body_len = if (small.has_body_len) blk: { + const body_len = self.code.extra[extra_index]; + extra_index += 1; + break :blk body_len; + } else 0; + + const fields_len = if (small.has_fields_len) blk: { + const fields_len = self.code.extra[extra_index]; + extra_index += 1; + break :blk fields_len; + } else 0; + + const decls_len = if (small.has_decls_len) blk: { + const decls_len = self.code.extra[extra_index]; + extra_index += 1; + break :blk decls_len; + } else 0; + + try self.writeFlag(stream, "known_has_bits, ", small.known_has_bits); + try stream.print("{s}, {s}, ", .{ + @tagName(small.name_strategy), @tagName(small.layout), + }); + + if (decls_len == 0) { + try stream.writeAll("{}, "); + } else { + try stream.writeAll("{\n"); + self.indent += 2; + extra_index = try self.writeDecls(stream, decls_len, extra_index); + self.indent -= 2; + try stream.writeByteNTimes(' ', self.indent); + try stream.writeAll("}, "); + } + + const body = self.code.extra[extra_index..][0..body_len]; + extra_index += body.len; + + if (fields_len == 0) { + assert(body.len == 0); + try stream.writeAll("{}, {})"); + } else { + const prev_parent_decl_node = self.parent_decl_node; + if (src_node) |off| self.parent_decl_node = self.relativeToNodeIndex(off); + self.indent += 2; + if (body.len == 0) { + try stream.writeAll("{}, {\n"); + } else { + try stream.writeAll("{\n"); + try self.writeBody(stream, body); + + try stream.writeByteNTimes(' ', self.indent - 2); + try stream.writeAll("}, {\n"); + } + + const bits_per_field = 4; + const fields_per_u32 = 32 / bits_per_field; + const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable; + var bit_bag_index: usize = extra_index; + extra_index += bit_bags_count; + var cur_bit_bag: u32 = undefined; + var field_i: u32 = 0; + while (field_i < fields_len) : (field_i += 1) { + if (field_i % fields_per_u32 == 0) { + cur_bit_bag = self.code.extra[bit_bag_index]; + bit_bag_index += 1; + } + const has_align = @truncate(u1, cur_bit_bag) != 0; + cur_bit_bag >>= 1; + const has_default = @truncate(u1, cur_bit_bag) != 0; + cur_bit_bag >>= 1; + const is_comptime = @truncate(u1, cur_bit_bag) != 0; + cur_bit_bag >>= 1; + const unused = @truncate(u1, cur_bit_bag) != 0; + cur_bit_bag >>= 1; + + _ = unused; + + const field_name = self.code.nullTerminatedString(self.code.extra[extra_index]); + extra_index += 1; + const field_type = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); + extra_index += 1; + + try stream.writeByteNTimes(' ', self.indent); + try self.writeFlag(stream, "comptime ", is_comptime); + try stream.print("{}: ", .{std.zig.fmtId(field_name)}); + try self.writeInstRef(stream, field_type); + + if (has_align) { + const align_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); + extra_index += 1; + + try stream.writeAll(" align("); + try self.writeInstRef(stream, align_ref); + try stream.writeAll(")"); + } + if (has_default) { + const default_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); + extra_index += 1; + + try stream.writeAll(" = "); + try self.writeInstRef(stream, default_ref); + } + try stream.writeAll(",\n"); + } + + self.parent_decl_node = prev_parent_decl_node; + self.indent -= 2; + try stream.writeByteNTimes(' ', self.indent); + try stream.writeAll("})"); + } + try self.writeSrcNode(stream, src_node); + } + + fn writeUnionDecl(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void { + const small = @bitCast(Zir.Inst.UnionDecl.Small, extended.small); + + var extra_index: usize = extended.operand; + + const src_node: ?i32 = if (small.has_src_node) blk: { + const src_node = @bitCast(i32, self.code.extra[extra_index]); + extra_index += 1; + break :blk src_node; + } else null; + + const tag_type_ref = if (small.has_tag_type) blk: { + const tag_type_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); + extra_index += 1; + break :blk tag_type_ref; + } else .none; + + const body_len = if (small.has_body_len) blk: { + const body_len = self.code.extra[extra_index]; + extra_index += 1; + break :blk body_len; + } else 0; + + const fields_len = if (small.has_fields_len) blk: { + const fields_len = self.code.extra[extra_index]; + extra_index += 1; + break :blk fields_len; + } else 0; + + const decls_len = if (small.has_decls_len) blk: { + const decls_len = self.code.extra[extra_index]; + extra_index += 1; + break :blk decls_len; + } else 0; + + try stream.print("{s}, {s}, ", .{ + @tagName(small.name_strategy), @tagName(small.layout), + }); + try self.writeFlag(stream, "autoenum, ", small.auto_enum_tag); + + if (decls_len == 0) { + try stream.writeAll("{}, "); + } else { + try stream.writeAll("{\n"); + self.indent += 2; + extra_index = try self.writeDecls(stream, decls_len, extra_index); + self.indent -= 2; + try stream.writeByteNTimes(' ', self.indent); + try stream.writeAll("}, "); + } + + assert(fields_len != 0); + + if (tag_type_ref != .none) { + try self.writeInstRef(stream, tag_type_ref); + try stream.writeAll(", "); + } + + const body = self.code.extra[extra_index..][0..body_len]; + extra_index += body.len; + + const prev_parent_decl_node = self.parent_decl_node; + if (src_node) |off| self.parent_decl_node = self.relativeToNodeIndex(off); + self.indent += 2; + if (body.len == 0) { + try stream.writeAll("{}, {\n"); + } else { + try stream.writeAll("{\n"); + try self.writeBody(stream, body); + + try stream.writeByteNTimes(' ', self.indent - 2); + try stream.writeAll("}, {\n"); + } + + const bits_per_field = 4; + const fields_per_u32 = 32 / bits_per_field; + const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable; + const body_end = extra_index; + extra_index += bit_bags_count; + var bit_bag_index: usize = body_end; + var cur_bit_bag: u32 = undefined; + var field_i: u32 = 0; + while (field_i < fields_len) : (field_i += 1) { + if (field_i % fields_per_u32 == 0) { + cur_bit_bag = self.code.extra[bit_bag_index]; + bit_bag_index += 1; + } + const has_type = @truncate(u1, cur_bit_bag) != 0; + cur_bit_bag >>= 1; + const has_align = @truncate(u1, cur_bit_bag) != 0; + cur_bit_bag >>= 1; + const has_value = @truncate(u1, cur_bit_bag) != 0; + cur_bit_bag >>= 1; + const unused = @truncate(u1, cur_bit_bag) != 0; + cur_bit_bag >>= 1; + + _ = unused; + + const field_name = self.code.nullTerminatedString(self.code.extra[extra_index]); + extra_index += 1; + try stream.writeByteNTimes(' ', self.indent); + try stream.print("{}", .{std.zig.fmtId(field_name)}); + + if (has_type) { + const field_type = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); + extra_index += 1; + + try stream.writeAll(": "); + try self.writeInstRef(stream, field_type); + } + if (has_align) { + const align_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); + extra_index += 1; + + try stream.writeAll(" align("); + try self.writeInstRef(stream, align_ref); + try stream.writeAll(")"); + } + if (has_value) { + const default_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); + extra_index += 1; + + try stream.writeAll(" = "); + try self.writeInstRef(stream, default_ref); + } + try stream.writeAll(",\n"); + } + + self.parent_decl_node = prev_parent_decl_node; + self.indent -= 2; + try stream.writeByteNTimes(' ', self.indent); + try stream.writeAll("})"); + try self.writeSrcNode(stream, src_node); + } + + fn writeDecls(self: *Writer, stream: anytype, decls_len: u32, extra_start: usize) !usize { + const parent_decl_node = self.parent_decl_node; + const bit_bags_count = std.math.divCeil(usize, decls_len, 8) catch unreachable; + var extra_index = extra_start + bit_bags_count; + var bit_bag_index: usize = extra_start; + var cur_bit_bag: u32 = undefined; + var decl_i: u32 = 0; + while (decl_i < decls_len) : (decl_i += 1) { + if (decl_i % 8 == 0) { + cur_bit_bag = self.code.extra[bit_bag_index]; + bit_bag_index += 1; + } + const is_pub = @truncate(u1, cur_bit_bag) != 0; + cur_bit_bag >>= 1; + const is_exported = @truncate(u1, cur_bit_bag) != 0; + cur_bit_bag >>= 1; + const has_align = @truncate(u1, cur_bit_bag) != 0; + cur_bit_bag >>= 1; + const has_section = @truncate(u1, cur_bit_bag) != 0; + cur_bit_bag >>= 1; + + const sub_index = extra_index; + + const hash_u32s = self.code.extra[extra_index..][0..4]; + extra_index += 4; + const line = self.code.extra[extra_index]; + extra_index += 1; + const decl_name_index = self.code.extra[extra_index]; + extra_index += 1; + const decl_index = self.code.extra[extra_index]; + extra_index += 1; + const align_inst: Zir.Inst.Ref = if (!has_align) .none else inst: { + const inst = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); + extra_index += 1; + break :inst inst; + }; + const section_inst: Zir.Inst.Ref = if (!has_section) .none else inst: { + const inst = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); + extra_index += 1; + break :inst inst; + }; + + const pub_str = if (is_pub) "pub " else ""; + const hash_bytes = @bitCast([16]u8, hash_u32s.*); + try stream.writeByteNTimes(' ', self.indent); + if (decl_name_index == 0) { + const name = if (is_exported) "usingnamespace" else "comptime"; + try stream.writeAll(pub_str); + try stream.writeAll(name); + } else if (decl_name_index == 1) { + try stream.writeAll("test"); + } else { + const raw_decl_name = self.code.nullTerminatedString(decl_name_index); + const decl_name = if (raw_decl_name.len == 0) + self.code.nullTerminatedString(decl_name_index + 1) + else + raw_decl_name; + const test_str = if (raw_decl_name.len == 0) "test " else ""; + const export_str = if (is_exported) "export " else ""; + try stream.print("[{d}] {s}{s}{s}{}", .{ + sub_index, pub_str, test_str, export_str, std.zig.fmtId(decl_name), + }); + if (align_inst != .none) { + try stream.writeAll(" align("); + try self.writeInstRef(stream, align_inst); + try stream.writeAll(")"); + } + if (section_inst != .none) { + try stream.writeAll(" linksection("); + try self.writeInstRef(stream, section_inst); + try stream.writeAll(")"); + } + } + const tag = self.code.instructions.items(.tag)[decl_index]; + try stream.print(" line({d}) hash({}): %{d} = {s}(", .{ + line, std.fmt.fmtSliceHexLower(&hash_bytes), decl_index, @tagName(tag), + }); + + const decl_block_inst_data = self.code.instructions.items(.data)[decl_index].pl_node; + const sub_decl_node_off = decl_block_inst_data.src_node; + self.parent_decl_node = self.relativeToNodeIndex(sub_decl_node_off); + try self.writePlNodeBlockWithoutSrc(stream, decl_index); + self.parent_decl_node = parent_decl_node; + try self.writeSrc(stream, decl_block_inst_data.src()); + try stream.writeAll("\n"); + } + return extra_index; + } + + fn writeEnumDecl(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void { + const small = @bitCast(Zir.Inst.EnumDecl.Small, extended.small); + var extra_index: usize = extended.operand; + + const src_node: ?i32 = if (small.has_src_node) blk: { + const src_node = @bitCast(i32, self.code.extra[extra_index]); + extra_index += 1; + break :blk src_node; + } else null; + + const tag_type_ref = if (small.has_tag_type) blk: { + const tag_type_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); + extra_index += 1; + break :blk tag_type_ref; + } else .none; + + const body_len = if (small.has_body_len) blk: { + const body_len = self.code.extra[extra_index]; + extra_index += 1; + break :blk body_len; + } else 0; + + const fields_len = if (small.has_fields_len) blk: { + const fields_len = self.code.extra[extra_index]; + extra_index += 1; + break :blk fields_len; + } else 0; + + const decls_len = if (small.has_decls_len) blk: { + const decls_len = self.code.extra[extra_index]; + extra_index += 1; + break :blk decls_len; + } else 0; + + try stream.print("{s}, ", .{@tagName(small.name_strategy)}); + try self.writeFlag(stream, "nonexhaustive, ", small.nonexhaustive); + + if (decls_len == 0) { + try stream.writeAll("{}, "); + } else { + try stream.writeAll("{\n"); + self.indent += 2; + extra_index = try self.writeDecls(stream, decls_len, extra_index); + self.indent -= 2; + try stream.writeByteNTimes(' ', self.indent); + try stream.writeAll("}, "); + } + + if (tag_type_ref != .none) { + try self.writeInstRef(stream, tag_type_ref); + try stream.writeAll(", "); + } + + const body = self.code.extra[extra_index..][0..body_len]; + extra_index += body.len; + + if (fields_len == 0) { + assert(body.len == 0); + try stream.writeAll("{}, {})"); + } else { + const prev_parent_decl_node = self.parent_decl_node; + if (src_node) |off| self.parent_decl_node = self.relativeToNodeIndex(off); + self.indent += 2; + if (body.len == 0) { + try stream.writeAll("{}, {\n"); + } else { + try stream.writeAll("{\n"); + try self.writeBody(stream, body); + + try stream.writeByteNTimes(' ', self.indent - 2); + try stream.writeAll("}, {\n"); + } + + const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable; + const body_end = extra_index; + extra_index += bit_bags_count; + var bit_bag_index: usize = body_end; + var cur_bit_bag: u32 = undefined; + var field_i: u32 = 0; + while (field_i < fields_len) : (field_i += 1) { + if (field_i % 32 == 0) { + cur_bit_bag = self.code.extra[bit_bag_index]; + bit_bag_index += 1; + } + const has_tag_value = @truncate(u1, cur_bit_bag) != 0; + cur_bit_bag >>= 1; + + const field_name = self.code.nullTerminatedString(self.code.extra[extra_index]); + extra_index += 1; + + try stream.writeByteNTimes(' ', self.indent); + try stream.print("{}", .{std.zig.fmtId(field_name)}); + + if (has_tag_value) { + const tag_value_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); + extra_index += 1; + + try stream.writeAll(" = "); + try self.writeInstRef(stream, tag_value_ref); + } + try stream.writeAll(",\n"); + } + self.parent_decl_node = prev_parent_decl_node; + self.indent -= 2; + try stream.writeByteNTimes(' ', self.indent); + try stream.writeAll("})"); + } + try self.writeSrcNode(stream, src_node); + } + + fn writeOpaqueDecl( + self: *Writer, + stream: anytype, + inst: Zir.Inst.Index, + name_strategy: Zir.Inst.NameStrategy, + ) !void { + const inst_data = self.code.instructions.items(.data)[inst].pl_node; + const extra = self.code.extraData(Zir.Inst.OpaqueDecl, inst_data.payload_index); + const decls_len = extra.data.decls_len; + + try stream.print("{s}, ", .{@tagName(name_strategy)}); + + if (decls_len == 0) { + try stream.writeAll("}) "); + } else { + try stream.writeAll("\n"); + self.indent += 2; + _ = try self.writeDecls(stream, decls_len, extra.end); + self.indent -= 2; + try stream.writeByteNTimes(' ', self.indent); + try stream.writeAll("}) "); + } + try self.writeSrc(stream, inst_data.src()); + } + + fn writeErrorSetDecl( + self: *Writer, + stream: anytype, + inst: Zir.Inst.Index, + name_strategy: Zir.Inst.NameStrategy, + ) !void { + const inst_data = self.code.instructions.items(.data)[inst].pl_node; + const extra = self.code.extraData(Zir.Inst.ErrorSetDecl, inst_data.payload_index); + const fields = self.code.extra[extra.end..][0..extra.data.fields_len]; + + try stream.print("{s}, ", .{@tagName(name_strategy)}); + + try stream.writeAll("{\n"); + self.indent += 2; + for (fields) |str_index| { + const name = self.code.nullTerminatedString(str_index); + try stream.writeByteNTimes(' ', self.indent); + try stream.print("{},\n", .{std.zig.fmtId(name)}); + } + self.indent -= 2; + try stream.writeByteNTimes(' ', self.indent); + try stream.writeAll("}) "); + + try self.writeSrc(stream, inst_data.src()); + } + + fn writePlNodeSwitchBr( + self: *Writer, + stream: anytype, + inst: Zir.Inst.Index, + special_prong: Zir.SpecialProng, + ) !void { + const inst_data = self.code.instructions.items(.data)[inst].pl_node; + const extra = self.code.extraData(Zir.Inst.SwitchBlock, inst_data.payload_index); + const special: struct { + body: []const Zir.Inst.Index, + end: usize, + } = switch (special_prong) { + .none => .{ .body = &.{}, .end = extra.end }, + .under, .@"else" => blk: { + const body_len = self.code.extra[extra.end]; + const extra_body_start = extra.end + 1; + break :blk .{ + .body = self.code.extra[extra_body_start..][0..body_len], + .end = extra_body_start + body_len, + }; + }, + }; + + try self.writeInstRef(stream, extra.data.operand); + + if (special.body.len != 0) { + const prong_name = switch (special_prong) { + .@"else" => "else", + .under => "_", + else => unreachable, + }; + try stream.print(", {s} => {{\n", .{prong_name}); + self.indent += 2; + try self.writeBody(stream, special.body); + self.indent -= 2; + try stream.writeByteNTimes(' ', self.indent); + try stream.writeAll("}"); + } + + var extra_index: usize = special.end; + { + var scalar_i: usize = 0; + while (scalar_i < extra.data.cases_len) : (scalar_i += 1) { + const item_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); + extra_index += 1; + const body_len = self.code.extra[extra_index]; + extra_index += 1; + const body = self.code.extra[extra_index..][0..body_len]; + extra_index += body_len; + + try stream.writeAll(", "); + try self.writeInstRef(stream, item_ref); + try stream.writeAll(" => {\n"); + self.indent += 2; + try self.writeBody(stream, body); + self.indent -= 2; + try stream.writeByteNTimes(' ', self.indent); + try stream.writeAll("}"); + } + } + try stream.writeAll(") "); + try self.writeSrc(stream, inst_data.src()); + } + + fn writePlNodeSwitchBlockMulti( + self: *Writer, + stream: anytype, + inst: Zir.Inst.Index, + special_prong: Zir.SpecialProng, + ) !void { + const inst_data = self.code.instructions.items(.data)[inst].pl_node; + const extra = self.code.extraData(Zir.Inst.SwitchBlockMulti, inst_data.payload_index); + const special: struct { + body: []const Zir.Inst.Index, + end: usize, + } = switch (special_prong) { + .none => .{ .body = &.{}, .end = extra.end }, + .under, .@"else" => blk: { + const body_len = self.code.extra[extra.end]; + const extra_body_start = extra.end + 1; + break :blk .{ + .body = self.code.extra[extra_body_start..][0..body_len], + .end = extra_body_start + body_len, + }; + }, + }; + + try self.writeInstRef(stream, extra.data.operand); + + if (special.body.len != 0) { + const prong_name = switch (special_prong) { + .@"else" => "else", + .under => "_", + else => unreachable, + }; + try stream.print(", {s} => {{\n", .{prong_name}); + self.indent += 2; + try self.writeBody(stream, special.body); + self.indent -= 2; + try stream.writeByteNTimes(' ', self.indent); + try stream.writeAll("}"); + } + + var extra_index: usize = special.end; + { + var scalar_i: usize = 0; + while (scalar_i < extra.data.scalar_cases_len) : (scalar_i += 1) { + const item_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); + extra_index += 1; + const body_len = self.code.extra[extra_index]; + extra_index += 1; + const body = self.code.extra[extra_index..][0..body_len]; + extra_index += body_len; + + try stream.writeAll(", "); + try self.writeInstRef(stream, item_ref); + try stream.writeAll(" => {\n"); + self.indent += 2; + try self.writeBody(stream, body); + self.indent -= 2; + try stream.writeByteNTimes(' ', self.indent); + try stream.writeAll("}"); + } + } + { + var multi_i: usize = 0; + while (multi_i < extra.data.multi_cases_len) : (multi_i += 1) { + const items_len = self.code.extra[extra_index]; + extra_index += 1; + const ranges_len = self.code.extra[extra_index]; + extra_index += 1; + const body_len = self.code.extra[extra_index]; + extra_index += 1; + const items = self.code.refSlice(extra_index, items_len); + extra_index += items_len; + + for (items) |item_ref| { + try stream.writeAll(", "); + try self.writeInstRef(stream, item_ref); + } + + var range_i: usize = 0; + while (range_i < ranges_len) : (range_i += 1) { + const item_first = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); + extra_index += 1; + const item_last = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); + extra_index += 1; + + try stream.writeAll(", "); + try self.writeInstRef(stream, item_first); + try stream.writeAll("..."); + try self.writeInstRef(stream, item_last); + } + + const body = self.code.extra[extra_index..][0..body_len]; + extra_index += body_len; + try stream.writeAll(" => {\n"); + self.indent += 2; + try self.writeBody(stream, body); + self.indent -= 2; + try stream.writeByteNTimes(' ', self.indent); + try stream.writeAll("}"); + } + } + try stream.writeAll(") "); + try self.writeSrc(stream, inst_data.src()); + } + + fn writePlNodeField(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { + const inst_data = self.code.instructions.items(.data)[inst].pl_node; + const extra = self.code.extraData(Zir.Inst.Field, inst_data.payload_index).data; + const name = self.code.nullTerminatedString(extra.field_name_start); + try self.writeInstRef(stream, extra.lhs); + try stream.print(", \"{}\") ", .{std.zig.fmtEscapes(name)}); + try self.writeSrc(stream, inst_data.src()); + } + + fn writeAs(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { + const inst_data = self.code.instructions.items(.data)[inst].pl_node; + const extra = self.code.extraData(Zir.Inst.As, inst_data.payload_index).data; + try self.writeInstRef(stream, extra.dest_type); + try stream.writeAll(", "); + try self.writeInstRef(stream, extra.operand); + try stream.writeAll(") "); + try self.writeSrc(stream, inst_data.src()); + } + + fn writeNode( + self: *Writer, + stream: anytype, + inst: Zir.Inst.Index, + ) (@TypeOf(stream).Error || error{OutOfMemory})!void { + const src_node = self.code.instructions.items(.data)[inst].node; + const src: LazySrcLoc = .{ .node_offset = src_node }; + try stream.writeAll(") "); + try self.writeSrc(stream, src); + } + + fn writeStrTok( + self: *Writer, + stream: anytype, + inst: Zir.Inst.Index, + ) (@TypeOf(stream).Error || error{OutOfMemory})!void { + const inst_data = self.code.instructions.items(.data)[inst].str_tok; + const str = inst_data.get(self.code); + try stream.print("\"{}\") ", .{std.zig.fmtEscapes(str)}); + try self.writeSrc(stream, inst_data.src()); + } + + fn writeFunc( + self: *Writer, + stream: anytype, + inst: Zir.Inst.Index, + inferred_error_set: bool, + ) !void { + const inst_data = self.code.instructions.items(.data)[inst].pl_node; + const src = inst_data.src(); + const extra = self.code.extraData(Zir.Inst.Func, inst_data.payload_index); + var extra_index = extra.end; + + const ret_ty_body = self.code.extra[extra_index..][0..extra.data.ret_body_len]; + extra_index += ret_ty_body.len; + + const body = self.code.extra[extra_index..][0..extra.data.body_len]; + extra_index += body.len; + + var src_locs: Zir.Inst.Func.SrcLocs = undefined; + if (body.len != 0) { + src_locs = self.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data; + } + return self.writeFuncCommon( + stream, + ret_ty_body, + inferred_error_set, + false, + false, + .none, + .none, + body, + src, + src_locs, + ); + } + + fn writeFuncExtended(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void { + const extra = self.code.extraData(Zir.Inst.ExtendedFunc, extended.operand); + const src: LazySrcLoc = .{ .node_offset = extra.data.src_node }; + const small = @bitCast(Zir.Inst.ExtendedFunc.Small, extended.small); + + var extra_index: usize = extra.end; + if (small.has_lib_name) { + const lib_name = self.code.nullTerminatedString(self.code.extra[extra_index]); + extra_index += 1; + try stream.print("lib_name=\"{}\", ", .{std.zig.fmtEscapes(lib_name)}); + } + try self.writeFlag(stream, "test, ", small.is_test); + const cc: Zir.Inst.Ref = if (!small.has_cc) .none else blk: { + const cc = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); + extra_index += 1; + break :blk cc; + }; + const align_inst: Zir.Inst.Ref = if (!small.has_align) .none else blk: { + const align_inst = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); + extra_index += 1; + break :blk align_inst; + }; + + const ret_ty_body = self.code.extra[extra_index..][0..extra.data.ret_body_len]; + extra_index += ret_ty_body.len; + + const body = self.code.extra[extra_index..][0..extra.data.body_len]; + extra_index += body.len; + + var src_locs: Zir.Inst.Func.SrcLocs = undefined; + if (body.len != 0) { + src_locs = self.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data; + } + return self.writeFuncCommon( + stream, + ret_ty_body, + small.is_inferred_error, + small.is_var_args, + small.is_extern, + cc, + align_inst, + body, + src, + src_locs, + ); + } + + fn writeVarExtended(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void { + const extra = self.code.extraData(Zir.Inst.ExtendedVar, extended.operand); + const small = @bitCast(Zir.Inst.ExtendedVar.Small, extended.small); + + try self.writeInstRef(stream, extra.data.var_type); + + var extra_index: usize = extra.end; + if (small.has_lib_name) { + const lib_name = self.code.nullTerminatedString(self.code.extra[extra_index]); + extra_index += 1; + try stream.print(", lib_name=\"{}\"", .{std.zig.fmtEscapes(lib_name)}); + } + const align_inst: Zir.Inst.Ref = if (!small.has_align) .none else blk: { + const align_inst = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); + extra_index += 1; + break :blk align_inst; + }; + const init_inst: Zir.Inst.Ref = if (!small.has_init) .none else blk: { + const init_inst = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); + extra_index += 1; + break :blk init_inst; + }; + try self.writeFlag(stream, ", is_extern", small.is_extern); + try self.writeOptionalInstRef(stream, ", align=", align_inst); + try self.writeOptionalInstRef(stream, ", init=", init_inst); + try stream.writeAll("))"); + } + + fn writeBoolBr(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { + const inst_data = self.code.instructions.items(.data)[inst].bool_br; + const extra = self.code.extraData(Zir.Inst.Block, inst_data.payload_index); + const body = self.code.extra[extra.end..][0..extra.data.body_len]; + try self.writeInstRef(stream, inst_data.lhs); + try stream.writeAll(", {\n"); + self.indent += 2; + try self.writeBody(stream, body); + self.indent -= 2; + try stream.writeByteNTimes(' ', self.indent); + try stream.writeAll("})"); + } + + fn writeIntType(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { + const int_type = self.code.instructions.items(.data)[inst].int_type; + const prefix: u8 = switch (int_type.signedness) { + .signed => 'i', + .unsigned => 'u', + }; + try stream.print("{c}{d}) ", .{ prefix, int_type.bit_count }); + try self.writeSrc(stream, int_type.src()); + } + + fn writeBreak(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { + const inst_data = self.code.instructions.items(.data)[inst].@"break"; + + try self.writeInstIndex(stream, inst_data.block_inst); + try stream.writeAll(", "); + try self.writeInstRef(stream, inst_data.operand); + try stream.writeAll(")"); + } + + fn writeUnreachable(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { + const inst_data = self.code.instructions.items(.data)[inst].@"unreachable"; + const safety_str = if (inst_data.safety) "safe" else "unsafe"; + try stream.print("{s}) ", .{safety_str}); + try self.writeSrc(stream, inst_data.src()); + } + + fn writeFuncCommon( + self: *Writer, + stream: anytype, + ret_ty_body: []const Zir.Inst.Index, + inferred_error_set: bool, + var_args: bool, + is_extern: bool, + cc: Zir.Inst.Ref, + align_inst: Zir.Inst.Ref, + body: []const Zir.Inst.Index, + src: LazySrcLoc, + src_locs: Zir.Inst.Func.SrcLocs, + ) !void { + if (ret_ty_body.len == 0) { + try stream.writeAll("ret_ty=void"); + } else { + try stream.writeAll("ret_ty={\n"); + self.indent += 2; + try self.writeBody(stream, ret_ty_body); + self.indent -= 2; + try stream.writeByteNTimes(' ', self.indent); + try stream.writeAll("}"); + } + + try self.writeOptionalInstRef(stream, ", cc=", cc); + try self.writeOptionalInstRef(stream, ", align=", align_inst); + try self.writeFlag(stream, ", vargs", var_args); + try self.writeFlag(stream, ", extern", is_extern); + try self.writeFlag(stream, ", inferror", inferred_error_set); + + if (body.len == 0) { + try stream.writeAll(", body={}) "); + } else { + try stream.writeAll(", body={\n"); + self.indent += 2; + try self.writeBody(stream, body); + self.indent -= 2; + try stream.writeByteNTimes(' ', self.indent); + try stream.writeAll("}) "); + } + if (body.len != 0) { + try stream.print("(lbrace={d}:{d},rbrace={d}:{d}) ", .{ + src_locs.lbrace_line, @truncate(u16, src_locs.columns), + src_locs.rbrace_line, @truncate(u16, src_locs.columns >> 16), + }); + } + try self.writeSrc(stream, src); + } + + fn writeSwitchCapture(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { + const inst_data = self.code.instructions.items(.data)[inst].switch_capture; + try self.writeInstIndex(stream, inst_data.switch_inst); + try stream.print(", {d})", .{inst_data.prong_index}); + } + + fn writeDbgStmt(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { + const inst_data = self.code.instructions.items(.data)[inst].dbg_stmt; + try stream.print("{d}, {d})", .{ inst_data.line, inst_data.column }); + } + + fn writeInstRef(self: *Writer, stream: anytype, ref: Zir.Inst.Ref) !void { + var i: usize = @enumToInt(ref); + + if (i < Zir.Inst.Ref.typed_value_map.len) { + return stream.print("@{}", .{ref}); + } + i -= Zir.Inst.Ref.typed_value_map.len; + + return self.writeInstIndex(stream, @intCast(Zir.Inst.Index, i)); + } + + fn writeInstIndex(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { + _ = self; + return stream.print("%{d}", .{inst}); + } + + fn writeOptionalInstRef( + self: *Writer, + stream: anytype, + prefix: []const u8, + inst: Zir.Inst.Ref, + ) !void { + if (inst == .none) return; + try stream.writeAll(prefix); + try self.writeInstRef(stream, inst); + } + + fn writeFlag( + self: *Writer, + stream: anytype, + name: []const u8, + flag: bool, + ) !void { + _ = self; + if (!flag) return; + try stream.writeAll(name); + } + + fn writeSrc(self: *Writer, stream: anytype, src: LazySrcLoc) !void { + const tree = self.file.tree; + const src_loc: Module.SrcLoc = .{ + .file_scope = self.file, + .parent_decl_node = self.parent_decl_node, + .lazy = src, + }; + // Caller must ensure AST tree is loaded. + const abs_byte_off = src_loc.byteOffset(self.gpa) catch unreachable; + const delta_line = std.zig.findLineColumn(tree.source, abs_byte_off); + try stream.print("{s}:{d}:{d}", .{ + @tagName(src), delta_line.line + 1, delta_line.column + 1, + }); + } + + fn writeSrcNode(self: *Writer, stream: anytype, src_node: ?i32) !void { + const node_offset = src_node orelse return; + const src: LazySrcLoc = .{ .node_offset = node_offset }; + try stream.writeAll(" "); + return self.writeSrc(stream, src); + } + + fn writeBody(self: *Writer, stream: anytype, body: []const Zir.Inst.Index) !void { + for (body) |inst| { + try stream.writeByteNTimes(' ', self.indent); + try stream.print("%{d} ", .{inst}); + try self.writeInstToStream(stream, inst); + try stream.writeByte('\n'); + } + } +}; |
