【发布时间】:2012-03-08 06:06:34
【问题描述】:
GCC 的 vector extensions 提供了一种不错的、合理可移植的方式来访问不同硬件架构上的一些 SIMD 指令,而无需诉诸 hardware specific intrinsics(或自动矢量化)。
一个真正的用例是计算一个简单的加法校验和。不清楚的一件事是如何安全地将数据加载到向量中。
typedef char v16qi __attribute__ ((vector_size(16)));
static uint8_t checksum(uint8_t *buf, size_t size)
{
assert(size%16 == 0);
uint8_t sum = 0;
vec16qi vec = {0};
for (size_t i=0; i<(size/16); i++)
{
// XXX: Yuck! Is there a better way?
vec += *((v16qi*) buf+i*16);
}
// Sum up the vector
sum = vec[0] + vec[1] + vec[2] + vec[3] + vec[4] + vec[5] + vec[6] + vec[7] + vec[8] + vec[9] + vec[10] + vec[11] + vec[12] + vec[13] + vec[14] + vec[15];
return sum;
}
将指针转换为向量类型似乎可行,但我担心如果 SIMD 硬件期望向量类型正确对齐,这可能会以可怕的方式爆炸。
我想到的唯一其他选择是使用临时向量并显式加载值(通过 memcpy 或元素分配),但在测试这个抵消大部分加速获得使用 SIMD 指令。理想情况下,我认为这类似于通用的 __builtin_load() 函数,但似乎不存在。
将数据加载到有对齐问题风险的向量中的更安全方法是什么?
【问题讨论】:
-
在 GCC x86_64 上的未对齐内存上运行此命令将在 CPU 尝试将未对齐内存加载到 SSE 寄存器时导致 SIGSEGV。一个合理的选择似乎是要么仅校验和对齐内存,要么使用普通循环对字节求和,直到第一个 16 字节边界。
-
在您当前的代码中,如果编译器知道输入(但总和不好),加载数据实际上编译得很好:godbolt.org/g/DeR3Qv。不知道输入就不太好了:godbolt.org/g/LxEkhp
标签: gcc checksum vectorization simd