Skip to content

Commit da99238

Browse files
committed
x86_64: implement error return traces
1 parent 31b9881 commit da99238

File tree

2 files changed

+97
-28
lines changed

2 files changed

+97
-28
lines changed

src/arch/x86_64/CodeGen.zig

Lines changed: 96 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ const FrameIndex = bits.FrameIndex;
3333

3434
const InnerError = codegen.CodeGenError || error{OutOfRegisters};
3535

36+
const error_return_trace_index: Air.Inst.Index = @enumFromInt(std.math.maxInt(u32));
37+
3638
gpa: Allocator,
3739
pt: Zcu.PerThread,
3840
air: Air,
@@ -626,6 +628,7 @@ const InstTracking = struct {
626628
switch (self.long) {
627629
.none => self.long = try cg.allocRegOrMem(inst, false),
628630
.load_frame => {},
631+
.lea_frame => return,
629632
.reserved_frame => |index| self.long = .{ .load_frame = .{ .index = index } },
630633
else => unreachable,
631634
}
@@ -962,8 +965,16 @@ pub fn generate(
962965
} },
963966
.x86_64_win => .{ .win64 = .{} },
964967
};
968+
if (call_info.error_return_trace_reg != .none) {
969+
function.register_manager.getRegAssumeFree(call_info.error_return_trace_reg, error_return_trace_index);
970+
try function.inst_tracking.putNoClobber(
971+
gpa,
972+
error_return_trace_index,
973+
.init(.{ .register = call_info.error_return_trace_reg }),
974+
);
975+
}
965976

966-
function.gen() catch |err| switch (err) {
977+
function.gen(call_info.error_return_trace_reg) catch |err| switch (err) {
967978
error.CodegenFail => return error.CodegenFail,
968979
error.OutOfRegisters => return function.fail("ran out of registers (Zig compiler bug)", .{}),
969980
else => |e| return e,
@@ -2141,7 +2152,7 @@ fn asmMemoryRegisterImmediate(
21412152
});
21422153
}
21432154

2144-
fn gen(self: *CodeGen) InnerError!void {
2155+
fn gen(self: *CodeGen, error_return_trace_reg: Register) InnerError!void {
21452156
const pt = self.pt;
21462157
const zcu = pt.zcu;
21472158
const fn_info = zcu.typeToFunc(self.fn_type).?;
@@ -2220,6 +2231,13 @@ fn gen(self: *CodeGen) InnerError!void {
22202231
break :epilogue_relocs self.epilogue_relocs.items[0..epilogue_relocs_last_index];
22212232
} else self.epilogue_relocs.items) |epilogue_reloc| self.performReloc(epilogue_reloc);
22222233

2234+
if (error_return_trace_reg != .none) try self.genSetReg(
2235+
error_return_trace_reg,
2236+
.usize,
2237+
self.getResolvedInstValue(error_return_trace_index).short,
2238+
.{},
2239+
);
2240+
22232241
try self.asmPseudo(.pseudo_dbg_epilogue_begin_none);
22242242
const backpatch_stack_dealloc = try self.asmPlaceholder();
22252243
const backpatch_pop_callee_preserved_regs = try self.asmPlaceholder();
@@ -2503,9 +2521,6 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
25032521
.optional_payload => try cg.airOptionalPayload(inst),
25042522
.unwrap_errunion_err => try cg.airUnwrapErrUnionErr(inst),
25052523
.unwrap_errunion_payload => try cg.airUnwrapErrUnionPayload(inst),
2506-
.err_return_trace => try cg.airErrReturnTrace(inst),
2507-
.set_err_return_trace => try cg.airSetErrReturnTrace(inst),
2508-
.save_err_return_trace_index=> try cg.airSaveErrReturnTraceIndex(inst),
25092524

25102525
.wrap_optional => try cg.airWrapOptional(inst),
25112526
.wrap_errunion_payload => try cg.airWrapErrUnionPayload(inst),
@@ -11236,12 +11251,50 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
1123611251
.wasm_memory_size => unreachable,
1123711252
.wasm_memory_grow => unreachable,
1123811253

11254+
.err_return_trace => {
11255+
const res = try cg.tempAlloc(.usize);
11256+
try cg.genSetReg(
11257+
res.tracking(cg).short.register,
11258+
.usize,
11259+
cg.getResolvedInstValue(error_return_trace_index).short,
11260+
.{},
11261+
);
11262+
try res.moveTo(inst, cg);
11263+
},
11264+
.set_err_return_trace => {
11265+
const un_op = air_datas[@intFromEnum(inst)].un_op;
11266+
var ops = try cg.tempsFromOperands(inst, .{un_op});
11267+
switch (ops[0].unwrap(cg)) {
11268+
.ref => {
11269+
const result = try cg.allocRegOrMem(error_return_trace_index, true);
11270+
try cg.genCopy(.usize, result, ops[0].tracking(cg).short, .{});
11271+
tracking_log.debug("{} => {} (birth)", .{ error_return_trace_index, result });
11272+
cg.inst_tracking.putAssumeCapacityNoClobber(error_return_trace_index, .init(result));
11273+
},
11274+
.temp => |temp_index| {
11275+
const temp_tracking = temp_index.tracking(cg);
11276+
tracking_log.debug("{} => {} (birth)", .{ error_return_trace_index, temp_tracking.short });
11277+
cg.inst_tracking.putAssumeCapacityNoClobber(error_return_trace_index, temp_tracking.*);
11278+
assert(cg.reuseTemp(error_return_trace_index, temp_index.toIndex(), temp_tracking));
11279+
},
11280+
}
11281+
},
11282+
1123911283
.addrspace_cast => {
1124011284
const ty_op = air_datas[@intFromEnum(inst)].ty_op;
1124111285
var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
1124211286
try ops[0].moveTo(inst, cg);
1124311287
},
1124411288

11289+
.save_err_return_trace_index => {
11290+
const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
11291+
const agg_ty = ty_pl.ty.toType();
11292+
assert(agg_ty.containerLayout(zcu) != .@"packed");
11293+
var ert: Temp = .{ .index = error_return_trace_index };
11294+
var res = try ert.load(.usize, .{ .disp = @intCast(agg_ty.structFieldOffset(ty_pl.payload, zcu)) }, cg);
11295+
try res.moveTo(inst, cg);
11296+
},
11297+
1124511298
.vector_store_elem => return cg.fail("TODO implement vector_store_elem", .{}),
1124611299

1124711300
.c_va_arg => try cg.airVaArg(inst),
@@ -11697,7 +11750,7 @@ fn restoreState(self: *CodeGen, state: State, deaths: []const Air.Inst.Index, co
1169711750
const target_maybe_inst = if (state.free_registers.isSet(reg_index)) null else target_slot;
1169811751
if (std.debug.runtime_safety) if (target_maybe_inst) |target_inst|
1169911752
assert(self.inst_tracking.getIndex(target_inst).? < state.inst_tracking_len);
11700-
if (opts.emit_instructions) {
11753+
if (opts.emit_instructions and current_maybe_inst != target_maybe_inst) {
1170111754
if (current_maybe_inst) |current_inst|
1170211755
try self.inst_tracking.getPtr(current_inst).?.spill(self, current_inst);
1170311756
if (target_maybe_inst) |target_inst|
@@ -11709,7 +11762,7 @@ fn restoreState(self: *CodeGen, state: State, deaths: []const Air.Inst.Index, co
1170911762
self.register_manager.freeRegIndex(reg_index);
1171011763
}
1171111764
if (target_maybe_inst) |target_inst| {
11712-
self.register_manager.getRegIndexAssumeFree(reg_index, target_maybe_inst);
11765+
self.register_manager.getRegIndexAssumeFree(reg_index, target_inst);
1171311766
self.inst_tracking.getPtr(target_inst).?.trackMaterialize(target_inst, reg_tracking);
1171411767
}
1171511768
} else if (target_maybe_inst) |_|
@@ -11750,9 +11803,10 @@ pub fn spillEflagsIfOccupied(self: *CodeGen) !void {
1175011803
}
1175111804
}
1175211805

11753-
pub fn spillCallerPreservedRegs(self: *CodeGen, cc: std.builtin.CallingConvention.Tag) !void {
11806+
pub fn spillCallerPreservedRegs(self: *CodeGen, cc: std.builtin.CallingConvention.Tag, ignore_reg: Register) !void {
1175411807
switch (cc) {
11755-
inline .auto, .x86_64_sysv, .x86_64_win => |tag| try self.spillRegisters(abi.getCallerPreservedRegs(tag)),
11808+
inline .auto, .x86_64_sysv, .x86_64_win => |tag| inline for (comptime abi.getCallerPreservedRegs(tag)) |reg|
11809+
if (reg != ignore_reg) try self.register_manager.getKnownReg(reg, null),
1175611810
else => unreachable,
1175711811
}
1175811812
}
@@ -14406,22 +14460,6 @@ fn genUnwrapErrUnionPayloadPtrMir(
1440614460
return result;
1440714461
}
1440814462

14409-
fn airErrReturnTrace(self: *CodeGen, inst: Air.Inst.Index) !void {
14410-
_ = inst;
14411-
return self.fail("TODO implement airErrReturnTrace for {}", .{self.target.cpu.arch});
14412-
//return self.finishAir(inst, result, .{ .none, .none, .none });
14413-
}
14414-
14415-
fn airSetErrReturnTrace(self: *CodeGen, inst: Air.Inst.Index) !void {
14416-
_ = inst;
14417-
return self.fail("TODO implement airSetErrReturnTrace for {}", .{self.target.cpu.arch});
14418-
}
14419-
14420-
fn airSaveErrReturnTraceIndex(self: *CodeGen, inst: Air.Inst.Index) !void {
14421-
_ = inst;
14422-
return self.fail("TODO implement airSaveErrReturnTraceIndex for {}", .{self.target.cpu.arch});
14423-
}
14424-
1442514463
fn airWrapOptional(self: *CodeGen, inst: Air.Inst.Index) !void {
1442614464
const pt = self.pt;
1442714465
const zcu = pt.zcu;
@@ -21188,7 +21226,7 @@ fn genCall(self: *CodeGen, info: union(enum) {
2118821226
}
2118921227

2119021228
try self.spillEflagsIfOccupied();
21191-
try self.spillCallerPreservedRegs(fn_info.cc);
21229+
try self.spillCallerPreservedRegs(fn_info.cc, call_info.error_return_trace_reg);
2119221230

2119321231
// set stack arguments first because this can clobber registers
2119421232
// also clobber spill arguments as we go
@@ -21273,6 +21311,24 @@ fn genCall(self: *CodeGen, info: union(enum) {
2127321311
else => unreachable,
2127421312
};
2127521313

21314+
if (call_info.error_return_trace_reg != .none) {
21315+
if (self.inst_tracking.getPtr(error_return_trace_index)) |error_return_trace| {
21316+
if (switch (error_return_trace.short) {
21317+
.register => |reg| call_info.error_return_trace_reg != reg,
21318+
else => true,
21319+
}) {
21320+
try self.register_manager.getReg(call_info.error_return_trace_reg, error_return_trace_index);
21321+
try reg_locks.append(self.register_manager.lockReg(call_info.error_return_trace_reg));
21322+
21323+
try self.genSetReg(call_info.error_return_trace_reg, .usize, error_return_trace.short, .{});
21324+
error_return_trace.trackMaterialize(error_return_trace_index, .{
21325+
.long = error_return_trace.long,
21326+
.short = .{ .register = call_info.error_return_trace_reg },
21327+
});
21328+
}
21329+
}
21330+
}
21331+
2127621332
// now we are free to set register arguments
2127721333
switch (call_info.return_value.long) {
2127821334
.none, .unreach => {},
@@ -26098,8 +26154,13 @@ fn airTagName(self: *CodeGen, inst: Air.Inst.Index) !void {
2609826154
stack_frame_align.* = stack_frame_align.max(needed_call_frame.abi_align);
2609926155
}
2610026156

26157+
const error_return_trace_reg = if (zcu.comp.config.any_error_tracing) error_return_trace_reg: {
26158+
const param_gpr = abi.getCAbiIntParamRegs(.auto);
26159+
break :error_return_trace_reg param_gpr[param_gpr.len - 1];
26160+
} else .none;
26161+
2610126162
try self.spillEflagsIfOccupied();
26102-
try self.spillCallerPreservedRegs(.auto);
26163+
try self.spillCallerPreservedRegs(.auto, error_return_trace_reg);
2610326164

2610426165
const param_regs = abi.getCAbiIntParamRegs(.auto);
2610526166

@@ -28564,6 +28625,7 @@ const CallMCValues = struct {
2856428625
stack_align: InternPool.Alignment,
2856528626
gp_count: u32,
2856628627
fp_count: u32,
28628+
error_return_trace_reg: Register,
2856728629

2856828630
fn deinit(self: *CallMCValues, func: *CodeGen) void {
2856928631
func.gpa.free(self.args);
@@ -28598,6 +28660,7 @@ fn resolveCallingConventionValues(
2859828660
.stack_align = undefined,
2859928661
.gp_count = 0,
2860028662
.fp_count = 0,
28663+
.error_return_trace_reg = .none,
2860128664
};
2860228665
errdefer self.gpa.free(result.args);
2860328666

@@ -28842,6 +28905,11 @@ fn resolveCallingConventionValues(
2884228905
var param_x87 = abi.getCAbiX87ParamRegs(cc);
2884328906
var param_sse = abi.getCAbiSseParamRegs(cc, self.target);
2884428907

28908+
if (zcu.comp.config.any_error_tracing) {
28909+
result.error_return_trace_reg = param_gpr[param_gpr.len - 1];
28910+
param_gpr = param_gpr[0 .. param_gpr.len - 1];
28911+
}
28912+
2884528913
// Return values
2884628914
result.return_value = if (ret_ty.isNoReturn(zcu))
2884728915
.init(.unreach)
@@ -29159,6 +29227,7 @@ fn typeOf(self: *CodeGen, inst: Air.Inst.Ref) Type {
2915929227
}
2916029228

2916129229
fn typeOfIndex(self: *CodeGen, inst: Air.Inst.Index) Type {
29230+
if (inst == error_return_trace_index) return .usize;
2916229231
const pt = self.pt;
2916329232
const zcu = pt.zcu;
2916429233
const temp: Temp = .{ .index = inst };

src/target.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -708,7 +708,7 @@ pub inline fn backendSupportsFeature(backend: std.builtin.CompilerBackend, compt
708708
else => false,
709709
},
710710
.error_return_trace => switch (backend) {
711-
.stage2_llvm => true,
711+
.stage2_llvm, .stage2_x86_64 => true,
712712
else => false,
713713
},
714714
.is_named_enum_value => switch (backend) {

0 commit comments

Comments
 (0)