aboutsummaryrefslogtreecommitdiff
path: root/src/codegen
diff options
context:
space:
mode:
Diffstat (limited to 'src/codegen')
-rw-r--r--src/codegen/c.zig12
-rw-r--r--src/codegen/llvm.zig84
2 files changed, 94 insertions, 2 deletions
diff --git a/src/codegen/c.zig b/src/codegen/c.zig
index 998271cd7f..92770168f4 100644
--- a/src/codegen/c.zig
+++ b/src/codegen/c.zig
@@ -1911,6 +1911,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
.wrap_errunion_payload => try airWrapErrUnionPay(f, inst),
.wrap_errunion_err => try airWrapErrUnionErr(f, inst),
.errunion_payload_ptr_set => try airErrUnionPayloadPtrSet(f, inst),
+ .err_return_trace => try airErrReturnTrace(f, inst),
+ .set_err_return_trace => try airSetErrReturnTrace(f, inst),
.wasm_memory_size => try airWasmMemorySize(f, inst),
.wasm_memory_grow => try airWasmMemoryGrow(f, inst),
@@ -3447,6 +3449,16 @@ fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
return local;
}
+fn airErrReturnTrace(f: *Function, inst: Air.Inst.Index) !CValue {
+ if (f.liveness.isUnused(inst)) return CValue.none;
+ return f.fail("TODO: C backend: implement airErrReturnTrace", .{});
+}
+
+fn airSetErrReturnTrace(f: *Function, inst: Air.Inst.Index) !CValue {
+ _ = inst;
+ return f.fail("TODO: C backend: implement airSetErrReturnTrace", .{});
+}
+
fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {
if (f.liveness.isUnused(inst))
return CValue.none;
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig
index 7392b2068b..dfb0f8f03b 100644
--- a/src/codegen/llvm.zig
+++ b/src/codegen/llvm.zig
@@ -636,10 +636,18 @@ pub const Object = struct {
const ret_ptr = if (sret) llvm_func.getParam(0) else null;
const gpa = dg.gpa;
+ const err_return_tracing = fn_info.return_type.isError() and
+ dg.module.comp.bin_file.options.error_return_tracing;
+
+ const err_ret_trace = if (err_return_tracing)
+ llvm_func.getParam(@boolToInt(ret_ptr != null))
+ else
+ null;
+
var args = std.ArrayList(*const llvm.Value).init(gpa);
defer args.deinit();
- const param_offset: c_uint = @boolToInt(ret_ptr != null);
+ const param_offset = @as(c_uint, @boolToInt(ret_ptr != null)) + @boolToInt(err_return_tracing);
for (fn_info.param_types) |param_ty| {
if (!param_ty.hasRuntimeBitsIgnoreComptime()) continue;
@@ -711,6 +719,7 @@ pub const Object = struct {
.base_line = dg.decl.src_line,
.prev_dbg_line = 0,
.prev_dbg_column = 0,
+ .err_ret_trace = err_ret_trace,
};
defer fg.deinit();
@@ -1755,6 +1764,17 @@ pub const Object = struct {
try param_di_types.append(try o.lowerDebugType(Type.void, .full));
}
+ if (fn_info.return_type.isError() and
+ o.module.comp.bin_file.options.error_return_tracing)
+ {
+ var ptr_ty_payload: Type.Payload.ElemType = .{
+ .base = .{ .tag = .single_mut_pointer },
+ .data = o.getStackTraceType(),
+ };
+ const ptr_ty = Type.initPayload(&ptr_ty_payload.base);
+ try param_di_types.append(try o.lowerDebugType(ptr_ty, .full));
+ }
+
for (fn_info.param_types) |param_ty| {
if (!param_ty.hasRuntimeBitsIgnoreComptime()) continue;
@@ -1824,6 +1844,27 @@ pub const Object = struct {
"", // unique id
);
}
+
+ fn getStackTraceType(o: *Object) Type {
+ const mod = o.module;
+
+ const std_pkg = mod.main_pkg.table.get("std").?;
+ const std_file = (mod.importPkg(std_pkg) catch unreachable).file;
+
+ const builtin_str: []const u8 = "builtin";
+ const std_namespace = mod.declPtr(std_file.root_decl.unwrap().?).src_namespace;
+ const builtin_decl = std_namespace.decls
+ .getKeyAdapted(builtin_str, Module.DeclAdapter{ .mod = mod }).?;
+
+ const stack_trace_str: []const u8 = "StackTrace";
+ // buffer is only used for int_type, `builtin` is a struct.
+ const builtin_ty = mod.declPtr(builtin_decl).val.toType(undefined);
+ const builtin_namespace = builtin_ty.getNamespace().?;
+ const stack_trace_decl = builtin_namespace.decls
+ .getKeyAdapted(stack_trace_str, Module.DeclAdapter{ .mod = mod }).?;
+
+ return mod.declPtr(stack_trace_decl).val.toType(undefined);
+ }
};
pub const DeclGen = struct {
@@ -1976,8 +2017,15 @@ pub const DeclGen = struct {
llvm_fn.addSretAttr(0, raw_llvm_ret_ty);
}
+ const err_return_tracing = fn_info.return_type.isError() and
+ dg.module.comp.bin_file.options.error_return_tracing;
+
+ if (err_return_tracing) {
+ dg.addArgAttr(llvm_fn, @boolToInt(sret), "nonnull");
+ }
+
// Set parameter attributes.
- var llvm_param_i: c_uint = @boolToInt(sret);
+ var llvm_param_i: c_uint = @as(c_uint, @boolToInt(sret)) + @boolToInt(err_return_tracing);
for (fn_info.param_types) |param_ty| {
if (!param_ty.hasRuntimeBitsIgnoreComptime()) continue;
@@ -2435,6 +2483,17 @@ pub const DeclGen = struct {
try llvm_params.append(llvm_sret_ty.pointerType(0));
}
+ if (fn_info.return_type.isError() and
+ dg.module.comp.bin_file.options.error_return_tracing)
+ {
+ var ptr_ty_payload: Type.Payload.ElemType = .{
+ .base = .{ .tag = .single_mut_pointer },
+ .data = dg.object.getStackTraceType(),
+ };
+ const ptr_ty = Type.initPayload(&ptr_ty_payload.base);
+ try llvm_params.append(try lowerFnParamTy(dg, fn_info.cc, ptr_ty));
+ }
+
for (fn_info.param_types) |param_ty| {
if (!param_ty.hasRuntimeBitsIgnoreComptime()) continue;
@@ -3449,6 +3508,8 @@ pub const FuncGen = struct {
llvm_func: *const llvm.Value,
+ err_ret_trace: ?*const llvm.Value = null,
+
/// This data structure is used to implement breaking to blocks.
blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, struct {
parent_bb: *const llvm.BasicBlock,
@@ -3678,6 +3739,8 @@ pub const FuncGen = struct {
.unwrap_errunion_err => try self.airErrUnionErr(inst, false),
.unwrap_errunion_err_ptr => try self.airErrUnionErr(inst, true),
.errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst),
+ .err_return_trace => try self.airErrReturnTrace(inst),
+ .set_err_return_trace => try self.airSetErrReturnTrace(inst),
.wrap_optional => try self.airWrapOptional(inst),
.wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
@@ -3732,6 +3795,12 @@ pub const FuncGen = struct {
break :blk ret_ptr;
};
+ if (fn_info.return_type.isError() and
+ self.dg.module.comp.bin_file.options.error_return_tracing)
+ {
+ try llvm_args.append(self.err_ret_trace.?);
+ }
+
for (args) |arg| {
const param_ty = self.air.typeOf(arg);
if (!param_ty.hasRuntimeBitsIgnoreComptime()) continue;
@@ -5149,6 +5218,17 @@ pub const FuncGen = struct {
return self.builder.buildInBoundsGEP(operand, &indices, indices.len, "");
}
+ fn airErrReturnTrace(self: *FuncGen, _: Air.Inst.Index) !?*const llvm.Value {
+ return self.err_ret_trace.?;
+ }
+
+ fn airSetErrReturnTrace(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
+ const un_op = self.air.instructions.items(.data)[inst].un_op;
+ const operand = try self.resolveInst(un_op);
+ self.err_ret_trace = operand;
+ return null;
+ }
+
fn airWrapOptional(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
if (self.liveness.isUnused(inst)) return null;