From 82f1b543ed9397cde3668a4d31c425d241fc2c17 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Sun, 23 Mar 2025 22:50:09 +0100 Subject: [PATCH] &self not runtime null-checked in macro #1827. Regression in temp allocators. --- lib/std/core/allocators/temp_allocator.c3 | 5 +- lib/std/core/mem.c3 | 10 +- lib/std/core/mem_allocator.c3 | 2 +- releasenotes.md | 1 + src/compiler/compiler_internal.h | 1 + src/compiler/expr.c | 13 + src/compiler/sema_expr.c | 32 +- .../methods/methods_with_inferred_type.c3t | 8 +- .../statements/custom_foreach_with_ref.c3t | 430 ++++++++++-------- test/test_suite/statements/foreach_custom.c3t | 12 +- .../statements/foreach_custom_macro.c3t | 10 +- .../statements/foreach_r_custom.c3t | 10 +- .../statements/foreach_r_custom_macro.c3t | 10 +- test/unit/regression/run_temp_mem.c3 | 15 + 14 files changed, 335 insertions(+), 224 deletions(-) create mode 100644 test/unit/regression/run_temp_mem.c3 diff --git a/lib/std/core/allocators/temp_allocator.c3 b/lib/std/core/allocators/temp_allocator.c3 index 36c478f16..076f98f44 100644 --- a/lib/std/core/allocators/temp_allocator.c3 +++ b/lib/std/core/allocators/temp_allocator.c3 @@ -203,10 +203,11 @@ fn void*? TempAllocator.resize(&self, void* pointer, usz size, usz alignment) @d } } void* data = self.acquire(size, NO_ZERO, alignment)!; - mem::copy(data, pointer, chunk.size, mem::DEFAULT_MEM_ALIGNMENT, mem::DEFAULT_MEM_ALIGNMENT); + usz len_to_copy = chunk.size > size ? size : chunk.size; + mem::copy(data, pointer, len_to_copy, mem::DEFAULT_MEM_ALIGNMENT, mem::DEFAULT_MEM_ALIGNMENT); if (is_realloc_of_last) { - self.used = ((void*)chunk - &self.data); + self.used = (uptr)chunk - (uptr)&self.data; $if env::ADDRESS_SANITIZER: asan::poison_memory_region(chunk, TempAllocatorChunk.sizeof + chunk.size); $endif diff --git a/lib/std/core/mem.c3 b/lib/std/core/mem.c3 index e4eccd22b..e835a8dd5 100644 --- a/lib/std/core/mem.c3 +++ b/lib/std/core/mem.c3 @@ -317,12 +317,13 @@ macro void clear_inline(void* dst, usz $len, usz $dst_align = 0, bool $is_volati Copy memory from src to dst efficiently, assuming the memory ranges do not overlap. @param [&out] dst : "The destination to copy to" - @param [&in] src : "The source to copy from" + @param [in] src : "The source to copy from" @param len : "The number of bytes to copy" @param $dst_align : "the alignment of the destination if different from the default, 0 assumes the default" @param $src_align : "the alignment of the destination if different from the default, 0 assumes the default" @param $is_volatile : "True if this copy should be treated as volatile, i.e. it can't be optimized away." + @require src != null || len == 0 : "Copying a null with non-zero length is invalid" @require len == 0 || dst + len <= src || src + len <= dst : "Ranges may not overlap" *> macro void copy(void* dst, void* src, usz len, usz $dst_align = 0, usz $src_align = 0, bool $is_volatile = false) @@ -335,12 +336,13 @@ macro void copy(void* dst, void* src, usz len, usz $dst_align = 0, usz $src_alig will always be inlined and never call memcopy @param [&out] dst : "The destination to copy to" - @param [&in] src : "The source to copy from" + @param [in] src : "The source to copy from" @param $len : "The number of bytes to copy" @param $dst_align : "the alignment of the destination if different from the default, 0 assumes the default" @param $src_align : "the alignment of the destination if different from the default, 0 assumes the default" @param $is_volatile : "True if this copy should be treated as volatile, i.e. it can't be optimized away." + @require src != null || len == 0 : "Copying a null with non-zero length is invalid" @require $len == 0 || dst + $len <= src || src + $len <= dst : "Ranges may not overlap" *> macro void copy_inline(void* dst, void* src, usz $len, usz $dst_align = 0, usz $src_align = 0, bool $is_volatile = false) @@ -352,11 +354,13 @@ macro void copy_inline(void* dst, void* src, usz $len, usz $dst_align = 0, usz $ Copy memory from src to dst but correctly handle the possibility of overlapping ranges. @param [&out] dst : "The destination to copy to" - @param [&in] src : "The source to copy from" + @param [in] src : "The source to copy from" @param len : "The number of bytes to copy" @param $dst_align : "the alignment of the destination if different from the default, 0 assumes the default" @param $src_align : "the alignment of the destination if different from the default, 0 assumes the default" @param $is_volatile : "True if this copy should be treated as volatile, i.e. it can't be optimized away." + + @require src != null || len == 0 : "Moving a null with non-zero length is invalid" *> macro void move(void* dst, void* src, usz len, usz $dst_align = 0, usz $src_align = 0, bool $is_volatile = false) { diff --git a/lib/std/core/mem_allocator.c3 b/lib/std/core/mem_allocator.c3 index 73e566031..bf8a2d54f 100644 --- a/lib/std/core/mem_allocator.c3 +++ b/lib/std/core/mem_allocator.c3 @@ -433,7 +433,7 @@ fn Allocator create_temp_allocator_on_demand() @private if (!auto_create_temp) { auto_create_temp = true; - abort("Use '@pool_init()' to enable the temp allocator on a new thread. A pool is implicitly created only on the main thread."); + abort("Use '@pool_init()' to enable the temp allocator on a new thread. A temp allocator is only implicitly created on the main thread."); } return create_temp_allocator(base_allocator(), temp_allocator_size()); } diff --git a/releasenotes.md b/releasenotes.md index 054569744..d296ce34e 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -55,6 +55,7 @@ - Crash resolving a method on `Foo[2]` when `Foo` is distinct #2042. - Bug due to missing cast when doing `$i[$x] = $z`. - Incorrectly allowed getting pointer to a macro #2049. +- &self not runtime null-checked in macro #1827. ### Stdlib changes - `new_*` functions in general moved to version without `new_` prefix. diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index f27dba22d..4048cd02d 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -2195,6 +2195,7 @@ Expr *expr_new_const_int(SourceSpan span, Type *type, uint64_t v); Expr *expr_new_const_bool(SourceSpan span, Type *type, bool value); Expr *expr_new_const_typeid(SourceSpan span, Type *type); Expr *expr_new_const_string(SourceSpan span, const char *string); +Expr *expr_new_const_null(SourceSpan span, Type *type); Expr *expr_new_const_initializer(SourceSpan span, Type *type, ConstInitializer *initializer); const char *expr_kind_to_string(ExprKind kind); bool expr_is_simple(Expr *expr, bool to_float); diff --git a/src/compiler/expr.c b/src/compiler/expr.c index af0553736..8ee3ea16d 100644 --- a/src/compiler/expr.c +++ b/src/compiler/expr.c @@ -1035,6 +1035,19 @@ Expr *expr_new_const_bool(SourceSpan span, Type *type, bool value) return expr; } +Expr *expr_new_const_null(SourceSpan span, Type *type) +{ + Expr *expr = expr_calloc(); + expr->expr_kind = EXPR_CONST; + expr->span = span; + expr->type = type; + ASSERT(type_flatten(type)->type_kind == TYPE_POINTER); + expr->const_expr.ptr = 0; + expr->const_expr.const_kind = CONST_POINTER; + expr->resolve_status = RESOLVE_DONE; + return expr; +} + Expr *expr_new_const_string(SourceSpan span, const char *string) { Expr *expr = expr_calloc(); diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 7e65de9e9..a98f8827a 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -1821,7 +1821,7 @@ static inline bool sema_call_check_contract_param_match(SemaContext *context, De { if (param->var.not_null && expr_is_const_pointer(expr) && !expr->const_expr.ptr) { - RETURN_SEMA_ERROR(expr, "You may not pass null to a '&' parameter."); + RETURN_SEMA_ERROR(expr, "You may not pass null to the '&' parameter."); } if (expr->expr_kind == EXPR_UNARY && expr->unary_expr.expr->expr_kind == EXPR_IDENTIFIER) { @@ -2211,15 +2211,37 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s BlockExit** block_exit_ref = CALLOCS(BlockExit*); macro_context.block_exit_ref = block_exit_ref; - FOREACH(Decl *, param, params) + AstId assert_first = 0; + AstId* next = &assert_first; + + FOREACH_IDX(idx, Decl *, param, params) { // Skip raw vararg if (!param) continue; if (!sema_add_local(¯o_context, param)) goto EXIT_FAIL; - } + if (param->var.init_expr && param->var.not_null) + { + Expr *expr = expr_variable(param); + Expr *binary = expr_new_expr(EXPR_BINARY, expr); + binary->binary_expr.left = exprid(expr); + binary->binary_expr.right = exprid(expr_new_const_null(expr->span, type_voidptr)); + binary->binary_expr.operator = BINARYOP_NE; + if (!sema_analyse_expr_rhs(context, type_bool, binary, false, NULL, false)) goto EXIT_FAIL; + const char *string = struct_var && idx == 0 ? "Called a method on a null value." : "Passed null to a ref ('&') parameter."; + if (expr_is_const_bool(binary) && !binary->const_expr.b) + { + sema_error_at(context, param->var.init_expr->span, string); + goto EXIT_FAIL; + } - AstId assert_first = 0; - AstId* next = &assert_first; + Ast *assert = new_ast(AST_ASSERT_STMT, param->var.init_expr->span); + assert->assert_stmt.is_ensure = true; + assert->assert_stmt.expr = exprid(binary); + Expr *comment_expr = expr_new_const_string(expr->span, string); + assert->assert_stmt.message = exprid(comment_expr); + ast_append(&next, assert); + } + } bool has_ensures = false; if (!sema_analyse_contracts(¯o_context, docs, &next, call_expr->span, &has_ensures)) goto EXIT_FAIL; diff --git a/test/test_suite/methods/methods_with_inferred_type.c3t b/test/test_suite/methods/methods_with_inferred_type.c3t index 74121da71..754b0d860 100644 --- a/test/test_suite/methods/methods_with_inferred_type.c3t +++ b/test/test_suite/methods/methods_with_inferred_type.c3t @@ -69,6 +69,8 @@ entry: call void @llvm.memcpy.p0.p0.i32(ptr align 4 %x, ptr align 4 @.__const, i32 8, i1 false) %0 = call i32 @test.Abc.add(ptr %x) store i32 %0, ptr %a, align 4 + %neq = icmp ne ptr %x, null + call void @llvm.assume(i1 %neq) %1 = load i32, ptr %x, align 4 %ptradd = getelementptr inbounds i8, ptr %x, i64 4 %2 = load i32, ptr %ptradd, align 4 @@ -76,8 +78,10 @@ entry: store i32 %add, ptr %b, align 4 store i32 100, ptr %f, align 4 call void @test.Foo.add(ptr %f) + %neq1 = icmp ne ptr %f, null + call void @llvm.assume(i1 %neq1) %3 = load i32, ptr %f, align 4 - %add1 = add i32 %3, 1 - store i32 %add1, ptr %f, align 4 + %add2 = add i32 %3, 1 + store i32 %add2, ptr %f, align 4 ret void } diff --git a/test/test_suite/statements/custom_foreach_with_ref.c3t b/test/test_suite/statements/custom_foreach_with_ref.c3t index 14880c684..1fb04c457 100644 --- a/test/test_suite/statements/custom_foreach_with_ref.c3t +++ b/test/test_suite/statements/custom_foreach_with_ref.c3t @@ -131,43 +131,51 @@ entry: %i = alloca i32, align 4 %y = alloca i32, align 4 %a = alloca i32, align 4 - %.anon2 = alloca i32, align 4 - %i6 = alloca i32, align 4 - %y7 = alloca ptr, align 8 - %a8 = alloca i32, align 4 - %.anon13 = alloca i32, align 4 - %i17 = alloca i32, align 4 - %y18 = alloca i32, align 4 - %a19 = alloca i32, align 4 - %.anon24 = alloca i32, align 4 - %i28 = alloca i32, align 4 - %y29 = alloca i32, align 4 - %a30 = alloca i32, align 4 - %.anon35 = alloca i32, align 4 - %i39 = alloca i32, align 4 - %y40 = alloca i32, align 4 - %a41 = alloca i32, align 4 - %.anon47 = alloca [5 x i32], align 16 - %.anon48 = alloca i64, align 8 - %i51 = alloca i64, align 8 - %y52 = alloca i32, align 4 - %.anon56 = alloca [5 x i32], align 16 - %.anon57 = alloca i64, align 8 - %i61 = alloca i64, align 8 - %y62 = alloca i32, align 4 + %.anon7 = alloca i32, align 4 + %i11 = alloca i32, align 4 + %y12 = alloca ptr, align 8 + %a13 = alloca i32, align 4 + %.anon20 = alloca i32, align 4 + %i24 = alloca i32, align 4 + %y25 = alloca i32, align 4 + %a26 = alloca i32, align 4 + %.anon33 = alloca i32, align 4 + %i37 = alloca i32, align 4 + %y38 = alloca i32, align 4 + %a39 = alloca i32, align 4 + %.anon46 = alloca i32, align 4 + %i50 = alloca i32, align 4 + %y51 = alloca i32, align 4 + %a52 = alloca i32, align 4 + %.anon59 = alloca [5 x i32], align 16 + %.anon60 = alloca i64, align 8 + %i63 = alloca i64, align 8 + %y64 = alloca i32, align 4 + %.anon68 = alloca [5 x i32], align 16 + %.anon69 = alloca i64, align 8 + %i73 = alloca i64, align 8 + %y74 = alloca i32, align 4 %sretparam = alloca [5 x i32], align 4 - %.anon66 = alloca i64, align 8 - %i70 = alloca i64, align 8 - %y71 = alloca i32, align 4 - %y76 = alloca ptr, align 8 + %.anon78 = alloca i64, align 8 + %i82 = alloca i64, align 8 + %y83 = alloca i32, align 4 + %y90 = alloca ptr, align 8 call void @llvm.memcpy.p0.p0.i32(ptr align 4 %x, ptr align 4 @.__const.2, i32 12, i1 false) + %neq = icmp ne ptr %x, null + call void @llvm.assume(i1 %neq) + %neq1 = icmp ne ptr %x, null + call void @llvm.assume(i1 %neq1) %ptradd = getelementptr inbounds i8, ptr %x, i64 4 - %ptradd1 = getelementptr inbounds i8, ptr %x, i64 8 + %neq2 = icmp ne ptr %x, null + call void @llvm.assume(i1 %neq2) + %ptradd3 = getelementptr inbounds i8, ptr %x, i64 8 %0 = load i32, ptr %x, align 4 %1 = load i32, ptr %ptradd, align 4 - %2 = load i32, ptr %ptradd1, align 4 + %2 = load i32, ptr %ptradd3, align 4 call void (ptr, ...) @printf(ptr @.str.3, i32 %0, i32 %1, i32 %2) %3 = call ptr @foo.call(ptr %x) + %neq4 = icmp ne ptr %3, null + call void @llvm.assume(i1 %neq4) store i32 0, ptr %.anon, align 4 br label %loop.cond @@ -181,6 +189,8 @@ loop.body: ; preds = %loop.cond store i32 %5, ptr %i, align 4 %6 = load i32, ptr %.anon, align 4 store i32 %6, ptr %a, align 4 + %neq5 = icmp ne ptr %3, null + call void @llvm.assume(i1 %neq5) %7 = load i32, ptr %a, align 4 %sext = sext i32 %7 to i64 %ptroffset = getelementptr inbounds [4 x i8], ptr %3, i64 %sext @@ -195,212 +205,238 @@ loop.body: ; preds = %loop.cond br label %loop.cond loop.exit: ; preds = %loop.cond - store i32 0, ptr %.anon2, align 4 - br label %loop.cond3 + %neq6 = icmp ne ptr %x, null + call void @llvm.assume(i1 %neq6) + store i32 0, ptr %.anon7, align 4 + br label %loop.cond8 -loop.cond3: ; preds = %loop.body5, %loop.exit - %12 = load i32, ptr %.anon2, align 4 - %lt4 = icmp slt i32 %12, 3 - br i1 %lt4, label %loop.body5, label %loop.exit12 +loop.cond8: ; preds = %loop.body10, %loop.exit + %12 = load i32, ptr %.anon7, align 4 + %lt9 = icmp slt i32 %12, 3 + br i1 %lt9, label %loop.body10, label %loop.exit18 -loop.body5: ; preds = %loop.cond3 - %13 = load i32, ptr %.anon2, align 4 - store i32 %13, ptr %i6, align 4 - %14 = load i32, ptr %.anon2, align 4 - store i32 %14, ptr %a8, align 4 - %15 = load i32, ptr %a8, align 4 - %sext9 = sext i32 %15 to i64 - %ptroffset10 = getelementptr inbounds [4 x i8], ptr %x, i64 %sext9 - store ptr %ptroffset10, ptr %y7, align 8 - %16 = load ptr, ptr %y7, align 8 +loop.body10: ; preds = %loop.cond8 + %13 = load i32, ptr %.anon7, align 4 + store i32 %13, ptr %i11, align 4 + %14 = load i32, ptr %.anon7, align 4 + store i32 %14, ptr %a13, align 4 + %neq14 = icmp ne ptr %x, null + call void @llvm.assume(i1 %neq14) + %15 = load i32, ptr %a13, align 4 + %sext15 = sext i32 %15 to i64 + %ptroffset16 = getelementptr inbounds [4 x i8], ptr %x, i64 %sext15 + store ptr %ptroffset16, ptr %y12, align 8 + %16 = load ptr, ptr %y12, align 8 %17 = load i32, ptr %16, align 4 %add = add i32 %17, 1 store i32 %add, ptr %16, align 4 - %18 = load ptr, ptr %y7, align 8 - %19 = load i32, ptr %i6, align 4 + %18 = load ptr, ptr %y12, align 8 + %19 = load i32, ptr %i11, align 4 %20 = load i32, ptr %18, align 4 call void (ptr, ...) @printf(ptr @.str.5, i32 %19, i32 %20) - %21 = load i32, ptr %.anon2, align 4 - %addnsw11 = add nsw i32 %21, 1 - store i32 %addnsw11, ptr %.anon2, align 4 - br label %loop.cond3 + %21 = load i32, ptr %.anon7, align 4 + %addnsw17 = add nsw i32 %21, 1 + store i32 %addnsw17, ptr %.anon7, align 4 + br label %loop.cond8 -loop.exit12: ; preds = %loop.cond3 - store i32 0, ptr %.anon13, align 4 - br label %loop.cond14 +loop.exit18: ; preds = %loop.cond8 + %neq19 = icmp ne ptr %x, null + call void @llvm.assume(i1 %neq19) + store i32 0, ptr %.anon20, align 4 + br label %loop.cond21 -loop.cond14: ; preds = %loop.body16, %loop.exit12 - %22 = load i32, ptr %.anon13, align 4 - %lt15 = icmp slt i32 %22, 3 - br i1 %lt15, label %loop.body16, label %loop.exit23 +loop.cond21: ; preds = %loop.body23, %loop.exit18 + %22 = load i32, ptr %.anon20, align 4 + %lt22 = icmp slt i32 %22, 3 + br i1 %lt22, label %loop.body23, label %loop.exit31 -loop.body16: ; preds = %loop.cond14 - %23 = load i32, ptr %.anon13, align 4 - store i32 %23, ptr %i17, align 4 - %24 = load i32, ptr %.anon13, align 4 - store i32 %24, ptr %a19, align 4 - %25 = load i32, ptr %a19, align 4 - %sext20 = sext i32 %25 to i64 - %ptroffset21 = getelementptr inbounds [4 x i8], ptr %x, i64 %sext20 - %26 = load i32, ptr %ptroffset21, align 4 - store i32 %26, ptr %y18, align 4 - %27 = load i32, ptr %i17, align 4 - %28 = load i32, ptr %y18, align 4 +loop.body23: ; preds = %loop.cond21 + %23 = load i32, ptr %.anon20, align 4 + store i32 %23, ptr %i24, align 4 + %24 = load i32, ptr %.anon20, align 4 + store i32 %24, ptr %a26, align 4 + %neq27 = icmp ne ptr %x, null + call void @llvm.assume(i1 %neq27) + %25 = load i32, ptr %a26, align 4 + %sext28 = sext i32 %25 to i64 + %ptroffset29 = getelementptr inbounds [4 x i8], ptr %x, i64 %sext28 + %26 = load i32, ptr %ptroffset29, align 4 + store i32 %26, ptr %y25, align 4 + %27 = load i32, ptr %i24, align 4 + %28 = load i32, ptr %y25, align 4 call void (ptr, ...) @printf(ptr @.str.6, i32 %27, i32 %28) - %29 = load i32, ptr %.anon13, align 4 - %addnsw22 = add nsw i32 %29, 1 - store i32 %addnsw22, ptr %.anon13, align 4 - br label %loop.cond14 + %29 = load i32, ptr %.anon20, align 4 + %addnsw30 = add nsw i32 %29, 1 + store i32 %addnsw30, ptr %.anon20, align 4 + br label %loop.cond21 -loop.exit23: ; preds = %loop.cond14 - store i32 0, ptr %.anon24, align 4 - br label %loop.cond25 +loop.exit31: ; preds = %loop.cond21 + %neq32 = icmp ne ptr %x, null + call void @llvm.assume(i1 %neq32) + store i32 0, ptr %.anon33, align 4 + br label %loop.cond34 -loop.cond25: ; preds = %loop.body27, %loop.exit23 - %30 = load i32, ptr %.anon24, align 4 - %lt26 = icmp slt i32 %30, 3 - br i1 %lt26, label %loop.body27, label %loop.exit34 +loop.cond34: ; preds = %loop.body36, %loop.exit31 + %30 = load i32, ptr %.anon33, align 4 + %lt35 = icmp slt i32 %30, 3 + br i1 %lt35, label %loop.body36, label %loop.exit44 -loop.body27: ; preds = %loop.cond25 - %31 = load i32, ptr %.anon24, align 4 - store i32 %31, ptr %i28, align 4 - %32 = load i32, ptr %.anon24, align 4 - store i32 %32, ptr %a30, align 4 - %33 = load i32, ptr %a30, align 4 - %sext31 = sext i32 %33 to i64 - %ptroffset32 = getelementptr inbounds [4 x i8], ptr %x, i64 %sext31 - %34 = load i32, ptr %ptroffset32, align 4 - store i32 %34, ptr %y29, align 4 - %35 = load i32, ptr %i28, align 4 - %36 = load i32, ptr %y29, align 4 +loop.body36: ; preds = %loop.cond34 + %31 = load i32, ptr %.anon33, align 4 + store i32 %31, ptr %i37, align 4 + %32 = load i32, ptr %.anon33, align 4 + store i32 %32, ptr %a39, align 4 + %neq40 = icmp ne ptr %x, null + call void @llvm.assume(i1 %neq40) + %33 = load i32, ptr %a39, align 4 + %sext41 = sext i32 %33 to i64 + %ptroffset42 = getelementptr inbounds [4 x i8], ptr %x, i64 %sext41 + %34 = load i32, ptr %ptroffset42, align 4 + store i32 %34, ptr %y38, align 4 + %35 = load i32, ptr %i37, align 4 + %36 = load i32, ptr %y38, align 4 call void (ptr, ...) @printf(ptr @.str.7, i32 %35, i32 %36) - %37 = load i32, ptr %.anon24, align 4 - %addnsw33 = add nsw i32 %37, 1 - store i32 %addnsw33, ptr %.anon24, align 4 - br label %loop.cond25 + %37 = load i32, ptr %.anon33, align 4 + %addnsw43 = add nsw i32 %37, 1 + store i32 %addnsw43, ptr %.anon33, align 4 + br label %loop.cond34 -loop.exit34: ; preds = %loop.cond25 - store i32 0, ptr %.anon35, align 4 - br label %loop.cond36 +loop.exit44: ; preds = %loop.cond34 + %neq45 = icmp ne ptr %x, null + call void @llvm.assume(i1 %neq45) + store i32 0, ptr %.anon46, align 4 + br label %loop.cond47 -loop.cond36: ; preds = %loop.body38, %loop.exit34 - %38 = load i32, ptr %.anon35, align 4 - %lt37 = icmp slt i32 %38, 3 - br i1 %lt37, label %loop.body38, label %loop.exit46 +loop.cond47: ; preds = %loop.body49, %loop.exit44 + %38 = load i32, ptr %.anon46, align 4 + %lt48 = icmp slt i32 %38, 3 + br i1 %lt48, label %loop.body49, label %loop.exit58 -loop.body38: ; preds = %loop.cond36 - %39 = load i32, ptr %.anon35, align 4 - store i32 %39, ptr %i39, align 4 - %40 = load i32, ptr %.anon35, align 4 - store i32 %40, ptr %a41, align 4 - %41 = load i32, ptr %a41, align 4 - %sext42 = sext i32 %41 to i64 - %ptroffset43 = getelementptr inbounds [4 x i8], ptr %x, i64 %sext42 - %42 = load i32, ptr %ptroffset43, align 4 - store i32 %42, ptr %y40, align 4 - %43 = load i32, ptr %i39, align 4 - %44 = load i32, ptr %y40, align 4 +loop.body49: ; preds = %loop.cond47 + %39 = load i32, ptr %.anon46, align 4 + store i32 %39, ptr %i50, align 4 + %40 = load i32, ptr %.anon46, align 4 + store i32 %40, ptr %a52, align 4 + %neq53 = icmp ne ptr %x, null + call void @llvm.assume(i1 %neq53) + %41 = load i32, ptr %a52, align 4 + %sext54 = sext i32 %41 to i64 + %ptroffset55 = getelementptr inbounds [4 x i8], ptr %x, i64 %sext54 + %42 = load i32, ptr %ptroffset55, align 4 + store i32 %42, ptr %y51, align 4 + %43 = load i32, ptr %i50, align 4 + %44 = load i32, ptr %y51, align 4 call void (ptr, ...) @printf(ptr @.str.8, i32 %43, i32 %44) - %45 = load i32, ptr %i39, align 4 - %add44 = add i32 %45, 1 - store i32 %add44, ptr %i39, align 4 - %46 = load i32, ptr %.anon35, align 4 - %addnsw45 = add nsw i32 %46, 1 - store i32 %addnsw45, ptr %.anon35, align 4 - br label %loop.cond36 + %45 = load i32, ptr %i50, align 4 + %add56 = add i32 %45, 1 + store i32 %add56, ptr %i50, align 4 + %46 = load i32, ptr %.anon46, align 4 + %addnsw57 = add nsw i32 %46, 1 + store i32 %addnsw57, ptr %.anon46, align 4 + br label %loop.cond47 -loop.exit46: ; preds = %loop.cond36 - call void @llvm.memcpy.p0.p0.i32(ptr align 16 %.anon47, ptr align 16 @.__const.9, i32 20, i1 false) - store i64 0, ptr %.anon48, align 8 - br label %loop.cond49 +loop.exit58: ; preds = %loop.cond47 + call void @llvm.memcpy.p0.p0.i32(ptr align 16 %.anon59, ptr align 16 @.__const.9, i32 20, i1 false) + store i64 0, ptr %.anon60, align 8 + br label %loop.cond61 -loop.cond49: ; preds = %loop.body50, %loop.exit46 - %47 = load i64, ptr %.anon48, align 8 +loop.cond61: ; preds = %loop.body62, %loop.exit58 + %47 = load i64, ptr %.anon60, align 8 %gt = icmp ugt i64 5, %47 - br i1 %gt, label %loop.body50, label %loop.exit55 + br i1 %gt, label %loop.body62, label %loop.exit67 -loop.body50: ; preds = %loop.cond49 - %48 = load i64, ptr %.anon48, align 8 - store i64 %48, ptr %i51, align 8 - %49 = load i64, ptr %.anon48, align 8 - %ptroffset53 = getelementptr inbounds [4 x i8], ptr %.anon47, i64 %49 - %50 = load i32, ptr %ptroffset53, align 4 - store i32 %50, ptr %y52, align 4 - %51 = load i64, ptr %i51, align 8 - %52 = load i32, ptr %y52, align 4 +loop.body62: ; preds = %loop.cond61 + %48 = load i64, ptr %.anon60, align 8 + store i64 %48, ptr %i63, align 8 + %49 = load i64, ptr %.anon60, align 8 + %ptroffset65 = getelementptr inbounds [4 x i8], ptr %.anon59, i64 %49 + %50 = load i32, ptr %ptroffset65, align 4 + store i32 %50, ptr %y64, align 4 + %51 = load i64, ptr %i63, align 8 + %52 = load i32, ptr %y64, align 4 call void (ptr, ...) @printf(ptr @.str.10, i64 %51, i32 %52) - %53 = load i64, ptr %i51, align 8 - %add54 = add i64 %53, 1 - store i64 %add54, ptr %i51, align 8 - %54 = load i64, ptr %.anon48, align 8 + %53 = load i64, ptr %i63, align 8 + %add66 = add i64 %53, 1 + store i64 %add66, ptr %i63, align 8 + %54 = load i64, ptr %.anon60, align 8 %addnuw = add nuw i64 %54, 1 - store i64 %addnuw, ptr %.anon48, align 8 - br label %loop.cond49 + store i64 %addnuw, ptr %.anon60, align 8 + br label %loop.cond61 -loop.exit55: ; preds = %loop.cond49 - call void @foo.getFields(ptr sret([5 x i32]) align 4 %.anon56) - store i64 0, ptr %.anon57, align 8 - br label %loop.cond58 +loop.exit67: ; preds = %loop.cond61 + call void @foo.getFields(ptr sret([5 x i32]) align 4 %.anon68) + store i64 0, ptr %.anon69, align 8 + br label %loop.cond70 -loop.cond58: ; preds = %loop.body60, %loop.exit55 - %55 = load i64, ptr %.anon57, align 8 - %gt59 = icmp ugt i64 5, %55 - br i1 %gt59, label %loop.body60, label %loop.exit65 +loop.cond70: ; preds = %loop.body72, %loop.exit67 + %55 = load i64, ptr %.anon69, align 8 + %gt71 = icmp ugt i64 5, %55 + br i1 %gt71, label %loop.body72, label %loop.exit77 -loop.body60: ; preds = %loop.cond58 - %56 = load i64, ptr %.anon57, align 8 - store i64 %56, ptr %i61, align 8 - %57 = load i64, ptr %.anon57, align 8 - %ptroffset63 = getelementptr inbounds [4 x i8], ptr %.anon56, i64 %57 - %58 = load i32, ptr %ptroffset63, align 4 - store i32 %58, ptr %y62, align 4 - %59 = load i64, ptr %i61, align 8 - %60 = load i32, ptr %y62, align 4 +loop.body72: ; preds = %loop.cond70 + %56 = load i64, ptr %.anon69, align 8 + store i64 %56, ptr %i73, align 8 + %57 = load i64, ptr %.anon69, align 8 + %ptroffset75 = getelementptr inbounds [4 x i8], ptr %.anon68, i64 %57 + %58 = load i32, ptr %ptroffset75, align 4 + store i32 %58, ptr %y74, align 4 + %59 = load i64, ptr %i73, align 8 + %60 = load i32, ptr %y74, align 4 call void (ptr, ...) @printf(ptr @.str.11, i64 %59, i32 %60) - %61 = load i64, ptr %.anon57, align 8 - %addnuw64 = add nuw i64 %61, 1 - store i64 %addnuw64, ptr %.anon57, align 8 - br label %loop.cond58 + %61 = load i64, ptr %.anon69, align 8 + %addnuw76 = add nuw i64 %61, 1 + store i64 %addnuw76, ptr %.anon69, align 8 + br label %loop.cond70 -loop.exit65: ; preds = %loop.cond58 +loop.exit77: ; preds = %loop.cond70 call void @foo.getFields(ptr sret([5 x i32]) align 4 %sretparam) - store i64 0, ptr %.anon66, align 8 - br label %loop.cond67 + store i64 0, ptr %.anon78, align 8 + br label %loop.cond79 -loop.cond67: ; preds = %loop.body69, %loop.exit65 - %62 = load i64, ptr %.anon66, align 8 - %gt68 = icmp ugt i64 5, %62 - br i1 %gt68, label %loop.body69, label %loop.exit74 +loop.cond79: ; preds = %loop.body81, %loop.exit77 + %62 = load i64, ptr %.anon78, align 8 + %gt80 = icmp ugt i64 5, %62 + br i1 %gt80, label %loop.body81, label %loop.exit86 -loop.body69: ; preds = %loop.cond67 - %63 = load i64, ptr %.anon66, align 8 - store i64 %63, ptr %i70, align 8 - %64 = load i64, ptr %.anon66, align 8 - %ptroffset72 = getelementptr inbounds [4 x i8], ptr %sretparam, i64 %64 - %65 = load i32, ptr %ptroffset72, align 4 - store i32 %65, ptr %y71, align 4 - %66 = load i64, ptr %i70, align 8 - %67 = load i32, ptr %y71, align 4 +loop.body81: ; preds = %loop.cond79 + %63 = load i64, ptr %.anon78, align 8 + store i64 %63, ptr %i82, align 8 + %64 = load i64, ptr %.anon78, align 8 + %ptroffset84 = getelementptr inbounds [4 x i8], ptr %sretparam, i64 %64 + %65 = load i32, ptr %ptroffset84, align 4 + store i32 %65, ptr %y83, align 4 + %66 = load i64, ptr %i82, align 8 + %67 = load i32, ptr %y83, align 4 call void (ptr, ...) @printf(ptr @.str.12, i64 %66, i32 %67) - %68 = load i64, ptr %.anon66, align 8 - %addnuw73 = add nuw i64 %68, 1 - store i64 %addnuw73, ptr %.anon66, align 8 - br label %loop.cond67 + %68 = load i64, ptr %.anon78, align 8 + %addnuw85 = add nuw i64 %68, 1 + store i64 %addnuw85, ptr %.anon78, align 8 + br label %loop.cond79 -loop.exit74: ; preds = %loop.cond67 - %ptradd75 = getelementptr inbounds i8, ptr %x, i64 4 +loop.exit86: ; preds = %loop.cond79 + %neq87 = icmp ne ptr %x, null + call void @llvm.assume(i1 %neq87) + %neq88 = icmp ne ptr %x, null + call void @llvm.assume(i1 %neq88) + %ptradd89 = getelementptr inbounds i8, ptr %x, i64 4 %69 = load i32, ptr %x, align 4 - %70 = load i32, ptr %ptradd75, align 4 + %70 = load i32, ptr %ptradd89, align 4 call void (ptr, ...) @printf(ptr @.str.13, i32 %69, i32 %70) - %ptradd77 = getelementptr inbounds i8, ptr %x, i64 4 - store ptr %ptradd77, ptr %y76, align 8 - %71 = load ptr, ptr %y76, align 8 + %neq91 = icmp ne ptr %x, null + call void @llvm.assume(i1 %neq91) + %ptradd92 = getelementptr inbounds i8, ptr %x, i64 4 + store ptr %ptradd92, ptr %y90, align 8 + %71 = load ptr, ptr %y90, align 8 %72 = load i32, ptr %71, align 4 - %add78 = add i32 %72, 1 - store i32 %add78, ptr %71, align 4 - %ptradd79 = getelementptr inbounds i8, ptr %x, i64 4 + %add93 = add i32 %72, 1 + store i32 %add93, ptr %71, align 4 + %neq94 = icmp ne ptr %x, null + call void @llvm.assume(i1 %neq94) + %neq95 = icmp ne ptr %x, null + call void @llvm.assume(i1 %neq95) + %ptradd96 = getelementptr inbounds i8, ptr %x, i64 4 %73 = load i32, ptr %x, align 4 - %74 = load i32, ptr %ptradd79, align 4 + %74 = load i32, ptr %ptradd96, align 4 call void (ptr, ...) @printf(ptr @.str.14, i32 %73, i32 %74) ret void } diff --git a/test/test_suite/statements/foreach_custom.c3t b/test/test_suite/statements/foreach_custom.c3t index 20fe1a3d9..067418d52 100644 --- a/test/test_suite/statements/foreach_custom.c3t +++ b/test/test_suite/statements/foreach_custom.c3t @@ -45,6 +45,8 @@ entry: %0 = insertvalue %"int[]" undef, ptr %i, 0 %1 = insertvalue %"int[]" %0, i64 3, 1 store %"int[]" %1, ptr %x, align 8 + %neq = icmp ne ptr %x, null + call void @llvm.assume(i1 %neq) %ptradd = getelementptr inbounds i8, ptr %x, i64 8 %2 = load i64, ptr %ptradd, align 8 store i64 0, ptr %.anon, align 8 @@ -58,6 +60,8 @@ loop.cond: ; preds = %entry loop.body: ; preds = %loop.cond %4 = load i64, ptr %.anon, align 8 store i64 %4, ptr %index, align 8 + %neq1 = icmp ne ptr %x, null + call void @llvm.assume(i1 %neq1) %5 = load ptr, ptr %x, align 8 %6 = load i64, ptr %index, align 8 %ptroffset = getelementptr inbounds [4 x i8], ptr %5, i64 %6 @@ -65,19 +69,17 @@ loop.body: ; preds = %loop.cond store i32 %7, ptr %f, align 4 %8 = load i32, ptr %f, align 4 %9 = call i32 (ptr, ...) @printf(ptr @.str, i32 %8) - br label %loop.body1 + br label %loop.body2 -loop.body1: ; preds = %loop.body +loop.body2: ; preds = %loop.body br label %loop.exit -loop.exit: ; preds = %loop.body1, %loop.cond +loop.exit: ; preds = %loop.body2, %loop.cond ret void } -; Function Attrs: declare i32 @printf(ptr, ...) #0 -; Function Attrs: define i32 @main(i32 %0, ptr %1) #0 { entry: call void @test.main() diff --git a/test/test_suite/statements/foreach_custom_macro.c3t b/test/test_suite/statements/foreach_custom_macro.c3t index 1f03574ea..85926974b 100644 --- a/test/test_suite/statements/foreach_custom_macro.c3t +++ b/test/test_suite/statements/foreach_custom_macro.c3t @@ -51,6 +51,8 @@ entry: %0 = insertvalue %"int[]" undef, ptr %i, 0 %1 = insertvalue %"int[]" %0, i64 3, 1 store %"int[]" %1, ptr %x, align 8 + %neq = icmp ne ptr %x, null + call void @llvm.assume(i1 %neq) %ptradd = getelementptr inbounds i8, ptr %x, i64 8 %2 = load i64, ptr %ptradd, align 8 store i64 0, ptr %.anon, align 8 @@ -64,6 +66,8 @@ loop.cond: ; preds = %entry loop.body: ; preds = %loop.cond %4 = load i64, ptr %.anon, align 8 store i64 %4, ptr %index, align 8 + %neq1 = icmp ne ptr %x, null + call void @llvm.assume(i1 %neq1) %5 = load ptr, ptr %x, align 8 %6 = load i64, ptr %index, align 8 %ptroffset = getelementptr inbounds [4 x i8], ptr %5, i64 %6 @@ -71,12 +75,12 @@ loop.body: ; preds = %loop.cond store i32 %7, ptr %f, align 4 %8 = load i32, ptr %f, align 4 %9 = call i32 (ptr, ...) @printf(ptr @.str, i32 %8) - br label %loop.body1 + br label %loop.body2 -loop.body1: ; preds = %loop.body +loop.body2: ; preds = %loop.body br label %loop.exit -loop.exit: ; preds = %loop.body1, %loop.cond +loop.exit: ; preds = %loop.body2, %loop.cond ret void } diff --git a/test/test_suite/statements/foreach_r_custom.c3t b/test/test_suite/statements/foreach_r_custom.c3t index 38ac06e01..1641f3e7a 100644 --- a/test/test_suite/statements/foreach_r_custom.c3t +++ b/test/test_suite/statements/foreach_r_custom.c3t @@ -45,6 +45,8 @@ entry: %0 = insertvalue %"int[]" undef, ptr %i, 0 %1 = insertvalue %"int[]" %0, i64 3, 1 store %"int[]" %1, ptr %x, align 8 + %neq = icmp ne ptr %x, null + call void @llvm.assume(i1 %neq) %ptradd = getelementptr inbounds i8, ptr %x, i64 8 %2 = load i64, ptr %ptradd, align 8 store i64 %2, ptr %.anon, align 8 @@ -61,6 +63,8 @@ loop.body: ; preds = %loop.cond store i64 %subnuw, ptr %.anon, align 8 %5 = load i64, ptr %.anon, align 8 store i64 %5, ptr %index, align 8 + %neq1 = icmp ne ptr %x, null + call void @llvm.assume(i1 %neq1) %6 = load ptr, ptr %x, align 8 %7 = load i64, ptr %index, align 8 %ptroffset = getelementptr inbounds [4 x i8], ptr %6, i64 %7 @@ -68,12 +72,12 @@ loop.body: ; preds = %loop.cond store i32 %8, ptr %f, align 4 %9 = load i32, ptr %f, align 4 %10 = call i32 (ptr, ...) @printf(ptr @.str, i32 %9) - br label %loop.body1 + br label %loop.body2 -loop.body1: ; preds = %loop.body +loop.body2: ; preds = %loop.body br label %loop.exit -loop.exit: ; preds = %loop.body1, %loop.cond +loop.exit: ; preds = %loop.body2, %loop.cond ret void } diff --git a/test/test_suite/statements/foreach_r_custom_macro.c3t b/test/test_suite/statements/foreach_r_custom_macro.c3t index 2239fa8cf..63375ff5c 100644 --- a/test/test_suite/statements/foreach_r_custom_macro.c3t +++ b/test/test_suite/statements/foreach_r_custom_macro.c3t @@ -44,6 +44,8 @@ entry: %0 = insertvalue %"int[]" undef, ptr %i, 0 %1 = insertvalue %"int[]" %0, i64 3, 1 store %"int[]" %1, ptr %x, align 8 + %neq = icmp ne ptr %x, null + call void @llvm.assume(i1 %neq) %ptradd = getelementptr inbounds i8, ptr %x, i64 8 %2 = load i64, ptr %ptradd, align 8 store i64 %2, ptr %.anon, align 8 @@ -60,6 +62,8 @@ loop.body: ; preds = %loop.cond store i64 %subnuw, ptr %.anon, align 8 %5 = load i64, ptr %.anon, align 8 store i64 %5, ptr %index, align 8 + %neq1 = icmp ne ptr %x, null + call void @llvm.assume(i1 %neq1) %6 = load ptr, ptr %x, align 8 %7 = load i64, ptr %index, align 8 %ptroffset = getelementptr inbounds [4 x i8], ptr %6, i64 %7 @@ -67,11 +71,11 @@ loop.body: ; preds = %loop.cond store i32 %8, ptr %f, align 4 %9 = load i32, ptr %f, align 4 %10 = call i32 (ptr, ...) @printf(ptr @.str, i32 %9) - br label %loop.body1 + br label %loop.body2 -loop.body1: ; preds = %loop.body +loop.body2: ; preds = %loop.body br label %loop.exit -loop.exit: ; preds = %loop.body1, %loop.cond +loop.exit: ; preds = %loop.body2, %loop.cond ret void } diff --git a/test/unit/regression/run_temp_mem.c3 b/test/unit/regression/run_temp_mem.c3 new file mode 100644 index 000000000..8453c2482 --- /dev/null +++ b/test/unit/regression/run_temp_mem.c3 @@ -0,0 +1,15 @@ +module temp_mem; + +fn void test_realloc() @test +{ + void* mem = tmalloc(10); + for (int i = 1; i < 4096 * 32 * 16 * 2; i <<= 1) + { + mem = mem::trealloc(mem, i); + } + for (int i = 4096 * 32 * 16 * 2; i > 2; i >>= 1) + { + mem = mem::trealloc(mem, i); + (void)tmalloc(1235); + } +} \ No newline at end of file