SSE 中的 0xFFFF 标志
0xFFFF flags in SSE
我想创建一个 SSE 寄存器,其中包含我可以存储在整数数组中的值,来自另一个包含标志 0xFFFF
和零的 SSE 寄存器。例如:
__m128i regComp = _mm_cmpgt_epi16(regA, regB);
为了论证,我们假设 regComp
加载了 { 0, 0xFFFF, 0, 0xFFFF }
。我想将其转换为 { 0, 80, 0, 80 }
.
我的想法是创建一个整数数组,初始化为 80 并将它们加载到寄存器 regC
。然后,在 regC
和 regComp
之间执行 _mm_and_si128
并将结果存储在 regD
中。然而,这并不能解决问题,这让我认为我不理解 SSE 寄存器中的正标志。有人可以回答这个问题并简要解释为什么我的解决方案不起作用吗?
short valA[16] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
short valB[16] = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 10, 10, 10, 10, 10, 10, 10 };
short ones[16] = { 1 };
short final[16];
__m128i vA, vB, vOnes, vRes, vRes2;
vOnes = _mm_load_si128((__m128i *)&(ones)[0] );
for( i=0 ; i < 16 ;i+=8){
vA = _mm_load_si128((__m128i *)&(valA)[i] );
vB = _mm_load_si128((__m128i *)&(valB)[i] );
vRes = _mm_cmpgt_epi16(vA,vB);
vRes2 = _mm_and_si128(vRes,vOnes);
_mm_storeu_si128((__m128i *)&(final)[i], vRes2);
}
您只将数组 ones
的第一个元素设置为 1(数组的其余部分初始化为 0)。
我建议您完全删除数组 ones
,然后更改此行:
vOnes = _mm_load_si128((__m128i *)&(ones)[0] );
至:
vOnes = _mm_set1_epi16(1);
不过,如果您只想将 SIMD TRUE (0xffff) 结果转换为 1,可能是更好的解决方案,那就是使用 shift:
for (i = 0; i < 16; i += 8) {
vA = _mm_loadu_si128((__m128i *)&pA[i]);
vB = _mm_loadu_si128((__m128i *)&pB[i]);
vRes = _mm_cmpgt_epi16(vA, vB); // generate 0xffff/0x0000 results
vRes = _mm_srli_epi16(vRes, 15); // convert to 1/0 results
_mm_storeu_si128((__m128i *)&final[i], vRes2);
}
尝试加载 1:
vOnes = _mm_set1_epi16(1);
这比创建常量数组要短。
请注意,在 C++ 中提供少于数组大小的数组值会将其他值初始化为零。这是你的错误,而不是 SSE 部分。
不要忘记调试器,现代调试器可以正确显示 SSE 变量。
我想创建一个 SSE 寄存器,其中包含我可以存储在整数数组中的值,来自另一个包含标志 0xFFFF
和零的 SSE 寄存器。例如:
__m128i regComp = _mm_cmpgt_epi16(regA, regB);
为了论证,我们假设 regComp
加载了 { 0, 0xFFFF, 0, 0xFFFF }
。我想将其转换为 { 0, 80, 0, 80 }
.
我的想法是创建一个整数数组,初始化为 80 并将它们加载到寄存器 regC
。然后,在 regC
和 regComp
之间执行 _mm_and_si128
并将结果存储在 regD
中。然而,这并不能解决问题,这让我认为我不理解 SSE 寄存器中的正标志。有人可以回答这个问题并简要解释为什么我的解决方案不起作用吗?
short valA[16] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
short valB[16] = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 10, 10, 10, 10, 10, 10, 10 };
short ones[16] = { 1 };
short final[16];
__m128i vA, vB, vOnes, vRes, vRes2;
vOnes = _mm_load_si128((__m128i *)&(ones)[0] );
for( i=0 ; i < 16 ;i+=8){
vA = _mm_load_si128((__m128i *)&(valA)[i] );
vB = _mm_load_si128((__m128i *)&(valB)[i] );
vRes = _mm_cmpgt_epi16(vA,vB);
vRes2 = _mm_and_si128(vRes,vOnes);
_mm_storeu_si128((__m128i *)&(final)[i], vRes2);
}
您只将数组 ones
的第一个元素设置为 1(数组的其余部分初始化为 0)。
我建议您完全删除数组 ones
,然后更改此行:
vOnes = _mm_load_si128((__m128i *)&(ones)[0] );
至:
vOnes = _mm_set1_epi16(1);
不过,如果您只想将 SIMD TRUE (0xffff) 结果转换为 1,可能是更好的解决方案,那就是使用 shift:
for (i = 0; i < 16; i += 8) {
vA = _mm_loadu_si128((__m128i *)&pA[i]);
vB = _mm_loadu_si128((__m128i *)&pB[i]);
vRes = _mm_cmpgt_epi16(vA, vB); // generate 0xffff/0x0000 results
vRes = _mm_srli_epi16(vRes, 15); // convert to 1/0 results
_mm_storeu_si128((__m128i *)&final[i], vRes2);
}
尝试加载 1:
vOnes = _mm_set1_epi16(1);
这比创建常量数组要短。
请注意,在 C++ 中提供少于数组大小的数组值会将其他值初始化为零。这是你的错误,而不是 SSE 部分。
不要忘记调试器,现代调试器可以正确显示 SSE 变量。