Commit 3a516433b0
Changed files (3)
src
arch
x86_64
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('!');
}
};