【问题标题】:Understanding the simplest LLVM IR了解最简单的 LLVM IR
【发布时间】:2014-12-12 16:25:45
【问题描述】:

我改造最简单的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 文档对初学者有帮助,但对初学者没有多大帮助)

  1. 为什么我们有%1 = alloca i32, align 4 ?它对应于原始代码中的什么?
  2. store i32 0, i32* %1 的同样问题
  3. alloca 是指堆栈上的分配(而不是动态分配)吗?
  4. “对齐 4”是什么意思?

【问题讨论】:

  • align表示内存操作要对齐到4个字节。我不确定其余的。

标签: syntax llvm


【解决方案1】:
 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

这从函数返回,返回值为 0 的 32 位

考虑到main 中没有局部变量,这个赋值很奇怪。 LLVM 使用BasicBlock 表示指令组,一个基本块有一个出口点和一个指令列表。我的猜测是编译器已决定使用return 作为基本块的出口,并选择将至少一条指令放入该块中。分配基本上是空操作。

【讨论】:

    【解决方案2】:

    %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 的 cmets。这些说明在那里:

    对于主要函数可能具有的隐式return 0

    【讨论】:

    • 谢谢。那为什么我们在这里需要 %1(我的问题 #1 和 #2)?
    • @zell:没必要。如果您启用了优化器(例如使用 -O3),它将被删除。
    • @zell:%1 用于主要功能可能具有的隐式return 0;。这基本上是他们如何生成代码的工件。
    • @BillLynch 你有这个事实的来源吗?这对我来说似乎很奇怪,因为推 0 对返回值有什么帮助?
    【解决方案3】:

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

    关于可移植性的评论并不完全正确,如果此 IR 通过“选择”传递,它将消除堆栈存储。

    【讨论】:

    • 但是 main 中没有变量可以尝试存储在堆栈中。在查看了许多其他 clang 输出后,它似乎总是将此 0 存储在 main 的堆栈中。
    • 放在那里的值就是返回值。
    • 谢谢科林。很棒的信息。在我自己的 caes 中将 -O3 添加到 ll 代使 IR 更容易理解:-)
    猜你喜欢
    • 1970-01-01
    • 2013-11-17
    • 1970-01-01
    • 1970-01-01
    • 2022-10-06
    • 1970-01-01
    • 2017-04-09
    • 2014-10-30
    • 1970-01-01
    相关资源
    最近更新 更多