From 8a335fc64c6ea298c1e52bf859c781a115277e55 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Mon, 31 Jul 2023 10:39:10 +0200 Subject: [PATCH] Updated stack trace. This addresses #898. --- lib/std/core/builtin.c3 | 21 +++- src/compiler/compiler_internal.h | 1 + src/compiler/copying.c | 1 + src/compiler/llvm_codegen.c | 8 +- src/compiler/llvm_codegen_builtins.c | 2 +- src/compiler/llvm_codegen_expr.c | 77 +++++++------ src/compiler/llvm_codegen_function.c | 159 +++++++++++++++++---------- src/compiler/llvm_codegen_internal.h | 24 +++- src/compiler/llvm_codegen_module.c | 5 +- src/compiler/llvm_codegen_stmt.c | 8 +- src/compiler/sema_expr.c | 1 + src/version.h | 2 +- 12 files changed, 193 insertions(+), 116 deletions(-) diff --git a/lib/std/core/builtin.c3 b/lib/std/core/builtin.c3 index ceb56d39c..ba3d86d90 100644 --- a/lib/std/core/builtin.c3 +++ b/lib/std/core/builtin.c3 @@ -68,11 +68,24 @@ macro anycast(any v, $Type) @builtin return ($Type*)v.ptr; } +enum CallLocation : int(String name) +{ + UNKNOWN("???"), + FUNCTION("function"), + METHOD("method"), + MACRO("macro"), + LAMBDA("lambda"), + TEST("test"), + INITIALIZER("initializer"), + FINALIZER("finalizer") +} + struct CallstackElement { CallstackElement* prev; String function; String file; + CallLocation location; uint line; } @@ -91,11 +104,11 @@ fn void default_panic(String message, String file, String function, uint line) { (void)io::stderr().print("\nERROR: '"); (void)io::stderr().print(message); - (void)io::stderr().printfn("', in function %s (%s:%d)", function, file, line); + (void)io::stderr().printfn("', in %s (%s:%d)", function, file, line); } while (stack) { - (void)io::stderr().printfn(" in function %s (%s:%d)", stack.function, stack.file, stack.line); + (void)io::stderr().printfn(" in %s %s (%s:%d)", stack.location.name, stack.function, stack.file, stack.line); if (stack == stack.prev) break; stack = stack.prev; } @@ -297,12 +310,12 @@ fn void sig_panic(String message) CallstackElement* stack = $$stacktrace(); if (stack) stack = stack.prev; if (stack) stack = stack.prev; - (void)io::stderr().print("\nERROR: '"); + (void)io::stderr().print("\nSYSTEM ERROR: '"); (void)io::stderr().print(message); (void)io::stderr().printn("'"); while (stack) { - (void)io::stderr().printfn(" in function %s (%s:%s)", stack.function, stack.file, stack.line); + (void)io::stderr().printfn(" in %s %s (%s:%s)", stack.location.name, stack.function, stack.file, stack.line); if (stack == stack.prev) break; stack = stack.prev; } diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 8c3f47a21..3c383be89 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -1018,6 +1018,7 @@ typedef struct bool is_must_use : 1; bool had_optional_arg : 1; Decl **params; + Decl *macro; BlockExit **block_exit; } ExprMacroBlock; diff --git a/src/compiler/copying.c b/src/compiler/copying.c index 7781a9d76..8b07cf7f9 100644 --- a/src/compiler/copying.c +++ b/src/compiler/copying.c @@ -438,6 +438,7 @@ Expr *copy_expr(CopyStruct *c, Expr *source_expr) case EXPR_MACRO_BLOCK: MACRO_COPY_DECL_LIST(expr->macro_block.params); MACRO_COPY_ASTID(expr->macro_block.first_stmt); + MACRO_COPY_DECL(expr->macro_block.macro); return expr; case EXPR_COMPOUND_LITERAL: MACRO_COPY_EXPR(expr->expr_compound_literal.initializer); diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index c306a7798..b030f6d79 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -1372,27 +1372,27 @@ static GenContext *llvm_gen_module(Module *module, LLVMContextRef shared_context if (decl->func_decl.body) { has_elements = true; - llvm_emit_function_body(gen_context, decl); + llvm_emit_function_body(gen_context, decl, decl->func_decl.attr_test ? ST_TEST : ST_FUNCTION); } FOREACH_END(); FOREACH_BEGIN(Decl *func, unit->lambdas) if (only_used && !func->is_live) continue; has_elements = true; - llvm_emit_function_body(gen_context, func); + llvm_emit_function_body(gen_context, func, ST_LAMBDA); FOREACH_END(); if (active_target.type != TARGET_TYPE_TEST && unit->main_function && unit->main_function->is_synthetic) { has_elements = true; - llvm_emit_function_body(gen_context, unit->main_function); + llvm_emit_function_body(gen_context, unit->main_function, ST_FUNCTION); } FOREACH_BEGIN(Decl *decl, unit->methods) if (only_used && !decl->is_live) continue; if (!decl->func_decl.body) continue; has_elements = true; - llvm_emit_function_body(gen_context, decl); + llvm_emit_function_body(gen_context, decl, ST_METHOD); FOREACH_END(); gencontext_end_file_emit(gen_context, unit); diff --git a/src/compiler/llvm_codegen_builtins.c b/src/compiler/llvm_codegen_builtins.c index 543e250c6..ade002504 100644 --- a/src/compiler/llvm_codegen_builtins.c +++ b/src/compiler/llvm_codegen_builtins.c @@ -132,7 +132,7 @@ INLINE void llvm_emit_stacktrace(GenContext *c, BEValue *result_value, Expr *exp llvm_value_set(result_value, llvm_get_zero(c, type_voidptr), type_voidptr); return; } - llvm_value_set(result_value, c->debug.stack_slot, type_voidptr); + llvm_value_set(result_value, c->debug.stacktrace, type_voidptr); } INLINE void llvm_emit_volatile_store(GenContext *c, BEValue *result_value, Expr *expr) diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index 1ab2df3fe..af25b823d 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -29,7 +29,7 @@ static inline void llvm_emit_initializer_list_expr(GenContext *c, BEValue *value static inline void llvm_emit_macro_block(GenContext *c, BEValue *be_value, Expr *expr); static inline void llvm_emit_post_inc_dec(GenContext *c, BEValue *value, Expr *expr, int diff); static inline void llvm_emit_pre_inc_dec(GenContext *c, BEValue *value, Expr *expr, int diff); -static inline void llvm_emit_return_block(GenContext *c, BEValue *be_value, Type *type, AstId current, BlockExit **block_exit); +static inline void llvm_emit_return_block(GenContext *c, BEValue *be_value, Type *type, AstId current, BlockExit **block_exit, LLVMValueRef *old_stack_trace); static inline void llvm_emit_subscript_addr_with_base(GenContext *c, BEValue *result, BEValue *parent, BEValue *index, SourceSpan loc); static inline void llvm_emit_try_unwrap(GenContext *c, BEValue *value, Expr *expr); static inline void llvm_emit_any(GenContext *c, BEValue *value, Expr *expr); @@ -5330,11 +5330,7 @@ void llvm_emit_raw_call(GenContext *c, BEValue *result_value, FunctionPrototype BEValue no_err; // Emit the current stack into the thread local or things will get messed up. - if (c->debug.current_stack_ptr) - llvm_store_to_ptr_raw_aligned(c, - c->debug.current_stack_ptr, - c->debug.stack_slot, - type_alloca_alignment(type_voidptr)); + llvm_emit_pop_stacktrace(c, NULL); // 17a. If we used the error var as the indirect recipient, then that will hold the error. // otherwise it's whatever value in be_value. @@ -5371,11 +5367,7 @@ void llvm_emit_raw_call(GenContext *c, BEValue *result_value, FunctionPrototype } // Emit the current stack into the thread local or things will get messed up. - if (c->debug.current_stack_ptr) - llvm_store_to_ptr_raw_aligned(c, - c->debug.current_stack_ptr, - c->debug.stack_slot, - type_alloca_alignment(type_voidptr)); + llvm_emit_pop_stacktrace(c, NULL); // 17i. The simple case here is where there is a normal return. // In this case be_value already holds the result @@ -5487,13 +5479,7 @@ static void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr return; } - if (c->debug.stack_slot_row) - { - llvm_store_to_ptr_raw_aligned(c, - c->debug.stack_slot_row, - llvm_const_int(c, type_uint, expr->span.row), - type_abi_alignment(type_uint)); - } + llvm_emit_update_stack_row(c, expr->span.row); LLVMTypeRef func_type; LLVMValueRef func; @@ -5749,13 +5735,7 @@ static void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr llvm_emit_raw_call(c, result_value, prototype, func_type, func, arg_values, arg_count, inline_flag, error_var, sret_return, &synthetic_return_param); // Emit the current stack into the thread local or things will get messed up. - if (c->debug.current_stack_ptr) - { - llvm_store_to_ptr_raw_aligned(c, - c->debug.current_stack_ptr, - c->debug.stack_slot, - type_alloca_alignment(type_voidptr)); - } + llvm_emit_pop_stacktrace(c, NULL); // 17i. The simple case here is where there is a normal return. // In this case be_value already holds the result @@ -5773,7 +5753,7 @@ static inline void llvm_emit_expression_list_expr(GenContext *c, BEValue *be_val } } -static inline void llvm_emit_return_block(GenContext *c, BEValue *be_value, Type *type, AstId current, BlockExit **block_exit) +static inline void llvm_emit_return_block(GenContext *c, BEValue *be_value, Type *type, AstId current, BlockExit **block_exit, LLVMValueRef *old_stack_trace) { Type *type_lowered = type_lowering(type); @@ -5799,6 +5779,7 @@ static inline void llvm_emit_return_block(GenContext *c, BEValue *be_value, Type if (!type_is_optional(type)) { llvm_emit_expr(c, be_value, expr); + if (old_stack_trace) llvm_emit_pop_stacktrace(c, old_stack_trace); return; } } @@ -5808,16 +5789,23 @@ static inline void llvm_emit_return_block(GenContext *c, BEValue *be_value, Type LLVMBasicBlockRef error_block = c->catch_block; LLVMValueRef return_out = NULL; LLVMBasicBlockRef expr_block = llvm_basic_block_new(c, "expr_block.exit"); - + LLVMBasicBlockRef cleanup_error_block = error_block; + bool error_env_restore = false; + if (old_stack_trace && error_block) + { + cleanup_error_block = llvm_basic_block_new(c, "restore_env_block"); + error_env_restore = true; + } BlockExit exit = { .block_return_exit = expr_block, - .block_optional_exit = error_block, + .block_optional_exit = cleanup_error_block, .block_error_var = error_out, .block_return_out = NULL, }; *block_exit= &exit; + if (type_no_optional(type_lowered) != type_void) { exit.block_return_out = llvm_emit_alloca_aligned(c, type_lowered, "blockret"); @@ -5836,7 +5824,7 @@ static inline void llvm_emit_return_block(GenContext *c, BEValue *be_value, Type { // Do we have more than one exit? // Then follow the normal path. - if (!llvm_basic_block_is_unused(expr_block)) break; + if (!llvm_basic_block_is_unused(expr_block) || error_env_restore) break; // Do we have a void function? That's the only // possible case if the last statement isn't return. @@ -5867,6 +5855,7 @@ static inline void llvm_emit_return_block(GenContext *c, BEValue *be_value, Type // Output directly to a value llvm_emit_expr(c, be_value, ret_expr); + if (old_stack_trace) llvm_emit_pop_stacktrace(c, old_stack_trace); return; } while (0); @@ -5875,7 +5864,7 @@ static inline void llvm_emit_return_block(GenContext *c, BEValue *be_value, Type llvm_emit_stmt(c, value); // In the case of a void with no return, then this may be true. - if (llvm_basic_block_is_unused(expr_block)) + if (llvm_basic_block_is_unused(expr_block) && !error_env_restore) { // Skip the expr block. llvm_value_set(be_value, llvm_get_undef(c, type_lowered), type_lowered); @@ -5884,6 +5873,12 @@ static inline void llvm_emit_return_block(GenContext *c, BEValue *be_value, Type llvm_emit_br(c, expr_block); + if (error_env_restore) + { + llvm_emit_block(c, cleanup_error_block); + llvm_emit_pop_stacktrace(c, old_stack_trace); + llvm_emit_br(c, error_block); + } // Emit the exit block. llvm_emit_block(c, expr_block); @@ -5897,6 +5892,8 @@ static inline void llvm_emit_return_block(GenContext *c, BEValue *be_value, Type } DONE: + if (old_stack_trace) llvm_emit_pop_stacktrace(c, old_stack_trace); + c->return_out = old_ret_out; c->catch_block = error_block; c->opt_var = error_out; @@ -5905,7 +5902,8 @@ DONE: static inline void llvm_emit_expr_block(GenContext *context, BEValue *be_value, Expr *expr) { - llvm_emit_return_block(context, be_value, expr->type, expr->expr_block.first_stmt, expr->expr_block.block_exit_ref); + llvm_emit_return_block(context, be_value, expr->type, expr->expr_block.first_stmt, expr->expr_block.block_exit_ref, + NULL); } static inline void llvm_emit_macro_block(GenContext *c, BEValue *be_value, Expr *expr) @@ -5950,12 +5948,25 @@ static inline void llvm_emit_macro_block(GenContext *c, BEValue *be_value, Expr val->backend_value = value.value; FOREACH_END(); + bool restore_at_exit = false; + LLVMValueRef old_stack_trace; if (llvm_use_debug(c)) { llvm_debug_push_lexical_scope(c, astptr(expr->macro_block.first_stmt)->span); + if (c->debug.enable_stacktrace) + { + restore_at_exit = true; + llvm_emit_update_stack_row(c, expr->span.row); + Decl *macro = expr->macro_block.macro; + Module *macro_module = macro->unit->module; + old_stack_trace = c->debug.stacktrace; + llvm_emit_push_stacktrace(c, macro, macro->name, ST_MACRO); + } } - llvm_emit_return_block(c, be_value, expr->type, expr->macro_block.first_stmt, expr->macro_block.block_exit); - if (expr->macro_block.is_noreturn && c->current_block && c->current_block_is_target) + llvm_emit_return_block(c, be_value, expr->type, expr->macro_block.first_stmt, expr->macro_block.block_exit, restore_at_exit ? &old_stack_trace : NULL); + if (restore_at_exit) c->debug.stacktrace = old_stack_trace; + bool is_unreachable = expr->macro_block.is_noreturn && c->current_block && c->current_block_is_target; + if (is_unreachable) { llvm_emit_unreachable(c); } diff --git a/src/compiler/llvm_codegen_function.c b/src/compiler/llvm_codegen_function.c index eb0c8f628..a425733c1 100644 --- a/src/compiler/llvm_codegen_function.c +++ b/src/compiler/llvm_codegen_function.c @@ -11,9 +11,9 @@ static inline void llvm_emit_return_value(GenContext *context, LLVMValueRef valu static void llvm_expand_from_args(GenContext *c, Type *type, LLVMValueRef ref, unsigned *index, AlignSize alignment); static inline void llvm_process_parameter_value(GenContext *c, Decl *decl, ABIArgInfo *info, unsigned *index); static inline void llvm_emit_func_parameter(GenContext *context, Decl *decl, ABIArgInfo *abi_info, unsigned *index, unsigned real_index); -static inline void llvm_emit_body(GenContext *c, LLVMValueRef function, const char *module_name, - const char *function_name, - FileId file_id, FunctionPrototype *prototype, Signature *signature, Ast *body); +static inline void +llvm_emit_body(GenContext *c, LLVMValueRef function, FunctionPrototype *prototype, Signature *signature, Ast *body, + Decl *decl, StacktraceType type); /** @@ -407,22 +407,19 @@ void llvm_emit_return_implicit(GenContext *c) llvm_emit_return_abi(c, NULL, &value); } -void llvm_emit_function_body(GenContext *c, Decl *decl) +void llvm_emit_function_body(GenContext *c, Decl *decl, StacktraceType type) { DEBUG_LOG("Generating function %s.", decl->extname); if (decl->func_decl.attr_dynamic) vec_add(c->dynamic_functions, decl); assert(decl->backend_ref); llvm_emit_body(c, - decl->backend_ref, - decl->unit->module->name->module, - decl->name, - decl->span.file_id, - type_get_resolved_prototype(decl->type), - decl->func_decl.attr_naked ? NULL : &decl->func_decl.signature, - astptr(decl->func_decl.body)); + decl->backend_ref, + type_get_resolved_prototype(decl->type), + decl->func_decl.attr_naked ? NULL : &decl->func_decl.signature, + astptr(decl->func_decl.body), decl, type); } -void llvm_emit_stacktrace_definitions(GenContext *c) +static void llvm_emit_stacktrace_definitions(GenContext *c) { const char *name = ".stacktrace_current"; LLVMValueRef current_stack = c->debug.current_stack_ptr = llvm_add_global_raw(c, name, c->ptr_type, 0); @@ -430,8 +427,8 @@ void llvm_emit_stacktrace_definitions(GenContext *c) LLVMSetInitializer(current_stack, llvm_get_zero_raw(c->ptr_type)); llvm_set_weak(c, current_stack); LLVMTypeRef uint_type = llvm_get_type(c, type_uint); - LLVMTypeRef args[6] = { c->ptr_type, c->ptr_type, c->size_type, c->ptr_type, c->size_type, uint_type }; - LLVMTypeRef func_type = c->debug.stack_init_fn_type = LLVMFunctionType(LLVMVoidTypeInContext(c->context), args, 6, false); + LLVMTypeRef args[7] = { c->ptr_type, c->ptr_type, c->size_type, c->ptr_type, c->size_type, uint_type, uint_type }; + LLVMTypeRef func_type = c->debug.stack_init_fn_type = LLVMFunctionType(LLVMVoidTypeInContext(c->context), args, 7, false); LLVMValueRef func = c->debug.stack_init_fn = LLVMAddFunction(c->module, ".stacktrace_init", func_type); llvm_set_weak(c, func); LLVMBuilderRef builder = LLVMCreateBuilderInContext(c->context); @@ -457,19 +454,65 @@ void llvm_emit_stacktrace_definitions(GenContext *c) llvm_store_to_ptr_raw_aligned(c, file_name_ptr, LLVMGetParam(func, 3), align_to_use); LLVMValueRef file_name_sz = llvm_emit_struct_gep_raw(c, file_name, c->chars_type, 1, align_to_use, &align_to_use); llvm_store_to_ptr_raw_aligned(c, file_name_sz, LLVMGetParam(func, 4), align_to_use); - llvm_store_to_ptr_raw_aligned(c, - c->debug.current_stack_ptr, - stacktrace, - type_alloca_alignment(type_voidptr)); - LLVMValueRef line = llvm_emit_struct_gep_raw(c, stacktrace, slot_type, 3, alignment, &align_to_use); - llvm_store_to_ptr_raw_aligned(c, line, LLVMGetParam(func, 5), align_to_use); + llvm_store_to_ptr_raw_aligned(c, c->debug.current_stack_ptr, stacktrace, type_alloca_alignment(type_voidptr)); + LLVMValueRef type = llvm_emit_struct_gep_raw(c, stacktrace, slot_type, 3, alignment, &align_to_use); + llvm_store_to_ptr_raw_aligned(c, type, LLVMGetParam(func, 5), align_to_use); + LLVMValueRef line = llvm_emit_struct_gep_raw(c, stacktrace, slot_type, 4, alignment, &align_to_use); + llvm_store_to_ptr_raw_aligned(c, line, LLVMGetParam(func, 6), align_to_use); LLVMBuildRetVoid(c->builder); LLVMDisposeBuilder(c->builder); c->builder = NULL; } -void llvm_emit_body(GenContext *c, LLVMValueRef function, const char *module_name, const char *function_name, - FileId file_id, FunctionPrototype *prototype, Signature *signature, Ast *body) +void llvm_emit_pop_stacktrace(GenContext *c, LLVMValueRef *slot) +{ + if (!c->debug.enable_stacktrace) return; + if (slot) + { + c->debug.stacktrace = *slot; + } + llvm_store_to_ptr_raw_aligned(c, c->debug.current_stack_ptr, c->debug.stacktrace, type_alloca_alignment(type_voidptr)); +} +void llvm_emit_update_stack_row(GenContext *c, uint32_t row) +{ + if (!c->debug.enable_stacktrace) return; + LLVMValueRef row_ptr = LLVMBuildStructGEP2(c->builder, c->debug.stack_type, c->debug.stacktrace, 4, ".$row"); + llvm_store_to_ptr_raw_aligned(c, row_ptr, llvm_const_int(c, type_uint, row ? row : 1), type_abi_alignment(type_uint)); + +} +void llvm_emit_push_stacktrace(GenContext *c, Decl *decl, const char *function_name, StacktraceType type) +{ + LLVMTypeRef slot_type = c->debug.stack_type; + AlignSize alignment = llvm_abi_alignment(c, slot_type); + LLVMValueRef stacktrace = llvm_emit_alloca(c, slot_type, alignment, ".$stacktrace"); + scratch_buffer_clear(); + scratch_buffer_append(decl->unit->module->name->module); + scratch_buffer_append("::"); + scratch_buffer_append(function_name); + size_t func_name_len = scratch_buffer.len; + LLVMValueRef func_name = llvm_emit_zstring_named(c, scratch_buffer_to_string(), ".callname"); + File *file = decl->unit->file; + size_t file_name_len = strlen(file->full_path); + LLVMValueRef file_name = llvm_emit_zstring_named(c, file->full_path, ".filename"); + LLVMValueRef args[] = {stacktrace, func_name, llvm_const_int(c, type_usz, func_name_len), + file_name, llvm_const_int(c, type_usz, file_name_len), + llvm_const_int(c, type_uint, type), + llvm_const_int(c, type_uint, decl->span.row)}; + LLVMBuildCall2(c->builder, c->debug.stack_init_fn_type, c->debug.stack_init_fn, args, 7, ""); + + if (type == ST_FUNCTION && (function_name == kw_main || function_name == kw_mainstub)) + { + AlignSize align_size; + LLVMValueRef last = llvm_emit_struct_gep_raw(c, stacktrace, slot_type, 0, alignment, &align_size); + llvm_store_to_ptr_raw_aligned(c, last, LLVMConstNull(c->ptr_type), align_size); + } + c->debug.stacktrace = stacktrace; +} + + +void +llvm_emit_body(GenContext *c, LLVMValueRef function, FunctionPrototype *prototype, Signature *signature, Ast *body, + Decl *decl, StacktraceType type) { bool emit_debug = llvm_use_debug(c); LLVMValueRef prev_function = c->function; @@ -484,25 +527,39 @@ void llvm_emit_body(GenContext *c, LLVMValueRef function, const char *module_nam c->opt_var = NULL; c->catch_block = NULL; + const char *function_name; + switch (type) + { + case ST_UNKNOWN: + UNREACHABLE + case ST_FUNCTION: + case ST_TEST: + assert(decl->name); + function_name = decl->name; + break; + case ST_METHOD: + function_name = decl->name; + break; + case ST_LAMBDA: + function_name = "[lambda]"; + break; + case ST_MACRO: + function_name = decl->name; + break; + case ST_INITIALIZER: + function_name = "[static initializer]"; + break; + case ST_FINALIZER: + function_name = "[static finalizer"; + break; + default: + UNREACHABLE + } + c->function = function; - if (!function_name) function_name = "anonymous function"; - size_t func_name_len = 0; - size_t file_name_len = 0; if (emit_debug) { c->debug.function = LLVMGetSubprogram(function); - if (use_stacktrace) - { - scratch_buffer_clear(); - scratch_buffer_append(module_name); - scratch_buffer_append("::"); - scratch_buffer_append(function_name); - c->debug.func_name = llvm_emit_zstring_named(c, scratch_buffer_to_string(), ".funcname"); - func_name_len = scratch_buffer.len; - File *file = source_file_by_id(file_id); - file_name_len = strlen(file->name); - c->debug.file_name = llvm_emit_zstring_named(c, file->name, ".filename"); - } } c->cur_func.name = function_name; @@ -518,27 +575,14 @@ void llvm_emit_body(GenContext *c, LLVMValueRef function, const char *module_nam unsigned arg = 0; + if (emit_debug) { llvm_debug_scope_push(c, c->debug.function); EMIT_LOC(c, body); if (use_stacktrace) { - LLVMTypeRef slot_type = c->debug.stack_type; - assert(c->debug.current_stack_ptr && c->debug.stack_init_fn); - AlignSize alignment = llvm_abi_alignment(c, slot_type); - LLVMValueRef stacktrace = c->debug.stack_slot = llvm_emit_alloca(c, slot_type, alignment, ".$stacktrace"); - LLVMValueRef args[] = { stacktrace, c->debug.func_name, llvm_const_int(c, type_usz, func_name_len), - c->debug.file_name, llvm_const_int(c, type_usz, file_name_len), - llvm_const_int(c, type_uint, body->span.row) }; - LLVMBuildCall2(c->builder, c->debug.stack_init_fn_type, c->debug.stack_init_fn, args, 6, ""); - c->debug.stack_slot_row = LLVMBuildStructGEP2(c->builder, slot_type, c->debug.stack_slot, 3, ".$row"); - if (function_name == kw_main || function_name == kw_mainstub) - { - AlignSize align_size; - LLVMValueRef last = llvm_emit_struct_gep_raw(c, c->debug.stack_slot, slot_type, 0, alignment, &align_size); - llvm_store_to_ptr_raw_aligned(c, last, LLVMConstNull(c->ptr_type), align_size); - } + llvm_emit_push_stacktrace(c, decl, function_name, type); } } @@ -655,13 +699,10 @@ void llvm_emit_xxlizer(GenContext *c, Decl *decl) LLVMSetSubprogram(function, c->debug.function); } llvm_emit_body(c, - function, - decl->unit->module->name->module, - is_initializer ? "[static initializer]" : "[static finalizer]", - decl->span.file_id, - NULL, - NULL, - body); + function, + NULL, + NULL, + body, decl, is_initializer ? ST_INITIALIZER : ST_FINALIZER); } diff --git a/src/compiler/llvm_codegen_internal.h b/src/compiler/llvm_codegen_internal.h index c821f69e9..7cbea36e1 100644 --- a/src/compiler/llvm_codegen_internal.h +++ b/src/compiler/llvm_codegen_internal.h @@ -49,6 +49,18 @@ typedef struct DebugFile_ LLVMMetadataRef debug_file; } DebugFile; +typedef enum +{ + ST_UNKNOWN = 0, + ST_FUNCTION, + ST_METHOD, + ST_MACRO, + ST_LAMBDA, + ST_TEST, + ST_INITIALIZER, + ST_FINALIZER +} StacktraceType; + typedef struct { unsigned runtime_version : 8; @@ -61,14 +73,11 @@ typedef struct SourceSpan current_range; LLVMMetadataRef *lexical_block_stack; LLVMMetadataRef inlined_at; - LLVMValueRef func_name; - LLVMValueRef file_name; LLVMValueRef current_stack_ptr; LLVMValueRef stack_init_fn; LLVMTypeRef stack_init_fn_type; LLVMTypeRef stack_type; - LLVMValueRef stack_slot; - LLVMValueRef stack_slot_row; + LLVMValueRef stacktrace; } DebugContext; @@ -478,7 +487,7 @@ void llvm_emit_subarray_len(GenContext *context, BEValue *subarray, BEValue *len void llvm_emit_subarray_pointer(GenContext *context, BEValue *subarray, BEValue *pointer); void llvm_emit_compound_stmt(GenContext *c, Ast *ast); LLVMValueRef llvm_emit_const_bitstruct(GenContext *c, ConstInitializer *initializer); -void llvm_emit_function_body(GenContext *context, Decl *decl); +void llvm_emit_function_body(GenContext *context, Decl *decl, StacktraceType type); void llvm_emit_dynamic_functions(GenContext *context, Decl **funcs); BEValue llvm_emit_assign_expr(GenContext *c, BEValue *ref, Expr *expr, LLVMValueRef optional); INLINE void llvm_emit_exprid(GenContext *c, BEValue *value, ExprId expr); @@ -511,6 +520,11 @@ void llvm_emit_debug_location(GenContext *c, SourceSpan location); void llvm_emit_debug_parameter(GenContext *c, Decl *parameter, unsigned index); void llvm_emit_debug_local_var(GenContext *c, Decl *var); void llvm_emit_debug_global_var(GenContext *c, Decl *global); +void llvm_emit_update_stack_row(GenContext *c, uint32_t row); +void llvm_emit_pop_stacktrace(GenContext *c, LLVMValueRef *slot); +void +llvm_emit_push_stacktrace(GenContext *c, Decl *decl, const char *function_name, StacktraceType type); + #define EMIT_LOC(c, x) do { if (c->debug.builder) llvm_emit_debug_location(c, x->span); } while (0); LLVMAtomicOrdering llvm_atomic_ordering(Atomicity atomicity); diff --git a/src/compiler/llvm_codegen_module.c b/src/compiler/llvm_codegen_module.c index 5a9343ae2..a5cfb2bea 100644 --- a/src/compiler/llvm_codegen_module.c +++ b/src/compiler/llvm_codegen_module.c @@ -160,11 +160,12 @@ void gencontext_begin_module(GenContext *c) if (active_target.debug_info == DEBUG_INFO_FULL && active_target.feature.safe_mode) { c->debug.stack_type = LLVMStructCreateNamed(c->context, ".$callstack"); - LLVMTypeRef types[4] = { c->ptr_type, + LLVMTypeRef types[5] = { c->ptr_type, c->chars_type, c->chars_type, + llvm_get_type(c, type_uint), llvm_get_type(c, type_uint) }; - LLVMStructSetBody(c->debug.stack_type, types, 4, false); + LLVMStructSetBody(c->debug.stack_type, types, 5, false); c->debug.current_stack_ptr = NULL; c->debug.enable_stacktrace = true; } diff --git a/src/compiler/llvm_codegen_stmt.c b/src/compiler/llvm_codegen_stmt.c index 66ba3bbf3..d05eeeb57 100644 --- a/src/compiler/llvm_codegen_stmt.c +++ b/src/compiler/llvm_codegen_stmt.c @@ -1295,13 +1295,7 @@ void llvm_emit_unreachable(GenContext *c) void llvm_emit_panic(GenContext *c, const char *message, SourceSpan loc, const char *fmt, BEValue *varargs) { if (c->debug.builder) llvm_emit_debug_location(c, loc); - if (c->debug.stack_slot_row) - { - llvm_store_to_ptr_raw_aligned(c, - c->debug.stack_slot_row, - llvm_const_int(c, type_uint, loc.row ? loc.row : 1), - type_abi_alignment(type_uint)); - } + llvm_emit_update_stack_row(c, loc.row); Decl *panic_var = c->panic_var; if (!panic_var) diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 56bd7c97f..06b787f33 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -2048,6 +2048,7 @@ NOT_CT: call_expr->macro_block.had_optional_arg = has_optional_arg; call_expr->macro_block.is_must_use = must_use; call_expr->macro_block.first_stmt = body->compound_stmt.first_stmt; + call_expr->macro_block.macro = decl; call_expr->macro_block.params = params; call_expr->macro_block.block_exit = block_exit_ref; call_expr->macro_block.is_noreturn = is_no_return; diff --git a/src/version.h b/src/version.h index 4db808e0a..f5413b952 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "0.4.591" \ No newline at end of file +#define COMPILER_VERSION "0.4.592" \ No newline at end of file