LLVM:变量来自哪里?

LLVM:变量来自哪里?,llvm,llvm-ir,Llvm,Llvm Ir,LLVM使用SSA(静态单一分配)形式作为其IR。这导致在IR级别向代码中引入新变量。然而,有什么方法,API。。。要确定某个变量最初是属于程序还是由编译器插入?没有将新变量插入LLVM IR的概念。源语言和LLVM IR只是两种不同的语言,您更应该将编译视为一个翻译步骤 从概念上讲,当变量是否属于原始程序时,很难给出精确的定义 例如,考虑这个小C函数: void test() { int i; i = 2; i = 3; } 将此函数编译为LLVM IR将导致至少两个

LLVM使用SSA(静态单一分配)形式作为其IR。这导致在IR级别向代码中引入新变量。然而,有什么方法,API。。。要确定某个变量最初是属于程序还是由编译器插入?

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

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

例如,考虑这个小C函数:

void test() {
    int i;
    i = 2;
    i = 3;
}
将此函数编译为LLVM IR将导致至少两个变量(如果未应用常数折叠),因为SSA形式是。哪一个是原始的,哪一个是插入的

当涉及控制流和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
}
define i32@func()#0{
%1=负载i32*@a,对齐4
%2=icmp ne i32%1,0
br i1%2,标签%3,标签%5
;:3;preds=%0
%4=负载i32*@b,对齐4
br标签%7
;:5;preds=%0
%6=负载i32*@c,对齐4
br标签%7
;:7;preds=%5,%3
%结果0=φi32[%4,%3],%6,%5]
ret i32%结果。0
}
如您所见,result的虚拟寄存器名不会显示在赋值阶段。它仅在合并点处可见。在这里,变量赋值的原始位置被移到函数的末尾。同样,插入了哪些变量,哪些没有,这是个问题


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

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

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

例如,考虑这个小C函数:

void test() {
    int i;
    i = 2;
    i = 3;
}
将此函数编译为LLVM IR将导致至少两个变量(如果未应用常数折叠),因为SSA形式是。哪一个是原始的,哪一个是插入的

当涉及控制流和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
}
define i32@func()#0{
%1=负载i32*@a,对齐4
%2=icmp ne i32%1,0
br i1%2,标签%3,标签%5
;:3;preds=%0
%4=负载i32*@b,对齐4
br标签%7
;:5;preds=%0
%6=负载i32*@c,对齐4
br标签%7
;:7;preds=%5,%3
%结果0=φi32[%4,%3],%6,%5]
ret i32%结果。0
}
如您所见,result的虚拟寄存器名不会显示在赋值阶段。它仅在合并点处可见。在这里,变量赋值的原始位置被移到函数的末尾。同样,插入了哪些变量,哪些没有,这是个问题


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

考虑为解析AST实现Clang过程,并执行与原始程序更相关的分析codeConsider实现了一个用于解析AST的铿锵过程,并执行与原始代码稍微相关的分析