From 8cc8c321a29d23da124ffb5fdea3c7bf395712e7 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Fri, 19 Nov 2021 13:06:43 +0100 Subject: [PATCH] Optimized rethrow expr. Fix to "Foo! x = {}" which would break. Remove unnecessary zeroing failables. Variables that are undefined do not have failable status zeroed. --- src/compiler/llvm_codegen.c | 1 + src/compiler/llvm_codegen_debug_info.c | 1 - src/compiler/llvm_codegen_expr.c | 11 +- src/compiler/llvm_codegen_stmt.c | 13 +- test/test_suite/enumerations/enum_cast.c3t | 2 - test/test_suite/errors/failable_inits.c3t | 117 ++++++++++++++++++ .../errors/failable_taddr_and_access.c3t | 1 - test/test_suite/errors/rethrow.c3t | 40 +++--- test/test_suite/errors/rethrow_mingw.c3t | 6 +- test/test_suite/errors/try_assign.c3t | 1 - test/test_suite/errors/try_with_unwrapper.c3t | 1 - .../from_docs/examples_if_catch.c3t | 6 +- 12 files changed, 157 insertions(+), 43 deletions(-) create mode 100644 test/test_suite/errors/failable_inits.c3t diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index e71b46eba..b26039f91 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -868,6 +868,7 @@ void llvm_value_fold_failable(GenContext *c, BEValue *value) } else { + assert(c->catch_block); llvm_emit_cond_br(c, &comp, after_block, c->catch_block); } llvm_emit_block(c, after_block); diff --git a/src/compiler/llvm_codegen_debug_info.c b/src/compiler/llvm_codegen_debug_info.c index 23f2f6ef6..7f5eefafc 100644 --- a/src/compiler/llvm_codegen_debug_info.c +++ b/src/compiler/llvm_codegen_debug_info.c @@ -453,7 +453,6 @@ static LLVMMetadataRef llvm_debug_vector_type(GenContext *c, Type *type) { LLVMMetadataRef *ranges = NULL; Type *current_type = type; - REMINDER("Handle Recursive Vector type"); while (current_type->canonical->type_kind == TYPE_VECTOR) { vec_add(ranges, LLVMDIBuilderGetOrCreateSubrange(c->debug.builder, 0, current_type->canonical->vector.len)); diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index a4d8e6a8e..13f4fc91f 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -3289,7 +3289,7 @@ static void gencontext_emit_or_error(GenContext *c, BEValue *be_value, Expr *exp /** * This is the foo? instruction. */ -static inline void gencontext_emit_rethrow_expr(GenContext *c, BEValue *be_value, Expr *expr) +static inline void llvm_emit_rethrow_expr(GenContext *c, BEValue *be_value, Expr *expr) { LLVMBasicBlockRef guard_block = llvm_basic_block_new(c, "guard_block"); LLVMBasicBlockRef no_err_block = llvm_basic_block_new(c, "noerr_block"); @@ -3304,8 +3304,8 @@ static inline void gencontext_emit_rethrow_expr(GenContext *c, BEValue *be_value c->catch_block = guard_block; llvm_emit_expr(c, be_value, expr->rethrow_expr.inner); - REMINDER("Passed rvalue on guard, consider semantics."); - llvm_value_rvalue(c, be_value); + // Fold the failable. + llvm_value_fold_failable(c, be_value); // Restore. POP_ERROR(); @@ -3313,8 +3313,6 @@ static inline void gencontext_emit_rethrow_expr(GenContext *c, BEValue *be_value // Emit success and to end. llvm_emit_br(c, no_err_block); - POP_ERROR(); - // Emit else llvm_emit_block(c, guard_block); @@ -3447,6 +3445,7 @@ static void llvm_emit_binary_expr(GenContext *c, BEValue *be_value, Expr *expr) if (expr->binary_expr.left->expr_kind == EXPR_IDENTIFIER) { failable_ref = decl_failable_ref(left->identifier_expr.decl); + be_value->kind = BE_ADDRESS; } *be_value = llvm_emit_assign_expr(c, be_value, expr->binary_expr.right, failable_ref); return; @@ -5084,7 +5083,7 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr) llvm_emit_force_unwrap_expr(c, value, expr); return; case EXPR_RETHROW: - gencontext_emit_rethrow_expr(c, value, expr); + llvm_emit_rethrow_expr(c, value, expr); return; case EXPR_TYPEID: case EXPR_GROUP: diff --git a/src/compiler/llvm_codegen_stmt.c b/src/compiler/llvm_codegen_stmt.c index e99311f14..69b8d174a 100644 --- a/src/compiler/llvm_codegen_stmt.c +++ b/src/compiler/llvm_codegen_stmt.c @@ -70,6 +70,7 @@ LLVMValueRef llvm_emit_local_decl(GenContext *c, Decl *decl) return decl->backend_ref; } llvm_emit_local_var_alloca(c, decl); + Expr *init = decl->var.init_expr; if (IS_FAILABLE(decl)) { scratch_buffer_clear(); @@ -77,13 +78,8 @@ LLVMValueRef llvm_emit_local_decl(GenContext *c, Decl *decl) scratch_buffer_append(".f"); decl->var.failable_ref = llvm_emit_alloca_aligned(c, type_anyerr, scratch_buffer_to_string()); // Only clear out the result if the assignment isn't a failable. - if (!decl->var.init_expr || !IS_FAILABLE(decl->var.init_expr)) - { - LLVMBuildStore(c->builder, LLVMConstNull(llvm_get_type(c, type_anyerr)), decl->var.failable_ref); - } } - Expr *init = decl->var.init_expr; if (init) { // If we don't have undef, then make an assign. @@ -91,12 +87,18 @@ LLVMValueRef llvm_emit_local_decl(GenContext *c, Decl *decl) { BEValue value; llvm_value_set_decl_address(&value, decl); + value.kind = BE_ADDRESS; llvm_emit_assign_expr(c, &value, decl->var.init_expr, decl->var.failable_ref); } // TODO trap on undef in debug mode. } else { + if (decl->var.failable_ref) + { + LLVMBuildStore(c->builder, LLVMConstNull(llvm_get_type(c, type_anyerr)), decl->var.failable_ref); + } + Type *type = type_lowering(decl->type); // Normal case, zero init. if (type_is_builtin(type->type_kind) || type->type_kind == TYPE_POINTER) @@ -107,6 +109,7 @@ LLVMValueRef llvm_emit_local_decl(GenContext *c, Decl *decl) { BEValue value; llvm_value_set_decl_address(&value, decl); + value.kind = BE_ADDRESS; llvm_emit_memclear(c, &value); } } diff --git a/test/test_suite/enumerations/enum_cast.c3t b/test/test_suite/enumerations/enum_cast.c3t index 14218cf93..2406b5827 100644 --- a/test/test_suite/enumerations/enum_cast.c3t +++ b/test/test_suite/enumerations/enum_cast.c3t @@ -49,10 +49,8 @@ entry: store i32 %uisiext, i32* %z2, align 4 store float 3.000000e+00, float* %d, align 4 store i8 1, i8* %hello, align 1 - store i64 0, i64* %xf.f, align 8 store i8 100, i8* %xf, align 1 store i64 0, i64* %xf.f, align 8 - store i64 0, i64* %e.f, align 8 %2 = load i8, i8* %x, align 1 %uifp = uitofp i8 %2 to float store float %uifp, float* %e, align 4 diff --git a/test/test_suite/errors/failable_inits.c3t b/test/test_suite/errors/failable_inits.c3t new file mode 100644 index 000000000..fafa6eda6 --- /dev/null +++ b/test/test_suite/errors/failable_inits.c3t @@ -0,0 +1,117 @@ +module test; +import std::io; +errtype Foo +{ + MY_VAL1, + MY_VAL2, +} + +struct Bar +{ + int x; +} + +fn void! test1() +{ + Bar! x = Foo.MY_VAL1!; + Bar y = x?; +} + +fn void! test2() +{ + Bar! x = {}; + Bar y = x?; +} + +fn void main() +{ + test1(); + test2(); +} + +/* #expect: test.ll + +define i64 @test.test1() #0 { +entry: + %x = alloca %Bar, align 4 + %x.f = alloca i64, align 8 + %y = alloca %Bar, align 4 + %error_var = alloca i64, align 8 + store i64 ptrtoint ([2 x i8*]* @"test.Foo$elements" to i64), i64* %x.f, align 8 + br label %after_assign + +after_assign: ; preds = %entry + %0 = load i64, i64* %x.f, align 8 + %not_err = icmp eq i64 %0, 0 + br i1 %not_err, label %after_check, label %error + +error: ; preds = %after_assign + store i64 %0, i64* %error_var, align 8 + br label %guard_block + +after_check: ; preds = %after_assign + br label %noerr_block + +guard_block: ; preds = %error + %1 = load i64, i64* %error_var, align 8 + ret i64 %1 + +noerr_block: ; preds = %after_check + %2 = bitcast %Bar* %y to i8* + %3 = bitcast %Bar* %x to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %2, i8* align 4 %3, i32 4, i1 false) + ret i64 0 +} + +define i64 @test.test2() #0 { +entry: + %x = alloca %Bar, align 4 + %x.f = alloca i64, align 8 + %y = alloca %Bar, align 4 + %error_var = alloca i64, align 8 + %0 = bitcast %Bar* %x to i32* + store i32 0, i32* %0, align 4 + store i64 0, i64* %x.f, align 8 + %1 = load i64, i64* %x.f, align 8 + %not_err = icmp eq i64 %1, 0 + br i1 %not_err, label %after_check, label %error + +error: ; preds = %entry + store i64 %1, i64* %error_var, align 8 + br label %guard_block + +after_check: ; preds = %entry + br label %noerr_block + +guard_block: ; preds = %error + %2 = load i64, i64* %error_var, align 8 + ret i64 %2 + +noerr_block: ; preds = %after_check + %3 = bitcast %Bar* %y to i8* + %4 = bitcast %Bar* %x to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %3, i8* align 4 %4, i32 4, i1 false) + ret i64 0 +} + +; Function Attrs: nounwind +define void @main() #0 { +entry: + %0 = call i64 @test.test1() + %not_err = icmp eq i64 %0, 0 + br i1 %not_err, label %after.errcheck, label %voiderr + +after.errcheck: ; preds = %entry + br label %voiderr + +voiderr: ; preds = %after.errcheck, %entry + %1 = call i64 @test.test2() + %not_err1 = icmp eq i64 %1, 0 + br i1 %not_err1, label %after.errcheck2, label %voiderr3 + +after.errcheck2: ; preds = %voiderr + br label %voiderr3 + +voiderr3: ; preds = %after.errcheck2, %voiderr + ret void +} diff --git a/test/test_suite/errors/failable_taddr_and_access.c3t b/test/test_suite/errors/failable_taddr_and_access.c3t index bd87a32c8..7a17f92d7 100644 --- a/test/test_suite/errors/failable_taddr_and_access.c3t +++ b/test/test_suite/errors/failable_taddr_and_access.c3t @@ -45,7 +45,6 @@ entry: %w.f = alloca i64, align 8 %literal = alloca %Foo, align 4 %literal5 = alloca %Foo, align 4 - store i64 0, i64* %z.f, align 8 store i32 2, i32* %z, align 4 store i64 0, i64* %z.f, align 8 %0 = getelementptr inbounds %Foo, %Foo* %literal, i32 0, i32 0 diff --git a/test/test_suite/errors/rethrow.c3t b/test/test_suite/errors/rethrow.c3t index 118ce8c6d..d3ceb814c 100644 --- a/test/test_suite/errors/rethrow.c3t +++ b/test/test_suite/errors/rethrow.c3t @@ -8,27 +8,27 @@ fn void! test() // #expect: rethrow.ll - %i = alloca i32, align 4 - %i.f = alloca i64, align 8 - %error_var = alloca i64, align 8 - store i64 0, i64* %i.f, align 8 - store i32 0, i32* %i, align 4 - %0 = load i64, i64* %i.f, align 8 - %not_err = icmp eq i64 %0, 0 - br i1 %not_err, label %after_check, label %error + %i = alloca i32, align 4 + %i.f = alloca i64, align 8 + %error_var = alloca i64, align 8 + store i64 0, i64* %i.f, align 8 + store i32 0, i32* %i, align 4 + %0 = load i64, i64* %i.f, align 8 + %not_err = icmp eq i64 %0, 0 + br i1 %not_err, label %after_check, label %error -error: ; preds = %entry - store i64 %0, i64* %error_var, align 8 - br label %guard_block + error: ; preds = %entry + store i64 %0, i64* %error_var, align 8 + br label %guard_block -after_check: ; preds = %entry - %1 = load i32, i32* %i, align 4 - br label %noerr_block + after_check: ; preds = %entry + br label %noerr_block -guard_block: ; preds = %error - %2 = load i64, i64* %error_var, align 8 - ret i64 %2 + guard_block: ; preds = %error + %1 = load i64, i64* %error_var, align 8 + ret i64 %1 -noerr_block: ; preds = %after_check - ret i64 0 -} + noerr_block: ; preds = %after_check + %2 = load i32, i32* %i, align 4 + ret i64 0 + } diff --git a/test/test_suite/errors/rethrow_mingw.c3t b/test/test_suite/errors/rethrow_mingw.c3t index 50a7957b7..5f488430f 100644 --- a/test/test_suite/errors/rethrow_mingw.c3t +++ b/test/test_suite/errors/rethrow_mingw.c3t @@ -26,14 +26,14 @@ error: ; preds = %entry br label %guard_block after_check: ; preds = %entry - %1 = load i32, i32* %i, align 4 br label %noerr_block guard_block: ; preds = %error - %2 = load i64, i64* %error_var, align 8 - ret i64 %2 + %1 = load i64, i64* %error_var, align 8 + ret i64 %1 noerr_block: ; preds = %after_check + %2 = load i32, i32* %i, align 4 ret i64 0 } diff --git a/test/test_suite/errors/try_assign.c3t b/test/test_suite/errors/try_assign.c3t index 6c29e36cd..262a81b29 100644 --- a/test/test_suite/errors/try_assign.c3t +++ b/test/test_suite/errors/try_assign.c3t @@ -37,7 +37,6 @@ entry: %gh = alloca i32, align 4 %e = alloca i64, align 8 store i32 123, i32* %x, align 4 - store i64 0, i64* %z.f, align 8 store i32 234, i32* %z, align 4 store i64 0, i64* %z.f, align 8 store i64 0, i64* %w.f, align 8 diff --git a/test/test_suite/errors/try_with_unwrapper.c3t b/test/test_suite/errors/try_with_unwrapper.c3t index b0d122a86..5f48b7f6d 100644 --- a/test/test_suite/errors/try_with_unwrapper.c3t +++ b/test/test_suite/errors/try_with_unwrapper.c3t @@ -73,7 +73,6 @@ entry: %b = alloca i32, align 4 %c = alloca i32, align 4 %retparam = alloca i32, align 4 - store i64 0, i64* %a.f, align 8 store i32 11, i32* %a, align 4 store i64 0, i64* %a.f, align 8 store i32 0, i32* %b, align 4 diff --git a/test/test_suite/from_docs/examples_if_catch.c3t b/test/test_suite/from_docs/examples_if_catch.c3t index a6039da1c..ae3eed530 100644 --- a/test/test_suite/from_docs/examples_if_catch.c3t +++ b/test/test_suite/from_docs/examples_if_catch.c3t @@ -94,14 +94,14 @@ error: ; preds = %entry br label %guard_block after.errcheck: ; preds = %entry - %3 = load double, double* %retparam, align 8 br label %noerr_block guard_block: ; preds = %error - %4 = load i64, i64* %error_var, align 8 - ret i64 %4 + %3 = load i64, i64* %error_var, align 8 + ret i64 %3 noerr_block: ; preds = %after.errcheck + %4 = load double, double* %retparam, align 8 ret i64 0 }