Commit eadbee2041
Changed files (7)
src/Air.zig
@@ -374,8 +374,8 @@ pub const Asm = struct {
pub fn getMainBody(air: Air) []const Air.Inst.Index {
const body_index = air.extra[@enumToInt(ExtraIndex.main_block)];
- const body_len = air.extra[body_index];
- return air.extra[body_index..][0..body_len];
+ const extra = air.extraData(Block, body_index);
+ return air.extra[extra.end..][0..extra.data.body_len];
}
pub fn getType(air: Air, inst: Air.Inst.Index) Type {
src/Compilation.zig
@@ -1,6 +1,7 @@
const Compilation = @This();
const std = @import("std");
+const builtin = @import("builtin");
const mem = std.mem;
const Allocator = std.mem.Allocator;
const assert = std.debug.assert;
@@ -907,7 +908,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
// comptime conditions
((build_options.have_llvm and comptime std.Target.current.isDarwin()) and
// runtime conditions
- (use_lld and std.builtin.os.tag == .macos and options.target.isDarwin()));
+ (use_lld and builtin.os.tag == .macos and options.target.isDarwin()));
const sysroot = blk: {
if (options.sysroot) |sysroot| {
@@ -2026,8 +2027,10 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
var liveness = try Liveness.analyze(gpa, air, decl.namespace.file_scope.zir);
defer liveness.deinit(gpa);
- if (std.builtin.mode == .Debug and self.verbose_air) {
- @panic("TODO implement dumping AIR and liveness");
+ if (builtin.mode == .Debug and self.verbose_air) {
+ std.debug.print("# Begin Function AIR: {s}:\n", .{decl.name});
+ @import("print_air.zig").dump(gpa, air, liveness);
+ std.debug.print("# End Function AIR: {s}:\n", .{decl.name});
}
assert(decl.ty.hasCodeGenBits());
src/Module.zig
@@ -3551,7 +3551,8 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) SemaError!Air {
try sema.analyzeFnBody(&inner_block, func.zir_body_inst);
// Copy the block into place and mark that as the main block.
- try sema.air_extra.ensureUnusedCapacity(gpa, inner_block.instructions.items.len + 1);
+ try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len +
+ inner_block.instructions.items.len);
const main_block_index = sema.addExtraAssumeCapacity(Air.Block{
.body_len = @intCast(u32, inner_block.instructions.items.len),
});
src/print_air.zig
@@ -0,0 +1,294 @@
+const std = @import("std");
+const Allocator = std.mem.Allocator;
+const fmtIntSizeBin = std.fmt.fmtIntSizeBin;
+
+const Module = @import("Module.zig");
+const Value = @import("value.zig").Value;
+const Air = @import("Air.zig");
+const Liveness = @import("Liveness.zig");
+
+pub fn dump(gpa: *Allocator, air: Air, liveness: Liveness) void {
+ const instruction_bytes = air.instructions.len *
+ // Here we don't use @sizeOf(Air.Inst.Data) because it would include
+ // the debug safety tag but we want to measure release size.
+ (@sizeOf(Air.Inst.Tag) + 8);
+ const extra_bytes = air.extra.len * @sizeOf(u32);
+ const values_bytes = air.values.len * @sizeOf(Value);
+ const variables_bytes = air.variables.len * @sizeOf(*Module.Var);
+ const tomb_bytes = liveness.tomb_bits.len * @sizeOf(usize);
+ const liveness_extra_bytes = liveness.extra.len * @sizeOf(u32);
+ const liveness_special_bytes = liveness.special.count() * 8;
+ const total_bytes = @sizeOf(Air) + instruction_bytes + extra_bytes +
+ values_bytes * variables_bytes + @sizeOf(Liveness) + liveness_extra_bytes +
+ liveness_special_bytes + tomb_bytes;
+
+ // zig fmt: off
+ std.debug.print(
+ \\# Total AIR+Liveness bytes: {}
+ \\# AIR Instructions: {d} ({})
+ \\# AIR Extra Data: {d} ({})
+ \\# AIR Values Bytes: {d} ({})
+ \\# AIR Variables Bytes: {d} ({})
+ \\# Liveness tomb_bits: {}
+ \\# Liveness Extra Data: {d} ({})
+ \\# Liveness special table: {d} ({})
+ \\
+ , .{
+ fmtIntSizeBin(total_bytes),
+ air.instructions.len, fmtIntSizeBin(instruction_bytes),
+ air.extra.len, fmtIntSizeBin(extra_bytes),
+ air.values.len, fmtIntSizeBin(values_bytes),
+ air.variables.len, fmtIntSizeBin(variables_bytes),
+ fmtIntSizeBin(tomb_bytes),
+ liveness.extra.len, fmtIntSizeBin(liveness_extra_bytes),
+ liveness.special.count(), fmtIntSizeBin(liveness_special_bytes),
+ });
+ // zig fmt: on
+ var arena = std.heap.ArenaAllocator.init(gpa);
+ defer arena.deinit();
+
+ var writer: Writer = .{
+ .gpa = gpa,
+ .arena = &arena.allocator,
+ .air = air,
+ .liveness = liveness,
+ .indent = 0,
+ };
+ const stream = std.io.getStdErr().writer();
+ writer.writeAllConstants(stream) catch return;
+ writer.writeBody(stream, air.getMainBody()) catch return;
+}
+
+const Writer = struct {
+ gpa: *Allocator,
+ arena: *Allocator,
+ air: Air,
+ liveness: Liveness,
+ indent: usize,
+
+ fn writeAllConstants(w: *Writer, s: anytype) @TypeOf(s).Error!void {
+ for (w.air.instructions.items(.tag)) |tag, i| {
+ const inst = @intCast(u32, i);
+ switch (tag) {
+ .constant, .const_ty => {
+ try s.writeByteNTimes(' ', w.indent);
+ try s.print("%{d} ", .{inst});
+ try w.writeInst(s, inst);
+ try s.writeAll(")\n");
+ },
+ else => continue,
+ }
+ }
+ }
+
+ fn writeBody(w: *Writer, s: anytype, body: []const Air.Inst.Index) @TypeOf(s).Error!void {
+ for (body) |inst| {
+ try s.writeByteNTimes(' ', w.indent);
+ try s.print("%{d} ", .{inst});
+ try w.writeInst(s, inst);
+ if (w.liveness.isUnused(inst)) {
+ try s.writeAll(") unused\n");
+ } else {
+ try s.writeAll("\n");
+ }
+ }
+ }
+
+ fn writeInst(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
+ const tags = w.air.instructions.items(.tag);
+ const tag = tags[inst];
+ try s.print("= {s}(", .{@tagName(tags[inst])});
+ switch (tag) {
+ .arg => try w.writeTyStr(s, inst),
+
+ .add,
+ .addwrap,
+ .sub,
+ .subwrap,
+ .mul,
+ .mulwrap,
+ .div,
+ .bit_and,
+ .bit_or,
+ .xor,
+ .cmp_lt,
+ .cmp_lte,
+ .cmp_eq,
+ .cmp_gte,
+ .cmp_gt,
+ .cmp_neq,
+ .bool_and,
+ .bool_or,
+ .store,
+ => try w.writeBinOp(s, inst),
+
+ .is_null,
+ .is_non_null,
+ .is_null_ptr,
+ .is_non_null_ptr,
+ .is_err,
+ .is_non_err,
+ .is_err_ptr,
+ .is_non_err_ptr,
+ .ptrtoint,
+ .ret,
+ => try w.writeUnOp(s, inst),
+
+ .breakpoint,
+ .unreach,
+ => try w.writeNoOp(s, inst),
+
+ .const_ty,
+ .alloc,
+ => try w.writeTy(s, inst),
+
+ .not,
+ .bitcast,
+ .load,
+ .ref,
+ .floatcast,
+ .intcast,
+ .optional_payload,
+ .optional_payload_ptr,
+ .wrap_optional,
+ .unwrap_errunion_payload,
+ .unwrap_errunion_err,
+ .unwrap_errunion_payload_ptr,
+ .unwrap_errunion_err_ptr,
+ .wrap_errunion_payload,
+ .wrap_errunion_err,
+ => try w.writeTyOp(s, inst),
+
+ .block,
+ .loop,
+ => try w.writeBlock(s, inst),
+
+ .struct_field_ptr => try w.writeStructFieldPtr(s, inst),
+ .varptr => try w.writeVarPtr(s, inst),
+ .constant => try w.writeConstant(s, inst),
+ .assembly => try w.writeAssembly(s, inst),
+ .dbg_stmt => try w.writeDbgStmt(s, inst),
+ .call => try w.writeCall(s, inst),
+ .br => try w.writeBr(s, inst),
+ .cond_br => try w.writeCondBr(s, inst),
+ .switch_br => try w.writeSwitchBr(s, inst),
+ }
+ }
+
+ fn writeTyStr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
+ _ = w;
+ _ = inst;
+ try s.writeAll("TODO");
+ }
+
+ fn writeBinOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
+ _ = w;
+ _ = inst;
+ try s.writeAll("TODO");
+ }
+
+ fn writeUnOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
+ _ = w;
+ _ = inst;
+ try s.writeAll("TODO");
+ }
+
+ fn writeNoOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
+ _ = w;
+ _ = inst;
+ try s.writeAll("TODO");
+ }
+
+ fn writeTy(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
+ const ty = w.air.instructions.items(.data)[inst].ty;
+ try s.print("{}", .{ty});
+ }
+
+ fn writeTyOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
+ _ = w;
+ _ = inst;
+ try s.writeAll("TODO");
+ }
+
+ fn writeBlock(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
+ _ = w;
+ _ = inst;
+ try s.writeAll("TODO");
+ }
+
+ fn writeStructFieldPtr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
+ _ = w;
+ _ = inst;
+ try s.writeAll("TODO");
+ }
+
+ fn writeVarPtr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
+ _ = w;
+ _ = inst;
+ try s.writeAll("TODO");
+ }
+
+ fn writeConstant(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
+ const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;
+ const val = w.air.values[ty_pl.payload];
+ try s.print("{}, {}", .{ ty_pl.ty, val });
+ }
+
+ fn writeAssembly(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
+ _ = w;
+ _ = inst;
+ try s.writeAll("TODO");
+ }
+
+ fn writeDbgStmt(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
+ const dbg_stmt = w.air.instructions.items(.data)[inst].dbg_stmt;
+ try s.print("{d}:{d}", .{ dbg_stmt.line + 1, dbg_stmt.column + 1 });
+ }
+
+ fn writeCall(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
+ const pl_op = w.air.instructions.items(.data)[inst].pl_op;
+ const extra = w.air.extraData(Air.Call, pl_op.payload);
+ const args = w.air.extra[extra.end..][0..extra.data.args_len];
+ try w.writeInstRef(s, pl_op.operand);
+ try s.writeAll(", [");
+ for (args) |arg, i| {
+ if (i != 0) try s.writeAll(", ");
+ try w.writeInstRef(s, @intToEnum(Air.Inst.Ref, arg));
+ }
+ try s.writeAll("]");
+ }
+
+ fn writeBr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
+ _ = w;
+ _ = inst;
+ try s.writeAll("TODO");
+ }
+
+ fn writeCondBr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
+ _ = w;
+ _ = inst;
+ try s.writeAll("TODO");
+ }
+
+ fn writeSwitchBr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
+ _ = w;
+ _ = inst;
+ try s.writeAll("TODO");
+ }
+
+ fn writeInstRef(w: *Writer, s: anytype, inst: Air.Inst.Ref) @TypeOf(s).Error!void {
+ var i: usize = @enumToInt(inst);
+
+ if (i < Air.Inst.Ref.typed_value_map.len) {
+ return s.print("@{}", .{inst});
+ }
+ i -= Air.Inst.Ref.typed_value_map.len;
+
+ return w.writeInstIndex(s, @intCast(Air.Inst.Index, i));
+ }
+
+ fn writeInstIndex(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
+ _ = w;
+ return s.print("%{d}", .{inst});
+ }
+};
src/Sema.zig
@@ -2028,6 +2028,7 @@ fn analyzeBlockBody(
refToIndex(coerced_operand).?);
// Convert the br operand to a block.
+ const br_operand_ty_ref = try sema.addType(br_operand_ty);
try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len +
coerce_block.instructions.items.len);
try sema.air_instructions.ensureUnusedCapacity(gpa, 2);
@@ -2037,7 +2038,7 @@ fn analyzeBlockBody(
sema.air_instructions.appendAssumeCapacity(.{
.tag = .block,
.data = .{ .ty_pl = .{
- .ty = try sema.addType(br_operand_ty),
+ .ty = br_operand_ty_ref,
.payload = sema.addExtraAssumeCapacity(Air.Block{
.body_len = @intCast(u32, coerce_block.instructions.items.len),
}),
src/value.zig
@@ -573,7 +573,7 @@ pub const Value = extern union {
.int_i64 => return std.fmt.formatIntValue(val.castTag(.int_i64).?.data, "", options, out_stream),
.int_big_positive => return out_stream.print("{}", .{val.castTag(.int_big_positive).?.asBigInt()}),
.int_big_negative => return out_stream.print("{}", .{val.castTag(.int_big_negative).?.asBigInt()}),
- .function => return out_stream.writeAll("(function)"),
+ .function => return out_stream.print("(function '{s}')", .{val.castTag(.function).?.data.owner_decl.name}),
.extern_fn => return out_stream.writeAll("(extern function)"),
.variable => return out_stream.writeAll("(variable)"),
.ref_val => {
BRANCH_TODO
@@ -1,566 +0,0 @@
- * be sure to test debug info of parameters
-
-
- pub fn specialOperandDeaths(self: Inst) bool {
- return (self.deaths & (1 << deaths_bits)) != 0;
- }
-
- /// Returns `null` if runtime-known.
- /// Should be called by codegen, not by Sema. Sema functions should call
- /// `resolvePossiblyUndefinedValue` or `resolveDefinedValue` instead.
- /// TODO audit Sema code for violations to the above guidance.
- pub fn value(base: *Inst) ?Value {
- if (base.ty.onePossibleValue()) |opv| return opv;
-
- const inst = base.castTag(.constant) orelse return null;
- return inst.val;
- }
-
-
-
-/// For debugging purposes, prints a function representation to stderr.
-pub fn dumpFn(old_module: Module, module_fn: *Module.Fn) void {
- const allocator = old_module.gpa;
- var ctx: DumpAir = .{
- .allocator = allocator,
- .arena = std.heap.ArenaAllocator.init(allocator),
- .old_module = &old_module,
- .module_fn = module_fn,
- .indent = 2,
- .inst_table = DumpAir.InstTable.init(allocator),
- .partial_inst_table = DumpAir.InstTable.init(allocator),
- .const_table = DumpAir.InstTable.init(allocator),
- };
- defer ctx.inst_table.deinit();
- defer ctx.partial_inst_table.deinit();
- defer ctx.const_table.deinit();
- defer ctx.arena.deinit();
-
- switch (module_fn.state) {
- .queued => std.debug.print("(queued)", .{}),
- .inline_only => std.debug.print("(inline_only)", .{}),
- .in_progress => std.debug.print("(in_progress)", .{}),
- .sema_failure => std.debug.print("(sema_failure)", .{}),
- .dependency_failure => std.debug.print("(dependency_failure)", .{}),
- .success => {
- const writer = std.io.getStdErr().writer();
- ctx.dump(module_fn.body, writer) catch @panic("failed to dump AIR");
- },
- }
-}
-
-const DumpAir = struct {
- allocator: *std.mem.Allocator,
- arena: std.heap.ArenaAllocator,
- old_module: *const Module,
- module_fn: *Module.Fn,
- indent: usize,
- inst_table: InstTable,
- partial_inst_table: InstTable,
- const_table: InstTable,
- next_index: usize = 0,
- next_partial_index: usize = 0,
- next_const_index: usize = 0,
-
- const InstTable = std.AutoArrayHashMap(*Inst, usize);
-
- /// TODO: Improve this code to include a stack of Body and store the instructions
- /// in there. Now we are putting all the instructions in a function local table,
- /// however instructions that are in a Body can be thown away when the Body ends.
- fn dump(dtz: *DumpAir, body: Body, writer: std.fs.File.Writer) !void {
- // First pass to pre-populate the table so that we can show even invalid references.
- // Must iterate the same order we iterate the second time.
- // We also look for constants and put them in the const_table.
- try dtz.fetchInstsAndResolveConsts(body);
-
- std.debug.print("Module.Function(name={s}):\n", .{dtz.module_fn.owner_decl.name});
-
- var it = dtz.const_table.iterator();
- while (it.next()) |entry| {
- const constant = entry.key_ptr.*.castTag(.constant).?;
- try writer.print(" @{d}: {} = {};\n", .{
- entry.value_ptr.*, constant.base.ty, constant.val,
- });
- }
-
- return dtz.dumpBody(body, writer);
- }
-
- fn fetchInstsAndResolveConsts(dtz: *DumpAir, body: Body) error{OutOfMemory}!void {
- for (body.instructions) |inst| {
- try dtz.inst_table.put(inst, dtz.next_index);
- dtz.next_index += 1;
- switch (inst.tag) {
- .alloc,
- .retvoid,
- .unreach,
- .breakpoint,
- .dbg_stmt,
- .arg,
- => {},
-
- .ref,
- .ret,
- .bitcast,
- .not,
- .is_non_null,
- .is_non_null_ptr,
- .is_null,
- .is_null_ptr,
- .is_err,
- .is_non_err,
- .is_err_ptr,
- .is_non_err_ptr,
- .ptrtoint,
- .floatcast,
- .intcast,
- .load,
- .optional_payload,
- .optional_payload_ptr,
- .wrap_optional,
- .wrap_errunion_payload,
- .wrap_errunion_err,
- .unwrap_errunion_payload,
- .unwrap_errunion_err,
- .unwrap_errunion_payload_ptr,
- .unwrap_errunion_err_ptr,
- => {
- const un_op = inst.cast(Inst.UnOp).?;
- try dtz.findConst(un_op.operand);
- },
-
- .add,
- .addwrap,
- .sub,
- .subwrap,
- .mul,
- .mulwrap,
- .div,
- .cmp_lt,
- .cmp_lte,
- .cmp_eq,
- .cmp_gte,
- .cmp_gt,
- .cmp_neq,
- .store,
- .bool_and,
- .bool_or,
- .bit_and,
- .bit_or,
- .xor,
- => {
- const bin_op = inst.cast(Inst.BinOp).?;
- try dtz.findConst(bin_op.lhs);
- try dtz.findConst(bin_op.rhs);
- },
-
- .br => {
- const br = inst.castTag(.br).?;
- try dtz.findConst(&br.block.base);
- try dtz.findConst(br.operand);
- },
-
- .br_block_flat => {
- const br_block_flat = inst.castTag(.br_block_flat).?;
- try dtz.findConst(&br_block_flat.block.base);
- try dtz.fetchInstsAndResolveConsts(br_block_flat.body);
- },
-
- .br_void => {
- const br_void = inst.castTag(.br_void).?;
- try dtz.findConst(&br_void.block.base);
- },
-
- .block => {
- const block = inst.castTag(.block).?;
- try dtz.fetchInstsAndResolveConsts(block.body);
- },
-
- .condbr => {
- const condbr = inst.castTag(.condbr).?;
- try dtz.findConst(condbr.condition);
- try dtz.fetchInstsAndResolveConsts(condbr.then_body);
- try dtz.fetchInstsAndResolveConsts(condbr.else_body);
- },
- .switchbr => {
- const switchbr = inst.castTag(.switchbr).?;
- try dtz.findConst(switchbr.target);
- try dtz.fetchInstsAndResolveConsts(switchbr.else_body);
- for (switchbr.cases) |case| {
- try dtz.fetchInstsAndResolveConsts(case.body);
- }
- },
-
- .loop => {
- const loop = inst.castTag(.loop).?;
- try dtz.fetchInstsAndResolveConsts(loop.body);
- },
- .call => {
- const call = inst.castTag(.call).?;
- try dtz.findConst(call.func);
- for (call.args) |arg| {
- try dtz.findConst(arg);
- }
- },
- .struct_field_ptr => {
- const struct_field_ptr = inst.castTag(.struct_field_ptr).?;
- try dtz.findConst(struct_field_ptr.struct_ptr);
- },
-
- // TODO fill out this debug printing
- .assembly,
- .constant,
- .varptr,
- => {},
- }
- }
- }
-
- fn dumpBody(dtz: *DumpAir, body: Body, writer: std.fs.File.Writer) (std.fs.File.WriteError || error{OutOfMemory})!void {
- for (body.instructions) |inst| {
- const my_index = dtz.next_partial_index;
- try dtz.partial_inst_table.put(inst, my_index);
- dtz.next_partial_index += 1;
-
- try writer.writeByteNTimes(' ', dtz.indent);
- try writer.print("%{d}: {} = {s}(", .{
- my_index, inst.ty, @tagName(inst.tag),
- });
- switch (inst.tag) {
- .alloc,
- .retvoid,
- .unreach,
- .breakpoint,
- .dbg_stmt,
- => try writer.writeAll(")\n"),
-
- .ref,
- .ret,
- .bitcast,
- .not,
- .is_non_null,
- .is_non_null_ptr,
- .is_null,
- .is_null_ptr,
- .is_err,
- .is_err_ptr,
- .is_non_err,
- .is_non_err_ptr,
- .ptrtoint,
- .floatcast,
- .intcast,
- .load,
- .optional_payload,
- .optional_payload_ptr,
- .wrap_optional,
- .wrap_errunion_err,
- .wrap_errunion_payload,
- .unwrap_errunion_err,
- .unwrap_errunion_payload,
- .unwrap_errunion_payload_ptr,
- .unwrap_errunion_err_ptr,
- => {
- const un_op = inst.cast(Inst.UnOp).?;
- const kinky = try dtz.writeInst(writer, un_op.operand);
- if (kinky != null) {
- try writer.writeAll(") // Instruction does not dominate all uses!\n");
- } else {
- try writer.writeAll(")\n");
- }
- },
-
- .add,
- .addwrap,
- .sub,
- .subwrap,
- .mul,
- .mulwrap,
- .div,
- .cmp_lt,
- .cmp_lte,
- .cmp_eq,
- .cmp_gte,
- .cmp_gt,
- .cmp_neq,
- .store,
- .bool_and,
- .bool_or,
- .bit_and,
- .bit_or,
- .xor,
- => {
- const bin_op = inst.cast(Inst.BinOp).?;
-
- const lhs_kinky = try dtz.writeInst(writer, bin_op.lhs);
- try writer.writeAll(", ");
- const rhs_kinky = try dtz.writeInst(writer, bin_op.rhs);
-
- if (lhs_kinky != null or rhs_kinky != null) {
- try writer.writeAll(") // Instruction does not dominate all uses!");
- if (lhs_kinky) |lhs| {
- try writer.print(" %{d}", .{lhs});
- }
- if (rhs_kinky) |rhs| {
- try writer.print(" %{d}", .{rhs});
- }
- try writer.writeAll("\n");
- } else {
- try writer.writeAll(")\n");
- }
- },
-
- .arg => {
- const arg = inst.castTag(.arg).?;
- try writer.print("{s})\n", .{arg.name});
- },
-
- .br => {
- const br = inst.castTag(.br).?;
-
- const lhs_kinky = try dtz.writeInst(writer, &br.block.base);
- try writer.writeAll(", ");
- const rhs_kinky = try dtz.writeInst(writer, br.operand);
-
- if (lhs_kinky != null or rhs_kinky != null) {
- try writer.writeAll(") // Instruction does not dominate all uses!");
- if (lhs_kinky) |lhs| {
- try writer.print(" %{d}", .{lhs});
- }
- if (rhs_kinky) |rhs| {
- try writer.print(" %{d}", .{rhs});
- }
- try writer.writeAll("\n");
- } else {
- try writer.writeAll(")\n");
- }
- },
-
- .br_block_flat => {
- const br_block_flat = inst.castTag(.br_block_flat).?;
- const block_kinky = try dtz.writeInst(writer, &br_block_flat.block.base);
- if (block_kinky != null) {
- try writer.writeAll(", { // Instruction does not dominate all uses!\n");
- } else {
- try writer.writeAll(", {\n");
- }
-
- const old_indent = dtz.indent;
- dtz.indent += 2;
- try dtz.dumpBody(br_block_flat.body, writer);
- dtz.indent = old_indent;
-
- try writer.writeByteNTimes(' ', dtz.indent);
- try writer.writeAll("})\n");
- },
-
- .br_void => {
- const br_void = inst.castTag(.br_void).?;
- const kinky = try dtz.writeInst(writer, &br_void.block.base);
- if (kinky) |_| {
- try writer.writeAll(") // Instruction does not dominate all uses!\n");
- } else {
- try writer.writeAll(")\n");
- }
- },
-
- .block => {
- const block = inst.castTag(.block).?;
-
- try writer.writeAll("{\n");
-
- const old_indent = dtz.indent;
- dtz.indent += 2;
- try dtz.dumpBody(block.body, writer);
- dtz.indent = old_indent;
-
- try writer.writeByteNTimes(' ', dtz.indent);
- try writer.writeAll("})\n");
- },
-
- .condbr => {
- const condbr = inst.castTag(.condbr).?;
-
- const condition_kinky = try dtz.writeInst(writer, condbr.condition);
- if (condition_kinky != null) {
- try writer.writeAll(", { // Instruction does not dominate all uses!\n");
- } else {
- try writer.writeAll(", {\n");
- }
-
- const old_indent = dtz.indent;
- dtz.indent += 2;
- try dtz.dumpBody(condbr.then_body, writer);
-
- try writer.writeByteNTimes(' ', old_indent);
- try writer.writeAll("}, {\n");
-
- try dtz.dumpBody(condbr.else_body, writer);
- dtz.indent = old_indent;
-
- try writer.writeByteNTimes(' ', old_indent);
- try writer.writeAll("})\n");
- },
-
- .switchbr => {
- const switchbr = inst.castTag(.switchbr).?;
-
- const condition_kinky = try dtz.writeInst(writer, switchbr.target);
- if (condition_kinky != null) {
- try writer.writeAll(", { // Instruction does not dominate all uses!\n");
- } else {
- try writer.writeAll(", {\n");
- }
- const old_indent = dtz.indent;
-
- if (switchbr.else_body.instructions.len != 0) {
- dtz.indent += 2;
- try dtz.dumpBody(switchbr.else_body, writer);
-
- try writer.writeByteNTimes(' ', old_indent);
- try writer.writeAll("}, {\n");
- dtz.indent = old_indent;
- }
- for (switchbr.cases) |case| {
- dtz.indent += 2;
- try dtz.dumpBody(case.body, writer);
-
- try writer.writeByteNTimes(' ', old_indent);
- try writer.writeAll("}, {\n");
- dtz.indent = old_indent;
- }
-
- try writer.writeByteNTimes(' ', old_indent);
- try writer.writeAll("})\n");
- },
-
- .loop => {
- const loop = inst.castTag(.loop).?;
-
- try writer.writeAll("{\n");
-
- const old_indent = dtz.indent;
- dtz.indent += 2;
- try dtz.dumpBody(loop.body, writer);
- dtz.indent = old_indent;
-
- try writer.writeByteNTimes(' ', dtz.indent);
- try writer.writeAll("})\n");
- },
-
- .call => {
- const call = inst.castTag(.call).?;
-
- const args_kinky = try dtz.allocator.alloc(?usize, call.args.len);
- defer dtz.allocator.free(args_kinky);
- std.mem.set(?usize, args_kinky, null);
- var any_kinky_args = false;
-
- const func_kinky = try dtz.writeInst(writer, call.func);
-
- for (call.args) |arg, i| {
- try writer.writeAll(", ");
-
- args_kinky[i] = try dtz.writeInst(writer, arg);
- any_kinky_args = any_kinky_args or args_kinky[i] != null;
- }
-
- if (func_kinky != null or any_kinky_args) {
- try writer.writeAll(") // Instruction does not dominate all uses!");
- if (func_kinky) |func_index| {
- try writer.print(" %{d}", .{func_index});
- }
- for (args_kinky) |arg_kinky| {
- if (arg_kinky) |arg_index| {
- try writer.print(" %{d}", .{arg_index});
- }
- }
- try writer.writeAll("\n");
- } else {
- try writer.writeAll(")\n");
- }
- },
-
- .struct_field_ptr => {
- const struct_field_ptr = inst.castTag(.struct_field_ptr).?;
- const kinky = try dtz.writeInst(writer, struct_field_ptr.struct_ptr);
- if (kinky != null) {
- try writer.print("{d}) // Instruction does not dominate all uses!\n", .{
- struct_field_ptr.field_index,
- });
- } else {
- try writer.print("{d})\n", .{struct_field_ptr.field_index});
- }
- },
-
- // TODO fill out this debug printing
- .assembly,
- .constant,
- .varptr,
- => {
- try writer.writeAll("!TODO!)\n");
- },
- }
- }
- }
-
- fn writeInst(dtz: *DumpAir, writer: std.fs.File.Writer, inst: *Inst) !?usize {
- if (dtz.partial_inst_table.get(inst)) |operand_index| {
- try writer.print("%{d}", .{operand_index});
- return null;
- } else if (dtz.const_table.get(inst)) |operand_index| {
- try writer.print("@{d}", .{operand_index});
- return null;
- } else if (dtz.inst_table.get(inst)) |operand_index| {
- try writer.print("%{d}", .{operand_index});
- return operand_index;
- } else {
- try writer.writeAll("!BADREF!");
- return null;
- }
- }
-
- fn findConst(dtz: *DumpAir, operand: *Inst) !void {
- if (operand.tag == .constant) {
- try dtz.const_table.put(operand, dtz.next_const_index);
- dtz.next_const_index += 1;
- }
- }
-};
-
-pub fn dumpInst(mod: *Module, scope: *Scope, inst: *ir.Inst) void {
- const zir_module = scope.namespace();
- const source = zir_module.getSource(mod) catch @panic("dumpInst failed to get source");
- const loc = std.zig.findLineColumn(source, inst.src);
- if (inst.tag == .constant) {
- std.debug.print("constant ty={} val={} src={s}:{d}:{d}\n", .{
- inst.ty,
- inst.castTag(.constant).?.val,
- zir_module.subFilePath(),
- loc.line + 1,
- loc.column + 1,
- });
- } else if (inst.deaths == 0) {
- std.debug.print("{s} ty={} src={s}:{d}:{d}\n", .{
- @tagName(inst.tag),
- inst.ty,
- zir_module.subFilePath(),
- loc.line + 1,
- loc.column + 1,
- });
- } else {
- std.debug.print("{s} ty={} deaths={b} src={s}:{d}:{d}\n", .{
- @tagName(inst.tag),
- inst.ty,
- inst.deaths,
- zir_module.subFilePath(),
- loc.line + 1,
- loc.column + 1,
- });
- }
-}
-
- /// For debugging purposes.
- pub fn dump(func: *Fn, mod: Module) void {
- ir.dumpFn(mod, func);
- }
-