From 6789fab93c288ac7262102ca791bd5aeac651173 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Fri, 18 Mar 2022 08:57:15 +0100 Subject: [PATCH] Panic function that may be redefined. Trap and stacktrace builtins. Bug using builtin fixed. Fixes to using $$LINE and friends. Produces a stacktrace on error. --- lib/std/builtin.c3 | 37 +++- lib/std/runtime.c3 | 1 - src/build/build_options.c | 6 + src/build/build_options.h | 2 + src/build/builder.c | 1 + src/build/project.c | 3 + src/compiler/compiler_internal.h | 22 +-- src/compiler/context.c | 2 +- src/compiler/enums.h | 3 + src/compiler/llvm_codegen.c | 9 + src/compiler/llvm_codegen_expr.c | 39 +++- src/compiler/llvm_codegen_function.c | 120 ++++++++----- src/compiler/llvm_codegen_internal.h | 13 +- src/compiler/llvm_codegen_module.c | 14 ++ src/compiler/llvm_codegen_stmt.c | 168 +++--------------- src/compiler/parse_global.c | 1 - src/compiler/sema_expr.c | 112 ++++++++---- src/compiler/sema_internal.h | 1 + src/compiler/sema_name_resolution.c | 11 ++ src/compiler/sema_stmts.c | 2 - src/compiler/semantic_analyser.c | 35 ++++ src/compiler/symtab.c | 30 ++-- src/compiler/target.c | 27 ++- test/test_suite/assert/unreachable.c3t | 37 ++-- test/test_suite/builtins/simple_builtins.c3t | 43 +++-- .../from_docs/examples_forswitch.c3t | 5 +- 26 files changed, 433 insertions(+), 311 deletions(-) diff --git a/lib/std/builtin.c3 b/lib/std/builtin.c3 index 46c94be29..06b60fb83 100644 --- a/lib/std/builtin.c3 +++ b/lib/std/builtin.c3 @@ -10,9 +10,44 @@ macro scope(&variable; @body) @autoimport @body(); } +extern fn void printf(char*, ...); + +struct CallstackElement +{ + CallstackElement* prev; + char* function; + char* file; + uint line; +} +fn void panic(char* message, char *file, char *function, uint line) @autoimport +{ + CallstackElement* stack = $$stacktrace(); + $if ($defined(libc::stderr) && $defined(libc::fprintf)): + + if (stack) stack = stack.prev; + if (stack) + { + libc::fprintf(@libc::stderr(), "\nERROR: '%s'\n", message); + } + else + { + libc::fprintf(@libc::stderr(), "\nERROR: '%s', function %s (%s:%d)\n", message, function, file, line); + } + while (stack) + { + libc::fprintf(@libc::stderr(), " at function %s (%s:%u)\n", stack.function, stack.file, stack.line); + stack = stack.prev; + } + + $endif; + + $$trap(); +} + macro unreachable($string = "Unreachable statement reached.") @autoimport @noreturn { - assert(false, $string); + panic($string, $$FILE, $$FUNC, $$LINE); + $$unreachable(); } /* diff --git a/lib/std/runtime.c3 b/lib/std/runtime.c3 index 463d83749..e4fe95fdb 100644 --- a/lib/std/runtime.c3 +++ b/lib/std/runtime.c3 @@ -26,6 +26,5 @@ struct VarArrayHeader usize size; usize capacity; void *allocator; - } diff --git a/src/build/build_options.c b/src/build/build_options.c index 73edbcc44..26c734c48 100644 --- a/src/build/build_options.c +++ b/src/build/build_options.c @@ -540,6 +540,12 @@ static void parse_option(BuildOptions *options) options->no_stdlib = true; return; } + if (match_longopt("panicfn")) + { + if (at_end() || next_is_opt()) error_exit("error: --panicfn needs a function name."); + options->panicfn = next_arg(); + return; + } if (match_longopt("lib")) { if (at_end() || next_is_opt()) error_exit("error: --lib needs a directory."); diff --git a/src/build/build_options.h b/src/build/build_options.h index e9a638291..019503b34 100644 --- a/src/build/build_options.h +++ b/src/build/build_options.h @@ -227,6 +227,7 @@ typedef struct BuildOptions_ bool emit_bitcode; bool test_mode; bool no_stdlib; + const char *panicfn; RelocModel reloc_model; X86VectorCapability x86_vector_capability; bool print_keywords; @@ -278,6 +279,7 @@ typedef struct CompilerBackend backend; uint32_t symtab_size; uint32_t switchrange_max_size; + const char *panicfn; const char *cc; const char *cflags; const char **csource_dirs; diff --git a/src/build/builder.c b/src/build/builder.c index b274a62ba..0153753dc 100644 --- a/src/build/builder.c +++ b/src/build/builder.c @@ -163,6 +163,7 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions * } target->no_stdlib = options->no_stdlib; target->emit_llvm = options->emit_llvm; + target->panicfn = options->panicfn; if (options->x86_vector_capability != X86VECTOR_DEFAULT) { target->feature.x86_vector_capability = options->x86_vector_capability; diff --git a/src/build/project.c b/src/build/project.c index d3d390f82..1fa96394a 100644 --- a/src/build/project.c +++ b/src/build/project.c @@ -120,7 +120,9 @@ static void load_into_build_target(JSONObject *json, const char *type, BuildTarg const char *cpu = get_valid_string(json, "cpu", type, false); int reloc = get_valid_string_setting(json, "reloc", type, reloc_models, 0, 5, "'none', 'pic', 'PIC', 'pie' or 'PIE'."); int x86vec = get_valid_string_setting(json, "x86vec", type, vector_capability, 0, 5, "none, mmx, sse, avx or avx512"); + const char *panicfn = get_valid_string(json, "panicfn", type, false); + target->panicfn = panicfn; if (cc) target->cc = cc; if (cflags) target->cflags = cflags; if (csource_dirs) target->csource_dirs = csource_dirs; @@ -156,6 +158,7 @@ static void load_into_build_target(JSONObject *json, const char *type, BuildTarg // Use the fact that they correspond to 0, 1, -1 target->feature.x86_struct_return = get_valid_bool(json, "x86-stack-struct-return", type, target->feature.x86_struct_return); target->feature.soft_float = get_valid_bool(json, "soft-float", type, target->feature.soft_float); + target->no_stdlib = get_valid_bool(json, "nostdlib", type, false); } static void project_add_target(Project *project, BuildTarget *default_target, JSONObject *json, const char *name, const char *type) diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 6e24a0a18..9fca0defa 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -1465,6 +1465,7 @@ typedef struct DeclTable symbols; DeclTable generic_symbols; Path std_module_path; + Decl *panic_fn; } GlobalContext; @@ -1645,21 +1646,6 @@ extern const char *kw_LINE; extern const char *kw_LINEREAL; extern const char *kw_incr; extern const char *kw_check_assign; -extern const char *kw_builtin_ceil; -extern const char *kw_builtin_trunc; -extern const char *kw_builtin_sqrt; -extern const char *kw_builtin_cos; -extern const char *kw_builtin_sin; -extern const char *kw_builtin_log; -extern const char *kw_builtin_log2; -extern const char *kw_builtin_log10; -extern const char *kw_builtin_max; -extern const char *kw_builtin_min; -extern const char *kw_builtin_pow; -extern const char *kw_builtin_exp; -extern const char *kw_builtin_fabs; -extern const char *kw_builtin_fma; -extern const char *kw_builtin_cmpxchg; extern const char *kw_argc; extern const char *kw_argv; extern const char *kw_mainstub; @@ -1675,6 +1661,11 @@ INLINE Expr *exprptrzero(ExprId id) return id ? exprptr(id) : NULL; } +INLINE Type *typeinfotype(TypeInfoId id_) +{ + return type_infoptr(id_)->type; +} + static inline bool ast_ok(Ast *ast) { return ast == NULL || ast->ast_kind != AST_POISONED; } static inline bool ast_poison(Ast *ast) { ast->ast_kind = AST_POISONED; return false; } bool ast_is_not_empty(Ast *ast); @@ -1987,6 +1978,7 @@ bool sema_expr_analyse_assign_right_side(SemaContext *context, Expr *expr, Type bool sema_expr_analyse_general_call(SemaContext *context, Expr *expr, Decl *decl, Expr *struct_var, bool is_macro, bool failable); Decl *sema_resolve_symbol_in_current_dynamic_scope(SemaContext *context, const char *symbol); +Decl *sema_find_decl_in_modules(Module **module_list, Path *path, const char *interned_name); Decl *unit_resolve_parameterized_symbol(CompilationUnit *unit, NameResolve *name_resolve); Decl *sema_resolve_method(CompilationUnit *unit, Decl *type, const char *method_name, Decl **ambiguous_ref, Decl **private_ref); Decl *sema_find_extension_method_in_module(Module *module, Type *type, const char *method_name); diff --git a/src/compiler/context.c b/src/compiler/context.c index 26800fb13..086a049ad 100644 --- a/src/compiler/context.c +++ b/src/compiler/context.c @@ -133,7 +133,7 @@ void unit_register_external_symbol(CompilationUnit *unit, Decl *decl) void decl_register(Decl *decl) { - if (decl->visibility != VISIBLE_PUBLIC) return; + if (decl->visibility != VISIBLE_PUBLIC && decl->visibility != VISIBLE_EXTERN) return; switch (decl->decl_kind) { case DECL_POISONED: diff --git a/src/compiler/enums.h b/src/compiler/enums.h index 6344b1741..6e4a07589 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -706,6 +706,9 @@ typedef enum typedef enum { + BUILTIN_UNREACHABLE, + BUILTIN_TRAP, + BUILTIN_STACKTRACE, BUILTIN_CEIL, BUILTIN_TRUNC, BUILTIN_SQRT, diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index 07c0b9305..21c19fe35 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -850,6 +850,13 @@ void *llvm_gen(Module *module) gencontext_init(gen_context, module); gencontext_begin_module(gen_context); + // Declare the panic function implicitly + Decl *panicfn = gen_context->panicfn; + if (panicfn && panicfn->module != module) + { + llvm_emit_extern_decl(gen_context, panicfn); + } + VECEACH(module->units, j) { CompilationUnit *unit = module->units[j]; @@ -857,11 +864,13 @@ void *llvm_gen(Module *module) gen_context->debug.compile_unit = unit->llvm.debug_compile_unit; gen_context->debug.file = unit->llvm.debug_file; + VECEACH(unit->external_symbol_list, i) { Decl *d = unit->external_symbol_list[i]; // Avoid duplicating symbol if (d->module == unit->module) continue; + if (d == panicfn) continue; llvm_emit_extern_decl(gen_context, unit->external_symbol_list[i]); } VECEACH(unit->methods, i) diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index f36d3f86a..dc6bf1d75 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -3590,8 +3590,7 @@ static inline void llvm_emit_force_unwrap_expr(GenContext *c, BEValue *be_value, // TODO, we should add info about the error. SourceSpan loc = expr->span; File *file = source_file_by_id(loc.file_id); - llvm_emit_debug_output(c, "Runtime error force unwrap!", file->name, c->cur_func_decl->extname, loc.row ? loc.row : 1); - llvm_emit_call_intrinsic(c, intrinsic_id.trap, NULL, 0, NULL, 0); + llvm_emit_panic(c, "Runtime error force unwrap!", file->name, c->cur_func_decl->extname, loc.row ? loc.row : 1); LLVMBuildUnreachable(c->builder); c->current_block = NULL; c->current_block_is_target = NULL; @@ -4213,12 +4212,12 @@ static void llvm_emit_intrinsic_expr(GenContext *c, unsigned intrinsic, BEValue LLVMValueRef arg_results[4]; for (unsigned i = 0; i < arguments; i++) { - llvm_emit_expr(c, be_value, expr->call_expr.arguments[0]); + llvm_emit_expr(c, be_value, expr->call_expr.arguments[i]); llvm_value_rvalue(c, be_value); arg_results[i] = be_value->value; } - LLVMTypeRef call_type = llvm_get_type(c, expr->type); - LLVMValueRef result = llvm_emit_call_intrinsic(c, intrinsic, &call_type, 1, arg_results, arguments); + LLVMTypeRef call_type = expr->type == type_void ? NULL : llvm_get_type(c, expr->type); + LLVMValueRef result = llvm_emit_call_intrinsic(c, intrinsic, &call_type, call_type ? 1 : 0, arg_results, arguments); llvm_value_set(be_value, result, expr->type); } @@ -4377,7 +4376,11 @@ unsigned llvm_get_intrinsic(BuiltinFunction func) switch (func) { case BUILTIN_NONE: + case BUILTIN_UNREACHABLE: + case BUILTIN_STACKTRACE: UNREACHABLE + case BUILTIN_TRAP: + return intrinsic_id.trap; case BUILTIN_CEIL: return intrinsic_id.ceil; case BUILTIN_TRUNC: @@ -4431,6 +4434,25 @@ LLVMAtomicOrdering llvm_atomic_ordering(Atomicity atomicity) void llvm_emit_builtin_call(GenContext *c, BEValue *result_value, Expr *expr) { BuiltinFunction func = exprptr(expr->call_expr.function)->builtin_expr.builtin; + if (func == BUILTIN_UNREACHABLE) + { + llvm_value_set(result_value, LLVMBuildUnreachable(c->builder), type_void); + c->current_block = NULL; + c->current_block_is_target = NULL; + LLVMBasicBlockRef after_unreachable = llvm_basic_block_new(c, "after.unreachable"); + llvm_emit_block(c, after_unreachable); + return; + } + if (func == BUILTIN_STACKTRACE) + { + if (!c->debug.enable_stacktrace) + { + llvm_value_set(result_value, llvm_get_zero(c, type_voidptr), type_voidptr); + return; + } + llvm_value_set(result_value, llvm_emit_bitcast(c, c->debug.stack_slot, type_voidptr), type_voidptr); + return; + } if (func == BUILTIN_VOLATILE_STORE) { BEValue value; @@ -4482,11 +4504,18 @@ void llvm_add_call_attributes(GenContext *c, LLVMValueRef call_value, int start_ } void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr) { + if (expr->call_expr.is_builtin) { llvm_emit_builtin_call(c, result_value, expr); return; } + + if (c->debug.stack_slot_row) + { + llvm_store(c, c->debug.stack_slot_row, llvm_const_int(c, type_uint, expr->span.row), type_abi_alignment(type_uint)); + } + LLVMTypeRef func_type; LLVMValueRef func; BEValue temp_value; diff --git a/src/compiler/llvm_codegen_function.c b/src/compiler/llvm_codegen_function.c index 3b9e40a51..2ae2e5a1b 100644 --- a/src/compiler/llvm_codegen_function.c +++ b/src/compiler/llvm_codegen_function.c @@ -402,62 +402,98 @@ void llvm_emit_return_implicit(GenContext *c) llvm_emit_return_abi(c, NULL, &value); } -void llvm_emit_function_body(GenContext *context, Decl *decl) +void llvm_emit_function_body(GenContext *c, Decl *decl) { DEBUG_LOG("Generating function %s.", decl->extname); assert(decl->backend_ref); - bool emit_debug = llvm_use_debug(context); - LLVMValueRef prev_function = context->function; - LLVMBuilderRef prev_builder = context->builder; + bool emit_debug = llvm_use_debug(c); + LLVMValueRef prev_function = c->function; + LLVMBuilderRef prev_builder = c->builder; - context->error_var = NULL; - context->catch_block = NULL; - context->function = decl->backend_ref; + c->error_var = NULL; + c->catch_block = NULL; + + c->function = decl->backend_ref; if (emit_debug) { - context->debug.function = LLVMGetSubprogram(context->function); + c->debug.function = LLVMGetSubprogram(c->function); + if (c->debug.enable_stacktrace) + { + scratch_buffer_clear(); + scratch_buffer_append(decl->module->name->module); + scratch_buffer_append("::"); + scratch_buffer_append(decl->name ? decl->name : "anon"); + c->debug.func_name = llvm_emit_zstring(c, scratch_buffer_to_string()); + + File *file = source_file_by_id(decl->span.file_id); + c->debug.file_name = llvm_emit_zstring(c, file->name); + } } - context->cur_func_decl = decl; + c->cur_func_decl = decl; - LLVMBasicBlockRef entry = LLVMAppendBasicBlockInContext(context->context, context->function, "entry"); - context->current_block = entry; - context->current_block_is_target = true; - context->block_return_exit = NULL; - context->in_block = 0; - context->builder = LLVMCreateBuilderInContext(context->context); - LLVMPositionBuilderAtEnd(context->builder, entry); + LLVMBasicBlockRef entry = LLVMAppendBasicBlockInContext(c->context, c->function, "entry"); + c->current_block = entry; + c->current_block_is_target = true; + c->block_return_exit = NULL; + c->in_block = 0; + c->builder = LLVMCreateBuilderInContext(c->context); + LLVMPositionBuilderAtEnd(c->builder, entry); - LLVMValueRef alloca_point = LLVMBuildAlloca(context->builder, LLVMInt32TypeInContext(context->context), "alloca_point"); - context->alloca_point = alloca_point; + LLVMValueRef alloca_point = LLVMBuildAlloca(c->builder, LLVMInt32TypeInContext(c->context), "alloca_point"); + c->alloca_point = alloca_point; FunctionPrototype *prototype = decl->type->func.prototype; unsigned arg = 0; if (emit_debug) { - llvm_debug_scope_push(context, context->debug.function); + llvm_debug_scope_push(c, c->debug.function); + if (c->debug.enable_stacktrace) + { + LLVMTypeRef slot_type = c->debug.stack_type; + LLVMTypeRef ptr_to_slot_type = LLVMPointerType(slot_type, 0); + if (!c->debug.last_ptr) + { + LLVMValueRef last_stack = c->debug.last_ptr = LLVMAddGlobal(c->module, ptr_to_slot_type, ".$last_stack"); + LLVMSetThreadLocal(last_stack, true); + LLVMSetInitializer(last_stack, LLVMConstNull(ptr_to_slot_type)); + LLVMSetVisibility(last_stack, LLVMDefaultVisibility); + LLVMSetLinkage(last_stack, LLVMWeakODRLinkage); + } + AlignSize alignment = llvm_abi_alignment(c, slot_type); + c->debug.stack_slot = llvm_emit_alloca(c, slot_type, alignment, ".$stackslot"); + AlignSize align_to_use; + LLVMValueRef prev_ptr = llvm_emit_struct_gep_raw(c, c->debug.stack_slot, slot_type, 0, alignment, &align_to_use); + llvm_store(c, prev_ptr, LLVMBuildLoad2(c->builder, ptr_to_slot_type, c->debug.last_ptr, ""), align_to_use); + LLVMValueRef func_name = llvm_emit_struct_gep_raw(c, c->debug.stack_slot, slot_type, 1, alignment, &align_to_use); + llvm_store(c, func_name, c->debug.func_name, align_to_use); + LLVMValueRef file_name = llvm_emit_struct_gep_raw(c, c->debug.stack_slot, slot_type, 2, alignment, &align_to_use); + llvm_store(c, file_name, c->debug.file_name, align_to_use); + c->debug.stack_slot_row = llvm_emit_struct_gep_raw(c, c->debug.stack_slot, slot_type, 3, alignment, &align_to_use); + llvm_store(c, c->debug.last_ptr, c->debug.stack_slot, type_alloca_alignment(type_voidptr)); + } } - context->failable_out = NULL; - context->return_out = NULL; + c->failable_out = NULL; + c->return_out = NULL; if (prototype->ret_abi_info->kind == ABI_ARG_INDIRECT) { if (prototype->is_failable) { - context->failable_out = LLVMGetParam(context->function, arg++); + c->failable_out = LLVMGetParam(c->function, arg++); } else { - context->return_out = LLVMGetParam(context->function, arg++); + c->return_out = LLVMGetParam(c->function, arg++); } } if (prototype->ret_by_ref_abi_info) { - assert(!context->return_out); - context->return_out = LLVMGetParam(context->function, arg++); + assert(!c->return_out); + c->return_out = LLVMGetParam(c->function, arg++); } @@ -466,49 +502,49 @@ void llvm_emit_function_body(GenContext *context, Decl *decl) // Generate LLVMValueRef's for all parameters, so we can use them as local vars in code VECEACH(decl->func_decl.function_signature.params, i) { - llvm_emit_parameter(context, decl->func_decl.function_signature.params[i], prototype->abi_args[i], &arg, i); + llvm_emit_parameter(c, decl->func_decl.function_signature.params[i], prototype->abi_args[i], &arg, i); } } - LLVMSetCurrentDebugLocation2(context->builder, NULL); + LLVMSetCurrentDebugLocation2(c->builder, NULL); assert(decl->func_decl.body); AstId current = astptr(decl->func_decl.body)->compound_stmt.first_stmt; while (current) { - llvm_emit_stmt(context, ast_next(¤t)); + llvm_emit_stmt(c, ast_next(¤t)); } - if (context->current_block && llvm_basic_block_is_unused(context->current_block)) + if (c->current_block && llvm_basic_block_is_unused(c->current_block)) { - LLVMBasicBlockRef prev_block = LLVMGetPreviousBasicBlock(context->current_block); - LLVMDeleteBasicBlock(context->current_block); - context->current_block = prev_block; - LLVMPositionBuilderAtEnd(context->builder, context->current_block); + LLVMBasicBlockRef prev_block = LLVMGetPreviousBasicBlock(c->current_block); + LLVMDeleteBasicBlock(c->current_block); + c->current_block = prev_block; + LLVMPositionBuilderAtEnd(c->builder, c->current_block); } // Insert a return (and defer) if needed. - if (context->current_block && !LLVMGetBasicBlockTerminator(context->current_block)) + if (c->current_block && !LLVMGetBasicBlockTerminator(c->current_block)) { - llvm_emit_return_implicit(context); + llvm_emit_return_implicit(c); } // erase alloca point if (LLVMGetInstructionParent(alloca_point)) { - context->alloca_point = NULL; + c->alloca_point = NULL; LLVMInstructionEraseFromParent(alloca_point); } - LLVMDisposeBuilder(context->builder); - context->builder = NULL; + LLVMDisposeBuilder(c->builder); + c->builder = NULL; - if (llvm_use_debug(context)) + if (llvm_use_debug(c)) { - llvm_debug_scope_pop(context); + llvm_debug_scope_pop(c); } - context->builder = prev_builder; - context->function = prev_function; + c->builder = prev_builder; + c->function = prev_function; } static void llvm_emit_param_attributes(GenContext *c, LLVMValueRef function, ABIArgInfo *info, bool is_return, int index, int last_index) diff --git a/src/compiler/llvm_codegen_internal.h b/src/compiler/llvm_codegen_internal.h index 88510e39f..8436e8e29 100644 --- a/src/compiler/llvm_codegen_internal.h +++ b/src/compiler/llvm_codegen_internal.h @@ -51,6 +51,7 @@ typedef struct typedef struct { unsigned runtime_version : 8; + bool enable_stacktrace : 1; LLVMDIBuilderRef builder; LLVMMetadataRef file; LLVMMetadataRef compile_unit; @@ -58,6 +59,12 @@ typedef struct SourceSpan current_range; LLVMMetadataRef *lexical_block_stack; LLVMMetadataRef inlined_at; + LLVMValueRef func_name; + LLVMValueRef file_name; + LLVMValueRef last_ptr; + LLVMTypeRef stack_type; + LLVMValueRef stack_slot; + LLVMValueRef stack_slot_row; } DebugContext; @@ -78,6 +85,7 @@ typedef struct LLVMValueRef error_var; LLVMTypeRef bool_type; LLVMTypeRef byte_type; + Decl *panicfn; Decl *cur_code_decl; Decl *cur_func_decl; TypeInfo *current_return_type; @@ -97,7 +105,6 @@ typedef struct BEValue retval; int in_block; bool current_block_is_target : 1; - bool did_call_stack_save : 1; LLVMTypeRef type_data_definitions[TYPE_KINDS]; SourceSpan last_emitted_loc; } GenContext; @@ -202,6 +209,7 @@ LLVMAttributeRef LLVMCreateTypeAttribute(LLVMContextRef C, unsigned KindID, LLVMTypeRef type_ref); #endif + // BE value void llvm_value_addr(GenContext *c, BEValue *value); static inline bool llvm_value_is_addr(BEValue *value) { return value->kind == BE_ADDRESS || value->kind == BE_ADDRESS_FAILABLE; } @@ -305,11 +313,12 @@ void llvm_store_zero(GenContext *c, BEValue *ref); void llvm_emit_memcpy(GenContext *c, LLVMValueRef dest, unsigned dest_align, LLVMValueRef source, unsigned src_align, uint64_t len); void llvm_emit_memcpy_to_decl(GenContext *c, Decl *decl, LLVMValueRef source, unsigned source_alignment); void llvm_emit_stmt(GenContext *c, Ast *ast); +LLVMValueRef llvm_emit_zstring(GenContext *c, const char *str); static inline LLVMValueRef llvm_emit_store(GenContext *context, Decl *decl, LLVMValueRef value); void llvm_emit_panic_on_true(GenContext *c, LLVMValueRef value, const char *panic_name, SourceSpan loc); void llvm_emit_panic_if_true(GenContext *c, BEValue *value, const char *panic_name, SourceSpan loc); void llvm_emit_ptr_from_array(GenContext *c, BEValue *value); -void llvm_emit_debug_output(GenContext *c, const char *message, const char *file, const char *func, unsigned line); +void llvm_emit_panic(GenContext *c, const char *message, const char *file, const char *func, unsigned line); void llvm_emit_return_abi(GenContext *c, BEValue *return_value, BEValue *failable); void llvm_emit_return_implicit(GenContext *c); void llvm_emit_struct_member_ref(GenContext *c, BEValue *struct_ref, BEValue *member_ref, unsigned member_id); diff --git a/src/compiler/llvm_codegen_module.c b/src/compiler/llvm_codegen_module.c index b86c5a61d..66db28cd0 100644 --- a/src/compiler/llvm_codegen_module.c +++ b/src/compiler/llvm_codegen_module.c @@ -13,6 +13,7 @@ void gencontext_begin_module(GenContext *c) c->ir_filename = strformat("%s.ll", result); c->object_filename = strformat("%s%s", result, get_object_extension()); + c->panicfn = global_context.panic_fn; c->module = LLVMModuleCreateWithNameInContext(c->code_module->name->module, c->context); c->machine = llvm_target_machine_create(); c->target_data = LLVMCreateTargetDataLayout(c->machine); @@ -60,10 +61,23 @@ void gencontext_begin_module(GenContext *c) global_context.type[i]->backend_debug_type = NULL; global_context.type[i]->backend_typeid = NULL; } + if (c->panicfn) c->panicfn->backend_ref = NULL; + if (active_target.debug_info != DEBUG_INFO_NONE) { c->debug.runtime_version = 1; c->debug.builder = LLVMCreateDIBuilder(c->module); + if (active_target.debug_info == DEBUG_INFO_FULL && active_target.feature.safe_mode) + { + c->debug.stack_type = LLVMStructCreateNamed(c->context, ".$callstack"); + LLVMTypeRef types[4] = { LLVMPointerType(c->debug.stack_type, 0), + LLVMPointerType(c->byte_type, 0), + LLVMPointerType(c->byte_type, 0), + llvm_get_type(c, type_uint) }; + LLVMStructSetBody(c->debug.stack_type, types, 4, false); + c->debug.last_ptr = NULL; + c->debug.enable_stacktrace = true; + } } } diff --git a/src/compiler/llvm_codegen_stmt.c b/src/compiler/llvm_codegen_stmt.c index 2667edb8a..ce03b0b78 100644 --- a/src/compiler/llvm_codegen_stmt.c +++ b/src/compiler/llvm_codegen_stmt.c @@ -420,7 +420,8 @@ void llvm_emit_for_stmt(GenContext *c, Ast *ast) { SourceSpan loc = ast->span; File *file = source_file_by_id(loc.file_id); - llvm_emit_debug_output(c, "Infinite loop found", file->name, c->cur_func_decl->extname, loc.row ? loc.row : 1); + + llvm_emit_panic(c, "Infinite loop found", file->name, c->cur_func_decl->extname, loc.row ? loc.row : 1); LLVMBuildUnreachable(c->builder); LLVMBasicBlockRef block = llvm_basic_block_new(c, "unreachable_block"); c->current_block = NULL; @@ -928,19 +929,6 @@ static inline void llvm_emit_assume(GenContext *c, Expr *expr) static inline void llvm_emit_assert_stmt(GenContext *c, Ast *ast) { ExprId exprid = ast->assert_stmt.expr; - if (!exprid) - { - File *file = source_file_by_id(ast->span.file_id); - unsigned row = ast->span.row; - llvm_emit_debug_output(c, "Unreachable statement reached.", file->name, c->cur_func_decl->extname, row ? row : 1); - llvm_emit_call_intrinsic(c, intrinsic_id.trap, NULL, 0, NULL, 0); - LLVMBuildUnreachable(c->builder); - LLVMBasicBlockRef block = llvm_basic_block_new(c, "unreachable_block"); - c->current_block = NULL; - c->current_block_is_target = false; - llvm_emit_block(c, block); - return; - } Expr *assert_expr = exprptr(exprid); if (active_target.feature.safe_mode) @@ -964,8 +952,7 @@ static inline void llvm_emit_assert_stmt(GenContext *c, Ast *ast) error = "Assert violation"; } File *file = source_file_by_id(loc.file_id); - llvm_emit_debug_output(c, error, file->name, c->cur_func_decl->name, loc.row ? loc.row : 1); - llvm_emit_call_intrinsic(c, intrinsic_id.trap, NULL, 0, NULL, 0); + llvm_emit_panic(c, error, file->name, c->cur_func_decl->name, loc.row ? loc.row : 1); llvm_emit_br(c, on_ok); llvm_emit_block(c, on_ok); } @@ -1032,7 +1019,7 @@ void gencontext_emit_expr_stmt(GenContext *c, Ast *ast) llvm_emit_expr(c, &value, ast->expr_stmt); } -static LLVMValueRef llvm_emit_string(GenContext *c, const char *str) +LLVMValueRef llvm_emit_zstring(GenContext *c, const char *str) { LLVMTypeRef char_type = llvm_get_type(c, type_char); unsigned len = (unsigned)strlen(str); @@ -1047,129 +1034,30 @@ static LLVMValueRef llvm_emit_string(GenContext *c, const char *str) 1, &alignment); return LLVMBuildBitCast(c->builder, string, LLVMPointerType(char_type, 0), ""); } -void llvm_emit_debug_output(GenContext *c, const char *message, const char *file, const char *func, unsigned line) + + +void llvm_emit_panic(GenContext *c, const char *message, const char *file, const char *func, unsigned line) { + if (c->debug.stack_slot_row) + { + llvm_store(c, c->debug.stack_slot_row, llvm_const_int(c, type_uint, line), type_abi_alignment(type_uint)); + } + + Decl *panicfn = c->panicfn; + if (!panicfn) + { + llvm_emit_call_intrinsic(c, intrinsic_id.trap, NULL, 0, NULL, 0); + return; + } LLVMTypeRef char_ptr_type = llvm_get_ptr_type(c, type_char); - LLVMTypeRef cint_type = llvm_get_type(c, type_cint); - const char *name; - int file_index; - int line_index; - int expr_index; - int func_index = -1; - OsType os = platform_target.os; - if (platform_target.arch == ARCH_TYPE_WASM32 || platform_target.arch == ARCH_TYPE_WASM64) os = OS_TYPE_WASI; - switch (os) - { - case OS_TYPE_WIN32: - name = "_assert"; - expr_index = 0; - file_index = 1; - line_index = 2; - break; - case OS_DARWIN_TYPES: - name = "__assert_rtn"; - func_index = 0; - expr_index = 3; - file_index = 1; - line_index = 2; - break; - case OS_TYPE_SOLARIS: - name = "__assert_c99"; - expr_index = 0; - file_index = 1; - line_index = 2; - func_index = 3; - break; - case OS_TYPE_LINUX: - case OS_TYPE_WASI: - name = "__assert_fail"; - expr_index = 0; - file_index = 1; - line_index = 2; - func_index = 3; - break; - case OS_TYPE_OPENBSD: - name = "__assert2"; - file_index = 0; - line_index = 1; - func_index = 2; - expr_index = 3; - break; - default: - name = "__assert"; - expr_index = 0; - file_index = 1; - line_index = 2; - func_index = -1; - break; - } - - LLVMTypeRef type; - LLVMTypeRef void_type = LLVMVoidTypeInContext(c->context); - switch (os) - { - case OS_TYPE_WIN32: - case OS_TYPE_FREE_BSD: - case OS_TYPE_DRAGON_FLY: - { - LLVMTypeRef args[3] = { char_ptr_type, char_ptr_type, cint_type }; - type = LLVMFunctionType(void_type, args, 3, false); - break; - } - case OS_DARWIN_TYPES: - case OS_TYPE_WASI: - case OS_TYPE_LINUX: - case OS_TYPE_SOLARIS: - { - LLVMTypeRef args[4] = { char_ptr_type, char_ptr_type, cint_type, char_ptr_type }; - type = LLVMFunctionType(void_type, args, 4, false); - break; - } - case OS_TYPE_OPENBSD: - { - LLVMTypeRef args[4] = { char_ptr_type, cint_type, char_ptr_type, char_ptr_type }; - type = LLVMFunctionType(void_type, args, 4, false); - break; - } - case OS_TYPE_NETBSD: - { - LLVMTypeRef args[3] = { char_ptr_type, cint_type, char_ptr_type }; - type = LLVMFunctionType(void_type, args, 3, false); - break; - } - default: - { - LLVMTypeRef args[3] = { char_ptr_type, char_ptr_type, cint_type }; - type = LLVMFunctionType(void_type, args, 3, false); - break; - } - } - LLVMValueRef assert_func = LLVMGetNamedFunction(c->module, name); - if (!assert_func) - { - assert_func = LLVMAddFunction(c->module, name, type); - } - - LLVMValueRef args[4]; - - if (func_index == -1) - { - scratch_buffer_clear(); - scratch_buffer_append(file); - scratch_buffer_append(" : "); - scratch_buffer_append(func); - file = scratch_buffer_to_string(); - } - else - { - args[func_index] = llvm_emit_string(c, func); - } - args[file_index] = llvm_emit_string(c, file); - args[expr_index] = llvm_emit_string(c, message); - args[line_index] = llvm_const_int(c, type_cint, line); - - LLVMBuildCall2(c->builder, type, assert_func, args, func_index > -1 ? 4 : 3, ""); + LLVMValueRef args[4] = { + llvm_emit_zstring(c, message), + llvm_emit_zstring(c, file), + func ? llvm_emit_zstring(c, func) : LLVMConstNull(char_ptr_type), + llvm_const_int(c, type_uint, line) + }; + LLVMBuildCall2(c->builder, llvm_get_type(c, panicfn->type), panicfn->backend_ref, args, 4, ""); } void llvm_emit_panic_if_true(GenContext *c, BEValue *value, const char *panic_name, SourceSpan loc) @@ -1180,8 +1068,7 @@ void llvm_emit_panic_if_true(GenContext *c, BEValue *value, const char *panic_na llvm_emit_cond_br(c, value, panic_block, ok_block); llvm_emit_block(c, panic_block); File *file = source_file_by_id(loc.file_id); - llvm_emit_debug_output(c, panic_name, file->name, c->cur_func_decl->name, loc.row); - llvm_emit_call_intrinsic(c, intrinsic_id.trap, NULL, 0, NULL, 0); + llvm_emit_panic(c, panic_name, file->name, c->cur_func_decl->name, loc.row); llvm_emit_br(c, ok_block); llvm_emit_block(c, ok_block); } @@ -1195,8 +1082,7 @@ void llvm_emit_panic_on_true(GenContext *c, LLVMValueRef value, const char *pani llvm_value_set_bool(&be_value, value); llvm_emit_cond_br(c, &be_value, panic_block, ok_block); llvm_emit_block(c, panic_block); - llvm_emit_debug_output(c, panic_name, file->name, c->cur_func_decl->name, loc.row ? loc.row : 1); - llvm_emit_call_intrinsic(c, intrinsic_id.trap, NULL, 0, NULL, 0); + llvm_emit_panic(c, panic_name, file->name, c->cur_func_decl->name, loc.row ? loc.row : 1); llvm_emit_br(c, ok_block); llvm_emit_block(c, ok_block); } diff --git a/src/compiler/parse_global.c b/src/compiler/parse_global.c index 4d4130a26..41bafebb3 100644 --- a/src/compiler/parse_global.c +++ b/src/compiler/parse_global.c @@ -2092,7 +2092,6 @@ static inline bool parse_doc_contract(ParseContext *c, AstId **docs_ref, DocDire ASSIGN_EXPR_OR_RET(ast->doc_stmt.contract.decl_exprs, parse_expression_list(c, kind == DOC_DIRECTIVE_CHECKED), false); const char *end = start; while (*++end != '\n' && *end != '\0') end++; - end--; if (end > c->data.lex_start) end = c->data.lex_start; while (end[-1] == ' ') end--; scratch_buffer_clear(); diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 42b228932..d0ce99372 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -67,51 +67,18 @@ const char *ct_eval_expr(SemaContext *c, const char *expr_type, Expr *inner, Tok SEMA_ERROR(inner, "'%s' expects a constant string as the argument.", expr_type); return ct_eval_error; } - const char *string = inner->const_expr.string.chars; - ArraySize len = inner->const_expr.string.len; - - ArraySize path_end = 0; - for (ArraySize i = 0; i < len; i++) - { - char ch = string[i]; - if (!is_alphanum_(ch)) - { - if (ch == ':' && i > 0 && string[i + 1] == ':') - { - path_end = i; - i++; - } - else - { - SEMA_ERROR(inner, "A valid name was expected here."); - return ct_eval_error; - } - } - } - if (path_end > 0) - { - *path_ref = path_create_from_string(string, path_end, inner->span); - string += path_end + 2; - len -= path_end + 2; - } - if (len == 0) + const char *interned_version = NULL; + if (!splitpathref(inner->const_expr.string.chars, inner->const_expr.string.len, path_ref, &interned_version, type)) { SEMA_ERROR(inner, "A valid name was expected here."); return ct_eval_error; } - const char *interned_version = symtab_find(string, len, fnv1a(string, len), type); - if (!interned_version) + if (*path_ref) (*path_ref)->span = inner->span; + if (*type == TOKEN_INVALID_TOKEN) { if (report_missing) { - if (*path_ref) - { - SEMA_ERROR(inner, "'%s::%.*s' could not be found, did you spell it right?", (*path_ref)->module, (int)len, string); - } - else - { - SEMA_ERROR(inner, "'%.*s' could not be found, did you spell it right?", (int)len, string); - } + SEMA_ERROR(inner, "'%s' could not be found, did you spell it right?", interned_version); return ct_eval_error; } return NULL; @@ -2209,6 +2176,10 @@ static inline unsigned builtin_expected_args(BuiltinFunction func) { switch (func) { + case BUILTIN_UNREACHABLE: + case BUILTIN_TRAP: + case BUILTIN_STACKTRACE: + return 0; case BUILTIN_CEIL: case BUILTIN_TRUNC: case BUILTIN_SQRT: @@ -2271,6 +2242,13 @@ static inline bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *ex Type *rtype = NULL; switch (func) { + case BUILTIN_UNREACHABLE: + case BUILTIN_TRAP: + rtype = type_void; + break; + case BUILTIN_STACKTRACE: + rtype = type_voidptr; + break; case BUILTIN_CEIL: case BUILTIN_TRUNC: case BUILTIN_SQRT: @@ -6221,7 +6199,7 @@ static inline bool sema_expr_analyse_compiler_const(SemaContext *context, Expr * const char *string = expr->builtin_expr.ident; if (string == kw_FILE) { - expr_rewrite_to_string(expr, context->unit->file->name); + expr_rewrite_to_string(expr, context->compilation_unit->file->name); return true; } if (string == kw_FUNC) @@ -7314,3 +7292,59 @@ bool sema_analyse_inferred_expr(SemaContext *context, Type *infer_type, Expr *ex return true; } +bool splitpathref(const char *string, ArraySize len, Path **path_ref, const char **ident_ref, TokenType *type_ref) +{ + ArraySize path_end = 0; + *path_ref = NULL; + for (ArraySize i = 0; i < len; i++) + { + char ch = string[i]; + if (!is_alphanum_(ch)) + { + if (ch == ':' && i > 0 && string[i + 1] == ':') + { + path_end = i; + i++; + } + else + { + return false; + } + } + } + if (path_end > 0) + { + *path_ref = path_create_from_string(string, path_end, INVALID_SPAN); + string += path_end + 2; + len -= path_end + 2; + } + while (len > 0) + { + char c = string[0]; + if (c != ' ' && c != '\t') break; + len--; + string++; + } + if (len == 0) return false; + uint32_t hash = FNV1_SEED; + for (size_t i = 0; i < len; i++) + { + char c = string[i]; + if (!is_alphanum_(c)) return false; + hash = FNV1a(c, hash); + } + *ident_ref = symtab_find(string, len, hash, type_ref); + if (!*ident_ref) + { + scratch_buffer_clear(); + if (*path_ref) + { + scratch_buffer_append_len((*path_ref)->module, (*path_ref)->len); + scratch_buffer_append("::"); + } + scratch_buffer_append_len(string, len); + *ident_ref = scratch_buffer_to_string(); + *type_ref = TOKEN_INVALID_TOKEN; + } + return true; +} \ No newline at end of file diff --git a/src/compiler/sema_internal.h b/src/compiler/sema_internal.h index bcdf2f67e..d1b19f6a4 100644 --- a/src/compiler/sema_internal.h +++ b/src/compiler/sema_internal.h @@ -42,6 +42,7 @@ void context_pop_defers_and_replace_ast(SemaContext *context, Ast *ast); void context_change_scope_for_label(SemaContext *context, Decl *label); void context_change_scope_with_flags(SemaContext *context, ScopeFlags flags); bool sema_analyse_defer_stmt_body(SemaContext *context, Ast *statement, Ast *body); +bool splitpathref(const char *string, ArraySize len, Path **path_ref, const char **ident_ref, TokenType *type_ref); #define PUSH_X(ast, X) AstId _old_##X##_defer = context->X##_defer; AstId _old_##X = context->X##_target; context->X##_target = ast ? astid(ast) : 0; context->X##_defer = context->active_scope.defer_last #define POP_X(X) context->X##_target = _old_##X; context->X##_defer = _old_##X##_defer diff --git a/src/compiler/sema_name_resolution.c b/src/compiler/sema_name_resolution.c index 6048c0dd9..7846c743a 100644 --- a/src/compiler/sema_name_resolution.c +++ b/src/compiler/sema_name_resolution.c @@ -104,6 +104,17 @@ static inline bool sema_is_path_found(Module **modules, Path *path, bool want_ge return false; } +Decl *sema_find_decl_in_modules(Module **module_list, Path *path, const char *interned_name) +{ + bool path_found = false; + VECEACH(module_list, i) + { + Module *module = module_list[i]; + Decl *decl = sema_find_decl_in_module(module, path, interned_name, &path_found); + if (decl) return decl; + } + return NULL; +} static Decl *sema_find_decl_in_global(DeclTable *table, Module **module_list, NameResolve *name_resolve, bool want_generic) { const char *symbol = name_resolve->symbol; diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index a0c254c55..0fa852f87 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -2159,8 +2159,6 @@ bool sema_analyse_assert_stmt(SemaContext *context, Ast *statement) } return false; } - - statement->assert_stmt.expr = 0; context->active_scope.jump_end = true; } } diff --git a/src/compiler/semantic_analyser.c b/src/compiler/semantic_analyser.c index c1e45cd3a..a253f6408 100644 --- a/src/compiler/semantic_analyser.c +++ b/src/compiler/semantic_analyser.c @@ -318,6 +318,41 @@ void sema_analysis_run(void) { sema_analyze_to_stage(stage); } + + if (active_target.panicfn || !active_target.no_stdlib) + { + const char *panicfn = active_target.panicfn ? active_target.panicfn : "std::builtin::panic"; + Path *path; + const char *ident; + TokenType type; + if (!splitpathref(panicfn, strlen(panicfn), &path, &ident, &type) || path == NULL) + { + error_exit("'%s' is not a valid panic function.", panicfn); + } + Decl *decl = sema_find_decl_in_modules(global_context.module_list, path, ident); + if (!decl) + { + error_exit("Panic function '%s::%s' could not be found.", path->module, ident); + } + if (decl->decl_kind != DECL_FUNC) + { + error_exit("'%s::%s' is not a function.", path->module, ident); + } + Decl **params = decl->func_decl.function_signature.params; + if (vec_size(params) != 4 || params[0]->type != type_get_ptr(type_char) + || params[1]->type != type_get_ptr(type_char) + || params[2]->type != type_get_ptr(type_char) + || params[3]->type != type_uint + || typeinfotype(decl->func_decl.function_signature.returntype) != type_void) + { + error_exit("Expected panic function to have the signature fn void(char*, char*, uint, uint)."); + } + global_context.panic_fn = decl; + } + else + { + global_context.panic_fn = NULL; + } compiler_sema_time = bench_mark(); } diff --git a/src/compiler/symtab.c b/src/compiler/symtab.c index 225da31fb..5d67fb29b 100644 --- a/src/compiler/symtab.c +++ b/src/compiler/symtab.c @@ -83,21 +83,6 @@ const char *kw_LINE; const char *kw_LINEREAL; const char *kw_incr; const char *kw_check_assign; -const char *kw_builtin_ceil; -const char *kw_builtin_trunc; -const char *kw_builtin_sqrt; -const char *kw_builtin_cos; -const char *kw_builtin_sin; -const char *kw_builtin_log; -const char *kw_builtin_log2; -const char *kw_builtin_log10; -const char *kw_builtin_max; -const char *kw_builtin_min; -const char *kw_builtin_pow; -const char *kw_builtin_exp; -const char *kw_builtin_fabs; -const char *kw_builtin_fma; -const char *kw_builtin_cmpxchg; const char *kw_argc; const char *kw_argv; const char *kw_mainstub;; @@ -140,8 +125,14 @@ void symtab_init(uint32_t capacity) } // Init some constant idents - TokenType type = TOKEN_IDENT; #define KW_DEF(x) symtab_add(x, sizeof(x) - 1, fnv1a(x, sizeof(x) - 1), &type) + TokenType type = TOKEN_CONST_IDENT; + kw_LINE = KW_DEF("LINE"); + kw_LINEREAL = KW_DEF("LINEREAL"); + kw_FILE = KW_DEF("FILE"); + kw_FUNC = KW_DEF("FUNC"); + + type = TOKEN_IDENT; kw_sizeof = KW_DEF("sizeof"); kw_in = KW_DEF("in"); kw_out = KW_DEF("out"); @@ -171,10 +162,6 @@ void symtab_init(uint32_t capacity) kw_require = KW_DEF("require"); kw_std = KW_DEF("std"); kw_values = KW_DEF("values"); - kw_LINE = KW_DEF("LINE"); - kw_LINEREAL = KW_DEF("LINEREAL"); - kw_FILE = KW_DEF("FILE"); - kw_FUNC = KW_DEF("FUNC"); kw_incr = KW_DEF("incr"); kw_check_assign = KW_DEF("check_assign"); @@ -182,6 +169,9 @@ void symtab_init(uint32_t capacity) kw_argv = KW_DEF("_$argv"); kw_mainstub = KW_DEF("_$mainstub"); + builtin_list[BUILTIN_TRAP] = KW_DEF("trap"); + builtin_list[BUILTIN_UNREACHABLE] = KW_DEF("unreachable"); + builtin_list[BUILTIN_STACKTRACE] = KW_DEF("stacktrace"); builtin_list[BUILTIN_CEIL] = KW_DEF("ceil"); builtin_list[BUILTIN_TRUNC] = KW_DEF("trunc"); builtin_list[BUILTIN_SIN] = KW_DEF("sin"); diff --git a/src/compiler/target.c b/src/compiler/target.c index cf356e17b..ac37db205 100644 --- a/src/compiler/target.c +++ b/src/compiler/target.c @@ -263,6 +263,30 @@ static AlignSize os_arch_max_alignment_of_tls(OsType os, ArchType arch, Environm return 0; } +static bool os_target_use_thread_local(OsType os) +{ + switch (os) + { + case OS_UNSUPPORTED: + return false; + case OS_TYPE_UNKNOWN: + case OS_TYPE_NONE: + return false; + case OS_TYPE_FREE_BSD: + case OS_TYPE_IOS: + case OS_TYPE_LINUX: + case OS_TYPE_MACOSX: + case OS_TYPE_NETBSD: + case OS_TYPE_OPENBSD: + case OS_TYPE_WIN32: + case OS_TYPE_TVOS: + case OS_TYPE_WATCHOS: + case OS_TYPE_WASI: + return true; + } + UNREACHABLE +} + static bool os_target_signed_c_char_type(OsType os, ArchType arch) { switch (arch) @@ -1293,11 +1317,10 @@ void target_setup(BuildTarget *target) // TLS should not be supported for: // ARM Cygwin // NVPTX - platform_target.tls_supported = true; + platform_target.tls_supported = os_target_use_thread_local(platform_target.os); platform_target.big_endian = arch_big_endian(platform_target.arch); platform_target.width_pointer = arch_pointer_bit_width(platform_target.os, platform_target.arch); platform_target.alloca_address_space = 0; - platform_target.object_format = object_format_from_os(platform_target.os); platform_target.int128 = os_target_supports_int128(platform_target.os, platform_target.arch); diff --git a/test/test_suite/assert/unreachable.c3t b/test/test_suite/assert/unreachable.c3t index 0ea68332d..dcd444acb 100644 --- a/test/test_suite/assert/unreachable.c3t +++ b/test/test_suite/assert/unreachable.c3t @@ -15,22 +15,27 @@ fn void test() // #expect: unreachable.ll - %x = alloca i32 - %0 = call i32 @unreachable.foo() - store i32 %0, i32* %x - %1 = load i32, i32* %x - %gt = icmp sgt i32 %1, 0 - br i1 %gt, label %if.then, label %if.exit -if.then: - ret void +define void @unreachable.test() #0 { +entry: + %x = alloca i32, align 4 + %0 = call i32 @unreachable.foo() + store i32 %0, i32* %x, align 4 + %1 = load i32, i32* %x, align 4 + %gt = icmp sgt i32 %1, 0 + br i1 %gt, label %if.then, label %if.exit -if.exit: - call void @llvm.trap() - unreachable +if.then: ; preds = %entry + ret void + +if.exit: ; preds = %entry + call void @"std::builtin.panic"(i8* getelementptr inbounds ([31 x i8], [31 x i8]* @.str, i32 0, i32 0), i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.str.1, i32 0, i32 0), i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.2, i32 0, i32 0), i32 11) + unreachable + +after.unreachable: ; No predecessors! + %2 = load i32, i32* %x, align 4 + %add = add i32 %2, 1 + store i32 %add, i32* %x, align 4 + ret void +} -unreachable_block: - %2 = load i32, i32* %x - %add = add i32 %2, 1 - store i32 %add, i32* %x - ret void diff --git a/test/test_suite/builtins/simple_builtins.c3t b/test/test_suite/builtins/simple_builtins.c3t index 761ce25ad..b2c394d87 100644 --- a/test/test_suite/builtins/simple_builtins.c3t +++ b/test/test_suite/builtins/simple_builtins.c3t @@ -28,31 +28,30 @@ entry: %sy = alloca i32, align 4 %1 = call double @llvm.ceil.f64(double %0) store double %1, double* %d, align 8 - %2 = call double @llvm.maxnum.f64(double 1.000000e+00, double 1.000000e+00) - store double %2, double* %e, align 8 - %3 = load double, double* %d, align 8 + %2 = load double, double* %d, align 8 + %3 = call double @llvm.maxnum.f64(double 1.000000e+00, double %2) + store double %3, double* %e, align 8 %4 = load double, double* %d, align 8 - %5 = load double, double* %d, align 8 - %6 = call double @llvm.fma.f64(double %3, double %4, double %5) - store double %6, double* %f, align 8 + %5 = call double @llvm.fma.f64(double %4, double 2.000000e+00, double 3.000000e+00) + store double %5, double* %f, align 8 store i32 13, i32* %xeb, align 4 - %7 = getelementptr inbounds [3 x i32], [3 x i32]* %abcd, i64 0, i64 0 + %6 = getelementptr inbounds [3 x i32], [3 x i32]* %abcd, i64 0, i64 0 + store i32 0, i32* %6, align 4 + %7 = getelementptr inbounds [3 x i32], [3 x i32]* %abcd, i64 0, i64 1 store i32 0, i32* %7, align 4 - %8 = getelementptr inbounds [3 x i32], [3 x i32]* %abcd, i64 0, i64 1 + %8 = getelementptr inbounds [3 x i32], [3 x i32]* %abcd, i64 0, i64 2 store i32 0, i32* %8, align 4 - %9 = getelementptr inbounds [3 x i32], [3 x i32]* %abcd, i64 0, i64 2 - store i32 0, i32* %9, align 4 - %10 = load volatile i32, i32* %xeb, align 4 - store i32 %10, i32* %sy, align 4 - %11 = load i32, i32* %sy, align 4 - %add = add i32 %11, 1 + %9 = load volatile i32, i32* %xeb, align 4 + store i32 %9, i32* %sy, align 4 + %10 = load i32, i32* %sy, align 4 + %add = add i32 %10, 1 store volatile i32 %add, i32* %xeb, align 4 - %12 = getelementptr inbounds [3 x i32], [3 x i32]* %abcd, i64 0, i64 2 - %13 = load i32, i32* %sy, align 4 - %add1 = add i32 %13, 2 - store volatile i32 %add1, i32* %12, align 4 - %14 = getelementptr inbounds [3 x i32], [3 x i32]* %abcd, i64 0, i64 2 - %15 = load volatile i32, i32* %14, align 4 - store i32 %15, i32* %sy, align 4 + %11 = getelementptr inbounds [3 x i32], [3 x i32]* %abcd, i64 0, i64 2 + %12 = load i32, i32* %sy, align 4 + %add1 = add i32 %12, 2 + store volatile i32 %add1, i32* %11, align 4 + %13 = getelementptr inbounds [3 x i32], [3 x i32]* %abcd, i64 0, i64 2 + %14 = load volatile i32, i32* %13, align 4 + store i32 %14, i32* %sy, align 4 ret i32 1 -} \ No newline at end of file +} diff --git a/test/test_suite/from_docs/examples_forswitch.c3t b/test/test_suite/from_docs/examples_forswitch.c3t index 943041707..775f547d6 100644 --- a/test/test_suite/from_docs/examples_forswitch.c3t +++ b/test/test_suite/from_docs/examples_forswitch.c3t @@ -110,8 +110,11 @@ loop.body: ; preds = %loop.cond br label %loop.cond loop.exit: ; preds = %loop.cond - call void @__assert_rtn(i8* getelementptr inbounds ([21 x i8], [21 x i8]* @0, i64 0, i64 0), i8* getelementptr inbounds ([22 x i8], [22 x i8]* @1, i64 0, i64 0), i32 14, i8* getelementptr inbounds ([20 x i8], [20 x i8]* @2, i64 0, i64 0)) + call void @"std::builtin.panic"(i8* getelementptr inbounds ([20 x i8], [20 x i8]* @0, i64 0, i64 0), i8* getelementptr inbounds ([22 x i8], [22 x i8]* @1, i64 0, i64 0), i8* getelementptr inbounds ([21 x i8], [21 x i8]* @2, i64 0, i64 0), i32 14) unreachable + +unreachable_block: ; No predecessors! + ret void } ; Function Attrs: nounwind