Добавление массива SIMD для произвольной длины массива.

Я учусь использовать возможности 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, что кажется неправильным.

Существует ли другой, более оптимальный шаблон таких векторизованных циклов?

6
задан reve_etrange 16 April 2012 в 01:24
поделиться