首页 > 解决方案 > 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

标签: cpointersgcc

解决方案


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

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


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

  • 实施起来很棘手
  • 扩展是完全无证的
  • 该扩展似乎很少使用

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

   ...
    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 建设者来说也是个好消息。


推荐阅读