了解最简单的LLVM IR

zel*_*ell 38 syntax llvm

我转换最简单的C代码

#include <stdio.h>

int main()
{
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

到它的LLVM IR,使用

clang -emit-llvm -S hello.c 
Run Code Online (Sandbox Code Playgroud)

生成的IR是:

define i32 @main() #0 {
  %1 = alloca i32, align 4
  store i32 0, i32* %1
  ret i32 0
}
Run Code Online (Sandbox Code Playgroud)

但是,我不明白这个IR.(LLVM doc对初学者有帮助但不是那么多)

  1. 我们为什么这么做%1 = alloca i32, align 4?它在原始代码中对应什么?
  2. 同样的问题 store i32 0, i32* %1
  3. alloca是否意味着堆栈上的分配(而不是动态分配)?
  4. '对齐4'是什么意思?

Sea*_*ean 37

 define i32 @main() #0
Run Code Online (Sandbox Code Playgroud)

这定义了一个main返回32位整数的函数.该#0方法使用命名的属性#0的功能.例如,attributes #0 = { alwaysinline alignstack=4 }IR中可能存在类似的属性,这些属性将应用于main.

%1 = alloca i32, align 4
Run Code Online (Sandbox Code Playgroud)

这会在堆栈上分配32位整数.%1是指向堆栈上此位置的指针的名称.的align 4保证了地址将是4的倍数

store i32 0, i32* %1
Run Code Online (Sandbox Code Playgroud)

这将指向的32位整数设置为32位%1值0.这就像*x = 1在C++中说的那样

ret i32 0
Run Code Online (Sandbox Code Playgroud)

这将从函数返回32位返回值0

考虑到你没有局部变量,赋值是奇数main.LLVM用于BasicBlock表示指令组,基本块具有退出点和指令列表.我的猜测是编译器决定使用returnas作为基本块的退出并选择将至少一条指令放入块中.作业基本上是无操作.


DrY*_*Yap 14

%n是虚拟寄存器为目标机器生成代码时,将被解析为实际的寄存器.

i32是类型信息.在原始代码中int,您的编译器将其作为32位整数.

alloca用于在堆栈上分配空间.在此示例中,它是i32(32位整数),因此您可以在0中加载返回值.align 4给出这个分配4字节对齐,即堆栈指针将在4字节对齐的地址上.

它不是最有效的表示,但如果是IR则不是目标.IR应该可以移植到不同的架构.然后到后端生成有效的机器代码.

LLVM语言参考手册

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

更新:我在C标准中找不到任何东西,但似乎clang为每个主要功能都做了这个.我不知道clang代码库是否能够很好地跟踪它.

更新:请参阅Bill Lynch的评论.这些指令在那里:

对于return 0主要功能可能隐含的

  • @zell:`%1`用于可能隐含的`return 0;`主函数有.它基本上是他们如何进行代码生成的工件. (6认同)
  • @DrYap:http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCall.cpp?revision=224047&amp;view=markup#l1638 (2认同)