diff --git a/src/build/build_options.c b/src/build/build_options.c index 13ffe584d..5f36e04a7 100644 --- a/src/build/build_options.c +++ b/src/build/build_options.c @@ -81,7 +81,7 @@ static void usage(void) OUTPUT(" --target-list - List all architectures the compiler supports."); OUTPUT(" --threads - Set the number of threads to use for compilation."); OUTPUT(" --safe - Set mode to 'safe', generating runtime traps on overflows and contract violations."); - OUTPUT(" --unsafe - Set mode to 'unsafe', remove runtime traps."); + OUTPUT(" --fast - Set mode to 'fast', removes runtime traps."); OUTPUT(""); OUTPUT(" -g - Emit full debug info."); OUTPUT(" -g0 - Emit no debug info."); @@ -480,7 +480,7 @@ static void parse_option(BuildOptions *options) options->safe_mode = 1; return; } - if (match_longopt("unsafe")) + if (match_longopt("fast")) { options->safe_mode = 0; return; diff --git a/src/build/builder.c b/src/build/builder.c index 5ad4da270..8bbe585c9 100644 --- a/src/build/builder.c +++ b/src/build/builder.c @@ -48,28 +48,35 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions * case OPT_SETTING_O0: target->optimization_level = OPTIMIZATION_NONE; target->size_optimization_level = SIZE_OPTIMIZATION_NONE; + target->feature.safe_mode = true; break; case OPT_SETTING_O1: target->optimization_level = OPTIMIZATION_LESS; target->size_optimization_level = SIZE_OPTIMIZATION_NONE; + target->feature.safe_mode = false; break; case OPT_SETTING_O2: target->optimization_level = OPTIMIZATION_DEFAULT; target->size_optimization_level = SIZE_OPTIMIZATION_NONE; + target->feature.safe_mode = false; break; case OPT_SETTING_O3: target->optimization_level = OPTIMIZATION_AGGRESSIVE; target->size_optimization_level = SIZE_OPTIMIZATION_NONE; + target->feature.safe_mode = false; break; case OPT_SETTING_OSMALL: target->optimization_level = OPTIMIZATION_DEFAULT; target->size_optimization_level = SIZE_OPTIMIZATION_SMALL; + target->feature.safe_mode = false; break; case OPT_SETTING_OTINY: target->optimization_level = OPTIMIZATION_DEFAULT; target->size_optimization_level = SIZE_OPTIMIZATION_TINY; + target->feature.safe_mode = false; break; case OPT_SETTING_NOT_SET: + target->feature.safe_mode = true; break; default: UNREACHABLE diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index 7c472ea22..3ed5006bd 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -10,7 +10,7 @@ static inline void llvm_emit_post_inc_dec(GenContext *c, BEValue *value, Expr *e static inline void llvm_emit_pre_inc_dec(GenContext *c, BEValue *value, Expr *expr, int diff, bool use_mod); static inline void llvm_emit_inc_dec_change(GenContext *c, bool use_mod, BEValue *addr, BEValue *after, BEValue *before, Expr *expr, int diff); static void llvm_emit_post_unary_expr(GenContext *context, BEValue *be_value, Expr *expr); -static inline LLVMValueRef llvm_emit_subscript_addr_with_base_new(GenContext *c, BEValue *parent, BEValue *index); +static inline LLVMValueRef llvm_emit_subscript_addr_with_base_new(GenContext *c, BEValue *parent, BEValue *index, SourceLocation *loc); static void llvm_emit_initialize_designated(GenContext *c, BEValue *ref, uint64_t offset, DesignatorElement** current, DesignatorElement **last, Expr *expr, BEValue *emitted_value); LLVMValueRef llvm_emit_is_no_error_value(GenContext *c, BEValue *value) @@ -33,7 +33,7 @@ LLVMValueRef llvm_emit_const_padding(GenContext *c, ByteSize size) return LLVMGetUndef(llvm_const_padding_type(c, size)); } -static inline LLVMValueRef llvm_emit_add_int(GenContext *c, Type *type, LLVMValueRef left, LLVMValueRef right) +static inline LLVMValueRef llvm_emit_add_int(GenContext *c, Type *type, LLVMValueRef left, LLVMValueRef right, SourceLocation *loc) { if (active_target.feature.trap_on_wrap) { @@ -51,7 +51,7 @@ static inline LLVMValueRef llvm_emit_add_int(GenContext *c, Type *type, LLVMValu } LLVMValueRef result = LLVMBuildExtractValue(c->builder, add_res, 0, ""); LLVMValueRef ok = LLVMBuildExtractValue(c->builder, add_res, 1, ""); - llvm_emit_panic_on_true(c, ok, "Addition overflow"); + llvm_emit_panic_on_true(c, ok, "Addition overflow", loc); return result; } @@ -257,7 +257,7 @@ void llvm_emit_convert_value_from_coerced(GenContext *c, BEValue *result, LLVMTy llvm_value_set_address(result, addr, original_type); } -static inline LLVMValueRef llvm_emit_sub_int(GenContext *c, Type *type, LLVMValueRef left, LLVMValueRef right) +static inline LLVMValueRef llvm_emit_sub_int(GenContext *c, Type *type, LLVMValueRef left, LLVMValueRef right, SourceLocation *loc) { if (active_target.feature.trap_on_wrap) { @@ -275,7 +275,7 @@ static inline LLVMValueRef llvm_emit_sub_int(GenContext *c, Type *type, LLVMValu } LLVMValueRef result = LLVMBuildExtractValue(c->builder, add_res, 0, ""); LLVMValueRef ok = LLVMBuildExtractValue(c->builder, add_res, 1, ""); - llvm_emit_panic_on_true(c, ok, "Subtraction overflow"); + llvm_emit_panic_on_true(c, ok, "Subtraction overflow", loc); return result; } @@ -288,7 +288,7 @@ static inline void llvm_emit_subscript_addr_base(GenContext *context, BEValue *v llvm_emit_ptr_from_array(context, value); } -static inline LLVMValueRef llvm_emit_subscript_addr_with_base(GenContext *c, Type *parent_type, LLVMValueRef parent_value, LLVMValueRef index_value) +static inline LLVMValueRef llvm_emit_subscript_addr_with_base(GenContext *c, Type *parent_type, LLVMValueRef parent_value, LLVMValueRef index_value, SourceLocation *loc) { Type *type = parent_type; switch (type->type_kind) @@ -322,22 +322,22 @@ static inline LLVMValueRef llvm_emit_subscript_addr_with_base(GenContext *c, Typ } } -static void llvm_emit_array_bounds_check(GenContext *c, BEValue *index, LLVMValueRef array_max_index) +static void llvm_emit_array_bounds_check(GenContext *c, BEValue *index, LLVMValueRef array_max_index, SourceLocation *loc) { // Negative values are not allowed. if (type_is_signed(index->type)) { LLVMValueRef index_negative = llvm_emit_int_comparison(c, index->type, index->type, index->value, llvm_get_zero(c, index->type), BINARYOP_LT); - llvm_emit_panic_on_true(c, index_negative, "Negative array indexing"); + llvm_emit_panic_on_true(c, index_negative, "Negative array indexing", loc); } LLVMValueRef exceeds_max_index = llvm_emit_int_comparison(c, index->type, index->type, index->value, array_max_index, BINARYOP_GE); - llvm_emit_panic_on_true(c, exceeds_max_index, "Array index out of bounds"); + llvm_emit_panic_on_true(c, exceeds_max_index, "Array index out of bounds", loc); } -static inline LLVMValueRef llvm_emit_subscript_addr_with_base_new(GenContext *c, BEValue *parent, BEValue *index) +static inline LLVMValueRef llvm_emit_subscript_addr_with_base_new(GenContext *c, BEValue *parent, BEValue *index, SourceLocation *loc) { assert(llvm_value_is_addr(parent)); Type *type = type_flatten(parent->type); @@ -349,7 +349,7 @@ static inline LLVMValueRef llvm_emit_subscript_addr_with_base_new(GenContext *c, { if (active_target.feature.safe_mode) { - llvm_emit_array_bounds_check(c, index, llvm_const_int(c, index->type, type->array.len)); + llvm_emit_array_bounds_check(c, index, llvm_const_int(c, index->type, type->array.len), loc); } LLVMValueRef zero = llvm_get_zero(c, index->type); LLVMValueRef indices[2] = { @@ -398,7 +398,7 @@ static inline void gencontext_emit_subscript(GenContext *c, BEValue *value, Expr llvm_value_rvalue(c, &index); // TODO set alignment - llvm_value_set_address(value, llvm_emit_subscript_addr_with_base_new(c, &ref, &index), expr->type); + llvm_value_set_address(value, llvm_emit_subscript_addr_with_base_new(c, &ref, &index, TOKLOC(expr->subscript_expr.index->span.loc)), expr->type); } @@ -1131,8 +1131,8 @@ static inline void llvm_emit_inc_dec_change(GenContext *c, bool use_mod, BEValue LLVMTypeRef llvm_type = llvm_get_type(c, type); LLVMValueRef diff_value = LLVMConstInt(llvm_type, 1, false); after_value = diff > 0 - ? llvm_emit_add_int(c, type, value.value, diff_value) - : llvm_emit_sub_int(c, type, value.value, diff_value); + ? llvm_emit_add_int(c, type, value.value, diff_value, TOKLOC(expr->span.loc)) + : llvm_emit_sub_int(c, type, value.value, diff_value, TOKLOC(expr->span.loc)); break; } default: @@ -1234,7 +1234,7 @@ static void gencontext_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr &type_to_use, 1, args, 2); value->value = LLVMBuildExtractValue(c->builder, call_res, 0, ""); LLVMValueRef ok = LLVMBuildExtractValue(c->builder, call_res, 1, ""); - llvm_emit_panic_on_true(c, ok, "Signed negation overflow"); + llvm_emit_panic_on_true(c, ok, "Signed negation overflow", TOKLOC(expr->span.loc)); return; } value->value = LLVMBuildNeg(c->builder, value->value, "neg"); @@ -1300,20 +1300,20 @@ static void llvm_emit_trap_negative(GenContext *c, Expr *expr, LLVMValueRef valu LLVMValueRef zero = llvm_const_int(c, expr->type, 0); LLVMValueRef ok = LLVMBuildICmp(c->builder, LLVMIntSLT, value, zero, "underflow"); - llvm_emit_panic_on_true(c, ok, error); + llvm_emit_panic_on_true(c, ok, error, TOKLOC(expr->span.loc)); } -static void llvm_emit_trap_zero(GenContext *c, Type *type, LLVMValueRef value, const char *error) +static void llvm_emit_trap_zero(GenContext *c, Type *type, LLVMValueRef value, const char *error, SourceLocation *loc) { if (!active_target.feature.safe_mode) return; LLVMValueRef zero = llvm_get_zero(c, type); LLVMValueRef ok = type_is_any_integer(type) ? LLVMBuildICmp(c->builder, LLVMIntEQ, value, zero, "zero") : LLVMBuildFCmp(c->builder, LLVMRealUEQ, value, zero, "zero"); - llvm_emit_panic_on_true(c, ok, error); + llvm_emit_panic_on_true(c, ok, error, loc); } -static void llvm_emit_trap_invalid_shift(GenContext *c, LLVMValueRef value, Type *type, const char *error) +static void llvm_emit_trap_invalid_shift(GenContext *c, LLVMValueRef value, Type *type, const char *error, SourceLocation *loc) { if (!active_target.feature.safe_mode) return; unsigned type_bit_size = type_size(type) * 8; @@ -1321,14 +1321,14 @@ static void llvm_emit_trap_invalid_shift(GenContext *c, LLVMValueRef value, Type if (type_is_unsigned(type)) { LLVMValueRef equal_or_greater = LLVMBuildICmp(c->builder, LLVMIntUGE, value, max, "shift_exceeds"); - llvm_emit_panic_on_true(c, equal_or_greater, error); + llvm_emit_panic_on_true(c, equal_or_greater, error, loc); return; } LLVMValueRef zero = llvm_const_int(c, type, 0); LLVMValueRef negative = LLVMBuildICmp(c->builder, LLVMIntSLT, value, zero, "shift_underflow"); - llvm_emit_panic_on_true(c, negative, error); + llvm_emit_panic_on_true(c, negative, error, loc); LLVMValueRef equal_or_greater = LLVMBuildICmp(c->builder, LLVMIntSGE, value, max, "shift_exceeds"); - llvm_emit_panic_on_true(c, equal_or_greater, error); + llvm_emit_panic_on_true(c, equal_or_greater, error, loc); } static void @@ -1398,7 +1398,7 @@ llvm_emit_slice_values(GenContext *c, Expr *slice, Type **parent_type_ref, LLVMV // Walk from end if it is slice from the back. if (slice->slice_expr.start_from_back) { - start_index.value = llvm_emit_sub_int(c, start_type, len, start_index.value); + start_index.value = llvm_emit_sub_int(c, start_type, len, start_index.value, TOKLOC(slice->span.loc)); } // Check that index does not extend beyond the length. @@ -1412,7 +1412,7 @@ llvm_emit_slice_values(GenContext *c, Expr *slice, Type **parent_type_ref, LLVMV start_index.value, len, BINARYOP_GE); - llvm_emit_panic_on_true(c, exceeds_size, "Index exceeds array length."); + llvm_emit_panic_on_true(c, exceeds_size, "Index exceeds array length.", TOKLOC(slice->span.loc)); } // Insert trap for negative start offset for non pointers. @@ -1434,7 +1434,7 @@ llvm_emit_slice_values(GenContext *c, Expr *slice, Type **parent_type_ref, LLVMV // Reverse if it is "from back" if (slice->slice_expr.end_from_back) { - end_index.value = llvm_emit_sub_int(c, end_type, len, end_index.value); + end_index.value = llvm_emit_sub_int(c, end_type, len, end_index.value, TOKLOC(slice->span.loc)); llvm_value_rvalue(c, &end_index); } @@ -1447,7 +1447,7 @@ llvm_emit_slice_values(GenContext *c, Expr *slice, Type **parent_type_ref, LLVMV start_index.value, end_index.value, BINARYOP_GT); - llvm_emit_panic_on_true(c, excess, "Negative size"); + llvm_emit_panic_on_true(c, excess, "Negative size", TOKLOC(slice->span.loc)); if (len) { @@ -1457,7 +1457,7 @@ llvm_emit_slice_values(GenContext *c, Expr *slice, Type **parent_type_ref, LLVMV len, end_index.value, BINARYOP_LT); - llvm_emit_panic_on_true(c, exceeds_size, "Size exceeds index"); + llvm_emit_panic_on_true(c, exceeds_size, "Size exceeds index", TOKLOC(slice->span.loc)); } } } @@ -1575,13 +1575,13 @@ static void gencontext_emit_slice_assign(GenContext *c, BEValue *be_value, Expr // Emit the assign. llvm_emit_block(c, assign_block); // Reuse this calculation - LLVMValueRef target = llvm_emit_subscript_addr_with_base(c, parent_type, parent_base, offset); + LLVMValueRef target = llvm_emit_subscript_addr_with_base(c, parent_type, parent_base, offset, TOKLOC(expr->span.loc)); // And store the value. // TODO correct alignment. llvm_store_bevalue_aligned(c, target, be_value, 0); // Create the new offset - LLVMValueRef next_offset = llvm_emit_add_int(c, start_type, offset, llvm_const_int(c, start_type, 1)); + LLVMValueRef next_offset = llvm_emit_add_int(c, start_type, offset, llvm_const_int(c, start_type, 1), TOKLOC(expr->span.loc)); // And jump back llvm_emit_br(c, cond_block); @@ -1797,7 +1797,7 @@ static LLVMValueRef llvm_emit_ptr_comparison(GenContext *c, LLVMValueRef lhs_val } -static inline LLVMValueRef llvm_fixup_shift_rhs(GenContext *c, LLVMValueRef left, LLVMValueRef right) +static inline LLVMValueRef llvm_fixup_shift_rhs(GenContext *c, LLVMValueRef left, LLVMValueRef right, SourceLocation *loc) { LLVMTypeRef left_type = LLVMTypeOf(left); LLVMTypeRef right_type = LLVMTypeOf(right); @@ -1809,7 +1809,7 @@ static inline LLVMValueRef llvm_fixup_shift_rhs(GenContext *c, LLVMValueRef left return LLVMBuildZExt(c->builder, right, left_type, ""); } -static inline LLVMValueRef llvm_emit_mult_int(GenContext *c, Type *type, LLVMValueRef left, LLVMValueRef right) +static inline LLVMValueRef llvm_emit_mult_int(GenContext *c, Type *type, LLVMValueRef left, LLVMValueRef right, SourceLocation *loc) { if (active_target.feature.trap_on_wrap) { @@ -1826,7 +1826,7 @@ static inline LLVMValueRef llvm_emit_mult_int(GenContext *c, Type *type, LLVMVal 2); LLVMValueRef val = LLVMBuildExtractValue(c->builder, call_res, 0, "mul"); LLVMValueRef ok = LLVMBuildExtractValue(c->builder, call_res, 1, ""); - llvm_emit_panic_on_true(c, ok, "Integer multiplication overflow"); + llvm_emit_panic_on_true(c, ok, "Integer multiplication overflow", loc); return val; } return LLVMBuildMul(c->builder, left, right, "mul"); @@ -1882,7 +1882,7 @@ static void gencontext_emit_binary(GenContext *c, BEValue *be_value, Expr *expr, val = LLVMBuildFMul(c->builder, lhs_value, rhs_value, "fmul"); break; } - val = llvm_emit_mult_int(c, lhs_type, lhs_value, rhs_value); + val = llvm_emit_mult_int(c, lhs_type, lhs_value, rhs_value, TOKLOC(expr->span.loc)); break; case BINARYOP_SUB: if (lhs_type->type_kind == TYPE_POINTER) @@ -1904,7 +1904,7 @@ static void gencontext_emit_binary(GenContext *c, BEValue *be_value, Expr *expr, val = LLVMBuildFSub(c->builder, lhs_value, rhs_value, "fsub"); break; } - val = llvm_emit_sub_int(c, lhs_type, lhs_value, rhs_value); + val = llvm_emit_sub_int(c, lhs_type, lhs_value, rhs_value, TOKLOC(expr->span.loc)); break; case BINARYOP_ADD: if (lhs_type->type_kind == TYPE_POINTER) @@ -1918,10 +1918,10 @@ static void gencontext_emit_binary(GenContext *c, BEValue *be_value, Expr *expr, val = LLVMBuildFAdd(c->builder, lhs_value, rhs_value, "fadd"); break; } - val = llvm_emit_add_int(c, lhs_type, lhs_value, rhs_value); + val = llvm_emit_add_int(c, lhs_type, lhs_value, rhs_value, TOKLOC(expr->span.loc)); break; case BINARYOP_DIV: - llvm_emit_trap_zero(c, rhs_type, rhs_value, "% by zero"); + llvm_emit_trap_zero(c, rhs_type, rhs_value, "% by zero", TOKLOC(expr->span.loc)); if (is_float) { val = LLVMBuildFDiv(c->builder, lhs_value, rhs_value, "fdiv"); @@ -1932,22 +1932,22 @@ static void gencontext_emit_binary(GenContext *c, BEValue *be_value, Expr *expr, : LLVMBuildSDiv(c->builder, lhs_value, rhs_value, "sdiv"); break; case BINARYOP_MOD: - llvm_emit_trap_zero(c, rhs_type, rhs_value, "% by zero"); + llvm_emit_trap_zero(c, rhs_type, rhs_value, "% by zero", TOKLOC(expr->span.loc)); val = type_is_unsigned(lhs_type) ? LLVMBuildURem(c->builder, lhs_value, rhs_value, "umod") : LLVMBuildSRem(c->builder, lhs_value, rhs_value, "smod"); break; case BINARYOP_SHR: - rhs_value = llvm_fixup_shift_rhs(c, lhs_value, rhs_value); - llvm_emit_trap_invalid_shift(c, rhs_value, lhs_type, "Shift amount out of range."); + rhs_value = llvm_fixup_shift_rhs(c, lhs_value, rhs_value, TOKLOC(expr->span.loc)); + llvm_emit_trap_invalid_shift(c, rhs_value, lhs_type, "Shift amount out of range.", TOKLOC(expr->span.loc)); val = type_is_unsigned(lhs_type) ? LLVMBuildLShr(c->builder, lhs_value, rhs_value, "lshr") : LLVMBuildAShr(c->builder, lhs_value, rhs_value, "ashr"); val = LLVMBuildFreeze(c->builder, val, ""); break; case BINARYOP_SHL: - rhs_value = llvm_fixup_shift_rhs(c, lhs_value, rhs_value); - llvm_emit_trap_invalid_shift(c, rhs_value, lhs_type, "Shift amount out of range."); + rhs_value = llvm_fixup_shift_rhs(c, lhs_value, rhs_value, TOKLOC(expr->span.loc)); + llvm_emit_trap_invalid_shift(c, rhs_value, lhs_type, "Shift amount out of range.", TOKLOC(expr->span.loc)); val = LLVMBuildShl(c->builder, lhs_value, rhs_value, "shl"); val = LLVMBuildFreeze(c->builder, val, ""); break; diff --git a/src/compiler/llvm_codegen_internal.h b/src/compiler/llvm_codegen_internal.h index 807cdb7fa..748feb4c3 100644 --- a/src/compiler/llvm_codegen_internal.h +++ b/src/compiler/llvm_codegen_internal.h @@ -250,9 +250,9 @@ void llvm_emit_memcpy(GenContext *c, LLVMValueRef dest, unsigned dest_align, LLV void llvm_emit_memcpy_to_decl(GenContext *c, Decl *decl, LLVMValueRef source, unsigned source_alignment); void llvm_emit_stmt(GenContext *c, Ast *ast); 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); +void llvm_emit_panic_on_true(GenContext *c, LLVMValueRef value, const char *panic_name, SourceLocation *loc); void llvm_emit_ptr_from_array(GenContext *c, BEValue *value); -void llvm_emit_puts_output(GenContext *c, const char *message); +void llvm_emit_debug_output(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); LLVMValueRef llvm_emit_struct_gep_raw(GenContext *context, LLVMValueRef ptr, LLVMTypeRef struct_type, unsigned index, unsigned struct_alignment, unsigned offset, unsigned *alignment); diff --git a/src/compiler/llvm_codegen_stmt.c b/src/compiler/llvm_codegen_stmt.c index 8bd20b3bd..5347b72ac 100644 --- a/src/compiler/llvm_codegen_stmt.c +++ b/src/compiler/llvm_codegen_stmt.c @@ -1063,13 +1063,12 @@ static inline void llvm_emit_assert_stmt(GenContext *c, Ast *ast) if (ast->assert_stmt.message) { error = ast->assert_stmt.message->const_expr.string.chars; - error = strformat("Assert violation '%s' on line %d, in file '%s'.", error, loc->line, loc->file->name); } else { - error = strformat("Assert violation on line %d, in file '%s'.", loc->line, loc->file->name); + error = "Assert violation"; } - llvm_emit_puts_output(c, error); + llvm_emit_debug_output(c, error, loc->file->name, c->cur_func_decl->name, loc->line); llvm_emit_call_intrinsic(c, intrinsic_id_trap, NULL, 0, NULL, 0); llvm_emit_br(c, on_ok); llvm_emit_block(c, on_ok); @@ -1080,7 +1079,8 @@ static inline void llvm_emit_assert_stmt(GenContext *c, Ast *ast) static inline void gencontext_emit_unreachable_stmt(GenContext *context, Ast *ast) { - llvm_emit_puts_output(context, "Unreachable statement reached."); + SourceLocation *loc = TOKLOC(ast->span.loc); + llvm_emit_debug_output(context, "Unreachable statement reached.", loc->file->name, context->cur_func_decl->external_name, loc->line); llvm_emit_call_intrinsic(context, intrinsic_id_trap, NULL, 0, NULL, 0); LLVMBuildUnreachable(context->builder); LLVMBasicBlockRef block = llvm_basic_block_new(context, "unreachable_block"); @@ -1171,28 +1171,138 @@ void gencontext_emit_catch_stmt(GenContext *c, Ast *ast) llvm_emit_br(c, after_catch); llvm_emit_block(c, after_catch); } - -void llvm_emit_puts_output(GenContext *c, const char *message) +static LLVMValueRef llvm_emit_string(GenContext *c, const char *str) +{ + LLVMTypeRef char_type = llvm_get_type(c, type_char); + unsigned len = strlen(str); + LLVMValueRef global_string = LLVMAddGlobal(c->module, LLVMArrayType(char_type, len + 1), ""); + LLVMSetLinkage(global_string, LLVMInternalLinkage); + LLVMSetGlobalConstant(global_string, 1); + LLVMSetInitializer(global_string, LLVMConstStringInContext(c->context, str, len, 0)); + LLVMValueRef zero = llvm_get_zero(c, type_usize); + LLVMValueRef string = LLVMBuildInBoundsGEP2(c->builder, LLVMTypeOf(global_string), global_string, &zero, 1, ""); + 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) { LLVMTypeRef char_ptr_type = llvm_get_ptr_type(c, type_char); - LLVMTypeRef type = LLVMFunctionType(LLVMVoidTypeInContext(c->context), &char_ptr_type, 1, false); - LLVMValueRef puts_func = LLVMGetNamedFunction(c->module, "puts"); - if (!puts_func) + 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; + switch (platform_target.os) { - puts_func = LLVMAddFunction(c->module, "puts", type); + 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: + 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 = 3; + break; + } + LLVMValueRef assert_func = LLVMGetNamedFunction(c->module, name); + if (!assert_func) + { + LLVMTypeRef type; + LLVMTypeRef void_type = LLVMVoidTypeInContext(c->context); + switch (platform_target.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_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; + } + } + assert_func = LLVMAddFunction(c->module, name, type); } - LLVMValueRef global_name = LLVMAddGlobal(c->module, LLVMArrayType(llvm_get_type(c, type_char), strlen(message) + 1), ""); - LLVMSetLinkage(global_name, LLVMInternalLinkage); - LLVMSetGlobalConstant(global_name, 1); - LLVMSetInitializer(global_name, LLVMConstStringInContext(c->context, message, strlen(message), 0)); - LLVMValueRef zero = llvm_get_zero(c, type_usize); - LLVMValueRef string = LLVMBuildInBoundsGEP2(c->builder, LLVMTypeOf(global_name), global_name, &zero, 1, ""); - string = LLVMBuildBitCast(c->builder, string, char_ptr_type, ""); - LLVMBuildCall(c->builder, puts_func, &string, 1, ""); + 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); + + LLVMBuildCall(c->builder, assert_func, args, func_index > -1 ? 4 : 3, ""); } -void llvm_emit_panic_on_true(GenContext *c, LLVMValueRef value, const char *panic_name) +void llvm_emit_panic_on_true(GenContext *c, LLVMValueRef value, const char *panic_name, SourceLocation *loc) { LLVMBasicBlockRef panic_block = llvm_basic_block_new(c, "panic"); LLVMBasicBlockRef ok_block = llvm_basic_block_new(c, "checkok"); @@ -1200,7 +1310,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_puts_output(c, panic_name); + llvm_emit_debug_output(c, panic_name, loc->file->name, c->cur_func_decl->name, loc->line); llvm_emit_call_intrinsic(c, intrinsic_id_trap, NULL, 0, NULL, 0); llvm_emit_br(c, ok_block); llvm_emit_block(c, ok_block); diff --git a/test/src/tester.py b/test/src/tester.py index fab011acb..1485579ea 100644 --- a/test/src/tester.py +++ b/test/src/tester.py @@ -126,7 +126,7 @@ class Issues: self.current_file.close() print("- " + self.sourcefile.filepath + ":", end="") - self.compile("--test compile " + self.current_file.filepath) + self.compile("--test --fast compile " + self.current_file.filepath) if not self.has_errors: self.conf.numsuccess += 1 print(" Passed.") @@ -191,7 +191,7 @@ class Issues: files_to_compile += " " + file.filepath - self.compile("--test compile " + files_to_compile) + self.compile("--test --fast compile " + files_to_compile) if self.has_errors: return for file in self.files: