【问题标题】:Clang generates local store in LLVM IRClang 在 LLVM IR 中生成本地存储
【发布时间】:2015-07-16 09:27:51
【问题描述】:

我正在通过 Clang 学习 LLVM IR,发现 C 函数如下:

int inc(int x)
{
  return x+1;
}

生成此 IR(优化已关闭):

define i32 @inc(i32 %x) #0 {
entry:
  %x.addr = alloca i32, align 4
  store i32 %x, i32* %x.addr, align 4
  %0 = load i32, i32* %x.addr, align 4
  %add = add nsw i32 %0, 1
  ret i32 %add
}

我的问题是确切地知道为什么它首先分配一个本地 (x.addr) 存储,然后从中加载。

【问题讨论】:

  • 没关系,mem2reg pass 会处理所有多余的allocas。
  • @SK-logic:现在主要是 SROA :)
  • @EliBendersky:你为什么说“它主要是聚合的标量替换”?
  • @Stringer:我的意思是在今天的优化管道中,SROA 进行了这种转换(分配到 SSA 值)

标签: clang llvm llvm-ir


【解决方案1】:

因为这是未优化的代码。 Clang(前端)不会花费太多(几乎没有?)时间来弄清楚如何使其发出的代码达到最佳状态。它将它留给后端优化(LLVM)。局部变量在未优化模式下“在堆栈上”,这意味着alloca。这也意味着x 有一个可寻址的位置,以后可能会使用也可能不会使用。如果没有优化,编译器不知道它是否会被使用,所以它无论如何都会保守地生成一个可寻址的位置。

int inc(int x)
{
  x = x + 1;
  int* px = &x;
  return x;
}

现在 Clang 发出:

define i32 @inc(i32 %x) #0 {
entry:
  %x.addr = alloca i32, align 4
  %px = alloca i32*, align 8
  store i32 %x, i32* %x.addr, align 4
  %0 = load i32, i32* %x.addr, align 4
  %add = add nsw i32 %0, 1
  store i32 %add, i32* %x.addr, align 4
  store i32* %x.addr, i32** %px, align 8
  %1 = load i32, i32* %x.addr, align 4
  ret i32 %1
}

看到地址%x.addr现在被用作指针了吗?

当然,如果你通过优化器运行它,你会得到:

define i32 @inc(i32 %x) #0 {
entry:
  %add = add nsw i32 %x, 1
  ret i32 %add
}

这可能更符合您对编译器的期望。

【讨论】:

  • 谢谢。我明白了,但 Clang 与堆栈分配相关的工作方式仍然让我感到困惑。我有这样的感觉,因为在 C 中,任何堆栈变量都可以通过副作用来触及。所以它必须“以防万一”从内存中加载。我试图编译这个:int test(int x, int y) { *((&y)+1) = 7; return x+1; } 但奇怪的是,打开优化后,仍然会生成与我的问题相同的代码,尽管x 被破坏了。
  • @Stringer:启用优化后,您发布的代码将编译为答案中我最新的 IR 示例(带有一个未使用的额外参数 %y
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-30
  • 2015-02-18
  • 1970-01-01
  • 2021-06-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多