了解最简单的LLVM IR

时间:2014-12-12 16:25:46

标签: syntax llvm

我转换最简单的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. 为什么我们有%1 = alloca i32, align 4?它在原始代码中对应什么?
  2. store i32 0, i32* %1
  3. 的同一问题
  4. alloca是否意味着在堆栈上进行分配(而不是动态分配)?
  5. &#39;对齐4&#39;意思?

3 个答案:

答案 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

为什么allocastoremain函数有关。如果您已将此函数调用为其他内容,则IR将按预期包含ret。从检查为main生成的程序集,它似乎与堆栈基指针有关 但我不完全理解它为什么存在。是时候推出C标准了。

更新:我在C标准中找不到任何内容,但似乎clang会为每个主要功能执行此操作。我不太了解clang代码库,但不足以跟踪它。

更新:请参阅Bill Lynch的评论。这些指导就在那里:

  

表示主要函数具有

的隐式return 0

答案 2 :(得分:2)

出于调试原因,变量通常放在未经优化的构建中的堆栈中。在使用真实寄存器的优化构建中,值可能会在函数退出之前消失。

关于可移植性的评论并非准确无误,如果此IR已通过&#39; opt&#39;它会消除堆栈存储。