我转换最简单的C代码
#include <stdio.h>
int main()
{
return 0;
}
到其LLVM IR,使用
clang -emit-llvm -S hello.c
生成的IR是:
define i32 @main() #0 {
%1 = alloca i32, align 4
store i32 0, i32* %1
ret i32 0
}
但是,我不明白这个IR。 (LLVM doc对初学者有帮助但不是那么多)
%1 = alloca i32, align 4
?它在原始代码中对应什么? store i32 0, i32* %1
答案 0 :(得分:34)
define i32 @main() #0
这定义了一个名为main
的函数,它返回一个32位整数。 #0
表示为函数使用名为#0
的属性。例如,IR中可能有类似attributes #0 = { alwaysinline alignstack=4 }
的内容,这些属性将应用于main
。
%1 = alloca i32, align 4
这会在堆栈上分配32位整数。 %1
是指向堆栈上此位置的指针的名称。 align 4
确保地址为4的倍数
store i32 0, i32* %1
这将%1
指向的32位整数设置为32位值0.这就像在C ++中说*x = 1
ret i32 0
从函数返回32位返回值0
考虑到main
中没有局部变量,分配很奇怪。 LLVM使用BasicBlock
来表示指令组,而基本块具有出口点和指令列表。我的猜测是编译器决定使用return
作为基本块的退出,并选择在块中放入至少一条指令。作业基本上是无操作。
答案 1 :(得分:14)
%n
是虚拟寄存器,在为目标机器生成代码时将被解析为实际寄存器。
i32
用于输入类型信息。在原始代码中,它是int
,编译器将其作为32位整数。
alloca
用于在堆栈上分配空间。在此示例中,它是i32
(32位整数),因此您可以在0中加载返回值。 align 4
为此分配提供4字节对齐,即堆栈指针将位于4字节对齐的地址上。
它不是最有效的表示,但如果是IR则不是目标。 IR应该可以移植到不同的架构。然后到后端生成有效的机器代码。
LLVM Language Reference Manual
为什么alloca
和store
与main
函数有关。如果您已将此函数调用为其他内容,则IR将按预期包含ret
。从检查为main生成的程序集,它似乎与堆栈基指针有关
但我不完全理解它为什么存在。是时候推出C标准了。
更新:我在C标准中找不到任何内容,但似乎clang会为每个主要功能执行此操作。我不太了解clang代码库,但不足以跟踪它。
更新:请参阅Bill Lynch的评论。这些指导就在那里:
表示主要函数具有
的隐式return 0
答案 2 :(得分:2)
出于调试原因,变量通常放在未经优化的构建中的堆栈中。在使用真实寄存器的优化构建中,值可能会在函数退出之前消失。
关于可移植性的评论并非准确无误,如果此IR已通过&#39; opt&#39;它会消除堆栈存储。