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
没有?
Clang 负责生成第一个代码段。Clang 选择了最简单的方式来为这些指令生成 IR——即为每一条指令分配内存,然后存储并加载到这块内存中。这创建了可以模拟 C 变量语义的 IR,可以在其整个生命周期中重新分配不同的值 - LLVM IR 中没有这样的东西(没有变量 -阅读更多关于 SSA)。
不过,Clang 所做的只是编译的第一步。然后,该 IR 将通过许多转换(称为“传递”)。正如您在第二个代码段中所示,一个人将负责摆脱内存使用- 这将允许稍后使用寄存器而不是堆栈来获取这些值。另一遍将摆脱未使用的 value %t1
,另一遍将识别此处使用的常量并将用return i32 7
...替换整个函数体,依此类推。
所以总结一下,这不是“迂回的方式”,它只是Clang生成IR的最简单的方式,让IR变得更好是LLVM后期的职责。