2012-05-06 53 views
6

我正在为我正在学习的课程编写一个简单的C语言编译器。这段代码:这个LLVM寄存器编号有什么问题?

int main() { 
    printInt(not(0)); 
    return 0; 
} 

int not(int n) { 
    if (n == 0) { 
     return 1; 
    } else { 
     int result = 0; 
     return result; 
    } 
} 

..我天真地编译此位码:

declare void @printInt(i32) 
declare void @printDouble(double) 
declare void @printString(i8*) 
declare i32 @readInt() 
declare double @readDouble() 

define i32 @main() { 
entry: 
    %0 = call i32 @not(i32 0) 
    call void @printInt(i32 %0) 
    ret i32 0 
    unreachable 
} 

define i32 @not(i32 %n_0) { 
entry: 
    %0 = icmp eq i32 %n_0, 0 
    br i1 %0, label %lab0, label %lab1 
lab0: 
    ret i32 1 
    br label %lab2 
lab1: 
    %result_0 = alloca i32 
    store i32 0, i32* %result_0 
    %1 = load i32* %result_0 
    ret i32 %1 
    br label %lab2 
lab2: 
    unreachable 
} 

然而,选择不接受该代码。

opt: core023.ll:25:5: error: instruction expected to be numbered '%2' 
%1 = load i32* %result_0 

现在,从我所了解的无名临时寄存器中,它们应该从0开始顺序编号,从0开始。这里是这种情况。但显然“%1 = sub ..”行应该被编号为%2。这是为什么?执行%0和%1之间的任何指令是否会增加序列号?或者,这可能仅仅是来自其他方面的后续故障?

回答

9

在LLVM中,的一切可以有一个名字,但没有被分配一个数字。这也包括基本块。在你的情况

lab0: 
    ret i32 1 
    br label %lab2 

定义,因为每个terminator instruction结束基本块两个基本块。这意味着,在概念上,你的代码被解析为

lab0: 
    ret i32 1 
1: 
    br label %lab2 

和下一个免费电话号码后,也就是2

为了防止奇怪的行为就是这样,我建议始终明确命名基本块。

+0

解释问题原因的另一种方法是,您需要在返回语句后立即避免分支。如果你的语言有代码来保证所有的控制路径都返回,那么检查你的前一个分支是否已经返回应该是微不足道的。在它返回的情况下,不需要插入分支(br)指令。为了使LLVM对你的基本块感到满意,你需要做一些状态簿记工作。 –