mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 04:48:20 +00:00
x86_64: add live codegen debug
This commit is contained in:
parent
abb37a7cb8
commit
3a516433b0
@ -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
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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('!');
|
||||
}
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user