diff options
Diffstat (limited to 'src/codegen')
| -rw-r--r-- | src/codegen/c.zig | 12 | ||||
| -rw-r--r-- | src/codegen/llvm.zig | 84 |
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; |
