我正在通过使用矢量内在函数重写我的个人图像处理库来学习使用 SIMD 功能。一个基本功能是一个简单的“数组+=
”,即
void arrayAdd(unsigned char* A, unsigned char* B, size_t n) {
for(size_t i=0; i < n; i++) { B[i] += A[i] };
}
对于任意数组长度,显而易见的 SIMD 代码(假设按 16 对齐)类似于:
size_t i = 0;
__m128i xmm0, xmm1;
n16 = n - (n % 16);
for (; i < n16; i+=16) {
xmm0 = _mm_load_si128( (__m128i*) (A + i) );
xmm1 = _mm_load_si128( (__m128i*) (B + i) );
xmm1 = _mm_add_epi8( xmm0, xmm1 );
_mm_store_si128( (__m128i*) (B + i), xmm1 );
}
for (; i < n; i++) { B[i] += A[i]; }
但是是否可以使用 SIMD 指令进行所有添加?我想试试这个:
__m128i mask = (0x100<<8*(n - n16))-1;
_mm_maskmoveu_si128( xmm1, mask, (__m128i*) (B + i) );
对于额外的元素,但这会导致未定义的行为吗?mask
应该保证实际上没有访问超出数组边界(我认为)。另一种方法是先做额外的元素,然后数组需要对齐n-n16
,这似乎不正确。
是否有另一种更优化的模式,比如矢量化循环?