mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
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:
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
117
test/test_suite/errors/failable_inits.c3t
Normal file
117
test/test_suite/errors/failable_inits.c3t
Normal 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
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user