LLVM:变量来自哪里?

1 llvm llvm-ir

LLVM对其IR使用SSA(静态单一分配)表格。这导致在IR级别将新变量引入代码中。但是,是否有任何方法... API ...确定变量是最初属于程序还是由编译器插入?

box*_*box 5

没有将新变量插入LLVM IR的想法。源语言和LLVM IR只是两种不同的语言,您应该将编译视为翻译步骤。

从概念上讲,当变量是否属于原始程序时,很难给出精确的定义。

考虑一下这个小的C函数:

void test() {
    int i;
    i = 2;
    i = 3;
}
Run Code Online (Sandbox Code Playgroud)

由于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;
}
Run Code Online (Sandbox Code Playgroud)

当将此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
}
Run Code Online (Sandbox Code Playgroud)

如您所见,结果的虚拟寄存器名称不会在分配阶段显示。仅在合并点可见。在这里,变量赋值的原始位置移到了函数的末尾。再次,有疑问的是插入了哪些变量,哪些没有插入。

您可以做的是使用调试元数据编译原始程序,然后处理调试信息以找出变量声明等。在Clang中,您可以输出带有-g标志的调试信息。