Commit 3a516433b0

Jacob Young <jacobly0@users.noreply.github.com>
2023-03-27 09:10:03
x86_64: add live codegen debug
1 parent abb37a7
Changed files (3)
src/arch/x86_64/CodeGen.zig
@@ -8,6 +8,7 @@ const link = @import("../../link.zig");
 const log = std.log.scoped(.codegen);
 const math = std.math;
 const mem = std.mem;
+const print_air = @import("../../print_air.zig");
 const trace = @import("../../tracy.zig").trace;
 
 const Air = @import("../../Air.zig");
@@ -20,6 +21,7 @@ const ErrorMsg = Module.ErrorMsg;
 const Result = codegen.Result;
 const Emit = @import("Emit.zig");
 const Liveness = @import("../../Liveness.zig");
+const Lower = @import("Lower.zig");
 const Mir = @import("Mir.zig");
 const Module = @import("../../Module.zig");
 const Target = std.Target;
@@ -44,6 +46,8 @@ const sse = abi.RegisterClass.sse;
 
 const InnerError = CodeGenError || error{OutOfRegisters};
 
+const debug_wip_mir = false;
+
 gpa: Allocator,
 air: Air,
 liveness: Liveness,
@@ -103,8 +107,12 @@ air_bookkeeping: @TypeOf(air_bookkeeping_init) = air_bookkeeping_init,
 /// For mir debug info, maps a mir index to a air index
 mir_to_air_map: if (builtin.mode == .Debug) std.AutoHashMap(Mir.Inst.Index, Air.Inst.Index) else void,
 
+debug_wip_mir_inst: @TypeOf(debug_wip_mir_inst_init) = debug_wip_mir_inst_init,
+
 const air_bookkeeping_init = if (std.debug.runtime_safety) @as(usize, 0) else {};
 
+const debug_wip_mir_inst_init = if (debug_wip_mir) @as(Mir.Inst.Index, 0) else {};
+
 pub const MCValue = union(enum) {
     /// No runtime bits. `void` types, empty structs, u0, enums with 1 tag, etc.
     /// TODO Look into deleting this tag and using `dead` instead, since every use
@@ -267,6 +275,12 @@ pub fn generate(
     assert(fn_owner_decl.has_tv);
     const fn_type = fn_owner_decl.ty;
 
+    if (debug_wip_mir) {
+        const stderr = std.io.getStdErr().writer();
+        fn_owner_decl.renderFullyQualifiedName(mod, stderr) catch {};
+        stderr.writeAll(":\n") catch {};
+    }
+
     var branch_stack = std.ArrayList(Branch).init(bin_file.allocator);
     try branch_stack.ensureUnusedCapacity(2);
     // The outermost branch is used for constants only.
@@ -683,6 +697,56 @@ fn asmMemoryRegisterImmediate(
     });
 }
 
+fn printWipMir(self: *Self, stream: anytype, air_inst: ?Air.Inst.Index) !void {
+    const mod = self.bin_file.options.module.?;
+    if (!debug_wip_mir) return;
+
+    var lower = Lower{
+        .allocator = self.gpa,
+        .mir = .{
+            .instructions = self.mir_instructions.slice(),
+            .extra = self.mir_extra.items,
+        },
+        .target = self.target,
+        .src_loc = self.src_loc,
+    };
+    var mir_inst = self.debug_wip_mir_inst;
+    var mir_end = @intCast(Mir.Inst.Index, self.mir_instructions.len);
+    defer self.debug_wip_mir_inst = mir_end;
+    while (mir_inst < mir_end) : (mir_inst += 1) {
+        for (lower.lowerMir(lower.mir.instructions.get(mir_inst)) catch |err| switch (err) {
+            error.LowerFail => {
+                defer {
+                    lower.err_msg.?.deinit(self.gpa);
+                    lower.err_msg = null;
+                }
+                try stream.print("{s}\n", .{lower.err_msg.?.msg});
+                continue;
+            },
+            error.InvalidInstruction, error.CannotEncode => |e| {
+                try stream.writeAll(switch (e) {
+                    error.InvalidInstruction => "CodeGen failed to find a viable instruction.\n",
+                    error.CannotEncode => "CodeGen failed to encode the instruction.\n",
+                });
+                continue;
+            },
+            else => |e| return e,
+        }) |lower_inst| {
+            try stream.writeAll("  | ");
+            try lower_inst.fmtPrint(stream);
+            try stream.writeByte('\n');
+        }
+    }
+
+    if (air_inst) |inst| {
+        print_air.writeInst(stream, inst, mod, self.air, self.liveness);
+    }
+}
+
+fn dumpWipMir(self: *Self, air_inst: ?Air.Inst.Index) void {
+    self.printWipMir(std.io.getStdErr().writer(), air_inst) catch return;
+}
+
 fn gen(self: *Self) InnerError!void {
     const cc = self.fn_type.fnCallingConvention();
     if (cc != .Naked) {
@@ -836,6 +900,8 @@ fn gen(self: *Self) InnerError!void {
         .ops = undefined,
         .data = .{ .payload = payload },
     });
+
+    self.dumpWipMir(null);
 }
 
 fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
@@ -845,8 +911,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
         const old_air_bookkeeping = self.air_bookkeeping;
         try self.ensureProcessDeathCapacity(Liveness.bpi);
         if (builtin.mode == .Debug) {
-            try self.mir_to_air_map.put(@intCast(u32, self.mir_instructions.len), inst);
+            try self.mir_to_air_map.put(@intCast(Mir.Inst.Index, self.mir_instructions.len), inst);
         }
+        self.dumpWipMir(inst);
 
         switch (air_tags[inst]) {
             // zig fmt: off
src/arch/x86_64/encoder.zig
@@ -54,18 +54,17 @@ pub const Instruction = struct {
             };
         }
 
-        pub fn fmtPrint(op: Operand, enc_op: Encoding.Op, writer: anytype) !void {
+        pub fn fmtPrint(op: Operand, enc_op: Encoding.Op, writer: anytype) @TypeOf(writer).Error!void {
             switch (op) {
                 .none => {},
                 .reg => |reg| try writer.writeAll(@tagName(reg)),
                 .mem => |mem| switch (mem) {
                     .rip => |rip| {
                         try writer.print("{s} ptr [rip", .{@tagName(rip.ptr_size)});
-                        if (rip.disp != 0) {
-                            const sign_bit = if (sign(rip.disp) < 0) "-" else "+";
-                            const disp_abs = try std.math.absInt(rip.disp);
-                            try writer.print(" {s} 0x{x}", .{ sign_bit, disp_abs });
-                        }
+                        if (rip.disp != 0) try writer.print(" {c} 0x{x}", .{
+                            @as(u8, if (rip.disp < 0) '-' else '+'),
+                            std.math.absCast(rip.disp),
+                        });
                         try writer.writeByte(']');
                     },
                     .sib => |sib| {
@@ -77,27 +76,31 @@ pub const Instruction = struct {
 
                         try writer.writeByte('[');
 
+                        var any = false;
                         if (sib.base) |base| {
                             try writer.print("{s}", .{@tagName(base)});
+                            any = true;
                         }
                         if (sib.scale_index) |si| {
-                            if (sib.base != null) {
-                                try writer.writeAll(" + ");
-                            }
+                            if (any) try writer.writeAll(" + ");
                             try writer.print("{s} * {d}", .{ @tagName(si.index), si.scale });
+                            any = true;
                         }
-                        if (sib.disp != 0) {
-                            if (sib.base != null or sib.scale_index != null) {
-                                try writer.writeByte(' ');
-                            }
-                            try writer.writeByte(if (sign(sib.disp) < 0) '-' else '+');
-                            const disp_abs = try std.math.absInt(sib.disp);
-                            try writer.print(" 0x{x}", .{disp_abs});
+                        if (sib.disp != 0 or !any) {
+                            if (any)
+                                try writer.print(" {c} ", .{@as(u8, if (sib.disp < 0) '-' else '+')})
+                            else if (sib.disp < 0)
+                                try writer.writeByte('-');
+                            try writer.print("0x{x}", .{std.math.absCast(sib.disp)});
+                            any = true;
                         }
 
                         try writer.writeByte(']');
                     },
-                    .moffs => |moffs| try writer.print("{s}:0x{x}", .{ @tagName(moffs.seg), moffs.offset }),
+                    .moffs => |moffs| try writer.print("{s}:0x{x}", .{
+                        @tagName(moffs.seg),
+                        moffs.offset,
+                    }),
                 },
                 .imm => |imm| try writer.print("0x{x}", .{imm.asUnsigned(enc_op.bitSize())}),
             }
@@ -127,10 +130,10 @@ pub const Instruction = struct {
         return inst;
     }
 
-    pub fn fmtPrint(inst: Instruction, writer: anytype) !void {
+    pub fn fmtPrint(inst: Instruction, writer: anytype) @TypeOf(writer).Error!void {
         if (inst.prefix != .none) try writer.print("{s} ", .{@tagName(inst.prefix)});
         try writer.print("{s}", .{@tagName(inst.encoding.mnemonic)});
-        for (inst.ops, inst.encodings.ops, 0..) |op, enc, i| {
+        for (inst.ops, inst.encoding.data.ops, 0..) |op, enc, i| {
             if (op == .none) break;
             if (i > 0) try writer.writeByte(',');
             try writer.writeByte(' ');
@@ -390,10 +393,6 @@ pub const Instruction = struct {
     }
 };
 
-inline fn sign(i: anytype) @TypeOf(i) {
-    return @as(@TypeOf(i), @boolToInt(i > 0)) - @boolToInt(i < 0);
-}
-
 pub const LegacyPrefixes = packed struct {
     /// LOCK
     prefix_f0: bool = false,
src/print_air.zig
@@ -8,7 +8,7 @@ const Type = @import("type.zig").Type;
 const Air = @import("Air.zig");
 const Liveness = @import("Liveness.zig");
 
-pub fn dump(module: *Module, air: Air, liveness: Liveness) void {
+pub fn write(stream: anytype, module: *Module, 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.
@@ -23,7 +23,7 @@ pub fn dump(module: *Module, air: Air, liveness: Liveness) void {
         liveness_special_bytes + tomb_bytes;
 
     // zig fmt: off
-    std.debug.print(
+    stream.print(
         \\# Total AIR+Liveness bytes: {}
         \\# AIR Instructions:         {d} ({})
         \\# AIR Extra Data:           {d} ({})
@@ -40,65 +40,78 @@ pub fn dump(module: *Module, air: Air, liveness: Liveness) void {
         fmtIntSizeBin(tomb_bytes),
         liveness.extra.len, fmtIntSizeBin(liveness_extra_bytes),
         liveness.special.count(), fmtIntSizeBin(liveness_special_bytes),
-    });
+    }) catch return;
     // zig fmt: on
-    var arena = std.heap.ArenaAllocator.init(module.gpa);
-    defer arena.deinit();
 
     var writer: Writer = .{
         .module = module,
         .gpa = module.gpa,
-        .arena = arena.allocator(),
         .air = air,
         .liveness = liveness,
         .indent = 2,
+        .skip_body = false,
     };
-    const stream = std.io.getStdErr().writer();
     writer.writeAllConstants(stream) catch return;
     stream.writeByte('\n') catch return;
     writer.writeBody(stream, air.getMainBody()) catch return;
 }
 
+pub fn writeInst(
+    stream: anytype,
+    inst: Air.Inst.Index,
+    module: *Module,
+    air: Air,
+    liveness: Liveness,
+) void {
+    var writer: Writer = .{
+        .module = module,
+        .gpa = module.gpa,
+        .air = air,
+        .liveness = liveness,
+        .indent = 2,
+        .skip_body = true,
+    };
+    writer.writeInst(stream, inst) catch return;
+}
+
+pub fn dump(module: *Module, air: Air, liveness: Liveness) void {
+    write(std.io.getStdErr().writer(), module, air, liveness);
+}
+
+pub fn dumpInst(inst: Air.Inst.Index, module: *Module, air: Air, liveness: Liveness) void {
+    writeInst(std.io.getStdErr().writer(), inst, module, air, liveness);
+}
+
 const Writer = struct {
     module: *Module,
     gpa: Allocator,
-    arena: Allocator,
     air: Air,
     liveness: Liveness,
     indent: usize,
+    skip_body: bool,
 
     fn writeAllConstants(w: *Writer, s: anytype) @TypeOf(s).Error!void {
         for (w.air.instructions.items(.tag), 0..) |tag, i| {
-            const inst = @intCast(u32, i);
+            const inst = @intCast(Air.Inst.Index, 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");
-                },
+                .constant, .const_ty => try w.writeInst(s, inst),
                 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);
-            if (w.liveness.isUnused(inst)) {
-                try s.print("%{d}!", .{inst});
-            } else {
-                try s.print("%{d} ", .{inst});
-            }
-            try w.writeInst(s, inst);
-            try s.writeAll(")\n");
-        }
+        for (body) |inst| try w.writeInst(s, inst);
     }
 
     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])});
+        const tag = w.air.instructions.items(.tag)[inst];
+        try s.writeByteNTimes(' ', w.indent);
+        try s.print("%{d}{c}= {s}(", .{
+            inst,
+            @as(u8, if (w.liveness.isUnused(inst)) '!' else ' '),
+            @tagName(tag),
+        });
         switch (tag) {
             .add,
             .addwrap,
@@ -316,6 +329,7 @@ const Writer = struct {
 
             .dbg_block_begin, .dbg_block_end => {},
         }
+        try s.writeAll(")\n");
     }
 
     fn writeBinOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
@@ -372,6 +386,7 @@ const Writer = struct {
         const body = w.air.extra[extra.end..][0..extra.data.body_len];
 
         try w.writeType(s, w.air.getRefType(ty_pl.ty));
+        if (w.skip_body) return s.writeAll(", ...");
         try s.writeAll(", {\n");
         const old_indent = w.indent;
         w.indent += 2;
@@ -703,6 +718,7 @@ const Writer = struct {
         const body = w.air.extra[extra.end..][0..extra.data.body_len];
 
         try w.writeOperand(s, inst, 0, pl_op.operand);
+        if (w.skip_body) return s.writeAll(", ...");
         try s.writeAll(", {\n");
         const old_indent = w.indent;
         w.indent += 2;
@@ -721,6 +737,7 @@ const Writer = struct {
 
         try s.writeAll(", ");
         try w.writeType(s, w.air.getRefType(ty_pl.ty));
+        if (w.skip_body) return s.writeAll(", ...");
         try s.writeAll(", {\n");
         const old_indent = w.indent;
         w.indent += 2;
@@ -738,6 +755,7 @@ const Writer = struct {
         const liveness_condbr = w.liveness.getCondBr(inst);
 
         try w.writeOperand(s, inst, 0, pl_op.operand);
+        if (w.skip_body) return s.writeAll(", ...");
         try s.writeAll(", {\n");
         const old_indent = w.indent;
         w.indent += 2;
@@ -900,10 +918,7 @@ const Writer = struct {
         dies: bool,
     ) @TypeOf(s).Error!void {
         _ = w;
-        if (dies) {
-            try s.print("%{d}!", .{inst});
-        } else {
-            try s.print("%{d}", .{inst});
-        }
+        try s.print("%{d}", .{inst});
+        if (dies) try s.writeByte('!');
     }
 };