zig/src/print_zir.zig
Andrew Kelley 9afa6835df frontend: replace elem_val_node with elem_ptr_load
avoids unnecessary copies
2025-09-20 18:33:00 -07:00

2879 lines
114 KiB
Zig

const std = @import("std");
const mem = std.mem;
const Allocator = std.mem.Allocator;
const assert = std.debug.assert;
const Ast = std.zig.Ast;
const InternPool = @import("InternPool.zig");
const Zir = std.zig.Zir;
const Zcu = @import("Zcu.zig");
const LazySrcLoc = Zcu.LazySrcLoc;
/// Write human-readable, debug formatted ZIR code.
pub fn renderAsText(gpa: Allocator, tree: ?Ast, zir: Zir, bw: *std.Io.Writer) !void {
var arena = std.heap.ArenaAllocator.init(gpa);
defer arena.deinit();
var writer: Writer = .{
.gpa = gpa,
.arena = arena.allocator(),
.tree = tree,
.code = zir,
.indent = 0,
.parent_decl_node = .root,
.recurse_decls = true,
.recurse_blocks = true,
};
const main_struct_inst: Zir.Inst.Index = .main_struct_inst;
try bw.print("%{d} ", .{@intFromEnum(main_struct_inst)});
try writer.writeInstToStream(bw, main_struct_inst);
try bw.writeAll("\n");
const imports_index = zir.extra[@intFromEnum(Zir.ExtraIndex.imports)];
if (imports_index != 0) {
try bw.writeAll("Imports:\n");
const extra = zir.extraData(Zir.Inst.Imports, imports_index);
var extra_index = extra.end;
for (0..extra.data.imports_len) |_| {
const item = zir.extraData(Zir.Inst.Imports.Item, extra_index);
extra_index = item.end;
const import_path = zir.nullTerminatedString(item.data.name);
try bw.print(" @import(\"{f}\") ", .{
std.zig.fmtString(import_path),
});
try writer.writeSrcTokAbs(bw, item.data.token);
try bw.writeAll("\n");
}
}
}
pub fn renderInstructionContext(
gpa: Allocator,
block: []const Zir.Inst.Index,
block_index: usize,
scope_file: *Zcu.File,
parent_decl_node: Ast.Node.Index,
indent: u32,
bw: *std.Io.Writer,
) !void {
var arena = std.heap.ArenaAllocator.init(gpa);
defer arena.deinit();
var writer: Writer = .{
.gpa = gpa,
.arena = arena.allocator(),
.tree = scope_file.tree,
.code = scope_file.zir.?,
.indent = if (indent < 2) 2 else indent,
.parent_decl_node = parent_decl_node,
.recurse_decls = false,
.recurse_blocks = true,
};
try writer.writeBody(bw, block[0..block_index]);
try bw.splatByteAll(' ', writer.indent - 2);
try bw.print("> %{d} ", .{@intFromEnum(block[block_index])});
try writer.writeInstToStream(bw, block[block_index]);
try bw.writeByte('\n');
if (block_index + 1 < block.len) {
try writer.writeBody(bw, block[block_index + 1 ..]);
}
}
pub fn renderSingleInstruction(
gpa: Allocator,
inst: Zir.Inst.Index,
scope_file: *Zcu.File,
parent_decl_node: Ast.Node.Index,
indent: u32,
bw: *std.Io.Writer,
) !void {
var arena = std.heap.ArenaAllocator.init(gpa);
defer arena.deinit();
var writer: Writer = .{
.gpa = gpa,
.arena = arena.allocator(),
.tree = scope_file.tree,
.code = scope_file.zir.?,
.indent = indent,
.parent_decl_node = parent_decl_node,
.recurse_decls = false,
.recurse_blocks = false,
};
try bw.print("%{d} ", .{@intFromEnum(inst)});
try writer.writeInstToStream(bw, inst);
}
const Writer = struct {
gpa: Allocator,
arena: Allocator,
tree: ?Ast,
code: Zir,
indent: u32,
parent_decl_node: Ast.Node.Index,
recurse_decls: bool,
recurse_blocks: bool,
/// Using `std.zig.findLineColumn` whenever we need to resolve a source location makes ZIR
/// printing O(N^2), which can have drastic effects - taking a ZIR dump from a few seconds to
/// many minutes. Since we're usually resolving source locations close to one another,
/// preserving state across source location resolutions speeds things up a lot.
line_col_cursor: struct {
line: usize = 0,
column: usize = 0,
line_start: usize = 0,
off: usize = 0,
fn find(cur: *@This(), source: []const u8, want_offset: usize) std.zig.Loc {
if (want_offset < cur.off) {
// Go back to the start of this line
cur.off = cur.line_start;
cur.column = 0;
while (want_offset < cur.off) {
// Go back to the newline
cur.off -= 1;
// Seek to the start of the previous line
while (cur.off > 0 and source[cur.off - 1] != '\n') {
cur.off -= 1;
}
cur.line_start = cur.off;
cur.line -= 1;
}
}
// The cursor is now positioned before `want_offset`.
// Seek forward as in `std.zig.findLineColumn`.
while (cur.off < want_offset) : (cur.off += 1) {
switch (source[cur.off]) {
'\n' => {
cur.line += 1;
cur.column = 0;
cur.line_start = cur.off + 1;
},
else => {
cur.column += 1;
},
}
}
while (cur.off < source.len and source[cur.off] != '\n') {
cur.off += 1;
}
return .{
.line = cur.line,
.column = cur.column,
.source_line = source[cur.line_start..cur.off],
};
}
} = .{},
const Error = std.Io.Writer.Error || Allocator.Error;
fn writeInstToStream(
self: *Writer,
stream: *std.Io.Writer,
inst: Zir.Inst.Index,
) Error!void {
const tags = self.code.instructions.items(.tag);
const tag = tags[@intFromEnum(inst)];
try stream.print("= {s}(", .{@tagName(tags[@intFromEnum(inst)])});
switch (tag) {
.alloc,
.alloc_mut,
.alloc_comptime_mut,
.elem_type,
.indexable_ptr_elem_type,
.splat_op_result_ty,
.indexable_ptr_len,
.anyframe_type,
.bit_not,
.bool_not,
.slice_sentinel_ty,
.negate,
.negate_wrap,
.load,
.ensure_result_used,
.ensure_result_non_error,
.ensure_err_union_payload_void,
.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_unsafe,
.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,
.ret_is_non_err,
.typeof,
.type_info,
.size_of,
.bit_size_of,
.typeof_log2_int_type,
.int_from_ptr,
.compile_error,
.set_eval_branch_quota,
.int_from_enum,
.align_of,
.int_from_bool,
.embed_file,
.error_name,
.panic,
.set_runtime_safety,
.sqrt,
.sin,
.cos,
.tan,
.exp,
.exp2,
.log,
.log2,
.log10,
.abs,
.floor,
.ceil,
.trunc,
.round,
.tag_name,
.type_name,
.frame_type,
.clz,
.ctz,
.pop_count,
.byte_swap,
.bit_reverse,
.@"resume",
.make_ptr_const,
.validate_deref,
.validate_const,
.check_comptime_control_flow,
.opt_eu_base_ptr_init,
.restore_err_ret_index_unconditional,
.restore_err_ret_index_fn_entry,
=> try self.writeUnNode(stream, inst),
.ref,
.ret_implicit,
.validate_ref_ty,
=> try self.writeUnTok(stream, inst),
.bool_br_and,
.bool_br_or,
=> try self.writeBoolBr(stream, inst),
.validate_destructure => try self.writeValidateDestructure(stream, inst),
.array_type_sentinel => try self.writeArrayTypeSentinel(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),
.save_err_ret_index => try self.writeSaveErrRetIndex(stream, inst),
.@"break",
.break_inline,
.switch_continue,
=> try self.writeBreak(stream, inst),
.slice_start => try self.writeSliceStart(stream, inst),
.slice_end => try self.writeSliceEnd(stream, inst),
.slice_sentinel => try self.writeSliceSentinel(stream, inst),
.slice_length => try self.writeSliceLength(stream, inst),
.union_init => try self.writeUnionInit(stream, inst),
// Struct inits
.struct_init_empty,
.struct_init_empty_result,
.struct_init_empty_ref_result,
=> try self.writeUnNode(stream, inst),
.struct_init_anon => try self.writeStructInitAnon(stream, inst),
.struct_init,
.struct_init_ref,
=> try self.writeStructInit(stream, inst),
.validate_struct_init_ty,
.validate_struct_init_result_ty,
=> try self.writeUnNode(stream, inst),
.validate_ptr_struct_init => try self.writeBlock(stream, inst),
.struct_init_field_type => try self.writeStructInitFieldType(stream, inst),
.struct_init_field_ptr => try self.writePlNodeField(stream, inst),
// Array inits
.array_init_anon => try self.writeArrayInitAnon(stream, inst),
.array_init,
.array_init_ref,
=> try self.writeArrayInit(stream, inst),
.validate_array_init_ty,
.validate_array_init_result_ty,
=> try self.writeValidateArrayInitTy(stream, inst),
.validate_array_init_ref_ty => try self.writeValidateArrayInitRefTy(stream, inst),
.validate_ptr_array_init => try self.writeBlock(stream, inst),
.array_init_elem_type => try self.writeArrayInitElemType(stream, inst),
.array_init_elem_ptr => try self.writeArrayInitElemPtr(stream, inst),
.atomic_load => try self.writeAtomicLoad(stream, inst),
.atomic_store => try self.writeAtomicStore(stream, inst),
.atomic_rmw => try self.writeAtomicRmw(stream, inst),
.shuffle => try self.writeShuffle(stream, inst),
.mul_add => try self.writeMulAdd(stream, inst),
.builtin_call => try self.writeBuiltinCall(stream, inst),
.field_type_ref => try self.writeFieldTypeRef(stream, inst),
.add,
.addwrap,
.add_sat,
.add_unsafe,
.array_cat,
.mul,
.mulwrap,
.mul_sat,
.sub,
.subwrap,
.sub_sat,
.cmp_lt,
.cmp_lte,
.cmp_eq,
.cmp_gte,
.cmp_gt,
.cmp_neq,
.div,
.has_decl,
.has_field,
.mod_rem,
.shl,
.shl_exact,
.shl_sat,
.shr,
.shr_exact,
.xor,
.store_node,
.store_to_inferred_ptr,
.error_union_type,
.merge_error_sets,
.bit_and,
.bit_or,
.int_from_float,
.float_from_int,
.ptr_from_int,
.enum_from_int,
.float_cast,
.int_cast,
.ptr_cast,
.truncate,
.div_exact,
.div_floor,
.div_trunc,
.mod,
.rem,
.bit_offset_of,
.offset_of,
.splat,
.reduce,
.bitcast,
.vector_type,
.max,
.min,
.memcpy,
.memset,
.memmove,
.elem_ptr_node,
.elem_ptr_load,
.elem_ptr,
.elem_val,
.array_type,
.coerce_ptr_elem_ty,
=> try self.writePlNodeBin(stream, inst),
.for_len => try self.writePlNodeMultiOp(stream, inst),
.array_mul => try self.writeArrayMul(stream, inst),
.elem_val_imm => try self.writeElemValImm(stream, inst),
.@"export" => try self.writePlNodeExport(stream, inst),
.call => try self.writeCall(stream, inst, .direct),
.field_call => try self.writeCall(stream, inst, .field),
.block,
.block_inline,
.suspend_block,
.loop,
.c_import,
.typeof_builtin,
=> try self.writeBlock(stream, inst),
.block_comptime => try self.writeBlockComptime(stream, inst),
.condbr,
.condbr_inline,
=> try self.writeCondBr(stream, inst),
.@"try",
.try_ptr,
=> try self.writeTry(stream, inst),
.error_set_decl => try self.writeErrorSetDecl(stream, inst),
.switch_block,
.switch_block_ref,
=> try self.writeSwitchBlock(stream, inst),
.switch_block_err_union => try self.writeSwitchBlockErrUnion(stream, inst),
.field_ptr_load,
.field_ptr,
.decl_literal,
.decl_literal_no_coerce,
=> try self.writePlNodeField(stream, inst),
.field_ptr_named,
.field_ptr_named_load,
=> try self.writePlNodeFieldNamed(stream, inst),
.as_node, .as_shift_operand => try self.writeAs(stream, inst),
.repeat,
.repeat_inline,
.alloc_inferred,
.alloc_inferred_mut,
.alloc_inferred_comptime,
.alloc_inferred_comptime_mut,
.ret_ptr,
.ret_type,
.trap,
=> try self.writeNode(stream, inst),
.error_value,
.enum_literal,
.decl_ref,
.decl_val,
.ret_err_value,
.ret_err_value_code,
.param_anytype,
.param_anytype_comptime,
=> try self.writeStrTok(stream, inst),
.dbg_var_ptr,
.dbg_var_val,
=> try self.writeStrOp(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),
.func_fancy => try self.writeFuncFancy(stream, inst),
.@"unreachable" => try self.writeUnreachable(stream, inst),
.dbg_stmt => try self.writeDbgStmt(stream, inst),
.@"defer" => try self.writeDefer(stream, inst),
.defer_err_code => try self.writeDeferErrCode(stream, inst),
.declaration => try self.writeDeclaration(stream, inst),
.extended => try self.writeExtended(stream, inst),
.import => try self.writeImport(stream, inst),
}
}
fn writeExtended(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const extended = self.code.instructions.items(.data)[@intFromEnum(inst)].extended;
try stream.print("{s}(", .{@tagName(extended.opcode)});
switch (extended.opcode) {
.this,
.ret_addr,
.error_return_trace,
.frame,
.frame_address,
.breakpoint,
.disable_instrumentation,
.disable_intrinsics,
.c_va_start,
.in_comptime,
.value_placeholder,
=> try self.writeExtNode(stream, extended),
.builtin_src => {
try stream.writeAll("))");
const inst_data = self.code.extraData(Zir.Inst.LineColumn, extended.operand).data;
try stream.print(":{d}:{d}", .{ inst_data.line + 1, inst_data.column + 1 });
},
.@"asm" => try self.writeAsm(stream, extended, false),
.asm_expr => try self.writeAsm(stream, extended, true),
.alloc => try self.writeAllocExtended(stream, extended),
.compile_log => try self.writeNodeMultiOp(stream, extended),
.typeof_peer => try self.writeTypeofPeer(stream, extended),
.min_multi => try self.writeNodeMultiOp(stream, extended),
.max_multi => try self.writeNodeMultiOp(stream, extended),
.select => try self.writeSelect(stream, extended),
.add_with_overflow,
.sub_with_overflow,
.mul_with_overflow,
.shl_with_overflow,
=> try self.writeOverflowArithmetic(stream, extended),
.struct_decl => try self.writeStructDecl(stream, extended),
.union_decl => try self.writeUnionDecl(stream, extended),
.enum_decl => try self.writeEnumDecl(stream, extended),
.opaque_decl => try self.writeOpaqueDecl(stream, extended),
.tuple_decl => try self.writeTupleDecl(stream, extended),
.c_undef,
.c_include,
.set_float_mode,
.wasm_memory_size,
.int_from_error,
.error_from_int,
.c_va_copy,
.c_va_end,
.work_item_id,
.work_group_size,
.work_group_id,
.branch_hint,
.float_op_result_ty,
=> {
const inst_data = self.code.extraData(Zir.Inst.UnNode, extended.operand).data;
try self.writeInstRef(stream, inst_data.operand);
try stream.writeAll(")) ");
try self.writeSrcNode(stream, inst_data.node);
},
.reify => {
const inst_data = self.code.extraData(Zir.Inst.Reify, extended.operand).data;
try stream.print("line({d}), ", .{inst_data.src_line});
try self.writeInstRef(stream, inst_data.operand);
try stream.writeAll(")) ");
const prev_parent_decl_node = self.parent_decl_node;
self.parent_decl_node = inst_data.node;
defer self.parent_decl_node = prev_parent_decl_node;
try self.writeSrcNode(stream, .zero);
},
.builtin_extern,
.c_define,
.error_cast,
.wasm_memory_grow,
.prefetch,
.c_va_arg,
=> {
const inst_data = self.code.extraData(Zir.Inst.BinNode, extended.operand).data;
try self.writeInstRef(stream, inst_data.lhs);
try stream.writeAll(", ");
try self.writeInstRef(stream, inst_data.rhs);
try stream.writeAll(")) ");
try self.writeSrcNode(stream, inst_data.node);
},
.cmpxchg => try self.writeCmpxchg(stream, extended),
.ptr_cast_full => try self.writePtrCastFull(stream, extended),
.ptr_cast_no_dest => try self.writePtrCastNoDest(stream, extended),
.restore_err_ret_index => try self.writeRestoreErrRetIndex(stream, extended),
.closure_get => try self.writeClosureGet(stream, extended),
.field_parent_ptr => try self.writeFieldParentPtr(stream, extended),
.builtin_value => try self.writeBuiltinValue(stream, extended),
.inplace_arith_result_ty => try self.writeInplaceArithResultTy(stream, extended),
.dbg_empty_stmt => try stream.writeAll("))"),
.astgen_error => try stream.writeAll("))"),
}
}
fn writeExtNode(self: *Writer, stream: *std.Io.Writer, extended: Zir.Inst.Extended.InstData) !void {
try stream.writeAll(")) ");
const src_node: Ast.Node.Offset = @enumFromInt(@as(i32, @bitCast(extended.operand)));
try self.writeSrcNode(stream, src_node);
}
fn writeArrayInitElemType(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].bin;
try self.writeInstRef(stream, inst_data.lhs);
try stream.print(", {d})", .{@intFromEnum(inst_data.rhs)});
}
fn writeUnNode(
self: *Writer,
stream: *std.Io.Writer,
inst: Zir.Inst.Index,
) Error!void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
try self.writeInstRef(stream, inst_data.operand);
try stream.writeAll(") ");
try self.writeSrcNode(stream, inst_data.src_node);
}
fn writeUnTok(
self: *Writer,
stream: *std.Io.Writer,
inst: Zir.Inst.Index,
) Error!void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].un_tok;
try self.writeInstRef(stream, inst_data.operand);
try stream.writeAll(") ");
try self.writeSrcTok(stream, inst_data.src_tok);
}
fn writeValidateDestructure(
self: *Writer,
stream: *std.Io.Writer,
inst: Zir.Inst.Index,
) Error!void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const extra = self.code.extraData(Zir.Inst.ValidateDestructure, inst_data.payload_index).data;
try self.writeInstRef(stream, extra.operand);
try stream.print(", {d}) (destructure=", .{extra.expect_len});
try self.writeSrcNode(stream, extra.destructure_node);
try stream.writeAll(") ");
try self.writeSrcNode(stream, inst_data.src_node);
}
fn writeValidateArrayInitTy(
self: *Writer,
stream: *std.Io.Writer,
inst: Zir.Inst.Index,
) Error!void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const extra = self.code.extraData(Zir.Inst.ArrayInit, inst_data.payload_index).data;
try self.writeInstRef(stream, extra.ty);
try stream.print(", {d}) ", .{extra.init_count});
try self.writeSrcNode(stream, inst_data.src_node);
}
fn writeArrayTypeSentinel(
self: *Writer,
stream: *std.Io.Writer,
inst: Zir.Inst.Index,
) Error!void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const extra = self.code.extraData(Zir.Inst.ArrayTypeSentinel, inst_data.payload_index).data;
try self.writeInstRef(stream, extra.len);
try stream.writeAll(", ");
try self.writeInstRef(stream, extra.sentinel);
try stream.writeAll(", ");
try self.writeInstRef(stream, extra.elem_type);
try stream.writeAll(") ");
try self.writeSrcNode(stream, inst_data.src_node);
}
fn writePtrType(
self: *Writer,
stream: *std.Io.Writer,
inst: Zir.Inst.Index,
) Error!void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].ptr_type;
const str_allowzero = if (inst_data.flags.is_allowzero) "allowzero, " else "";
const str_const = if (!inst_data.flags.is_mutable) "const, " else "";
const str_volatile = if (inst_data.flags.is_volatile) "volatile, " else "";
const extra = self.code.extraData(Zir.Inst.PtrType, inst_data.payload_index);
try self.writeInstRef(stream, extra.data.elem_type);
try stream.print(", {s}{s}{s}{s}", .{
str_allowzero,
str_const,
str_volatile,
@tagName(inst_data.size),
});
var extra_index = extra.end;
if (inst_data.flags.has_sentinel) {
try stream.writeAll(", ");
try self.writeInstRef(stream, @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index])));
extra_index += 1;
}
if (inst_data.flags.has_align) {
try stream.writeAll(", align(");
try self.writeInstRef(stream, @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index])));
extra_index += 1;
if (inst_data.flags.has_bit_range) {
const bit_start = extra_index + @intFromBool(inst_data.flags.has_addrspace);
try stream.writeAll(":");
try self.writeInstRef(stream, @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[bit_start])));
try stream.writeAll(":");
try self.writeInstRef(stream, @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[bit_start + 1])));
}
try stream.writeAll(")");
}
if (inst_data.flags.has_addrspace) {
try stream.writeAll(", addrspace(");
try self.writeInstRef(stream, @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index])));
try stream.writeAll(")");
}
try stream.writeAll(") ");
try self.writeSrcNode(stream, extra.data.src_node);
}
fn writeInt(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].int;
try stream.print("{d})", .{inst_data});
}
fn writeIntBig(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].str;
const byte_count = inst_data.len * @sizeOf(std.math.big.Limb);
const limb_bytes = self.code.string_bytes[@intFromEnum(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);
@memcpy(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: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const number = self.code.instructions.items(.data)[@intFromEnum(inst)].float;
try stream.print("{d})", .{number});
}
fn writeFloat128(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const extra = self.code.extraData(Zir.Inst.Float128, inst_data.payload_index).data;
const number = extra.get();
// TODO improve std.format to be able to print f128 values
try stream.print("{d}) ", .{@as(f64, @floatCast(number))});
try self.writeSrcNode(stream, inst_data.src_node);
}
fn writeStr(
self: *Writer,
stream: *std.Io.Writer,
inst: Zir.Inst.Index,
) Error!void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].str;
const str = inst_data.get(self.code);
try stream.print("\"{f}\")", .{std.zig.fmtString(str)});
}
fn writeSliceStart(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const extra = self.code.extraData(Zir.Inst.SliceStart, inst_data.payload_index).data;
try self.writeInstRef(stream, extra.lhs);
try stream.writeAll(", ");
try self.writeInstRef(stream, extra.start);
try stream.writeAll(") ");
try self.writeSrcNode(stream, inst_data.src_node);
}
fn writeSliceEnd(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const extra = self.code.extraData(Zir.Inst.SliceEnd, inst_data.payload_index).data;
try self.writeInstRef(stream, extra.lhs);
try stream.writeAll(", ");
try self.writeInstRef(stream, extra.start);
try stream.writeAll(", ");
try self.writeInstRef(stream, extra.end);
try stream.writeAll(") ");
try self.writeSrcNode(stream, inst_data.src_node);
}
fn writeSliceSentinel(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const extra = self.code.extraData(Zir.Inst.SliceSentinel, inst_data.payload_index).data;
try self.writeInstRef(stream, extra.lhs);
try stream.writeAll(", ");
try self.writeInstRef(stream, extra.start);
try stream.writeAll(", ");
try self.writeInstRef(stream, extra.end);
try stream.writeAll(", ");
try self.writeInstRef(stream, extra.sentinel);
try stream.writeAll(") ");
try self.writeSrcNode(stream, inst_data.src_node);
}
fn writeSliceLength(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const extra = self.code.extraData(Zir.Inst.SliceLength, inst_data.payload_index).data;
try self.writeInstRef(stream, extra.lhs);
try stream.writeAll(", ");
try self.writeInstRef(stream, extra.start);
try stream.writeAll(", ");
try self.writeInstRef(stream, extra.len);
if (extra.sentinel != .none) {
try stream.writeAll(", ");
try self.writeInstRef(stream, extra.sentinel);
}
try stream.writeAll(") ");
try self.writeSrcNode(stream, inst_data.src_node);
}
fn writeUnionInit(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const extra = self.code.extraData(Zir.Inst.UnionInit, inst_data.payload_index).data;
try self.writeInstRef(stream, extra.union_type);
try stream.writeAll(", ");
try self.writeInstRef(stream, extra.field_name);
try stream.writeAll(", ");
try self.writeInstRef(stream, extra.init);
try stream.writeAll(") ");
try self.writeSrcNode(stream, inst_data.src_node);
}
fn writeShuffle(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const extra = self.code.extraData(Zir.Inst.Shuffle, inst_data.payload_index).data;
try self.writeInstRef(stream, extra.elem_type);
try stream.writeAll(", ");
try self.writeInstRef(stream, extra.a);
try stream.writeAll(", ");
try self.writeInstRef(stream, extra.b);
try stream.writeAll(", ");
try self.writeInstRef(stream, extra.mask);
try stream.writeAll(") ");
try self.writeSrcNode(stream, inst_data.src_node);
}
fn writeSelect(self: *Writer, stream: *std.Io.Writer, extended: Zir.Inst.Extended.InstData) !void {
const extra = self.code.extraData(Zir.Inst.Select, extended.operand).data;
try self.writeInstRef(stream, extra.elem_type);
try stream.writeAll(", ");
try self.writeInstRef(stream, extra.pred);
try stream.writeAll(", ");
try self.writeInstRef(stream, extra.a);
try stream.writeAll(", ");
try self.writeInstRef(stream, extra.b);
try stream.writeAll(") ");
try self.writeSrcNode(stream, extra.node);
}
fn writeMulAdd(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const extra = self.code.extraData(Zir.Inst.MulAdd, inst_data.payload_index).data;
try self.writeInstRef(stream, extra.mulend1);
try stream.writeAll(", ");
try self.writeInstRef(stream, extra.mulend2);
try stream.writeAll(", ");
try self.writeInstRef(stream, extra.addend);
try stream.writeAll(") ");
try self.writeSrcNode(stream, inst_data.src_node);
}
fn writeBuiltinCall(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const extra = self.code.extraData(Zir.Inst.BuiltinCall, inst_data.payload_index).data;
try self.writeFlag(stream, "nodiscard ", extra.flags.ensure_result_used);
try self.writeFlag(stream, "nosuspend ", extra.flags.is_nosuspend);
try self.writeInstRef(stream, extra.modifier);
try stream.writeAll(", ");
try self.writeInstRef(stream, extra.callee);
try stream.writeAll(", ");
try self.writeInstRef(stream, extra.args);
try stream.writeAll(") ");
try self.writeSrcNode(stream, inst_data.src_node);
}
fn writeFieldParentPtr(self: *Writer, stream: *std.Io.Writer, extended: Zir.Inst.Extended.InstData) !void {
const extra = self.code.extraData(Zir.Inst.FieldParentPtr, extended.operand).data;
const FlagsInt = @typeInfo(Zir.Inst.FullPtrCastFlags).@"struct".backing_integer.?;
const flags: Zir.Inst.FullPtrCastFlags = @bitCast(@as(FlagsInt, @truncate(extended.small)));
if (flags.align_cast) try stream.writeAll("align_cast, ");
if (flags.addrspace_cast) try stream.writeAll("addrspace_cast, ");
if (flags.const_cast) try stream.writeAll("const_cast, ");
if (flags.volatile_cast) try stream.writeAll("volatile_cast, ");
try self.writeInstRef(stream, extra.parent_ptr_type);
try stream.writeAll(", ");
try self.writeInstRef(stream, extra.field_name);
try stream.writeAll(", ");
try self.writeInstRef(stream, extra.field_ptr);
try stream.writeAll(") ");
try self.writeSrcNode(stream, extra.src_node);
}
fn writeParam(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_tok;
const extra = self.code.extraData(Zir.Inst.Param, inst_data.payload_index);
const body = self.code.bodySlice(extra.end, extra.data.type.body_len);
try stream.print("\"{f}\", ", .{
std.zig.fmtString(self.code.nullTerminatedString(extra.data.name)),
});
if (extra.data.type.is_generic) try stream.writeAll("[generic] ");
try self.writeBracedBody(stream, body);
try stream.writeAll(") ");
try self.writeSrcTok(stream, inst_data.src_tok);
}
fn writePlNodeBin(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(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.writeSrcNode(stream, inst_data.src_node);
}
fn writePlNodeMultiOp(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const extra = self.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index);
const args = self.code.refSlice(extra.end, extra.data.operands_len);
try stream.writeAll("{");
for (args, 0..) |arg, i| {
if (i != 0) try stream.writeAll(", ");
try self.writeInstRef(stream, arg);
}
try stream.writeAll("}) ");
try self.writeSrcNode(stream, inst_data.src_node);
}
fn writeArrayMul(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const extra = self.code.extraData(Zir.Inst.ArrayMul, inst_data.payload_index).data;
try self.writeInstRef(stream, extra.res_ty);
try stream.writeAll(", ");
try self.writeInstRef(stream, extra.lhs);
try stream.writeAll(", ");
try self.writeInstRef(stream, extra.rhs);
try stream.writeAll(") ");
try self.writeSrcNode(stream, inst_data.src_node);
}
fn writeElemValImm(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].elem_val_imm;
try self.writeInstRef(stream, inst_data.operand);
try stream.print(", {d})", .{inst_data.idx});
}
fn writeArrayInitElemPtr(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const extra = self.code.extraData(Zir.Inst.ElemPtrImm, inst_data.payload_index).data;
try self.writeInstRef(stream, extra.ptr);
try stream.print(", {d}) ", .{extra.index});
try self.writeSrcNode(stream, inst_data.src_node);
}
fn writePlNodeExport(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const extra = self.code.extraData(Zir.Inst.Export, inst_data.payload_index).data;
try self.writeInstRef(stream, extra.exported);
try stream.writeAll(", ");
try self.writeInstRef(stream, extra.options);
try stream.writeAll(") ");
try self.writeSrcNode(stream, inst_data.src_node);
}
fn writeValidateArrayInitRefTy(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const extra = self.code.extraData(Zir.Inst.ArrayInitRefTy, inst_data.payload_index).data;
try self.writeInstRef(stream, extra.ptr_ty);
try stream.writeAll(", ");
try stream.print(", {}) ", .{extra.elem_count});
try self.writeSrcNode(stream, inst_data.src_node);
}
fn writeStructInit(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(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.writeSrcNode(stream, inst_data.src_node);
}
fn writeCmpxchg(self: *Writer, stream: *std.Io.Writer, extended: Zir.Inst.Extended.InstData) !void {
const extra = self.code.extraData(Zir.Inst.Cmpxchg, extended.operand).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.writeSrcNode(stream, extra.node);
}
fn writePtrCastFull(self: *Writer, stream: *std.Io.Writer, extended: Zir.Inst.Extended.InstData) !void {
const FlagsInt = @typeInfo(Zir.Inst.FullPtrCastFlags).@"struct".backing_integer.?;
const flags: Zir.Inst.FullPtrCastFlags = @bitCast(@as(FlagsInt, @truncate(extended.small)));
const extra = self.code.extraData(Zir.Inst.BinNode, extended.operand).data;
if (flags.ptr_cast) try stream.writeAll("ptr_cast, ");
if (flags.align_cast) try stream.writeAll("align_cast, ");
if (flags.addrspace_cast) try stream.writeAll("addrspace_cast, ");
if (flags.const_cast) try stream.writeAll("const_cast, ");
if (flags.volatile_cast) try stream.writeAll("volatile_cast, ");
try self.writeInstRef(stream, extra.lhs);
try stream.writeAll(", ");
try self.writeInstRef(stream, extra.rhs);
try stream.writeAll(")) ");
try self.writeSrcNode(stream, extra.node);
}
fn writePtrCastNoDest(self: *Writer, stream: *std.Io.Writer, extended: Zir.Inst.Extended.InstData) !void {
const FlagsInt = @typeInfo(Zir.Inst.FullPtrCastFlags).@"struct".backing_integer.?;
const flags: Zir.Inst.FullPtrCastFlags = @bitCast(@as(FlagsInt, @truncate(extended.small)));
const extra = self.code.extraData(Zir.Inst.UnNode, extended.operand).data;
if (flags.const_cast) try stream.writeAll("const_cast, ");
if (flags.volatile_cast) try stream.writeAll("volatile_cast, ");
try self.writeInstRef(stream, extra.operand);
try stream.writeAll(")) ");
try self.writeSrcNode(stream, extra.node);
}
fn writeAtomicLoad(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const extra = self.code.extraData(Zir.Inst.AtomicLoad, inst_data.payload_index).data;
try self.writeInstRef(stream, extra.elem_type);
try stream.writeAll(", ");
try self.writeInstRef(stream, extra.ptr);
try stream.writeAll(", ");
try self.writeInstRef(stream, extra.ordering);
try stream.writeAll(") ");
try self.writeSrcNode(stream, inst_data.src_node);
}
fn writeAtomicStore(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(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.writeSrcNode(stream, inst_data.src_node);
}
fn writeAtomicRmw(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(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.writeSrcNode(stream, inst_data.src_node);
}
fn writeStructInitAnon(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(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.writeSrcNode(stream, inst_data.src_node);
}
fn writeStructInitFieldType(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(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.writeSrcNode(stream, inst_data.src_node);
}
fn writeFieldTypeRef(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(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.writeSrcNode(stream, inst_data.src_node);
}
fn writeNodeMultiOp(self: *Writer, stream: *std.Io.Writer, extended: Zir.Inst.Extended.InstData) !void {
const extra = self.code.extraData(Zir.Inst.NodeMultiOp, extended.operand);
const operands = self.code.refSlice(extra.end, extended.small);
for (operands, 0..) |operand, i| {
if (i != 0) try stream.writeAll(", ");
try self.writeInstRef(stream, operand);
}
try stream.writeAll(")) ");
try self.writeSrcNode(stream, extra.data.src_node);
}
fn writeInstNode(
self: *Writer,
stream: *std.Io.Writer,
inst: Zir.Inst.Index,
) Error!void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].inst_node;
try self.writeInstIndex(stream, inst_data.inst);
try stream.writeAll(") ");
try self.writeSrcNode(stream, inst_data.src_node);
}
fn writeAsm(
self: *Writer,
stream: *std.Io.Writer,
extended: Zir.Inst.Extended.InstData,
tmpl_is_expr: bool,
) !void {
const extra = self.code.extraData(Zir.Inst.Asm, extended.operand);
const outputs_len = @as(u5, @truncate(extended.small));
const inputs_len = @as(u5, @truncate(extended.small >> 5));
const clobbers_len = @as(u5, @truncate(extended.small >> 10));
const is_volatile = @as(u1, @truncate(extended.small >> 15)) != 0;
try self.writeFlag(stream, "volatile, ", is_volatile);
if (tmpl_is_expr) {
try self.writeInstRef(stream, @enumFromInt(@intFromEnum(extra.data.asm_source)));
try stream.writeAll(", ");
} else {
const asm_source = self.code.nullTerminatedString(extra.data.asm_source);
try stream.print("\"{f}\", ", .{std.zig.fmtString(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 = @as(u1, @truncate(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({f}, \"{f}\", ", .{
std.zig.fmtIdP(name), std.zig.fmtString(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({f}, \"{f}\", ", .{
std.zig.fmtIdP(name), std.zig.fmtString(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(@enumFromInt(str_index));
try stream.print("{f}", .{std.zig.fmtIdP(clobber)});
if (i + 1 < clobbers_len) {
try stream.writeAll(", ");
}
}
}
try stream.writeAll(")) ");
try self.writeSrcNode(stream, extra.data.src_node);
}
fn writeOverflowArithmetic(self: *Writer, stream: *std.Io.Writer, extended: Zir.Inst.Extended.InstData) !void {
const extra = self.code.extraData(Zir.Inst.BinNode, extended.operand).data;
try self.writeInstRef(stream, extra.lhs);
try stream.writeAll(", ");
try self.writeInstRef(stream, extra.rhs);
try stream.writeAll(")) ");
try self.writeSrcNode(stream, extra.node);
}
fn writeCall(
self: *Writer,
stream: *std.Io.Writer,
inst: Zir.Inst.Index,
comptime kind: enum { direct, field },
) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const ExtraType = switch (kind) {
.direct => Zir.Inst.Call,
.field => Zir.Inst.FieldCall,
};
const extra = self.code.extraData(ExtraType, inst_data.payload_index);
const args_len = extra.data.flags.args_len;
const body = self.code.extra[extra.end..];
if (extra.data.flags.ensure_result_used) {
try stream.writeAll("nodiscard ");
}
try stream.print(".{s}, ", .{@tagName(@as(std.builtin.CallModifier, @enumFromInt(extra.data.flags.packed_modifier)))});
switch (kind) {
.direct => try self.writeInstRef(stream, extra.data.callee),
.field => {
const field_name = self.code.nullTerminatedString(extra.data.field_name_start);
try self.writeInstRef(stream, extra.data.obj_ptr);
try stream.print(", \"{f}\"", .{std.zig.fmtString(field_name)});
},
}
try stream.writeAll(", [");
self.indent += 2;
if (args_len != 0) {
try stream.writeAll("\n");
}
var i: usize = 0;
var arg_start: u32 = args_len;
while (i < args_len) : (i += 1) {
try stream.splatByteAll(' ', self.indent);
const arg_end = self.code.extra[extra.end + i];
defer arg_start = arg_end;
const arg_body = body[arg_start..arg_end];
try self.writeBracedBody(stream, @ptrCast(arg_body));
try stream.writeAll(",\n");
}
self.indent -= 2;
if (args_len != 0) {
try stream.splatByteAll(' ', self.indent);
}
try stream.writeAll("]) ");
try self.writeSrcNode(stream, inst_data.src_node);
}
fn writeBlock(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const extra = self.code.extraData(Zir.Inst.Block, inst_data.payload_index);
const body = self.code.bodySlice(extra.end, extra.data.body_len);
try self.writeBracedBody(stream, body);
try stream.writeAll(") ");
try self.writeSrcNode(stream, inst_data.src_node);
}
fn writeBlockComptime(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const extra = self.code.extraData(Zir.Inst.BlockComptime, inst_data.payload_index);
const body = self.code.bodySlice(extra.end, extra.data.body_len);
try stream.print("reason={s}, ", .{@tagName(extra.data.reason)});
try self.writeBracedBody(stream, body);
try stream.writeAll(") ");
try self.writeSrcNode(stream, inst_data.src_node);
}
fn writeCondBr(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const extra = self.code.extraData(Zir.Inst.CondBr, inst_data.payload_index);
const then_body = self.code.bodySlice(extra.end, extra.data.then_body_len);
const else_body = self.code.bodySlice(extra.end + then_body.len, extra.data.else_body_len);
try self.writeInstRef(stream, extra.data.condition);
try stream.writeAll(", ");
try self.writeBracedBody(stream, then_body);
try stream.writeAll(", ");
try self.writeBracedBody(stream, else_body);
try stream.writeAll(") ");
try self.writeSrcNode(stream, inst_data.src_node);
}
fn writeTry(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const extra = self.code.extraData(Zir.Inst.Try, inst_data.payload_index);
const body = self.code.bodySlice(extra.end, extra.data.body_len);
try self.writeInstRef(stream, extra.data.operand);
try stream.writeAll(", ");
try self.writeBracedBody(stream, body);
try stream.writeAll(") ");
try self.writeSrcNode(stream, inst_data.src_node);
}
fn writeStructDecl(self: *Writer, stream: *std.Io.Writer, extended: Zir.Inst.Extended.InstData) !void {
const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
const extra = self.code.extraData(Zir.Inst.StructDecl, extended.operand);
const prev_parent_decl_node = self.parent_decl_node;
self.parent_decl_node = extra.data.src_node;
defer self.parent_decl_node = prev_parent_decl_node;
const fields_hash: std.zig.SrcHash = @bitCast([4]u32{
extra.data.fields_hash_0,
extra.data.fields_hash_1,
extra.data.fields_hash_2,
extra.data.fields_hash_3,
});
try stream.print("hash({x}) ", .{&fields_hash});
var extra_index: usize = extra.end;
const captures_len = if (small.has_captures_len) blk: {
const captures_len = self.code.extra[extra_index];
extra_index += 1;
break :blk captures_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_non_opv, ", small.known_non_opv);
try self.writeFlag(stream, "known_comptime_only, ", small.known_comptime_only);
try stream.print("{s}, ", .{@tagName(small.name_strategy)});
extra_index = try self.writeCaptures(stream, extra_index, captures_len);
try stream.writeAll(", ");
if (small.has_backing_int) {
const backing_int_body_len = self.code.extra[extra_index];
extra_index += 1;
try stream.writeAll("packed(");
if (backing_int_body_len == 0) {
const backing_int_ref: Zir.Inst.Ref = @enumFromInt(self.code.extra[extra_index]);
extra_index += 1;
try self.writeInstRef(stream, backing_int_ref);
} else {
const body = self.code.bodySlice(extra_index, backing_int_body_len);
extra_index += backing_int_body_len;
self.indent += 2;
try self.writeBracedDecl(stream, body);
self.indent -= 2;
}
try stream.writeAll("), ");
} else {
try stream.print("{s}, ", .{@tagName(small.layout)});
}
if (decls_len == 0) {
try stream.writeAll("{}, ");
} else {
try stream.writeAll("{\n");
self.indent += 2;
try self.writeBody(stream, self.code.bodySlice(extra_index, decls_len));
self.indent -= 2;
extra_index += decls_len;
try stream.splatByteAll(' ', self.indent);
try stream.writeAll("}, ");
}
if (fields_len == 0) {
try stream.writeAll("{}, {}) ");
} else {
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 Field = struct {
type_len: u32 = 0,
align_len: u32 = 0,
init_len: u32 = 0,
type: Zir.Inst.Ref = .none,
name: Zir.NullTerminatedString,
is_comptime: bool,
};
const fields = try self.arena.alloc(Field, fields_len);
{
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 = @as(u1, @truncate(cur_bit_bag)) != 0;
cur_bit_bag >>= 1;
const has_default = @as(u1, @truncate(cur_bit_bag)) != 0;
cur_bit_bag >>= 1;
const is_comptime = @as(u1, @truncate(cur_bit_bag)) != 0;
cur_bit_bag >>= 1;
const has_type_body = @as(u1, @truncate(cur_bit_bag)) != 0;
cur_bit_bag >>= 1;
const field_name_index: Zir.NullTerminatedString = @enumFromInt(self.code.extra[extra_index]);
extra_index += 1;
fields[field_i] = .{
.is_comptime = is_comptime,
.name = field_name_index,
};
if (has_type_body) {
fields[field_i].type_len = self.code.extra[extra_index];
} else {
fields[field_i].type = @enumFromInt(self.code.extra[extra_index]);
}
extra_index += 1;
if (has_align) {
fields[field_i].align_len = self.code.extra[extra_index];
extra_index += 1;
}
if (has_default) {
fields[field_i].init_len = self.code.extra[extra_index];
extra_index += 1;
}
}
}
try stream.writeAll("{\n");
self.indent += 2;
for (fields, 0..) |field, i| {
try stream.splatByteAll(' ', self.indent);
try self.writeFlag(stream, "comptime ", field.is_comptime);
if (field.name != .empty) {
const field_name = self.code.nullTerminatedString(field.name);
try stream.print("{f}: ", .{std.zig.fmtIdP(field_name)});
} else {
try stream.print("@\"{d}\": ", .{i});
}
if (field.type != .none) {
try self.writeInstRef(stream, field.type);
}
if (field.type_len > 0) {
const body = self.code.bodySlice(extra_index, field.type_len);
extra_index += body.len;
self.indent += 2;
try self.writeBracedDecl(stream, body);
self.indent -= 2;
}
if (field.align_len > 0) {
const body = self.code.bodySlice(extra_index, field.align_len);
extra_index += body.len;
self.indent += 2;
try stream.writeAll(" align(");
try self.writeBracedDecl(stream, body);
try stream.writeAll(")");
self.indent -= 2;
}
if (field.init_len > 0) {
const body = self.code.bodySlice(extra_index, field.init_len);
extra_index += body.len;
self.indent += 2;
try stream.writeAll(" = ");
try self.writeBracedDecl(stream, body);
self.indent -= 2;
}
try stream.writeAll(",\n");
}
self.indent -= 2;
try stream.splatByteAll(' ', self.indent);
try stream.writeAll("}) ");
}
try self.writeSrcNode(stream, .zero);
}
fn writeUnionDecl(self: *Writer, stream: *std.Io.Writer, extended: Zir.Inst.Extended.InstData) !void {
const small = @as(Zir.Inst.UnionDecl.Small, @bitCast(extended.small));
const extra = self.code.extraData(Zir.Inst.UnionDecl, extended.operand);
const prev_parent_decl_node = self.parent_decl_node;
self.parent_decl_node = extra.data.src_node;
defer self.parent_decl_node = prev_parent_decl_node;
const fields_hash: std.zig.SrcHash = @bitCast([4]u32{
extra.data.fields_hash_0,
extra.data.fields_hash_1,
extra.data.fields_hash_2,
extra.data.fields_hash_3,
});
try stream.print("hash({x}) ", .{&fields_hash});
var extra_index: usize = extra.end;
const tag_type_ref = if (small.has_tag_type) blk: {
const tag_type_ref = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
extra_index += 1;
break :blk tag_type_ref;
} else .none;
const captures_len = if (small.has_captures_len) blk: {
const captures_len = self.code.extra[extra_index];
extra_index += 1;
break :blk captures_len;
} else 0;
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);
extra_index = try self.writeCaptures(stream, extra_index, captures_len);
try stream.writeAll(", ");
if (decls_len == 0) {
try stream.writeAll("{}");
} else {
try stream.writeAll("{\n");
self.indent += 2;
try self.writeBody(stream, self.code.bodySlice(extra_index, decls_len));
self.indent -= 2;
extra_index += decls_len;
try stream.splatByteAll(' ', self.indent);
try stream.writeAll("}");
}
if (tag_type_ref != .none) {
try stream.writeAll(", ");
try self.writeInstRef(stream, tag_type_ref);
}
if (fields_len == 0) {
try stream.writeAll("}) ");
try self.writeSrcNode(stream, .zero);
return;
}
try stream.writeAll(", ");
const body = self.code.bodySlice(extra_index, body_len);
extra_index += body.len;
try self.writeBracedDecl(stream, body);
try stream.writeAll(", {\n");
self.indent += 2;
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 = @as(u1, @truncate(cur_bit_bag)) != 0;
cur_bit_bag >>= 1;
const has_align = @as(u1, @truncate(cur_bit_bag)) != 0;
cur_bit_bag >>= 1;
const has_value = @as(u1, @truncate(cur_bit_bag)) != 0;
cur_bit_bag >>= 1;
const unused = @as(u1, @truncate(cur_bit_bag)) != 0;
cur_bit_bag >>= 1;
_ = unused;
const field_name_index: Zir.NullTerminatedString = @enumFromInt(self.code.extra[extra_index]);
const field_name = self.code.nullTerminatedString(field_name_index);
extra_index += 1;
try stream.splatByteAll(' ', self.indent);
try stream.print("{f}", .{std.zig.fmtIdP(field_name)});
if (has_type) {
const field_type = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
extra_index += 1;
try stream.writeAll(": ");
try self.writeInstRef(stream, field_type);
}
if (has_align) {
const align_ref = @as(Zir.Inst.Ref, @enumFromInt(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 = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
extra_index += 1;
try stream.writeAll(" = ");
try self.writeInstRef(stream, default_ref);
}
try stream.writeAll(",\n");
}
self.indent -= 2;
try stream.splatByteAll(' ', self.indent);
try stream.writeAll("}) ");
try self.writeSrcNode(stream, .zero);
}
fn writeEnumDecl(self: *Writer, stream: *std.Io.Writer, extended: Zir.Inst.Extended.InstData) !void {
const small = @as(Zir.Inst.EnumDecl.Small, @bitCast(extended.small));
const extra = self.code.extraData(Zir.Inst.EnumDecl, extended.operand);
const prev_parent_decl_node = self.parent_decl_node;
self.parent_decl_node = extra.data.src_node;
defer self.parent_decl_node = prev_parent_decl_node;
const fields_hash: std.zig.SrcHash = @bitCast([4]u32{
extra.data.fields_hash_0,
extra.data.fields_hash_1,
extra.data.fields_hash_2,
extra.data.fields_hash_3,
});
try stream.print("hash({x}) ", .{&fields_hash});
var extra_index: usize = extra.end;
const tag_type_ref = if (small.has_tag_type) blk: {
const tag_type_ref = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
extra_index += 1;
break :blk tag_type_ref;
} else .none;
const captures_len = if (small.has_captures_len) blk: {
const captures_len = self.code.extra[extra_index];
extra_index += 1;
break :blk captures_len;
} else 0;
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);
extra_index = try self.writeCaptures(stream, extra_index, captures_len);
try stream.writeAll(", ");
if (decls_len == 0) {
try stream.writeAll("{}, ");
} else {
try stream.writeAll("{\n");
self.indent += 2;
try self.writeBody(stream, self.code.bodySlice(extra_index, decls_len));
self.indent -= 2;
extra_index += decls_len;
try stream.splatByteAll(' ', self.indent);
try stream.writeAll("}, ");
}
if (tag_type_ref != .none) {
try self.writeInstRef(stream, tag_type_ref);
try stream.writeAll(", ");
}
const body = self.code.bodySlice(extra_index, body_len);
extra_index += body.len;
try self.writeBracedDecl(stream, body);
if (fields_len == 0) {
try stream.writeAll(", {}) ");
} else {
try stream.writeAll(", {\n");
self.indent += 2;
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 = @as(u1, @truncate(cur_bit_bag)) != 0;
cur_bit_bag >>= 1;
const field_name = self.code.nullTerminatedString(@enumFromInt(self.code.extra[extra_index]));
extra_index += 1;
try stream.splatByteAll(' ', self.indent);
try stream.print("{f}", .{std.zig.fmtIdP(field_name)});
if (has_tag_value) {
const tag_value_ref = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
extra_index += 1;
try stream.writeAll(" = ");
try self.writeInstRef(stream, tag_value_ref);
}
try stream.writeAll(",\n");
}
self.indent -= 2;
try stream.splatByteAll(' ', self.indent);
try stream.writeAll("}) ");
}
try self.writeSrcNode(stream, .zero);
}
fn writeOpaqueDecl(
self: *Writer,
stream: *std.Io.Writer,
extended: Zir.Inst.Extended.InstData,
) !void {
const small = @as(Zir.Inst.OpaqueDecl.Small, @bitCast(extended.small));
const extra = self.code.extraData(Zir.Inst.OpaqueDecl, extended.operand);
const prev_parent_decl_node = self.parent_decl_node;
self.parent_decl_node = extra.data.src_node;
defer self.parent_decl_node = prev_parent_decl_node;
var extra_index: usize = extra.end;
const captures_len = if (small.has_captures_len) blk: {
const captures_len = self.code.extra[extra_index];
extra_index += 1;
break :blk captures_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)});
extra_index = try self.writeCaptures(stream, extra_index, captures_len);
try stream.writeAll(", ");
if (decls_len == 0) {
try stream.writeAll("{}) ");
} else {
try stream.writeAll("{\n");
self.indent += 2;
try self.writeBody(stream, self.code.bodySlice(extra_index, decls_len));
self.indent -= 2;
try stream.splatByteAll(' ', self.indent);
try stream.writeAll("}) ");
}
try self.writeSrcNode(stream, .zero);
}
fn writeTupleDecl(self: *Writer, stream: *std.Io.Writer, extended: Zir.Inst.Extended.InstData) !void {
const fields_len = extended.small;
assert(fields_len != 0);
const extra = self.code.extraData(Zir.Inst.TupleDecl, extended.operand);
var extra_index = extra.end;
try stream.writeAll("{ ");
for (0..fields_len) |field_idx| {
if (field_idx != 0) try stream.writeAll(", ");
const field_ty, const field_init = self.code.extra[extra_index..][0..2].*;
extra_index += 2;
try stream.print("@\"{d}\": ", .{field_idx});
try self.writeInstRef(stream, @enumFromInt(field_ty));
try stream.writeAll(" = ");
try self.writeInstRef(stream, @enumFromInt(field_init));
}
try stream.writeAll(" }) ");
try self.writeSrcNode(stream, extra.data.src_node);
}
fn writeErrorSetDecl(
self: *Writer,
stream: *std.Io.Writer,
inst: Zir.Inst.Index,
) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const extra = self.code.extraData(Zir.Inst.ErrorSetDecl, inst_data.payload_index);
try stream.writeAll("{\n");
self.indent += 2;
var extra_index = @as(u32, @intCast(extra.end));
const extra_index_end = extra_index + extra.data.fields_len;
while (extra_index < extra_index_end) : (extra_index += 1) {
const name_index: Zir.NullTerminatedString = @enumFromInt(self.code.extra[extra_index]);
const name = self.code.nullTerminatedString(name_index);
try stream.splatByteAll(' ', self.indent);
try stream.print("{f},\n", .{std.zig.fmtIdP(name)});
}
self.indent -= 2;
try stream.splatByteAll(' ', self.indent);
try stream.writeAll("}) ");
try self.writeSrcNode(stream, inst_data.src_node);
}
fn writeSwitchBlockErrUnion(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const extra = self.code.extraData(Zir.Inst.SwitchBlockErrUnion, inst_data.payload_index);
var extra_index: usize = extra.end;
const multi_cases_len = if (extra.data.bits.has_multi_cases) blk: {
const multi_cases_len = self.code.extra[extra_index];
extra_index += 1;
break :blk multi_cases_len;
} else 0;
const err_capture_inst: Zir.Inst.Index = if (extra.data.bits.any_uses_err_capture) blk: {
const tag_capture_inst = self.code.extra[extra_index];
extra_index += 1;
break :blk @enumFromInt(tag_capture_inst);
} else undefined;
try self.writeInstRef(stream, extra.data.operand);
if (extra.data.bits.any_uses_err_capture) {
try stream.writeAll(", err_capture=");
try self.writeInstIndex(stream, err_capture_inst);
}
self.indent += 2;
{
const info = @as(Zir.Inst.SwitchBlock.ProngInfo, @bitCast(self.code.extra[extra_index]));
extra_index += 1;
assert(!info.is_inline);
const body = self.code.bodySlice(extra_index, info.body_len);
extra_index += body.len;
try stream.writeAll(",\n");
try stream.splatByteAll(' ', self.indent);
try stream.writeAll("non_err => ");
try self.writeBracedBody(stream, body);
}
if (extra.data.bits.has_else) {
const info = @as(Zir.Inst.SwitchBlock.ProngInfo, @bitCast(self.code.extra[extra_index]));
extra_index += 1;
const capture_text = switch (info.capture) {
.none => "",
.by_val => "by_val ",
.by_ref => "by_ref ",
};
const inline_text = if (info.is_inline) "inline " else "";
const body = self.code.bodySlice(extra_index, info.body_len);
extra_index += body.len;
try stream.writeAll(",\n");
try stream.splatByteAll(' ', self.indent);
try stream.print("{s}{s}else => ", .{ capture_text, inline_text });
try self.writeBracedBody(stream, body);
}
{
const scalar_cases_len = extra.data.bits.scalar_cases_len;
var scalar_i: usize = 0;
while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
const item_ref = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
extra_index += 1;
const info = @as(Zir.Inst.SwitchBlock.ProngInfo, @bitCast(self.code.extra[extra_index]));
extra_index += 1;
const body = self.code.bodySlice(extra_index, info.body_len);
extra_index += info.body_len;
try stream.writeAll(",\n");
try stream.splatByteAll(' ', self.indent);
switch (info.capture) {
.none => {},
.by_val => try stream.writeAll("by_val "),
.by_ref => try stream.writeAll("by_ref "),
}
if (info.is_inline) try stream.writeAll("inline ");
try self.writeInstRef(stream, item_ref);
try stream.writeAll(" => ");
try self.writeBracedBody(stream, body);
}
}
{
var multi_i: usize = 0;
while (multi_i < 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 info = @as(Zir.Inst.SwitchBlock.ProngInfo, @bitCast(self.code.extra[extra_index]));
extra_index += 1;
const items = self.code.refSlice(extra_index, items_len);
extra_index += items_len;
try stream.writeAll(",\n");
try stream.splatByteAll(' ', self.indent);
switch (info.capture) {
.none => {},
.by_val => try stream.writeAll("by_val "),
.by_ref => try stream.writeAll("by_ref "),
}
if (info.is_inline) try stream.writeAll("inline ");
for (items, 0..) |item_ref, item_i| {
if (item_i != 0) 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 = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
extra_index += 1;
const item_last = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
extra_index += 1;
if (range_i != 0 or items.len != 0) {
try stream.writeAll(", ");
}
try self.writeInstRef(stream, item_first);
try stream.writeAll("...");
try self.writeInstRef(stream, item_last);
}
const body = self.code.bodySlice(extra_index, info.body_len);
extra_index += info.body_len;
try stream.writeAll(" => ");
try self.writeBracedBody(stream, body);
}
}
self.indent -= 2;
try stream.writeAll(") ");
try self.writeSrcNode(stream, inst_data.src_node);
}
fn writeSwitchBlock(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const extra = self.code.extraData(Zir.Inst.SwitchBlock, inst_data.payload_index);
var extra_index: usize = extra.end;
const multi_cases_len = if (extra.data.bits.has_multi_cases) blk: {
const multi_cases_len = self.code.extra[extra_index];
extra_index += 1;
break :blk multi_cases_len;
} else 0;
const tag_capture_inst: Zir.Inst.Index = if (extra.data.bits.any_has_tag_capture) blk: {
const tag_capture_inst = self.code.extra[extra_index];
extra_index += 1;
break :blk @enumFromInt(tag_capture_inst);
} else undefined;
try self.writeInstRef(stream, extra.data.operand);
if (extra.data.bits.any_has_tag_capture) {
try stream.writeAll(", tag_capture=");
try self.writeInstIndex(stream, tag_capture_inst);
}
self.indent += 2;
const special_prongs = extra.data.bits.special_prongs;
if (special_prongs.hasElse()) {
const info: Zir.Inst.SwitchBlock.ProngInfo = @bitCast(self.code.extra[extra_index]);
const capture_text = switch (info.capture) {
.none => "",
.by_val => "by_val ",
.by_ref => "by_ref ",
};
const inline_text = if (info.is_inline) "inline " else "";
extra_index += 1;
const body = self.code.bodySlice(extra_index, info.body_len);
extra_index += body.len;
try stream.writeAll(",\n");
try stream.splatByteAll(' ', self.indent);
try stream.print("{s}{s}else => ", .{ capture_text, inline_text });
try self.writeBracedBody(stream, body);
}
if (special_prongs.hasUnder()) {
var single_item_ref: Zir.Inst.Ref = .none;
var items_len: u32 = 0;
var ranges_len: u32 = 0;
if (special_prongs.hasOneAdditionalItem()) {
single_item_ref = @enumFromInt(self.code.extra[extra_index]);
extra_index += 1;
} else if (special_prongs.hasManyAdditionalItems()) {
items_len = self.code.extra[extra_index];
extra_index += 1;
ranges_len = self.code.extra[extra_index];
extra_index += 1;
}
const info: Zir.Inst.SwitchBlock.ProngInfo = @bitCast(self.code.extra[extra_index]);
extra_index += 1;
const items = self.code.refSlice(extra_index, items_len);
extra_index += items_len;
try stream.writeAll(",\n");
try stream.splatByteAll(' ', self.indent);
switch (info.capture) {
.none => {},
.by_val => try stream.writeAll("by_val "),
.by_ref => try stream.writeAll("by_ref "),
}
if (info.is_inline) try stream.writeAll("inline ");
try stream.writeAll("_");
if (single_item_ref != .none) {
try stream.writeAll(", ");
try self.writeInstRef(stream, single_item_ref);
}
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: Zir.Inst.Ref = @enumFromInt(self.code.extra[extra_index]);
extra_index += 1;
const item_last: Zir.Inst.Ref = @enumFromInt(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.bodySlice(extra_index, info.body_len);
extra_index += info.body_len;
try stream.writeAll(" => ");
try self.writeBracedBody(stream, body);
}
{
const scalar_cases_len = extra.data.bits.scalar_cases_len;
var scalar_i: usize = 0;
while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
const item_ref: Zir.Inst.Ref = @enumFromInt(self.code.extra[extra_index]);
extra_index += 1;
const info: Zir.Inst.SwitchBlock.ProngInfo = @bitCast(self.code.extra[extra_index]);
extra_index += 1;
const body = self.code.bodySlice(extra_index, info.body_len);
extra_index += info.body_len;
try stream.writeAll(",\n");
try stream.splatByteAll(' ', self.indent);
switch (info.capture) {
.none => {},
.by_val => try stream.writeAll("by_val "),
.by_ref => try stream.writeAll("by_ref "),
}
if (info.is_inline) try stream.writeAll("inline ");
try self.writeInstRef(stream, item_ref);
try stream.writeAll(" => ");
try self.writeBracedBody(stream, body);
}
}
{
var multi_i: usize = 0;
while (multi_i < 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 info: Zir.Inst.SwitchBlock.ProngInfo = @bitCast(self.code.extra[extra_index]);
extra_index += 1;
const items = self.code.refSlice(extra_index, items_len);
extra_index += items_len;
try stream.writeAll(",\n");
try stream.splatByteAll(' ', self.indent);
switch (info.capture) {
.none => {},
.by_val => try stream.writeAll("by_val "),
.by_ref => try stream.writeAll("by_ref "),
}
if (info.is_inline) try stream.writeAll("inline ");
for (items, 0..) |item_ref, item_i| {
if (item_i != 0) 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: Zir.Inst.Ref = @enumFromInt(self.code.extra[extra_index]);
extra_index += 1;
const item_last: Zir.Inst.Ref = @enumFromInt(self.code.extra[extra_index]);
extra_index += 1;
if (range_i != 0 or items.len != 0) {
try stream.writeAll(", ");
}
try self.writeInstRef(stream, item_first);
try stream.writeAll("...");
try self.writeInstRef(stream, item_last);
}
const body = self.code.bodySlice(extra_index, info.body_len);
extra_index += info.body_len;
try stream.writeAll(" => ");
try self.writeBracedBody(stream, body);
}
}
self.indent -= 2;
try stream.writeAll(") ");
try self.writeSrcNode(stream, inst_data.src_node);
}
fn writePlNodeField(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(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(", \"{f}\") ", .{std.zig.fmtString(name)});
try self.writeSrcNode(stream, inst_data.src_node);
}
fn writePlNodeFieldNamed(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const extra = self.code.extraData(Zir.Inst.FieldNamed, inst_data.payload_index).data;
try self.writeInstRef(stream, extra.lhs);
try stream.writeAll(", ");
try self.writeInstRef(stream, extra.field_name);
try stream.writeAll(") ");
try self.writeSrcNode(stream, inst_data.src_node);
}
fn writeAs(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(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.writeSrcNode(stream, inst_data.src_node);
}
fn writeNode(
self: *Writer,
stream: *std.Io.Writer,
inst: Zir.Inst.Index,
) Error!void {
const src_node = self.code.instructions.items(.data)[@intFromEnum(inst)].node;
try stream.writeAll(") ");
try self.writeSrcNode(stream, src_node);
}
fn writeStrTok(
self: *Writer,
stream: *std.Io.Writer,
inst: Zir.Inst.Index,
) Error!void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].str_tok;
const str = inst_data.get(self.code);
try stream.print("\"{f}\") ", .{std.zig.fmtString(str)});
try self.writeSrcTok(stream, inst_data.src_tok);
}
fn writeStrOp(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].str_op;
const str = inst_data.getStr(self.code);
try self.writeInstRef(stream, inst_data.operand);
try stream.print(", \"{f}\")", .{std.zig.fmtString(str)});
}
fn writeFunc(
self: *Writer,
stream: *std.Io.Writer,
inst: Zir.Inst.Index,
inferred_error_set: bool,
) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const extra = self.code.extraData(Zir.Inst.Func, inst_data.payload_index);
var extra_index = extra.end;
var ret_ty_ref: Zir.Inst.Ref = .none;
var ret_ty_body: []const Zir.Inst.Index = &.{};
switch (extra.data.ret_ty.body_len) {
0 => {
ret_ty_ref = .void_type;
},
1 => {
ret_ty_ref = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
extra_index += 1;
},
else => {
ret_ty_body = self.code.bodySlice(extra_index, extra.data.ret_ty.body_len);
extra_index += ret_ty_body.len;
},
}
const body = self.code.bodySlice(extra_index, 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,
inferred_error_set,
false,
false,
.none,
&.{},
ret_ty_ref,
ret_ty_body,
extra.data.ret_ty.is_generic,
body,
inst_data.src_node,
src_locs,
0,
);
}
fn writeFuncFancy(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const extra = self.code.extraData(Zir.Inst.FuncFancy, inst_data.payload_index);
var extra_index: usize = extra.end;
var cc_ref: Zir.Inst.Ref = .none;
var cc_body: []const Zir.Inst.Index = &.{};
var ret_ty_ref: Zir.Inst.Ref = .none;
var ret_ty_body: []const Zir.Inst.Index = &.{};
if (extra.data.bits.has_cc_body) {
const body_len = self.code.extra[extra_index];
extra_index += 1;
cc_body = self.code.bodySlice(extra_index, body_len);
extra_index += cc_body.len;
} else if (extra.data.bits.has_cc_ref) {
cc_ref = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
extra_index += 1;
}
if (extra.data.bits.has_ret_ty_body) {
const body_len = self.code.extra[extra_index];
extra_index += 1;
ret_ty_body = self.code.bodySlice(extra_index, body_len);
extra_index += ret_ty_body.len;
} else if (extra.data.bits.has_ret_ty_ref) {
ret_ty_ref = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
extra_index += 1;
}
const noalias_bits: u32 = if (extra.data.bits.has_any_noalias) blk: {
const x = self.code.extra[extra_index];
extra_index += 1;
break :blk x;
} else 0;
const body = self.code.bodySlice(extra_index, 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,
extra.data.bits.is_inferred_error,
extra.data.bits.is_var_args,
extra.data.bits.is_noinline,
cc_ref,
cc_body,
ret_ty_ref,
ret_ty_body,
extra.data.bits.ret_ty_is_generic,
body,
inst_data.src_node,
src_locs,
noalias_bits,
);
}
fn writeAllocExtended(self: *Writer, stream: *std.Io.Writer, extended: Zir.Inst.Extended.InstData) !void {
const extra = self.code.extraData(Zir.Inst.AllocExtended, extended.operand);
const small = @as(Zir.Inst.AllocExtended.Small, @bitCast(extended.small));
var extra_index: usize = extra.end;
const type_inst: Zir.Inst.Ref = if (!small.has_type) .none else blk: {
const type_inst = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
extra_index += 1;
break :blk type_inst;
};
const align_inst: Zir.Inst.Ref = if (!small.has_align) .none else blk: {
const align_inst = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
extra_index += 1;
break :blk align_inst;
};
try self.writeFlag(stream, ",is_const", small.is_const);
try self.writeFlag(stream, ",is_comptime", small.is_comptime);
try self.writeOptionalInstRef(stream, ",ty=", type_inst);
try self.writeOptionalInstRef(stream, ",align=", align_inst);
try stream.writeAll(")) ");
try self.writeSrcNode(stream, extra.data.src_node);
}
fn writeTypeofPeer(self: *Writer, stream: *std.Io.Writer, extended: Zir.Inst.Extended.InstData) !void {
const extra = self.code.extraData(Zir.Inst.TypeOfPeer, extended.operand);
const body = self.code.bodySlice(extra.data.body_index, extra.data.body_len);
try self.writeBracedBody(stream, body);
try stream.writeAll(",[");
const args = self.code.refSlice(extra.end, extended.small);
for (args, 0..) |arg, i| {
if (i != 0) try stream.writeAll(", ");
try self.writeInstRef(stream, arg);
}
try stream.writeAll("])");
}
fn writeBoolBr(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const extra = self.code.extraData(Zir.Inst.BoolBr, inst_data.payload_index);
const body = self.code.bodySlice(extra.end, extra.data.body_len);
try self.writeInstRef(stream, extra.data.lhs);
try stream.writeAll(", ");
try self.writeBracedBody(stream, body);
try stream.writeAll(") ");
try self.writeSrcNode(stream, inst_data.src_node);
}
fn writeIntType(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const int_type = self.code.instructions.items(.data)[@intFromEnum(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.writeSrcNode(stream, int_type.src_node);
}
fn writeSaveErrRetIndex(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].save_err_ret_index;
try self.writeInstRef(stream, inst_data.operand);
try stream.writeAll(")");
}
fn writeRestoreErrRetIndex(self: *Writer, stream: *std.Io.Writer, extended: Zir.Inst.Extended.InstData) !void {
const extra = self.code.extraData(Zir.Inst.RestoreErrRetIndex, extended.operand).data;
try self.writeInstRef(stream, extra.block);
try self.writeInstRef(stream, extra.operand);
try stream.writeAll(") ");
try self.writeSrcNode(stream, extra.src_node);
}
fn writeBreak(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].@"break";
const extra = self.code.extraData(Zir.Inst.Break, inst_data.payload_index).data;
try self.writeInstIndex(stream, extra.block_inst);
try stream.writeAll(", ");
try self.writeInstRef(stream, inst_data.operand);
try stream.writeAll(")");
}
fn writeArrayInit(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const extra = self.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index);
const args = self.code.refSlice(extra.end, extra.data.operands_len);
try self.writeInstRef(stream, args[0]);
try stream.writeAll("{");
for (args[1..], 0..) |arg, i| {
if (i != 0) try stream.writeAll(", ");
try self.writeInstRef(stream, arg);
}
try stream.writeAll("}) ");
try self.writeSrcNode(stream, inst_data.src_node);
}
fn writeArrayInitAnon(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const extra = self.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index);
const args = self.code.refSlice(extra.end, extra.data.operands_len);
try stream.writeAll("{");
for (args, 0..) |arg, i| {
if (i != 0) try stream.writeAll(", ");
try self.writeInstRef(stream, arg);
}
try stream.writeAll("}) ");
try self.writeSrcNode(stream, inst_data.src_node);
}
fn writeArrayInitSent(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const extra = self.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index);
const args = self.code.refSlice(extra.end, extra.data.operands_len);
const sent = args[args.len - 1];
const elems = args[0 .. args.len - 1];
try self.writeInstRef(stream, sent);
try stream.writeAll(", ");
try stream.writeAll(".{");
for (elems, 0..) |elem, i| {
if (i != 0) try stream.writeAll(", ");
try self.writeInstRef(stream, elem);
}
try stream.writeAll("}) ");
try self.writeSrcNode(stream, inst_data.src_node);
}
fn writeUnreachable(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].@"unreachable";
try stream.writeAll(") ");
try self.writeSrcNode(stream, inst_data.src_node);
}
fn writeFuncCommon(
self: *Writer,
stream: *std.Io.Writer,
inferred_error_set: bool,
var_args: bool,
is_noinline: bool,
cc_ref: Zir.Inst.Ref,
cc_body: []const Zir.Inst.Index,
ret_ty_ref: Zir.Inst.Ref,
ret_ty_body: []const Zir.Inst.Index,
ret_ty_is_generic: bool,
body: []const Zir.Inst.Index,
src_node: Ast.Node.Offset,
src_locs: Zir.Inst.Func.SrcLocs,
noalias_bits: u32,
) !void {
try self.writeOptionalInstRefOrBody(stream, "cc=", cc_ref, cc_body);
if (ret_ty_is_generic) try stream.writeAll("[generic] ");
try self.writeOptionalInstRefOrBody(stream, "ret_ty=", ret_ty_ref, ret_ty_body);
try self.writeFlag(stream, "vargs, ", var_args);
try self.writeFlag(stream, "inferror, ", inferred_error_set);
try self.writeFlag(stream, "noinline, ", is_noinline);
if (noalias_bits != 0) {
try stream.print("noalias=0b{b}, ", .{noalias_bits});
}
try stream.writeAll("body=");
try self.writeBracedBody(stream, body);
try stream.writeAll(") ");
if (body.len != 0) {
try stream.print("(lbrace={d}:{d},rbrace={d}:{d}) ", .{
src_locs.lbrace_line + 1, @as(u16, @truncate(src_locs.columns)) + 1,
src_locs.rbrace_line + 1, @as(u16, @truncate(src_locs.columns >> 16)) + 1,
});
}
try self.writeSrcNode(stream, src_node);
}
fn writeDbgStmt(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].dbg_stmt;
try stream.print("{d}, {d})", .{ inst_data.line + 1, inst_data.column + 1 });
}
fn writeDefer(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].@"defer";
const body = self.code.bodySlice(inst_data.index, inst_data.len);
try self.writeBracedBody(stream, body);
try stream.writeByte(')');
}
fn writeDeferErrCode(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].defer_err_code;
const extra = self.code.extraData(Zir.Inst.DeferErrCode, inst_data.payload_index).data;
try self.writeInstRef(stream, extra.remapped_err_code.toRef());
try stream.writeAll(" = ");
try self.writeInstRef(stream, inst_data.err_code);
try stream.writeAll(", ");
const body = self.code.bodySlice(extra.index, extra.len);
try self.writeBracedBody(stream, body);
try stream.writeByte(')');
}
fn writeDeclaration(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const decl = self.code.getDeclaration(inst);
const prev_parent_decl_node = self.parent_decl_node;
defer self.parent_decl_node = prev_parent_decl_node;
self.parent_decl_node = decl.src_node;
if (decl.is_pub) try stream.writeAll("pub ");
switch (decl.linkage) {
.normal => {},
.@"export" => try stream.writeAll("export "),
.@"extern" => try stream.writeAll("extern "),
}
switch (decl.kind) {
.@"comptime" => try stream.writeAll("comptime"),
.unnamed_test => try stream.writeAll("test"),
.@"test", .decltest, .@"const", .@"var" => {
try stream.print("{s} '{s}'", .{ @tagName(decl.kind), self.code.nullTerminatedString(decl.name) });
},
}
const src_hash = self.code.getAssociatedSrcHash(inst).?;
try stream.print(" line({d}) column({d}) hash({x})", .{
decl.src_line, decl.src_column, &src_hash,
});
{
if (decl.type_body) |b| {
try stream.writeAll(" type=");
try self.writeBracedDecl(stream, b);
}
if (decl.align_body) |b| {
try stream.writeAll(" align=");
try self.writeBracedDecl(stream, b);
}
if (decl.linksection_body) |b| {
try stream.writeAll(" linksection=");
try self.writeBracedDecl(stream, b);
}
if (decl.addrspace_body) |b| {
try stream.writeAll(" addrspace=");
try self.writeBracedDecl(stream, b);
}
if (decl.value_body) |b| {
try stream.writeAll(" value=");
try self.writeBracedDecl(stream, b);
}
}
try stream.writeAll(") ");
try self.writeSrcNode(stream, .zero);
}
fn writeClosureGet(self: *Writer, stream: *std.Io.Writer, extended: Zir.Inst.Extended.InstData) !void {
try stream.print("{d})) ", .{extended.small});
const src_node: Ast.Node.Offset = @enumFromInt(@as(i32, @bitCast(extended.operand)));
try self.writeSrcNode(stream, src_node);
}
fn writeBuiltinValue(self: *Writer, stream: *std.Io.Writer, extended: Zir.Inst.Extended.InstData) !void {
const val: Zir.Inst.BuiltinValue = @enumFromInt(extended.small);
try stream.print("{s})) ", .{@tagName(val)});
const src_node: Ast.Node.Offset = @enumFromInt(@as(i32, @bitCast(extended.operand)));
try self.writeSrcNode(stream, src_node);
}
fn writeInplaceArithResultTy(self: *Writer, stream: *std.Io.Writer, extended: Zir.Inst.Extended.InstData) !void {
const op: Zir.Inst.InplaceOp = @enumFromInt(extended.small);
try self.writeInstRef(stream, @enumFromInt(extended.operand));
try stream.print(", {s}))", .{@tagName(op)});
}
fn writeInstRef(self: *Writer, stream: *std.Io.Writer, ref: Zir.Inst.Ref) !void {
if (ref == .none) {
return stream.writeAll(".none");
} else if (ref.toIndex()) |i| {
return self.writeInstIndex(stream, i);
} else {
const val: InternPool.Index = @enumFromInt(@intFromEnum(ref));
return stream.print("@{s}", .{@tagName(val)});
}
}
fn writeInstIndex(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
_ = self;
return stream.print("%{d}", .{@intFromEnum(inst)});
}
fn writeCaptures(self: *Writer, stream: *std.Io.Writer, extra_index: usize, captures_len: u32) !usize {
if (captures_len == 0) {
try stream.writeAll("{}");
return extra_index;
}
const captures: []const Zir.Inst.Capture = @ptrCast(self.code.extra[extra_index..][0..captures_len]);
const capture_names: []const Zir.NullTerminatedString = @ptrCast(self.code.extra[extra_index + captures_len ..][0..captures_len]);
for (captures, capture_names) |capture, name| {
try stream.writeAll("{ ");
if (name != .empty) {
const name_slice = self.code.nullTerminatedString(name);
try stream.print("{s} = ", .{name_slice});
}
try self.writeCapture(stream, capture);
}
return extra_index + 2 * captures_len;
}
fn writeCapture(self: *Writer, stream: *std.Io.Writer, capture: Zir.Inst.Capture) !void {
switch (capture.unwrap()) {
.nested => |i| return stream.print("[{d}]", .{i}),
.instruction => |inst| return self.writeInstIndex(stream, inst),
.instruction_load => |ptr_inst| {
try stream.writeAll("load ");
try self.writeInstIndex(stream, ptr_inst);
},
.decl_val => |str| try stream.print("decl_val \"{f}\"", .{
std.zig.fmtString(self.code.nullTerminatedString(str)),
}),
.decl_ref => |str| try stream.print("decl_ref \"{f}\"", .{
std.zig.fmtString(self.code.nullTerminatedString(str)),
}),
}
}
fn writeOptionalInstRef(
self: *Writer,
stream: *std.Io.Writer,
prefix: []const u8,
inst: Zir.Inst.Ref,
) !void {
if (inst == .none) return;
try stream.writeAll(prefix);
try self.writeInstRef(stream, inst);
}
fn writeOptionalInstRefOrBody(
self: *Writer,
stream: *std.Io.Writer,
prefix: []const u8,
ref: Zir.Inst.Ref,
body: []const Zir.Inst.Index,
) !void {
if (body.len != 0) {
try stream.writeAll(prefix);
try self.writeBracedBody(stream, body);
try stream.writeAll(", ");
} else if (ref != .none) {
try stream.writeAll(prefix);
try self.writeInstRef(stream, ref);
try stream.writeAll(", ");
}
}
fn writeFlag(
self: *Writer,
stream: *std.Io.Writer,
name: []const u8,
flag: bool,
) !void {
_ = self;
if (!flag) return;
try stream.writeAll(name);
}
fn writeSrcNode(self: *Writer, stream: *std.Io.Writer, src_node: Ast.Node.Offset) !void {
const tree = self.tree orelse return;
const abs_node = src_node.toAbsolute(self.parent_decl_node);
const src_span = tree.nodeToSpan(abs_node);
const start = self.line_col_cursor.find(tree.source, src_span.start);
const end = self.line_col_cursor.find(tree.source, src_span.end);
try stream.print("node_offset:{d}:{d} to :{d}:{d}", .{
start.line + 1, start.column + 1,
end.line + 1, end.column + 1,
});
}
fn writeSrcTok(self: *Writer, stream: *std.Io.Writer, src_tok: Ast.TokenOffset) !void {
const tree = self.tree orelse return;
const abs_tok = src_tok.toAbsolute(tree.firstToken(self.parent_decl_node));
const span_start = tree.tokenStart(abs_tok);
const span_end = span_start + @as(u32, @intCast(tree.tokenSlice(abs_tok).len));
const start = self.line_col_cursor.find(tree.source, span_start);
const end = self.line_col_cursor.find(tree.source, span_end);
try stream.print("token_offset:{d}:{d} to :{d}:{d}", .{
start.line + 1, start.column + 1,
end.line + 1, end.column + 1,
});
}
fn writeSrcTokAbs(self: *Writer, stream: *std.Io.Writer, src_tok: Ast.TokenIndex) !void {
const tree = self.tree orelse return;
const span_start = tree.tokenStart(src_tok);
const span_end = span_start + @as(u32, @intCast(tree.tokenSlice(src_tok).len));
const start = self.line_col_cursor.find(tree.source, span_start);
const end = self.line_col_cursor.find(tree.source, span_end);
try stream.print("token_abs:{d}:{d} to :{d}:{d}", .{
start.line + 1, start.column + 1,
end.line + 1, end.column + 1,
});
}
fn writeBracedDecl(self: *Writer, stream: *std.Io.Writer, body: []const Zir.Inst.Index) !void {
try self.writeBracedBodyConditional(stream, body, self.recurse_decls);
}
fn writeBracedBody(self: *Writer, stream: *std.Io.Writer, body: []const Zir.Inst.Index) !void {
try self.writeBracedBodyConditional(stream, body, self.recurse_blocks);
}
fn writeBracedBodyConditional(self: *Writer, stream: *std.Io.Writer, body: []const Zir.Inst.Index, enabled: bool) !void {
if (body.len == 0) {
try stream.writeAll("{}");
} else if (enabled) {
try stream.writeAll("{\n");
self.indent += 2;
try self.writeBody(stream, body);
self.indent -= 2;
try stream.splatByteAll(' ', self.indent);
try stream.writeAll("}");
} else if (body.len == 1) {
try stream.writeByte('{');
try self.writeInstIndex(stream, body[0]);
try stream.writeByte('}');
} else if (body.len == 2) {
try stream.writeByte('{');
try self.writeInstIndex(stream, body[0]);
try stream.writeAll(", ");
try self.writeInstIndex(stream, body[1]);
try stream.writeByte('}');
} else {
try stream.writeByte('{');
try self.writeInstIndex(stream, body[0]);
try stream.writeAll("..");
try self.writeInstIndex(stream, body[body.len - 1]);
try stream.writeByte('}');
}
}
fn writeBody(self: *Writer, stream: *std.Io.Writer, body: []const Zir.Inst.Index) !void {
for (body) |inst| {
try stream.splatByteAll(' ', self.indent);
try stream.print("%{d} ", .{@intFromEnum(inst)});
try self.writeInstToStream(stream, inst);
try stream.writeByte('\n');
}
}
fn writeImport(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_tok;
const extra = self.code.extraData(Zir.Inst.Import, inst_data.payload_index).data;
try self.writeInstRef(stream, extra.res_ty);
const import_path = self.code.nullTerminatedString(extra.path);
try stream.print(", \"{f}\") ", .{std.zig.fmtString(import_path)});
try self.writeSrcTok(stream, inst_data.src_tok);
}
};