10

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

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

int main() {
    enum days d;
    d = WED;
    return 0;
}

它转译为以下 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
}

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

4

3 回答 3

5

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

int factorial(int n){
    int result;
    if(n < 2)
      result = 1;
    else{
      result = n * factorial(n-1);
    }
    return result;
}

你可能会这样做

int factorial(int n){
    if(n < 2)
      return 1;
    return n * factorial(n-1);
}

为什么?因为 Clang 将插入result为您保存返回值的变量。耶。%1这就是这个变量的原因。查看 ir 以获得稍微修改过的代码版本。

修改后的代码,

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

int main() {
    enum days d;
    d = WED;
    if(d) return 1;
    return 0;
}

红外,

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
}

现在你看到%1让自己有用了吧?大多数具有单个 return 语句的函数都将通过 llvm 的其中一个传递来剥离此变量。

于 2020-05-02T21:01:09.483 回答
1

为什么这很重要——真正的问题是什么?

我认为您正在寻找的更深层次的答案可能是:LLVM 的架构基于相当简单的前端和许多通道。前端必须生成正确的代码,但不一定是好的代码。他们可以做最简单的事情。

在这种情况下,Clang 生成了几条指令,这些指令最终没有用于任何用途。这通常不是问题,因为 LLVM 的某些部分会去掉多余的指令。Clang 相信会发生这种情况。Clang 不需要避免发出死代码;它的实现可能侧重于正确性、简单性、可测试性等。

于 2020-01-06T15:48:37.310 回答
1

因为 Clang 已经完成了语法分析,但 LLVM 甚至还没有开始优化。

Clang 前端生成了 IR(中间表示)而不是机器代码。这些变量是 SSA(单一静态分配);它们还没有绑定到寄存器,实际上在优化之后,永远不会因为它们是多余的。

该代码是源代码的某种字面表示。这就是 LLVM 进行优化的原因。基本上,LLVM 从那里开始并从那里进行优化。实际上,对于版本 10 和 x86_64,llc -O2最终会生成:

main: # @main
  xor eax, eax
  ret
于 2020-05-02T15:27:35.990 回答