authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-03-27 03:10:03-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-03-27 05:58:00-04:00
log3a516433b0cf94e8aa67819acc49c03e0b72f296
tree38987d39742575658f31fe9b1b2fee4c355350df
parentabb37a7cb8d4bfae2da6d2cb9e9e6305ef6e52c4

x86_64: add live codegen debug


3 files changed, 138 insertions(+), 57 deletions(-)

src/arch/x86_64/CodeGen.zig+68-1
......@@ -8,6 +8,7 @@ const link = @import("../../link.zig");
88const log = std.log.scoped(.codegen);
99const math = std.math;
1010const mem = std.mem;
11const print_air = @import("../../print_air.zig");
1112const trace = @import("../../tracy.zig").trace;
1213
1314const Air = @import("../../Air.zig");
......@@ -20,6 +21,7 @@ const ErrorMsg = Module.ErrorMsg;
2021const Result = codegen.Result;
2122const Emit = @import("Emit.zig");
2223const Liveness = @import("../../Liveness.zig");
24const Lower = @import("Lower.zig");
2325const Mir = @import("Mir.zig");
2426const Module = @import("../../Module.zig");
2527const Target = std.Target;
......@@ -44,6 +46,8 @@ const sse = abi.RegisterClass.sse;
4446
4547const InnerError = CodeGenError || error{OutOfRegisters};
4648
49const debug_wip_mir = false;
50
4751gpa: Allocator,
4852air: Air,
4953liveness: Liveness,
......@@ -103,8 +107,12 @@ air_bookkeeping: @TypeOf(air_bookkeeping_init) = air_bookkeeping_init,
103107/// For mir debug info, maps a mir index to a air index
104108mir_to_air_map: if (builtin.mode == .Debug) std.AutoHashMap(Mir.Inst.Index, Air.Inst.Index) else void,
105109
110debug_wip_mir_inst: @TypeOf(debug_wip_mir_inst_init) = debug_wip_mir_inst_init,
111
106112const air_bookkeeping_init = if (std.debug.runtime_safety) @as(usize, 0) else {};
107113
114const debug_wip_mir_inst_init = if (debug_wip_mir) @as(Mir.Inst.Index, 0) else {};
115
108116pub const MCValue = union(enum) {
109117 /// No runtime bits. `void` types, empty structs, u0, enums with 1 tag, etc.
110118 /// TODO Look into deleting this tag and using `dead` instead, since every use
......@@ -267,6 +275,12 @@ pub fn generate(
267275 assert(fn_owner_decl.has_tv);
268276 const fn_type = fn_owner_decl.ty;
269277
278 if (debug_wip_mir) {
279 const stderr = std.io.getStdErr().writer();
280 fn_owner_decl.renderFullyQualifiedName(mod, stderr) catch {};
281 stderr.writeAll(":\n") catch {};
282 }
283
270284 var branch_stack = std.ArrayList(Branch).init(bin_file.allocator);
271285 try branch_stack.ensureUnusedCapacity(2);
272286 // The outermost branch is used for constants only.
......@@ -683,6 +697,56 @@ fn asmMemoryRegisterImmediate(
683697 });
684698}
685699
700fn printWipMir(self: *Self, stream: anytype, air_inst: ?Air.Inst.Index) !void {
701 const mod = self.bin_file.options.module.?;
702 if (!debug_wip_mir) return;
703
704 var lower = Lower{
705 .allocator = self.gpa,
706 .mir = .{
707 .instructions = self.mir_instructions.slice(),
708 .extra = self.mir_extra.items,
709 },
710 .target = self.target,
711 .src_loc = self.src_loc,
712 };
713 var mir_inst = self.debug_wip_mir_inst;
714 var mir_end = @intCast(Mir.Inst.Index, self.mir_instructions.len);
715 defer self.debug_wip_mir_inst = mir_end;
716 while (mir_inst < mir_end) : (mir_inst += 1) {
717 for (lower.lowerMir(lower.mir.instructions.get(mir_inst)) catch |err| switch (err) {
718 error.LowerFail => {
719 defer {
720 lower.err_msg.?.deinit(self.gpa);
721 lower.err_msg = null;
722 }
723 try stream.print("{s}\n", .{lower.err_msg.?.msg});
724 continue;
725 },
726 error.InvalidInstruction, error.CannotEncode => |e| {
727 try stream.writeAll(switch (e) {
728 error.InvalidInstruction => "CodeGen failed to find a viable instruction.\n",
729 error.CannotEncode => "CodeGen failed to encode the instruction.\n",
730 });
731 continue;
732 },
733 else => |e| return e,
734 }) |lower_inst| {
735 try stream.writeAll(" | ");
736 try lower_inst.fmtPrint(stream);
737 try stream.writeByte('\n');
738 }
739 }
740
741 if (air_inst) |inst| {
742 print_air.writeInst(stream, inst, mod, self.air, self.liveness);
743 }
744}
745
746fn dumpWipMir(self: *Self, air_inst: ?Air.Inst.Index) void {
747 self.printWipMir(std.io.getStdErr().writer(), air_inst) catch return;
748}
749
686750fn gen(self: *Self) InnerError!void {
687751 const cc = self.fn_type.fnCallingConvention();
688752 if (cc != .Naked) {
......@@ -836,6 +900,8 @@ fn gen(self: *Self) InnerError!void {
836900 .ops = undefined,
837901 .data = .{ .payload = payload },
838902 });
903
904 self.dumpWipMir(null);
839905}
840906
841907fn 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 {
845911 const old_air_bookkeeping = self.air_bookkeeping;
846912 try self.ensureProcessDeathCapacity(Liveness.bpi);
847913 if (builtin.mode == .Debug) {
848 try self.mir_to_air_map.put(@intCast(u32, self.mir_instructions.len), inst);
914 try self.mir_to_air_map.put(@intCast(Mir.Inst.Index, self.mir_instructions.len), inst);
849915 }
916 self.dumpWipMir(inst);
850917
851918 switch (air_tags[inst]) {
852919 // zig fmt: off
src/arch/x86_64/encoder.zig+22-23
......@@ -54,18 +54,17 @@ pub const Instruction = struct {
5454 };
5555 }
5656
57 pub fn fmtPrint(op: Operand, enc_op: Encoding.Op, writer: anytype) !void {
57 pub fn fmtPrint(op: Operand, enc_op: Encoding.Op, writer: anytype) @TypeOf(writer).Error!void {
5858 switch (op) {
5959 .none => {},
6060 .reg => |reg| try writer.writeAll(@tagName(reg)),
6161 .mem => |mem| switch (mem) {
6262 .rip => |rip| {
6363 try writer.print("{s} ptr [rip", .{@tagName(rip.ptr_size)});
64 if (rip.disp != 0) {
65 const sign_bit = if (sign(rip.disp) < 0) "-" else "+";
66 const disp_abs = try std.math.absInt(rip.disp);
67 try writer.print(" {s} 0x{x}", .{ sign_bit, disp_abs });
68 }
64 if (rip.disp != 0) try writer.print(" {c} 0x{x}", .{
65 @as(u8, if (rip.disp < 0) '-' else '+'),
66 std.math.absCast(rip.disp),
67 });
6968 try writer.writeByte(']');
7069 },
7170 .sib => |sib| {
......@@ -77,27 +76,31 @@ pub const Instruction = struct {
7776
7877 try writer.writeByte('[');
7978
79 var any = false;
8080 if (sib.base) |base| {
8181 try writer.print("{s}", .{@tagName(base)});
82 any = true;
8283 }
8384 if (sib.scale_index) |si| {
84 if (sib.base != null) {
85 try writer.writeAll(" + ");
86 }
85 if (any) try writer.writeAll(" + ");
8786 try writer.print("{s} * {d}", .{ @tagName(si.index), si.scale });
87 any = true;
8888 }
89 if (sib.disp != 0) {
90 if (sib.base != null or sib.scale_index != null) {
91 try writer.writeByte(' ');
92 }
93 try writer.writeByte(if (sign(sib.disp) < 0) '-' else '+');
94 const disp_abs = try std.math.absInt(sib.disp);
95 try writer.print(" 0x{x}", .{disp_abs});
89 if (sib.disp != 0 or !any) {
90 if (any)
91 try writer.print(" {c} ", .{@as(u8, if (sib.disp < 0) '-' else '+')})
92 else if (sib.disp < 0)
93 try writer.writeByte('-');
94 try writer.print("0x{x}", .{std.math.absCast(sib.disp)});
95 any = true;
9696 }
9797
9898 try writer.writeByte(']');
9999 },
100 .moffs => |moffs| try writer.print("{s}:0x{x}", .{ @tagName(moffs.seg), moffs.offset }),
100 .moffs => |moffs| try writer.print("{s}:0x{x}", .{
101 @tagName(moffs.seg),
102 moffs.offset,
103 }),
101104 },
102105 .imm => |imm| try writer.print("0x{x}", .{imm.asUnsigned(enc_op.bitSize())}),
103106 }
......@@ -127,10 +130,10 @@ pub const Instruction = struct {
127130 return inst;
128131 }
129132
130 pub fn fmtPrint(inst: Instruction, writer: anytype) !void {
133 pub fn fmtPrint(inst: Instruction, writer: anytype) @TypeOf(writer).Error!void {
131134 if (inst.prefix != .none) try writer.print("{s} ", .{@tagName(inst.prefix)});
132135 try writer.print("{s}", .{@tagName(inst.encoding.mnemonic)});
133 for (inst.ops, inst.encodings.ops, 0..) |op, enc, i| {
136 for (inst.ops, inst.encoding.data.ops, 0..) |op, enc, i| {
134137 if (op == .none) break;
135138 if (i > 0) try writer.writeByte(',');
136139 try writer.writeByte(' ');
......@@ -390,10 +393,6 @@ pub const Instruction = struct {
390393 }
391394};
392395
393inline fn sign(i: anytype) @TypeOf(i) {
394 return @as(@TypeOf(i), @boolToInt(i > 0)) - @boolToInt(i < 0);
395}
396
397396pub const LegacyPrefixes = packed struct {
398397 /// LOCK
399398 prefix_f0: bool = false,
src/print_air.zig+48-33
......@@ -8,7 +8,7 @@ const Type = @import("type.zig").Type;
88const Air = @import("Air.zig");
99const Liveness = @import("Liveness.zig");
1010
11pub fn dump(module: *Module, air: Air, liveness: Liveness) void {
11pub fn write(stream: anytype, module: *Module, air: Air, liveness: Liveness) void {
1212 const instruction_bytes = air.instructions.len *
1313 // Here we don't use @sizeOf(Air.Inst.Data) because it would include
1414 // 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 {
2323 liveness_special_bytes + tomb_bytes;
2424
2525 // zig fmt: off
26 std.debug.print(
26 stream.print(
2727 \\# Total AIR+Liveness bytes: {}
2828 \\# AIR Instructions: {d} ({})
2929 \\# AIR Extra Data: {d} ({})
......@@ -40,65 +40,78 @@ pub fn dump(module: *Module, air: Air, liveness: Liveness) void {
4040 fmtIntSizeBin(tomb_bytes),
4141 liveness.extra.len, fmtIntSizeBin(liveness_extra_bytes),
4242 liveness.special.count(), fmtIntSizeBin(liveness_special_bytes),
43 });
43 }) catch return;
4444 // zig fmt: on
45 var arena = std.heap.ArenaAllocator.init(module.gpa);
46 defer arena.deinit();
4745
4846 var writer: Writer = .{
4947 .module = module,
5048 .gpa = module.gpa,
51 .arena = arena.allocator(),
5249 .air = air,
5350 .liveness = liveness,
5451 .indent = 2,
52 .skip_body = false,
5553 };
56 const stream = std.io.getStdErr().writer();
5754 writer.writeAllConstants(stream) catch return;
5855 stream.writeByte('\n') catch return;
5956 writer.writeBody(stream, air.getMainBody()) catch return;
6057}
6158
59pub fn writeInst(
60 stream: anytype,
61 inst: Air.Inst.Index,
62 module: *Module,
63 air: Air,
64 liveness: Liveness,
65) void {
66 var writer: Writer = .{
67 .module = module,
68 .gpa = module.gpa,
69 .air = air,
70 .liveness = liveness,
71 .indent = 2,
72 .skip_body = true,
73 };
74 writer.writeInst(stream, inst) catch return;
75}
76
77pub fn dump(module: *Module, air: Air, liveness: Liveness) void {
78 write(std.io.getStdErr().writer(), module, air, liveness);
79}
80
81pub fn dumpInst(inst: Air.Inst.Index, module: *Module, air: Air, liveness: Liveness) void {
82 writeInst(std.io.getStdErr().writer(), inst, module, air, liveness);
83}
84
6285const Writer = struct {
6386 module: *Module,
6487 gpa: Allocator,
65 arena: Allocator,
6688 air: Air,
6789 liveness: Liveness,
6890 indent: usize,
91 skip_body: bool,
6992
7093 fn writeAllConstants(w: *Writer, s: anytype) @TypeOf(s).Error!void {
7194 for (w.air.instructions.items(.tag), 0..) |tag, i| {
72 const inst = @intCast(u32, i);
95 const inst = @intCast(Air.Inst.Index, i);
7396 switch (tag) {
74 .constant, .const_ty => {
75 try s.writeByteNTimes(' ', w.indent);
76 try s.print("%{d} ", .{inst});
77 try w.writeInst(s, inst);
78 try s.writeAll(")\n");
79 },
97 .constant, .const_ty => try w.writeInst(s, inst),
8098 else => continue,
8199 }
82100 }
83101 }
84102
85103 fn writeBody(w: *Writer, s: anytype, body: []const Air.Inst.Index) @TypeOf(s).Error!void {
86 for (body) |inst| {
87 try s.writeByteNTimes(' ', w.indent);
88 if (w.liveness.isUnused(inst)) {
89 try s.print("%{d}!", .{inst});
90 } else {
91 try s.print("%{d} ", .{inst});
92 }
93 try w.writeInst(s, inst);
94 try s.writeAll(")\n");
95 }
104 for (body) |inst| try w.writeInst(s, inst);
96105 }
97106
98107 fn writeInst(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
99 const tags = w.air.instructions.items(.tag);
100 const tag = tags[inst];
101 try s.print("= {s}(", .{@tagName(tags[inst])});
108 const tag = w.air.instructions.items(.tag)[inst];
109 try s.writeByteNTimes(' ', w.indent);
110 try s.print("%{d}{c}= {s}(", .{
111 inst,
112 @as(u8, if (w.liveness.isUnused(inst)) '!' else ' '),
113 @tagName(tag),
114 });
102115 switch (tag) {
103116 .add,
104117 .addwrap,
......@@ -316,6 +329,7 @@ const Writer = struct {
316329
317330 .dbg_block_begin, .dbg_block_end => {},
318331 }
332 try s.writeAll(")\n");
319333 }
320334
321335 fn writeBinOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
......@@ -372,6 +386,7 @@ const Writer = struct {
372386 const body = w.air.extra[extra.end..][0..extra.data.body_len];
373387
374388 try w.writeType(s, w.air.getRefType(ty_pl.ty));
389 if (w.skip_body) return s.writeAll(", ...");
375390 try s.writeAll(", {\n");
376391 const old_indent = w.indent;
377392 w.indent += 2;
......@@ -703,6 +718,7 @@ const Writer = struct {
703718 const body = w.air.extra[extra.end..][0..extra.data.body_len];
704719
705720 try w.writeOperand(s, inst, 0, pl_op.operand);
721 if (w.skip_body) return s.writeAll(", ...");
706722 try s.writeAll(", {\n");
707723 const old_indent = w.indent;
708724 w.indent += 2;
......@@ -721,6 +737,7 @@ const Writer = struct {
721737
722738 try s.writeAll(", ");
723739 try w.writeType(s, w.air.getRefType(ty_pl.ty));
740 if (w.skip_body) return s.writeAll(", ...");
724741 try s.writeAll(", {\n");
725742 const old_indent = w.indent;
726743 w.indent += 2;
......@@ -738,6 +755,7 @@ const Writer = struct {
738755 const liveness_condbr = w.liveness.getCondBr(inst);
739756
740757 try w.writeOperand(s, inst, 0, pl_op.operand);
758 if (w.skip_body) return s.writeAll(", ...");
741759 try s.writeAll(", {\n");
742760 const old_indent = w.indent;
743761 w.indent += 2;
......@@ -900,10 +918,7 @@ const Writer = struct {
900918 dies: bool,
901919 ) @TypeOf(s).Error!void {
902920 _ = w;
903 if (dies) {
904 try s.print("%{d}!", .{inst});
905 } else {
906 try s.print("%{d}", .{inst});
907 }
921 try s.print("%{d}", .{inst});
922 if (dies) try s.writeByte('!');
908923 }
909924};