c - 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
:)
解决方案
这种行为也会发生在 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 建设者来说也是个好消息。
推荐阅读
- python - ValueError:未知标签类型sklearn
- c# - XML 文件序列化问题
- kubernetes - 无法连接到服务器:net/http: TLS 握手超时
- python - 查找匹配熊猫条件的第一行的索引
- elasticsearch - 向 elasticsearch 添加索引并在 Kibana 地图中创建术语连接
- python - 使用 flask_sqlalchemy 的多对多查询
- java - Java 这是多重继承吗?还是可以接受的?
- php - 发送数据时循环遍历数组
- javascript - 是 d3.axisBottom().tickFormat(""); 一种用刻度和没有刻度标签来渲染轴的预期方法?
- halide - 使用 AutoScheduler 和 GPU 调度时卤化物索引错误,但不是默认 CPU 调度