Fix defer with static variables.

This commit is contained in:
Christoffer Lerno
2022-03-31 10:11:37 +02:00
parent 34bd5fa6da
commit 2e2a1ca21a
5 changed files with 231 additions and 4 deletions

View File

@@ -2441,6 +2441,7 @@ typedef struct CopyStruct_
{
CopyFixup fixups[MAX_FIXUPS];
CopyFixup *current_fixup;
bool single_static;
} CopyStruct;
#define MACRO_COPY_DECL(x) x = copy_decl(c, x)
@@ -2460,6 +2461,7 @@ typedef struct CopyStruct_
Expr *expr_macro_copy(Expr *source_expr);
Decl **decl_copy_list(Decl **decl_list);
Ast *ast_macro_copy(Ast *source_ast);
Ast *ast_defer_copy(Ast *source_ast);
Expr **copy_expr_list(CopyStruct *c, Expr **expr_list);
Expr *copy_expr(CopyStruct *c, Expr *source_expr);

View File

@@ -3,8 +3,6 @@
#define SCOPE_FIXUP_START do { CopyFixup *current = c->current_fixup;
#define SCOPE_FIXUP_END c->current_fixup = current; } while (0)
static inline void copy_reg_ref(CopyStruct *c, void *original, void *result)
{
c->current_fixup->new_ptr = result;
@@ -146,12 +144,21 @@ static CopyStruct copy_struct;
Ast *ast_macro_copy(Ast *source_ast)
{
copy_struct.current_fixup = copy_struct.fixups;
copy_struct.single_static = false;
return ast_copy_deep(&copy_struct, source_ast);
}
Ast *ast_defer_copy(Ast *source_ast)
{
copy_struct.current_fixup = copy_struct.fixups;
copy_struct.single_static = true;
return ast_copy_deep(&copy_struct, source_ast);
}
Expr *expr_macro_copy(Expr *source_expr)
{
copy_struct.current_fixup = copy_struct.fixups;
copy_struct.single_static = false;
return copy_expr(&copy_struct, source_expr);
}
@@ -560,9 +567,19 @@ static Attr **copy_attributes(CopyStruct *c, Attr** attr_list)
}
return list;
}
static inline bool decl_is_resolved_static_var(Decl *decl)
{
if (decl->resolve_status != RESOLVE_DONE) return false;
if (decl->decl_kind != DECL_VAR) return false;
if (decl->var.kind != VARDECL_LOCAL) return false;
return decl->var.is_static;
}
Decl *copy_decl(CopyStruct *c, Decl *decl)
{
if (!decl) return NULL;
if (c->single_static && decl_is_resolved_static_var(decl)) return decl;
Decl *copy = decl_copy(decl);
copy_reg_ref(c, decl, copy);
copy->attributes = copy_attributes(c, copy->attributes);

View File

@@ -34,6 +34,8 @@ LLVMValueRef llvm_emit_local_decl(GenContext *c, Decl *decl)
// then we essentially treat this as a global.
if (decl->var.is_static)
{
// In defers we might already have generated this variable.
if (decl->backend_ref) return decl->backend_ref;
void *builder = c->builder;
c->builder = NULL;
decl->backend_ref = LLVMAddGlobal(c->module, alloc_type, "tempglobal");
@@ -48,6 +50,7 @@ LLVMValueRef llvm_emit_local_decl(GenContext *c, Decl *decl)
c->builder = builder;
return decl->backend_ref;
}
assert(!decl->backend_ref);
llvm_emit_local_var_alloca(c, decl);
Expr *init = decl->var.init_expr;
if (IS_FAILABLE(decl))

View File

@@ -88,7 +88,7 @@ AstId context_get_defers(SemaContext *context, AstId defer_top, AstId defer_bott
while (defer_bottom != defer_top)
{
Ast *defer = astptr(defer_top);
Ast *defer_body = ast_macro_copy(astptr(defer->defer_stmt.body));
Ast *defer_body = ast_defer_copy(astptr(defer->defer_stmt.body));
*next = astid(defer_body);
next = &defer_body->next;
defer_top = defer->defer_stmt.prev_defer;
@@ -105,7 +105,7 @@ void context_pop_defers(SemaContext *context, AstId *next)
while (defer_current != defer_start)
{
Ast *defer = astptr(defer_current);
Ast *defer_body = ast_macro_copy(astptr(defer->defer_stmt.body));
Ast *defer_body = ast_defer_copy(astptr(defer->defer_stmt.body));
*next = astid(defer_body);
next = &defer_body->next;
defer_current = defer->defer_stmt.prev_defer;

View File

@@ -0,0 +1,205 @@
// #target: x64-darwin
module foo;
extern fn void printf(char*,...);
fn int foo(int x)
{
defer
{
static int y = 0;
y++;
printf("Here we go %d\n", y);
}
if (x > 0) return 2;
return x;
}
macro void foo2(int x)
{
printf("->%d\n", x);
for (int i = 0; i < 100; i++)
{
defer
{
static int y = 0;
y++;
printf(">%d--%d\n", i, y);
}
if (i == x) break;
printf("--");
}
}
fn void main()
{
foo(1);
foo(2);
foo(-2);
@foo2(0);
@foo2(1);
@foo2(2);
}
/* #expect: foo.ll
@foo.y = internal unnamed_addr global i32 0, align 4
@main.y = internal unnamed_addr global i32 0, align 4
@main.y.7 = internal unnamed_addr global i32 0, align 4
@main.y.12 = internal unnamed_addr global i32 0, align 4
define i32 @foo.foo(i32 %0) #0 {
entry:
%gt = icmp sgt i32 %0, 0
br i1 %gt, label %if.then, label %if.exit
if.then: ; preds = %entry
%1 = load i32, i32* @foo.y, align 4
%add = add i32 %1, 1
store i32 %add, i32* @foo.y, align 4
%2 = load i32, i32* @foo.y, align 4
call void (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.str, i32 0, i32 0), i32 %2)
ret i32 2
if.exit: ; preds = %entry
%3 = load i32, i32* @foo.y, align 4
%add1 = add i32 %3, 1
store i32 %add1, i32* @foo.y, align 4
%4 = load i32, i32* @foo.y, align 4
call void (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.str.1, i32 0, i32 0), i32 %4)
ret i32 %0
}
define void @foo.main() #0 {
entry:
%x = alloca i32, align 4
%i = alloca i32, align 4
%x3 = alloca i32, align 4
%i4 = alloca i32, align 4
%x15 = alloca i32, align 4
%i16 = alloca i32, align 4
%0 = call i32 @foo.foo(i32 1)
%1 = call i32 @foo.foo(i32 2)
%2 = call i32 @foo.foo(i32 -2)
store i32 0, i32* %x, align 4
%3 = load i32, i32* %x, align 4
call void (i8*, ...) @printf(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.2, i32 0, i32 0), i32 %3)
store i32 0, i32* %i, align 4
br label %loop.cond
loop.cond: ; preds = %if.exit, %entry
%4 = load i32, i32* %i, align 4
%lt = icmp slt i32 %4, 100
br i1 %lt, label %loop.body, label %loop.exit
loop.body: ; preds = %loop.cond
%5 = load i32, i32* %i, align 4
%6 = load i32, i32* %x, align 4
%eq = icmp eq i32 %5, %6
br i1 %eq, label %if.then, label %if.exit
if.then: ; preds = %loop.body
%7 = load i32, i32* @main.y, align 4
%add = add i32 %7, 1
store i32 %add, i32* @main.y, align 4
%8 = load i32, i32* %i, align 4
%9 = load i32, i32* @main.y, align 4
call void (i8*, ...) @printf(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str.3, i32 0, i32 0), i32 %8, i32 %9)
br label %loop.exit
if.exit: ; preds = %loop.body
call void (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.4, i32 0, i32 0))
%10 = load i32, i32* @main.y, align 4
%add1 = add i32 %10, 1
store i32 %add1, i32* @main.y, align 4
%11 = load i32, i32* %i, align 4
%12 = load i32, i32* @main.y, align 4
call void (i8*, ...) @printf(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str.5, i32 0, i32 0), i32 %11, i32 %12)
%13 = load i32, i32* %i, align 4
%add2 = add i32 %13, 1
store i32 %add2, i32* %i, align 4
br label %loop.cond
loop.exit: ; preds = %if.then, %loop.cond
store i32 1, i32* %x3, align 4
%14 = load i32, i32* %x3, align 4
call void (i8*, ...) @printf(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.6, i32 0, i32 0), i32 %14)
store i32 0, i32* %i4, align 4
br label %loop.cond5
loop.cond5: ; preds = %if.exit11, %loop.exit
%15 = load i32, i32* %i4, align 4
%lt6 = icmp slt i32 %15, 100
br i1 %lt6, label %loop.body7, label %loop.exit14
loop.body7: ; preds = %loop.cond5
%16 = load i32, i32* %i4, align 4
%17 = load i32, i32* %x3, align 4
%eq8 = icmp eq i32 %16, %17
br i1 %eq8, label %if.then9, label %if.exit11
if.then9: ; preds = %loop.body7
%18 = load i32, i32* @main.y.7, align 4
%add10 = add i32 %18, 1
store i32 %add10, i32* @main.y.7, align 4
%19 = load i32, i32* %i4, align 4
%20 = load i32, i32* @main.y.7, align 4
call void (i8*, ...) @printf(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str.8, i32 0, i32 0), i32 %19, i32 %20)
br label %loop.exit14
if.exit11: ; preds = %loop.body7
call void (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.9, i32 0, i32 0))
%21 = load i32, i32* @main.y.7, align 4
%add12 = add i32 %21, 1
store i32 %add12, i32* @main.y.7, align 4
%22 = load i32, i32* %i4, align 4
%23 = load i32, i32* @main.y.7, align 4
call void (i8*, ...) @printf(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str.10, i32 0, i32 0), i32 %22, i32 %23)
%24 = load i32, i32* %i4, align 4
%add13 = add i32 %24, 1
store i32 %add13, i32* %i4, align 4
br label %loop.cond5
loop.exit14: ; preds = %if.then9, %loop.cond5
store i32 2, i32* %x15, align 4
%25 = load i32, i32* %x15, align 4
call void (i8*, ...) @printf(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.11, i32 0, i32 0), i32 %25)
store i32 0, i32* %i16, align 4
br label %loop.cond17
loop.cond17: ; preds = %if.exit23, %loop.exit14
%26 = load i32, i32* %i16, align 4
%lt18 = icmp slt i32 %26, 100
br i1 %lt18, label %loop.body19, label %loop.exit26
loop.body19: ; preds = %loop.cond17
%27 = load i32, i32* %i16, align 4
%28 = load i32, i32* %x15, align 4
%eq20 = icmp eq i32 %27, %28
br i1 %eq20, label %if.then21, label %if.exit23
if.then21: ; preds = %loop.body19
%29 = load i32, i32* @main.y.12, align 4
%add22 = add i32 %29, 1
store i32 %add22, i32* @main.y.12, align 4
%30 = load i32, i32* %i16, align 4
%31 = load i32, i32* @main.y.12, align 4
call void (i8*, ...) @printf(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str.13, i32 0, i32 0), i32 %30, i32 %31)
br label %loop.exit26
if.exit23: ; preds = %loop.body19
call void (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.14, i32 0, i32 0))
%32 = load i32, i32* @main.y.12, align 4
%add24 = add i32 %32, 1
store i32 %add24, i32* @main.y.12, align 4
%33 = load i32, i32* %i16, align 4
%34 = load i32, i32* @main.y.12, align 4
call void (i8*, ...) @printf(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str.15, i32 0, i32 0), i32 %33, i32 %34)
%35 = load i32, i32* %i16, align 4
%add25 = add i32 %35, 1
store i32 %add25, i32* %i16, align 4
br label %loop.cond17
loop.exit26: ; preds = %if.then21, %loop.cond17
ret void
}