将文字值分配给 LLVM IR 中的局部变量

Jum*_*hyn 6 assembly llvm llvm-clang llvm-ir

我一直在搞乱 LLVM IR 的代码生成,有一点我不太明白,那就是什么时候必须分配局部变量,以及如何将文字值加载到局部变量中的区别。如果我将以下简单的 C 代码编译为 LLVM IR,

//test.c
int main() {
    int x = 3;
    int y = x + 4;
    return y;
}
Run Code Online (Sandbox Code Playgroud)

我得到这个输出:

; ModuleID = 'test.c'
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.10.0"

; Function Attrs: nounwind ssp uwtable
define i32 @main() #0 {
    %1 = alloca i32, align 4
    %x = alloca i32, align 4
    %y = alloca i32, align 4
    store i32 0, i32* %1
    store i32 3, i32* %x, align 4
    %2 = load i32* %x, align 4
    %3 = add nsw i32 %2, 4
    store i32 %3, i32* %y, align 4
    %4 = load i32* %y, align 4
    ret i32 %4
}

attributes #0 = { nounwind ssp uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }

!llvm.ident = !{!0}

!0 = metadata !{metadata !"Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn)"}
Run Code Online (Sandbox Code Playgroud)

我可以精简到

target triple = "x86_64-apple-macosx10.10.0"

define i32 @main() {
    %t1 = alloca i32
    store i32 3, i32* %t1
    %x = add nsw i32 0, 3

    %y = add nsw i32 %x, 4
    ret i32 %y
}
Run Code Online (Sandbox Code Playgroud)

所以我想我的问题是,为什么将文字数字加载到变量中是一种迂回的方法?有没有更好/更直接的方法?此外,为什么%t1需要被alloca-ed,但%x%y没有?

Oak*_*Oak 6

Clang 负责生成第一个代码段。Clang 选择了最简单的方式来为这些指令生成 IR——即为每一条指令分配内存,然后存储并加载到这块内存中。这创建了可以模拟 C 变量语义的 IR,可以在其整个生命周期中重新分配不同的值 - LLVM IR 中没有这样的东西(没有变量 -阅读更多关于 SSA)。

不过,Clang 所做的只是编译的第一步。然后,该 IR 将通过许多转换(称为“传递”)。正如您在第二个代码段中所示,一个人将负责摆脱内存使用- 这将允许稍后使用寄存器而不是堆栈来获取这些值。另一遍将摆脱未使用的 value %t1,另一遍将识别此处使用的常量并将用return i32 7...替换整个函数体,依此类推。

所以总结一下,这不是“迂回的方式”,它只是Clang生成IR的最简单的方式,让IR变得更好是LLVM后期的职责。