我正在为正在学习的课程编写一种类似于C的简单语言的编译器。这段代码:
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不接受该代码。
opt: core023.ll:25:5: error: instruction expected to be numbered '%2'
%1 = load i32* %result_0
现在,根据我对未命名临时寄存器的了解,应该将它们从0开始顺序编号。在这种情况下。但是显然“%1 = sub ..”行应该已被编号为%2。这是为什么? %0和%1之间的任何指令是否会增加序列号?还是仅仅是其他方面的后续错误?
最佳答案
在LLVM中,所有可以命名但不能命名的东西都被分配了一个数字。这也包括基本块。就你而言
lab0:
ret i32 1
br label %lab2
定义两个基本块,因为每个terminator instruction结尾一个基本块。这意味着,从概念上讲,您的代码被解析为
lab0:
ret i32 1
1:
br label %lab2
之后的下一个免费号码是2。
为了防止出现这种奇怪的行为,我建议始终明确命名基本块。