C语言 为什么LLVM要分配一个冗余变量?

ogq8wdun  于 11个月前  发布在  其他
关注(0)|答案(3)|浏览(80)

下面是一个简单的C文件,其中包含一个枚举定义和一个main函数:

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赋值给它。如果直接返回0,%1对应什么?

nwo49xxi

nwo49xxi1#

%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;
}


IR,

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的一次传递剥离这个变量。

xcitsw88

xcitsw882#

为什么这很重要-实际的问题是什么?
我认为你正在寻找的更深层次的答案可能是:LLVM的架构基于相当简单的前端和许多通道。前端必须生成正确的代码,但它不一定是好的代码。它们可以做最简单的事情。
在这种情况下,Clang生成了几条指令,这些指令最终没有被用于任何事情。这通常不是问题,因为LLVM的某些部分会删除多余的指令。Clang相信这会发生。Clang不需要避免发出死代码;它的实现可能会专注于正确性,简单性,可测试性等。

wdebmtf2

wdebmtf23#

因为Clang已经完成了语法分析,但LLVM甚至还没有开始优化。
Clang前端生成的是IR(Intermediate Representation)而不是机器码。这些变量是SSA(Single Static Representation);它们还没有绑定到寄存器,实际上在优化之后,它们永远不会绑定到寄存器,因为它们是冗余的。
这段代码是源代码的字面表示。它是clang交给LLVM进行优化的代码。基本上,LLVM从那里开始并从那里优化。实际上,对于版本10和x86_64,llc -O2 最终将生成:

main: # @main
  xor eax, eax
  ret

字符串

相关问题