为什么LLVM会分配一个冗余变量?

mac*_*inn 9 c llvm llvm-codegen

这是一个带有枚举定义和main函数的简单 C 文件:

enum days {MON, TUE, WED, THU};

int main() {
    enum days d;
    d = WED;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

它转换为以下 LLVM IR:

define dso_local i32 @main() #0 {
  %1 = alloca i32, align 4
  %2 = alloca i32, align 4
  store i32 0, i32* %1, align 4
  store i32 2, i32* %2, align 4
  ret i32 0
}
Run Code Online (Sandbox Code Playgroud)

%2显然是d变量,它被分配了 2。%1直接返回零对应什么?

dro*_*top 6

寄存器%1是由 clang 生成的,用于处理函数中的多个返回语句。想象一下您正在编写一个函数来计算整数的阶乘。而不是这个

int factorial(int n){
    int result;
    if(n < 2)
      result = 1;
    else{
      result = n * factorial(n-1);
    }
    return result;
}
Run Code Online (Sandbox Code Playgroud)

你可能会这样做

int factorial(int n){
    if(n < 2)
      return 1;
    return n * factorial(n-1);
}
Run Code Online (Sandbox Code Playgroud)

为什么?因为 Clang 会插入result为您保存返回值的变量。耶。这就是该变量的原因%1。查看 IR 中的代码稍作修改的版本。

修改后的代码,

enum days {MON, TUE, WED, THU};

int main() {
    enum days d;
    d = WED;
    if(d) return 1;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

红外,

define dso_local i32 @main() #0 !dbg !15 {
    %1 = alloca i32, align 4
    %2 = alloca i32, align 4
    store i32 0, i32* %1, align 4
    store i32 2, i32* %2, align 4, !dbg !22
    %3 = load i32, i32* %2, align 4, !dbg !23
    %4 = icmp ne i32 %3, 0, !dbg !23
    br i1 %4, label %5, label %6, !dbg !25

 5:                                                ; preds = %0
   store i32 1, i32* %1, align 4, !dbg !26
   br label %7, !dbg !26

 6:                                                ; preds = %0
  store i32 0, i32* %1, align 4, !dbg !27
  br label %7, !dbg !27

 7:                                                ; preds = %6, %5
  %8 = load i32, i32* %1, align 4, !dbg !28
  ret i32 %8, !dbg !28
}
Run Code Online (Sandbox Code Playgroud)

现在你知道%1它本身很有用了吧?大多数具有单个 return 语句的函数都会通过 LLVM 的一次传递删除该变量。