【发布时间】:2017-01-11 01:26:59
【问题描述】:
我需要将某个内存位置的几个四字加在一起:
uint64_t sum2 (const char * p, size_t n)
{
uint64_t res = 0;
const uint32_t * q = (const uint32_t*) p;
size_t i;
for (i = 0; i < n; i++) res += q[i];
return res;
}
我知道这段代码不必在任意机器上的任意 C 编译器上工作。并非每个指向 char 的指针都可以转换为指向 int 的有效指针。但是,在 Intel 上,您可以从任何地址读取 32 位值,在大多数情况下甚至没有任何性能损失,因此无论p 的对齐方式如何,这段代码都应该可以正常工作。我的程序在 64 位 Intel Sandy Bridge 上运行,使用 GCC 4.8 使用 -msse4.2 -O3 编译。
当地址不是 4 对齐时,此代码 SIGSEGV。原因是循环被展开四次并使用 SSE 编译。使用MOVDQA一起读取四个值,需要16对齐。循环之前,指针16对齐,前提是已经对齐4。
如何防止在 GCC 上进行这种 SSE 优化?我真的需要添加未对齐的 32 位数字。
【问题讨论】:
-
可能使用
memcpy将&q[i]复制到临时位置。 -
UB 在第二行。为什么要这样做?
-
它不应该对这段代码进行矢量化,p 没有对齐,并且是任何东西的有效别名。你可以尝试加入 __builtin_assume_aligned(q, 1)。请务必提及版本号。
-
您是否可以控制 p 的分配方式?如果是这样,只需使用正确的对齐方式进行分配。