dco*_*les 8 gcc checksum simd vectorization
GCC的向量扩展提供了一种不错的,合理的可移植方式,可以访问不同硬件架构上的某些SIMD指令,而无需借助硬件特定的内在函数(或自动向量化).
一个真实的用例,就是计算一个简单的加法校验和.有一点不明确的是如何将数据安全地加载到矢量中.
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;
}
Run Code Online (Sandbox Code Playgroud)
向指向矢量类型转换指针似乎有效,但我担心如果SIMD硬件期望矢量类型正确对齐,这可能会以可怕的方式爆炸.
我想到的唯一另一个选择是使用临时向量并显式加载值(通过memcpy或逐元素分配),但在测试这种抵消时,大部分加速都获得了SIMD指令的使用.理想情况下,我想这会像通用__builtin_load()
函数,但似乎没有.
将数据加载到矢量冒险对齐问题的更安全的方法是什么?
您可以使用初始化程序来加载值,即
const vec16qi e = { buf[0], buf[1], ... , buf[15] }
Run Code Online (Sandbox Code Playgroud)
并希望 GCC 将其转换为 SSE 加载指令。不过,我会用反汇编程序来验证这一点;-)。另外,为了获得更好的性能,您尝试进行buf
16 字节对齐,并通过aligned
属性通知编译器。如果您可以保证输入缓冲区对齐,请按字节处理它,直到达到 16 字节边界。