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");...@@ -8,6 +8,7 @@ const link = @import("../../link.zig");
8const log = std.log.scoped(.codegen);8const log = std.log.scoped(.codegen);
9const math = std.math;9const math = std.math;
10const mem = std.mem;10const mem = std.mem;
11const print_air = @import("../../print_air.zig");
11const trace = @import("../../tracy.zig").trace;12const trace = @import("../../tracy.zig").trace;
1213
13const Air = @import("../../Air.zig");14const Air = @import("../../Air.zig");
...@@ -20,6 +21,7 @@ const ErrorMsg = Module.ErrorMsg;...@@ -20,6 +21,7 @@ const ErrorMsg = Module.ErrorMsg;
20const Result = codegen.Result;21const Result = codegen.Result;
21const Emit = @import("Emit.zig");22const Emit = @import("Emit.zig");
22const Liveness = @import("../../Liveness.zig");23const Liveness = @import("../../Liveness.zig");
24const Lower = @import("Lower.zig");
23const Mir = @import("Mir.zig");25const Mir = @import("Mir.zig");
24const Module = @import("../../Module.zig");26const Module = @import("../../Module.zig");
25const Target = std.Target;27const Target = std.Target;
...@@ -44,6 +46,8 @@ const sse = abi.RegisterClass.sse;...@@ -44,6 +46,8 @@ const sse = abi.RegisterClass.sse;
4446
45const InnerError = CodeGenError || error{OutOfRegisters};47const InnerError = CodeGenError || error{OutOfRegisters};
4648
49const debug_wip_mir = false;
50
47gpa: Allocator,51gpa: Allocator,
48air: Air,52air: Air,
49liveness: Liveness,53liveness: Liveness,
...@@ -103,8 +107,12 @@ air_bookkeeping: @TypeOf(air_bookkeeping_init) = air_bookkeeping_init,...@@ -103,8 +107,12 @@ air_bookkeeping: @TypeOf(air_bookkeeping_init) = air_bookkeeping_init,
103/// For mir debug info, maps a mir index to a air index107/// For mir debug info, maps a mir index to a air index
104mir_to_air_map: if (builtin.mode == .Debug) std.AutoHashMap(Mir.Inst.Index, Air.Inst.Index) else void,108mir_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
106const air_bookkeeping_init = if (std.debug.runtime_safety) @as(usize, 0) else {};112const 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
108pub const MCValue = union(enum) {116pub const MCValue = union(enum) {
109 /// No runtime bits. `void` types, empty structs, u0, enums with 1 tag, etc.117 /// No runtime bits. `void` types, empty structs, u0, enums with 1 tag, etc.
110 /// TODO Look into deleting this tag and using `dead` instead, since every use118 /// TODO Look into deleting this tag and using `dead` instead, since every use
...@@ -267,6 +275,12 @@ pub fn generate(...@@ -267,6 +275,12 @@ pub fn generate(
267 assert(fn_owner_decl.has_tv);275 assert(fn_owner_decl.has_tv);
268 const fn_type = fn_owner_decl.ty;276 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
270 var branch_stack = std.ArrayList(Branch).init(bin_file.allocator);284 var branch_stack = std.ArrayList(Branch).init(bin_file.allocator);
271 try branch_stack.ensureUnusedCapacity(2);285 try branch_stack.ensureUnusedCapacity(2);
272 // The outermost branch is used for constants only.286 // The outermost branch is used for constants only.
...@@ -683,6 +697,56 @@ fn asmMemoryRegisterImmediate(...@@ -683,6 +697,56 @@ fn asmMemoryRegisterImmediate(
683 });697 });
684}698}
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
686fn gen(self: *Self) InnerError!void {750fn gen(self: *Self) InnerError!void {
687 const cc = self.fn_type.fnCallingConvention();751 const cc = self.fn_type.fnCallingConvention();
688 if (cc != .Naked) {752 if (cc != .Naked) {
...@@ -836,6 +900,8 @@ fn gen(self: *Self) InnerError!void {...@@ -836,6 +900,8 @@ fn gen(self: *Self) InnerError!void {
836 .ops = undefined,900 .ops = undefined,
837 .data = .{ .payload = payload },901 .data = .{ .payload = payload },
838 });902 });
903
904 self.dumpWipMir(null);
839}905}
840906
841fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {907fn 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 {...@@ -845,8 +911,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
845 const old_air_bookkeeping = self.air_bookkeeping;911 const old_air_bookkeeping = self.air_bookkeeping;
846 try self.ensureProcessDeathCapacity(Liveness.bpi);912 try self.ensureProcessDeathCapacity(Liveness.bpi);
847 if (builtin.mode == .Debug) {913 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);
849 }915 }
916 self.dumpWipMir(inst);
850917
851 switch (air_tags[inst]) {918 switch (air_tags[inst]) {
852 // zig fmt: off919 // zig fmt: off
src/arch/x86_64/encoder.zig+22-23
...@@ -54,18 +54,17 @@ pub const Instruction = struct {...@@ -54,18 +54,17 @@ pub const Instruction = struct {
54 };54 };
55 }55 }
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 {
58 switch (op) {58 switch (op) {
59 .none => {},59 .none => {},
60 .reg => |reg| try writer.writeAll(@tagName(reg)),60 .reg => |reg| try writer.writeAll(@tagName(reg)),
61 .mem => |mem| switch (mem) {61 .mem => |mem| switch (mem) {
62 .rip => |rip| {62 .rip => |rip| {
63 try writer.print("{s} ptr [rip", .{@tagName(rip.ptr_size)});63 try writer.print("{s} ptr [rip", .{@tagName(rip.ptr_size)});
64 if (rip.disp != 0) {64 if (rip.disp != 0) try writer.print(" {c} 0x{x}", .{
65 const sign_bit = if (sign(rip.disp) < 0) "-" else "+";65 @as(u8, if (rip.disp < 0) '-' else '+'),
66 const disp_abs = try std.math.absInt(rip.disp);66 std.math.absCast(rip.disp),
67 try writer.print(" {s} 0x{x}", .{ sign_bit, disp_abs });67 });
68 }
69 try writer.writeByte(']');68 try writer.writeByte(']');
70 },69 },
71 .sib => |sib| {70 .sib => |sib| {
...@@ -77,27 +76,31 @@ pub const Instruction = struct {...@@ -77,27 +76,31 @@ pub const Instruction = struct {
7776
78 try writer.writeByte('[');77 try writer.writeByte('[');
7978
79 var any = false;
80 if (sib.base) |base| {80 if (sib.base) |base| {
81 try writer.print("{s}", .{@tagName(base)});81 try writer.print("{s}", .{@tagName(base)});
82 any = true;
82 }83 }
83 if (sib.scale_index) |si| {84 if (sib.scale_index) |si| {
84 if (sib.base != null) {85 if (any) try writer.writeAll(" + ");
85 try writer.writeAll(" + ");
86 }
87 try writer.print("{s} * {d}", .{ @tagName(si.index), si.scale });86 try writer.print("{s} * {d}", .{ @tagName(si.index), si.scale });
87 any = true;
88 }88 }
89 if (sib.disp != 0) {89 if (sib.disp != 0 or !any) {
90 if (sib.base != null or sib.scale_index != null) {90 if (any)
91 try writer.writeByte(' ');91 try writer.print(" {c} ", .{@as(u8, if (sib.disp < 0) '-' else '+')})
92 }92 else if (sib.disp < 0)
93 try writer.writeByte(if (sign(sib.disp) < 0) '-' else '+');93 try writer.writeByte('-');
94 const disp_abs = try std.math.absInt(sib.disp);94 try writer.print("0x{x}", .{std.math.absCast(sib.disp)});
95 try writer.print(" 0x{x}", .{disp_abs});95 any = true;
96 }96 }
9797
98 try writer.writeByte(']');98 try writer.writeByte(']');
99 },99 },
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 }),
101 },104 },
102 .imm => |imm| try writer.print("0x{x}", .{imm.asUnsigned(enc_op.bitSize())}),105 .imm => |imm| try writer.print("0x{x}", .{imm.asUnsigned(enc_op.bitSize())}),
103 }106 }
...@@ -127,10 +130,10 @@ pub const Instruction = struct {...@@ -127,10 +130,10 @@ pub const Instruction = struct {
127 return inst;130 return inst;
128 }131 }
129132
130 pub fn fmtPrint(inst: Instruction, writer: anytype) !void {133 pub fn fmtPrint(inst: Instruction, writer: anytype) @TypeOf(writer).Error!void {
131 if (inst.prefix != .none) try writer.print("{s} ", .{@tagName(inst.prefix)});134 if (inst.prefix != .none) try writer.print("{s} ", .{@tagName(inst.prefix)});
132 try writer.print("{s}", .{@tagName(inst.encoding.mnemonic)});135 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| {
134 if (op == .none) break;137 if (op == .none) break;
135 if (i > 0) try writer.writeByte(',');138 if (i > 0) try writer.writeByte(',');
136 try writer.writeByte(' ');139 try writer.writeByte(' ');
...@@ -390,10 +393,6 @@ pub const Instruction = struct {...@@ -390,10 +393,6 @@ pub const Instruction = struct {
390 }393 }
391};394};
392395
393inline fn sign(i: anytype) @TypeOf(i) {
394 return @as(@TypeOf(i), @boolToInt(i > 0)) - @boolToInt(i < 0);
395}
396
397pub const LegacyPrefixes = packed struct {396pub const LegacyPrefixes = packed struct {
398 /// LOCK397 /// LOCK
399 prefix_f0: bool = false,398 prefix_f0: bool = false,
src/print_air.zig+48-33
...@@ -8,7 +8,7 @@ const Type = @import("type.zig").Type;...@@ -8,7 +8,7 @@ const Type = @import("type.zig").Type;
8const Air = @import("Air.zig");8const Air = @import("Air.zig");
9const Liveness = @import("Liveness.zig");9const 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 {
12 const instruction_bytes = air.instructions.len *12 const instruction_bytes = air.instructions.len *
13 // Here we don't use @sizeOf(Air.Inst.Data) because it would include13 // Here we don't use @sizeOf(Air.Inst.Data) because it would include
14 // the debug safety tag but we want to measure release size.14 // 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 {...@@ -23,7 +23,7 @@ pub fn dump(module: *Module, air: Air, liveness: Liveness) void {
23 liveness_special_bytes + tomb_bytes;23 liveness_special_bytes + tomb_bytes;
2424
25 // zig fmt: off25 // zig fmt: off
26 std.debug.print(26 stream.print(
27 \\# Total AIR+Liveness bytes: {}27 \\# Total AIR+Liveness bytes: {}
28 \\# AIR Instructions: {d} ({})28 \\# AIR Instructions: {d} ({})
29 \\# AIR Extra Data: {d} ({})29 \\# AIR Extra Data: {d} ({})
...@@ -40,65 +40,78 @@ pub fn dump(module: *Module, air: Air, liveness: Liveness) void {...@@ -40,65 +40,78 @@ pub fn dump(module: *Module, air: Air, liveness: Liveness) void {
40 fmtIntSizeBin(tomb_bytes),40 fmtIntSizeBin(tomb_bytes),
41 liveness.extra.len, fmtIntSizeBin(liveness_extra_bytes),41 liveness.extra.len, fmtIntSizeBin(liveness_extra_bytes),
42 liveness.special.count(), fmtIntSizeBin(liveness_special_bytes),42 liveness.special.count(), fmtIntSizeBin(liveness_special_bytes),
43 });43 }) catch return;
44 // zig fmt: on44 // zig fmt: on
45 var arena = std.heap.ArenaAllocator.init(module.gpa);
46 defer arena.deinit();
4745
48 var writer: Writer = .{46 var writer: Writer = .{
49 .module = module,47 .module = module,
50 .gpa = module.gpa,48 .gpa = module.gpa,
51 .arena = arena.allocator(),
52 .air = air,49 .air = air,
53 .liveness = liveness,50 .liveness = liveness,
54 .indent = 2,51 .indent = 2,
52 .skip_body = false,
55 };53 };
56 const stream = std.io.getStdErr().writer();
57 writer.writeAllConstants(stream) catch return;54 writer.writeAllConstants(stream) catch return;
58 stream.writeByte('\n') catch return;55 stream.writeByte('\n') catch return;
59 writer.writeBody(stream, air.getMainBody()) catch return;56 writer.writeBody(stream, air.getMainBody()) catch return;
60}57}
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
62const Writer = struct {85const Writer = struct {
63 module: *Module,86 module: *Module,
64 gpa: Allocator,87 gpa: Allocator,
65 arena: Allocator,
66 air: Air,88 air: Air,
67 liveness: Liveness,89 liveness: Liveness,
68 indent: usize,90 indent: usize,
91 skip_body: bool,
6992
70 fn writeAllConstants(w: *Writer, s: anytype) @TypeOf(s).Error!void {93 fn writeAllConstants(w: *Writer, s: anytype) @TypeOf(s).Error!void {
71 for (w.air.instructions.items(.tag), 0..) |tag, i| {94 for (w.air.instructions.items(.tag), 0..) |tag, i| {
72 const inst = @intCast(u32, i);95 const inst = @intCast(Air.Inst.Index, i);
73 switch (tag) {96 switch (tag) {
74 .constant, .const_ty => {97 .constant, .const_ty => try w.writeInst(s, inst),
75 try s.writeByteNTimes(' ', w.indent);
76 try s.print("%{d} ", .{inst});
77 try w.writeInst(s, inst);
78 try s.writeAll(")\n");
79 },
80 else => continue,98 else => continue,
81 }99 }
82 }100 }
83 }101 }
84102
85 fn writeBody(w: *Writer, s: anytype, body: []const Air.Inst.Index) @TypeOf(s).Error!void {103 fn writeBody(w: *Writer, s: anytype, body: []const Air.Inst.Index) @TypeOf(s).Error!void {
86 for (body) |inst| {104 for (body) |inst| try w.writeInst(s, 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 }
96 }105 }
97106
98 fn writeInst(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {107 fn writeInst(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
99 const tags = w.air.instructions.items(.tag);108 const tag = w.air.instructions.items(.tag)[inst];
100 const tag = tags[inst];109 try s.writeByteNTimes(' ', w.indent);
101 try s.print("= {s}(", .{@tagName(tags[inst])});110 try s.print("%{d}{c}= {s}(", .{
111 inst,
112 @as(u8, if (w.liveness.isUnused(inst)) '!' else ' '),
113 @tagName(tag),
114 });
102 switch (tag) {115 switch (tag) {
103 .add,116 .add,
104 .addwrap,117 .addwrap,
...@@ -316,6 +329,7 @@ const Writer = struct {...@@ -316,6 +329,7 @@ const Writer = struct {
316329
317 .dbg_block_begin, .dbg_block_end => {},330 .dbg_block_begin, .dbg_block_end => {},
318 }331 }
332 try s.writeAll(")\n");
319 }333 }
320334
321 fn writeBinOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {335 fn writeBinOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
...@@ -372,6 +386,7 @@ const Writer = struct {...@@ -372,6 +386,7 @@ const Writer = struct {
372 const body = w.air.extra[extra.end..][0..extra.data.body_len];386 const body = w.air.extra[extra.end..][0..extra.data.body_len];
373387
374 try w.writeType(s, w.air.getRefType(ty_pl.ty));388 try w.writeType(s, w.air.getRefType(ty_pl.ty));
389 if (w.skip_body) return s.writeAll(", ...");
375 try s.writeAll(", {\n");390 try s.writeAll(", {\n");
376 const old_indent = w.indent;391 const old_indent = w.indent;
377 w.indent += 2;392 w.indent += 2;
...@@ -703,6 +718,7 @@ const Writer = struct {...@@ -703,6 +718,7 @@ const Writer = struct {
703 const body = w.air.extra[extra.end..][0..extra.data.body_len];718 const body = w.air.extra[extra.end..][0..extra.data.body_len];
704719
705 try w.writeOperand(s, inst, 0, pl_op.operand);720 try w.writeOperand(s, inst, 0, pl_op.operand);
721 if (w.skip_body) return s.writeAll(", ...");
706 try s.writeAll(", {\n");722 try s.writeAll(", {\n");
707 const old_indent = w.indent;723 const old_indent = w.indent;
708 w.indent += 2;724 w.indent += 2;
...@@ -721,6 +737,7 @@ const Writer = struct {...@@ -721,6 +737,7 @@ const Writer = struct {
721737
722 try s.writeAll(", ");738 try s.writeAll(", ");
723 try w.writeType(s, w.air.getRefType(ty_pl.ty));739 try w.writeType(s, w.air.getRefType(ty_pl.ty));
740 if (w.skip_body) return s.writeAll(", ...");
724 try s.writeAll(", {\n");741 try s.writeAll(", {\n");
725 const old_indent = w.indent;742 const old_indent = w.indent;
726 w.indent += 2;743 w.indent += 2;
...@@ -738,6 +755,7 @@ const Writer = struct {...@@ -738,6 +755,7 @@ const Writer = struct {
738 const liveness_condbr = w.liveness.getCondBr(inst);755 const liveness_condbr = w.liveness.getCondBr(inst);
739756
740 try w.writeOperand(s, inst, 0, pl_op.operand);757 try w.writeOperand(s, inst, 0, pl_op.operand);
758 if (w.skip_body) return s.writeAll(", ...");
741 try s.writeAll(", {\n");759 try s.writeAll(", {\n");
742 const old_indent = w.indent;760 const old_indent = w.indent;
743 w.indent += 2;761 w.indent += 2;
...@@ -900,10 +918,7 @@ const Writer = struct {...@@ -900,10 +918,7 @@ const Writer = struct {
900 dies: bool,918 dies: bool,
901 ) @TypeOf(s).Error!void {919 ) @TypeOf(s).Error!void {
902 _ = w;920 _ = w;
903 if (dies) {921 try s.print("%{d}", .{inst});
904 try s.print("%{d}!", .{inst});922 if (dies) try s.writeByte('!');
905 } else {
906 try s.print("%{d}", .{inst});
907 }
908 }923 }
909};924};