diff --git a/src/all_types.hpp b/src/all_types.hpp index 024c78eb73..caae13d20d 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1595,6 +1595,8 @@ struct CodeGen { ZigList tld_ref_source_node_stack; TypeTableEntry *align_amt_type; + TypeTableEntry *stack_trace_type; + TypeTableEntry *ptr_to_stack_trace_type; }; enum VarLinkage { diff --git a/src/analyze.cpp b/src/analyze.cpp index 7e4a861f0f..2e51e5151c 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -869,6 +869,16 @@ static const char *calling_convention_fn_type_str(CallingConvention cc) { zig_unreachable(); } +static TypeTableEntry *get_ptr_to_stack_trace_type(CodeGen *g) { + if (g->stack_trace_type == nullptr) { + ConstExprValue *stack_trace_type_val = get_builtin_value(g, "StackTrace"); + assert(stack_trace_type_val->type->id == TypeTableEntryIdMetaType); + g->stack_trace_type = stack_trace_type_val->data.x_type; + g->ptr_to_stack_trace_type = get_pointer_to_type(g, g->stack_trace_type, false); + } + return g->ptr_to_stack_trace_type; +} + TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { auto table_entry = g->fn_type_table.maybe_get(fn_type_id); if (table_entry) { @@ -915,10 +925,15 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { if (!skip_debug_info) { bool first_arg_return = calling_convention_does_first_arg_return(fn_type_id->cc) && handle_is_ptr(fn_type_id->return_type); + bool last_arg_error_return_trace = fn_type_id->return_type->id == TypeTableEntryIdErrorUnion || + fn_type_id->return_type->id == TypeTableEntryIdPureError; // +1 for maybe making the first argument the return value - LLVMTypeRef *gen_param_types = allocate(1 + fn_type_id->param_count); - // +1 because 0 is the return type and +1 for maybe making first arg ret val - ZigLLVMDIType **param_di_types = allocate(2 + fn_type_id->param_count); + // +1 for maybe last argument the error return trace + LLVMTypeRef *gen_param_types = allocate(2 + fn_type_id->param_count); + // +1 because 0 is the return type and + // +1 for maybe making first arg ret val and + // +1 for maybe last argument the error return trace + ZigLLVMDIType **param_di_types = allocate(3 + fn_type_id->param_count); param_di_types[0] = fn_type_id->return_type->di_type; size_t gen_param_index = 0; TypeTableEntry *gen_return_type; @@ -965,6 +980,14 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { } } + if (last_arg_error_return_trace) { + TypeTableEntry *gen_type = get_ptr_to_stack_trace_type(g); + gen_param_types[gen_param_index] = gen_type->type_ref; + gen_param_index += 1; + // after the gen_param_index += 1 because 0 is the return type + param_di_types[gen_param_index] = gen_type->di_type; + } + fn_type->data.fn.gen_param_count = gen_param_index; fn_type->data.fn.raw_type_ref = LLVMFunctionType(gen_return_type->type_ref, @@ -5527,3 +5550,13 @@ bool type_ptr_eql(const TypeTableEntry *a, const TypeTableEntry *b) { return a == b; } +ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name) { + Tld *tld = codegen->compile_var_import->decls_scope->decl_table.get(buf_create_from_str(name)); + resolve_top_level_decl(codegen, tld, false, nullptr); + assert(tld->id == TldIdVar); + TldVar *tld_var = (TldVar *)tld; + ConstExprValue *var_value = tld_var->var->value; + assert(var_value != nullptr); + return var_value; +} + diff --git a/src/analyze.hpp b/src/analyze.hpp index 6224e64dd5..050630bc07 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -185,4 +185,8 @@ PackageTableEntry *new_anonymous_package(void); Buf *const_value_to_buffer(ConstExprValue *const_val); void add_fn_export(CodeGen *g, FnTableEntry *fn_table_entry, Buf *symbol_name, GlobalLinkageId linkage, bool ccc); + +ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name); + + #endif diff --git a/src/codegen.cpp b/src/codegen.cpp index 9ad71a936e..4de0fcec51 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -483,7 +483,8 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) { LLVMSetUnnamedAddr(fn_table_entry->llvm_value, true); } - if (fn_type->data.fn.fn_type_id.return_type->id == TypeTableEntryIdUnreachable) { + TypeTableEntry *return_type = fn_type->data.fn.fn_type_id.return_type; + if (return_type->id == TypeTableEntryIdUnreachable) { addLLVMFnAttr(fn_table_entry->llvm_value, "noreturn"); } @@ -520,13 +521,11 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) { // use the ABI alignment, which is fine. } - if (!type_has_bits(fn_type->data.fn.fn_type_id.return_type)) { + if (!type_has_bits(return_type)) { // nothing to do - } else if (fn_type->data.fn.fn_type_id.return_type->id == TypeTableEntryIdPointer || - fn_type->data.fn.fn_type_id.return_type->id == TypeTableEntryIdFn) - { + } else if (return_type->id == TypeTableEntryIdPointer || return_type->id == TypeTableEntryIdFn) { addLLVMAttr(fn_table_entry->llvm_value, 0, "nonnull"); - } else if (handle_is_ptr(fn_type->data.fn.fn_type_id.return_type) && + } else if (handle_is_ptr(return_type) && calling_convention_does_first_arg_return(fn_type->data.fn.fn_type_id.cc)) { addLLVMArgAttr(fn_table_entry->llvm_value, 0, "sret"); @@ -562,6 +561,10 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) { addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)gen_index, "byval"); } } + if (return_type->id == TypeTableEntryIdErrorUnion || return_type->id == TypeTableEntryIdPureError) { + unsigned gen_index = LLVMCountParamTypes(fn_llvm_type) - 1; + addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)gen_index, "nonnull"); + } return fn_table_entry->llvm_value; } @@ -2330,7 +2333,8 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr TypeTableEntry *src_return_type = fn_type_id->return_type; bool ret_has_bits = type_has_bits(src_return_type); bool first_arg_ret = ret_has_bits && handle_is_ptr(src_return_type); - size_t actual_param_count = instruction->arg_count + (first_arg_ret ? 1 : 0); + bool last_arg_err_ret_stack = src_return_type->id == TypeTableEntryIdErrorUnion || src_return_type->id == TypeTableEntryIdPureError; + size_t actual_param_count = instruction->arg_count + (first_arg_ret ? 1 : 0) + (last_arg_err_ret_stack ? 1 : 0); bool is_var_args = fn_type_id->is_var_args; LLVMValueRef *gen_param_values = allocate(actual_param_count); size_t gen_param_index = 0; @@ -2348,6 +2352,10 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr gen_param_index += 1; } } + if (last_arg_err_ret_stack) { + gen_param_values[gen_param_index] = LLVMGetUndef(g->ptr_to_stack_trace_type->type_ref); + gen_param_index += 1; + } ZigLLVM_FnInline fn_inline; switch (instruction->fn_inline) { @@ -5088,6 +5096,13 @@ static void define_builtin_compile_vars(CodeGen *g) { os_path_join(g->cache_dir, buf_create_from_str(builtin_zig_basename), builtin_zig_path); Buf *contents = buf_alloc(); + buf_append_str(contents, + "pub const StackTrace = struct {\n" + " index: usize,\n" + " instruction_addresses: [31]usize,\n" + "};\n\n" + ); + const char *cur_os = nullptr; { buf_appendf(contents, "pub const Os = enum {\n"); diff --git a/src/ir.cpp b/src/ir.cpp index f236910250..340e4fbeda 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -8230,16 +8230,6 @@ static bool ir_resolve_comptime(IrAnalyze *ira, IrInstruction *value, bool *out) return ir_resolve_bool(ira, value, out); } -static ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name) { - Tld *tld = codegen->compile_var_import->decls_scope->decl_table.get(buf_create_from_str(name)); - resolve_top_level_decl(codegen, tld, false, nullptr); - assert(tld->id == TldIdVar); - TldVar *tld_var = (TldVar *)tld; - ConstExprValue *var_value = tld_var->var->value; - assert(var_value != nullptr); - return var_value; -} - static bool ir_resolve_atomic_order(IrAnalyze *ira, IrInstruction *value, AtomicOrder *out) { if (type_is_invalid(value->value.type)) return false;