gcc 奇怪的 -O0 代码生成。简单的 malloc。指向多维数组的指针

P__*_*J__ 15 c gcc pointers

非常简单的代码:

void *allocateMemory5DArray(size_t x, size_t y, size_t z, size_t q, size_t r)
{
    int (*array)[x][y][z][q][r];

    array = malloc(sizeof(*array));
    return array;
}
Run Code Online (Sandbox Code Playgroud)

-O0gcc需要 296 字节的堆栈,生成的代码长度 > 180 行。任何人都可以解释其背后的原理吗?

其他编译器(除了 clang)也会生成奇怪的代码,但不像gcc:)

https://godbolt.org/z/1zx4YE

Jos*_*ose 5

这种行为也发生在 VLA 中,Clang 也生成比 GCC 更短的代码。

虽然GCC生成的代码较长,-O0拥有最快的编译时间(显然这是最快的GCC),汇编代码不优化,但我们并没有要求这一点。当 时-O1,GCC 通过优化牺牲了时间,生成的代码与 clang 非常相似。


Clang 和 GCC 在 VLA 方面存在差异。第一个不支持结构中的VLA,原因:

  • 实施起来很棘手
  • 扩展名完全没有记录
  • 扩展似乎很少使用

Clang 对 C-99 VLA 很满意,但仅此而已。GCC 4.1(考虑到 GCC 4.5 对 C99 “基本上完全支持”)生成了类似的(小)尺寸

   ...
    mov     %rax, QWORD PTR [%rbp-56]
    mov     %rdx, QWORD PTR [%rbp-48]
    mov     %rcx, QWORD PTR [%rbp-40]
    mov     %rsi, QWORD PTR [%rbp-32]
    mov     %rdi, QWORD PTR [%rbp-24]
    ...

Run Code Online (Sandbox Code Playgroud)

但是,在 GCC 4.8 中,代码变得更大。GCC 4.8文件没有说明有关 VLA 的任何更改,考虑到生成的代码中的明显差异,这很奇怪。

GCC 中 C99 功能的状态表明存在与 VLA 相关的“GCC 4.5 中修复的各种极端情况”。但是,4.5 更新日志什么也没说。令人惊讶的是,汇编在 4.4 中略有不同,但在 4.5 中没有。

看起来 Clang 关于结构中 VLA 的原因非常准确,在某些情况下,它们可能会扩展到整个 VLA 功能。


这种不良行为是众所周知的。Linux 的内核以性能的名义摆脱了它们

   Buffer allocation |  Encoding throughput (Mbit/s)
 ---------------------------------------------------
  on-stack, VLA      |   3988
  on-stack, fixed    |   4494
  kmalloc            |   1967
Run Code Online (Sandbox Code Playgroud)

这对 CLang 建设者来说也是个好消息。

  • -O0 的目标不一定是最快的编译时间,经常发生 -O1 实际上更快。 (2认同)
  • @MarcGlisse 同意 -O1 可能更快(在某些情况下,IMO),但是 [GCC](https://gcc.gnu.org/onlinedocs/gnat_ugn/Optimization-Levels.html) 是明确的:“-O0 生成未优化的代码但具有最快的编译时间”和“-O1 优化得相当好,但不会显着降低编译时间”。无论如何,我编辑了答案以提供与官方答案类似的信息,谢谢。 (2认同)