GCC优化内存访问[重复]

Posted

技术标签:

【中文标题】GCC优化内存访问[重复]【英文标题】:GCC optimizing memory accesses [duplicate] 【发布时间】:2020-11-01 19:42:55 【问题描述】:

我有一段 C 代码,它有一个 int 数组 - 该代码对数组进行了多次读取。当我使用 -O0 标志将 GCC 编译为 X86 程序集时,在程序集中,对数组的所有读取访问都是使用 movl 指令进行的 - 32 位加载。这是有道理的,因为ints 是 32 位的,因此访问它们的数组应该使用 32 位加载。

但是,当我使用 -O3 标志编译它时,读取到数组的几个 32 位 movl 被替换为 64 位加载到 XMM 寄存器中......我假设这是某种优化,但优化的反汇编很难破译,我对发生的事情有点迷茫。

无需过多详细介绍我的工作,我需要使用 O3 标志,但我需要对我的 32 位 int 数组的所有访问才能使用 32 位访问。

是否有人对可能发生的情况以及如何在仍使用 -O3 标志的同时将所有加载到我的数组的负载强制为 32 位有任何见解?

重现示例:

这是 C 代码:

#include <stdlib.h>

int main() 
  int* arr = malloc(sizeof(int) * 64);
  int sum = 0;

  for (int i = 0; i < 10; i++) 
    sum += arr [i] + arr[i+1];
  

  if (sum == 0)
    return 0;
  else
    return 1;

对于未优化的反汇编,编译(注意反汇编中的 32 位加载):

gcc -S -fverbose-asm -o mb64BitLoadsNoOpt.s mb64BitLoads.c

为了优化反汇编,编译(注意在反汇编中加载 XMM 寄存器 64 位):

gcc -O3 -S -fverbose-asm -o mb64BitLoadsOpt mb64BitLoads.c

【问题讨论】:

在您的问题中包含您的 C 或 C++ 代码以及该代码的反汇编。使用适当的语言标签 - 不能同时使用。 尝试使用gcc -Wall -Wextra -O3 -S -fverbose-asm yourcode.c,然后检查yourcode.s。请注意,C 和 C++ 是不同的编程语言。请参阅this reference website 并在您的问题中提供一些minimal reproducible example I need to use the O3 flag, but I need all accesses to my 32 bit int array to use 32 bit accesses. 你为什么需要那个?目标硬件是否不支持 O3 生成的指令? @Phidias 很难说出您想要达到的目标。但是你可以用例如编译它吗? -mno-sse2 或使用-march @t.niese:或-fno-tree-vectorize,这不会阻止它使用 SSE2 进行 memcpy,也不会破坏浮点代码(其中用于 XMM 寄存器的 SSE2 是 ABI 的一部分/调用约定) 【参考方案1】:

无需过多详细介绍我的工作,我需要使用 -O3 标志,但我需要对 32 位 int 数组的所有访问才能使用 32 位访问。

这是矛盾的。请参阅this reference 网站、C11 草案标准n1570 和 C++11 草案标准n3337。

这些标准并不要求对 32 位数组的所有访问都使用 32 位访问。

使用最近的GCC 10,使用gcc -fverbose-asm -O3 -S foo.c,然后查看foo.s 以了解编译器优化的原因。

你可以试试其他编译器,

比如Compcert或Clang(甚至tinycc,或nwcc,或者从Frama-C开始写你自己的,或者甚至从头开始......)。如果他们的许可证适合您的工作,请向您的老板征求许可。

您还可以根据自己的需要改进这些编译器,或者编写自己的 GCC plugin 以满足您的需要。

如果你坚持使用 GCC,你可以考虑使用various assembler-related extensions。当然,请阅读invoking GCC。

GCC 是free software,你可以研究它的源代码然后改进它。

Download the source code 的 GCC。然后编译并install它。特别关注its pass manager。您当然可以删除让您烦恼的优化。你可能可以用你的 GCC 插件来做到这一点。寻求帮助并订阅gcc-help@gcc.gnu.org mailing list。

【讨论】:

抱歉,这些文件很长 - 我应该在其中查看什么?为什么它是矛盾的 - 我不能关闭 -O3 所做的某些特定优化吗? 因为 C 标准规定这样的优化是合法的 您当然可以关闭某些优化。您只需要下载 GCC 的源代码并深入了解它。 可以从listed mirrors下载GCC源代码,例如mirrors.kernel.org/gnu/gcc/gcc-10.2.0/gcc-10.2.0.tar.xz @Phidias:公平地说,其他代码中可能会发生其他优化,例如arr[0] = arr[1] = 0; 可以用一个整数 mov qword ptr [rdi], 0 存储完成。自动矢量化是与商店合并不同的优化。如果您只想在大多数正常情况下易于阅读 asm,而不是对编译器可能执行的操作有任何严格的正确性要求,那么这个答案完全是矫枉过正。但考虑到你提出问题的方式,它并没有真正错,只是不是很有帮助。另请参阅How to remove "noise" from GCC asm output?

以上是关于GCC优化内存访问[重复]的主要内容,如果未能解决你的问题,请参考以下文章

为啥在内存位置写入访问冲突[重复]

谁决定内存访问模式?

如何优化间接基数排序? (又名如何优化不可预测的内存访问模式)

释放的分配内存仍然可以访问[重复]

优化具有不规则内存访问的 CUDA 内核

尽管我的系统中有可用内存,但被阻止访问 R 中的更多内存[重复]