LLVM alloca causes stack overflow at runtime

I am implementing an external compiler for LLVM-IR-oriented toy language, and I encounter a stack overflow when running compiled statements while:

For example, this code should run forever, but our compiled version of the stack overflows after a while.

def run(): Void = {
    i = 0;
    while(true) {
        i = i + 1;
    }
}

And here is the combined LLVM-IR:

define i32 @run() nounwind ssp {
    ; i = 0
    %i = alloca i32, align 4
    %1 = alloca i32, align 4
    store i32 0, i32* %1, align 4
    %2 = load i32* %1, align 4
    store i32 %2, i32* %i, align 4
    br label %3

; <label>: %3
    ; while(true)
    ; Generated by compileExpression(condition)
    %4 = alloca i1, align 4
    store i1 true, i1* %4, align 4
    %5 = load i1* %4, align 4
    br i1 %5, label %6, label %11

; <label>: %6
    ; i = i + 1
    ; Generated by compileExpression(body)
    %7 = load i32* %i, align 4
    %8 = alloca i32, align 4
    store i32 1, i32* %8, align 4
    %9 = load i32* %8, align 4
    %10 = add nsw i32 %7, %9
    store i32 %10, i32* %i, align 4
    br label %3

; <label>: %11
    %12 = load i32* %i, align 4
    ret i32 %12
}

We think that our problem comes from all allocathat are not released, because we are still in the same function.

LLVM Documentation :

'alloca'd is automatically freed when the function returns.

How to compile while loop? Can we avoid this problem?

+4
3

IR: , alloca .

, , - alloca , load, add store . mem2reg, alloca load store phi.

alloca while: , store .

+7

mem2reg allocas . , .

0
define i32 @run() nounwind ssp {
    ; i = 0
    %i = alloca i32, align 4
    %1 = alloca i32, align 4
    store i32 0, i32* %1, align 4
    %2 = load i32* %1, align 4
    store i32 %2, i32* %i, align 4
    %3 = alloca i1, align 4
    store i1 true, i1* %3, align 4
    %4 = alloca i32, align 4
    br label %whilecond

whilecond:
    ; while(true)
    ; Generated by compileExpression(condition)
    %5 = load i1* %3, align 4
    br i1 %5, label %whilebody, label %whileexit

whilebody:
    ; i = i + 1
    ; Generated by compileExpression(body)
    %6 = load i32* %i, align 4
    store i32 1, i32* %4, align 4
    %7 = load i32* %4, align 4
    %8 = add nsw i32 %6, %7
    store i32 %8, i32* %i, align 4
    br label %whilecond

whileexit:
    %9 = load i32* %i, align 4
    ret i32 %9
}

opt -mem2reg :

define i32 @run() #0 {
       br label %whilecond

whilecond:                                        ; preds = %whilebody, %0
       %i.0 = phi i32 [ 0, %0 ], [ %1, %whilebody ]
       br i1 true, label %whilebody, label %whileexit

whilebody:                                        ; preds = %whilecond
       %1 = add nsw i32 %i.0, 1
       br label %whilecond

whileexit:                                        ; preds = %whilecond
       ret i32 %i.0
}
0

All Articles