Commit eadbee2041

Andrew Kelley <andrew@ziglang.org>
2021-07-16 00:52:06
stage2: first pass at printing AIR/Liveness to text
* some instructions are not implemented yet * fix off-by-1 in Air.getMainBody * Compilation: use `@import("builtin")` rather than `std.builtin` for the values that are different for different build configurations. * Sema: avoid calling `addType` in between air_instructions.ensureUnusedCapacity and corresponding appendAssumeCapacity because it can possibly add an instruction. * Value: functions print their names
1 parent 12c1013
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);
-    }
-