LLVM为其IR使用SSA(静态单一分配)表单。这导致在IR级别的代码中引入新变量。但是,有没有任何方法,API ...来确定变量最初是属于程序还是由编译器插入?
答案 0 :(得分:4)
没有将新变量插入LLVM IR的概念。源语言和LLVM IR只是两种不同的语言,您应该将编译视为转换步骤。
从概念上讲,当变量属于原始程序时,很难得出一个精确的定义。
考虑一下这个小C函数:
void test() {
int i;
i = 2;
i = 3;
}
从SSA格式开始,将此函数编译为LLVM IR将导致至少两个变量(如果未应用常量折叠)。哪一个是原始的,哪一个插入?
当涉及控制流和phi函数时,这也变得复杂:
int a = 1;
int b = 2;
int c = 3;
int func() {
int result;
if (a) {
result = b;
} else {
result = c;
}
return result;
}
将此C函数转换为LLVM IR并应用-mem2reg传递时,我们得到以下结果:
define i32 @func() #0 {
%1 = load i32* @a, align 4
%2 = icmp ne i32 %1, 0
br i1 %2, label %3, label %5
; <label>:3 ; preds = %0
%4 = load i32* @b, align 4
br label %7
; <label>:5 ; preds = %0
%6 = load i32* @c, align 4
br label %7
; <label>:7 ; preds = %5, %3
%result.0 = phi i32 [ %4, %3 ], [ %6, %5 ]
ret i32 %result.0
}
如您所见,结果的虚拟寄存器名称不会在分配阶段显示。它仅在合并点可见。这里,变量赋值的原始位置移向函数的末尾。同样,插入哪些变量以及哪些变量没有插入是值得怀疑的。
您可以做的是使用调试元数据编译原始程序,然后处理调试信息以找出变量声明等。在Clang中,您可以输出带有-g
标志的调试信息。