我有两个 uint8_t
数组,它们都有 64 个元素。
我想出的“最好”方法是加载 4x 16 个元素,将它们放入两个 m128i
寄存器中,然后将它们都放入 >m256
注册。这是针对两个 uint8_t
数组完成的,如下所示:
__m128i a1, a2, b1, b2, s1, s2;
__m256i u, v, c;
// 128 bit of data x 2
a1 = _mm_set_epi64(*(__m64*)block1, *((__m64*)(block1 + stride)));
block1 += stride + stride;
a2 = _mm_set_epi64(*(__m64*)block1, *((__m64*)(block1 + stride)));
// the upper 128 bits of the result are undefined
u = _mm256_castsi128_si256(a1);
// Copy a to dst, then insert 128 bits from b into dst at the location specified by imm.
u = _mm256_insertf128_si256(u, a2, 0x1);
b1 = _mm_set_epi64(*(__m64*)block2, *((__m64*)(block2 + stride)));
block2 += stride + stride;
b2 = _mm_set_epi64(*(__m64*)block2, *((__m64*)(block2 + stride)));
// the upper 128 bits of the result are undefined
v = _mm256_castsi128_si256(b1);
// Copy a to dst, then insert 128 bits from b into dst at the location specified by imm.
v = _mm256_insertf128_si256(v, b2, 0x1);
我现在有两个m256
寄存器,u
和v
,并且可以计算SAD:
c = _mm256_sad_epu8(u, v);
但是,可能由于时间很晚,我无法想出更好的方法来获得结果...... 这就是我现在得到的:
s1 = _mm256_extractf128_si256(c, 0x0);
s2 = _mm256_extractf128_si256(c, 0x1);
int p, q;
p = _mm_extract_epi32(s1, 0x0);
q = _mm_extract_epi32(s1, 0x2);
*result += p + q;
p = _mm_extract_epi32(s2, 0x0);
q = _mm_extract_epi32(s2, 0x2);
*result += p + q;
result
是一个 int,如果不清楚的话。
这会生成相当多的指令。在我看来,这是加载我想要的所有单元的唯一方法。但是,这可能不是从 m256ic
寄存器中获取结果的最佳方式。
你说什么? 你能帮助我以更优化的方式做到这一点吗?
放在一起,该函数看起来像:
void foobar(uint8_t *block1, uint8_t *block2, int stride, int *result)
{
*result = 0;
int i;
__m128i a1, a2, b1, b2, s1, s2;
__m256i u, v, c;
for (i = 0; i < 2; ++i) {
// loading of uints
// calculating SAD, and getting result
block1 += stride; block2 += stride;
block1 += stride; block2 += stride;
}
}
由于 uint 组织方式的本质,我一次只能加载八个,然后我必须使用 stride
增加地址。一次加载(即加载 16 个)会产生不好的结果。
最佳答案
关于获取两个字节数组的绝对差之和,这是我使用 SSE 的方式:
__m128i sum1 = _mm_sad_epu8(u,v);
__m128i sum2 = _mm_shuffle_epi32(sum1,2);
__m128i sum3 = _mm_add_epi16(sum1,sum2);
int8_t sum4 = (int8_t)_mm_cvtsi128_si32(sum3);
我现在无法在 AVX2 上测试它,但这是我会先尝试的未经测试的代码
__m256i sum1 = _mm256_sad_epu8(u,v);
__m256i sum2 = _mm256_shuffle_epi32(sum1,2);
__m256i sum3 = _mm256_add_epi16(sum1,sum2);
__m128i sum4 = _mm_add_epi16(_mm256_castsi256_si128(sum3),
_mm256_extracti128_si256(sum3,1));
int8_t sum5 = (int8_t)_mm_cvtsi128_si32(sum4);
我可以稍后测试。
关于给定两个 uint8_t 数组,计算 128 个元素的 SAD,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25676105/