Optimized rethrow expr. Fix to "Foo! x = {}" which would break. Remove unnecessary zeroing failables. Variables that are undefined do not have failable status zeroed.

This commit is contained in:
Christoffer Lerno
2021-11-19 13:06:43 +01:00
parent 0358724451
commit 8cc8c321a2
12 changed files with 157 additions and 43 deletions

View File

@@ -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);

View File

@@ -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));

View File

@@ -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:

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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
}

View File

@@ -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

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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

View File

@@ -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

View File

@@ -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
}