LLVM alloca导致while语句上的堆栈溢出

时间:2014-01-09 16:00:30

标签: compiler-construction llvm llvm-ir

我正在为针对LLVM-IR的玩具语言实现前端编译器,并且在运行编译的while语句时遇到堆栈溢出:

例如,此代码应该永远运行,但我们的编译版本堆栈会在一段时间后溢出。

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

这是编译的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
}

我们认为我们的问题来自每个alloca未发布的问题,因为我们仍处于相同的功能中。

LLVM Documentation

  当函数返回时,

'alloca'd内存会自动释放。

我们应该如何编译while循环?
我们可以避免这个问题吗?

3 个答案:

答案 0 :(得分:7)

你生成了错误的IR:具体来说,循环中的alloca是一个坏主意,并且确实会导致堆栈溢出。

我希望看到的是循环外的alloca,然后是循环内的loadaddstore序列。稍后您可以运行mem2reg传递,它将删除alloca并将loadstore转换为效率更高的phi

对于while条件,alloca也是如此:你需要做同样的事情,提前准备内存并在循环内只准备store

答案 1 :(得分:0)

使用mem2reg pass将allocas转换为寄存器值。寄存器值在上次使用时会被释放。

答案 2 :(得分: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
}

在选择-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
}
相关问题