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

非常简单的代码:

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;
}

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

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

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

回答

这种行为也发生在 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]
    ...

但是,在 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

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

  • The goal of -O0 is not necessarily the fastest compilation time, it happens regularly that -O1 is actually faster.
  • @MarcGlisse Agree that -O1 may be faster (IMO under certain circumstances), but [GCC](https://gcc.gnu.org/onlinedocs/gnat_ugn/Optimization-Levels.html) is categorical: "-O0 generates unoptimized code but has the fastest compilation time" and "-O1 optimizes reasonably well but does not degrade compilation time significantly" . Anyway, I edit the answer to provide similar info to the official one, thanks for that.

以上是gcc奇怪的-O0代码生成。简单的malloc。指向多维数组的指针的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>