我可以正确地比较 avx 中的零寄存器吗?
Could I compare to zero register in avx correctly?
我遇到了 AVX 内部指令 _mm256_testc_pd() 的一个非常奇怪的行为。
在这里你可以看到这个函数的描述 https://software.intel.com/sites/landingpage/IntrinsicsGuide/#techs=AVX,AVX2&text=test&expand=5432
我在我的代码中使用它 2 次,希望看到与零寄存器进行比较的类似结果。
#include <immintrin.h>
#include <stdio.h>
int main(void)
{
unsigned char arr[32] __attribute__ ((aligned (32)));
__m256d a, zero;
int res1, res2;
memset(arr, 0 , 32);
arr[0] = 0xff;
arr[4] = 0xff;
arr[8] = 0xff;
arr[12] = 0xff;
arr[16] = 0xff;
arr[20] = 0xfd;
arr[24] = 0xff;
arr[28] = 0xff;
zero = _mm256_setzero_pd();
a = _mm256_load_pd((double *)arr);
res1 = _mm256_testc_pd(zero, a);
printf("res1 = %d\n" , res1);
memset(arr, 0xff, 32);
a = _mm256_load_pd((double *)arr);
res2 = _mm256_testc_pd(zero, a);
printf("res2 = %d\n" , res2);
return 0;
}
结果我得到了
res1 = 1
res2 = 0
有人知道为什么会这样吗?我认为在这两种情况下 a
都不等于零。
更新
在评论中讨论后我的问题解决了,但我对函数 _mm256_testc_si256 和 _mm256_testz_si256
有一点误解
例如:
unsigned char arr[32] __attribute__ ((aligned (32)));
__m256d a, zero;
int res1, res2;
memset(arr, 0 , 32);
arr[0] = 0x80;
zero = _mm256_setzero_pd();
a = _mm256_load_pd((double *)arr);
res1 = _mm256_testc_si256(_mm256_castpd_si256(zero),_mm256_castpd_si256(a));
res2 = _mm256_testz_si256(_mm256_castpd_si256(zero),_mm256_castpd_si256(a));
printf("res1 = %d\n" , res1);
printf("res2 = %d\n" , res2);
输出为
res1 = 0
res2 = 1
而且我认为只有第一个是正确的。那么为什么这个函数会产生不同的输出?
_mm256_testc_pd
仅对每个双精度元素的 符号位 进行操作,因此观察到的行为是正确的。如果你想在每个元素中测试双精度 values 那么首先使用合适的比较指令(例如 _mm256_cmp_pd
和适当的 _CMP_xxx
参数)然后使用 _mm256_testc_pd
或 _mm256_testz_pd
之后,具体取决于您的具体要求。
感谢 Peter Cordes 和其他所有人,我的问题的正确(也是最漂亮)解决方案是
res = _mm256_testz_si256(_mm256_castpd_si256(a), _mm256_castpd_si256(a))
我遇到了 AVX 内部指令 _mm256_testc_pd() 的一个非常奇怪的行为。 在这里你可以看到这个函数的描述 https://software.intel.com/sites/landingpage/IntrinsicsGuide/#techs=AVX,AVX2&text=test&expand=5432
我在我的代码中使用它 2 次,希望看到与零寄存器进行比较的类似结果。
#include <immintrin.h>
#include <stdio.h>
int main(void)
{
unsigned char arr[32] __attribute__ ((aligned (32)));
__m256d a, zero;
int res1, res2;
memset(arr, 0 , 32);
arr[0] = 0xff;
arr[4] = 0xff;
arr[8] = 0xff;
arr[12] = 0xff;
arr[16] = 0xff;
arr[20] = 0xfd;
arr[24] = 0xff;
arr[28] = 0xff;
zero = _mm256_setzero_pd();
a = _mm256_load_pd((double *)arr);
res1 = _mm256_testc_pd(zero, a);
printf("res1 = %d\n" , res1);
memset(arr, 0xff, 32);
a = _mm256_load_pd((double *)arr);
res2 = _mm256_testc_pd(zero, a);
printf("res2 = %d\n" , res2);
return 0;
}
结果我得到了
res1 = 1
res2 = 0
有人知道为什么会这样吗?我认为在这两种情况下 a
都不等于零。
更新
在评论中讨论后我的问题解决了,但我对函数 _mm256_testc_si256 和 _mm256_testz_si256
例如:
unsigned char arr[32] __attribute__ ((aligned (32)));
__m256d a, zero;
int res1, res2;
memset(arr, 0 , 32);
arr[0] = 0x80;
zero = _mm256_setzero_pd();
a = _mm256_load_pd((double *)arr);
res1 = _mm256_testc_si256(_mm256_castpd_si256(zero),_mm256_castpd_si256(a));
res2 = _mm256_testz_si256(_mm256_castpd_si256(zero),_mm256_castpd_si256(a));
printf("res1 = %d\n" , res1);
printf("res2 = %d\n" , res2);
输出为
res1 = 0
res2 = 1
而且我认为只有第一个是正确的。那么为什么这个函数会产生不同的输出?
_mm256_testc_pd
仅对每个双精度元素的 符号位 进行操作,因此观察到的行为是正确的。如果你想在每个元素中测试双精度 values 那么首先使用合适的比较指令(例如 _mm256_cmp_pd
和适当的 _CMP_xxx
参数)然后使用 _mm256_testc_pd
或 _mm256_testz_pd
之后,具体取决于您的具体要求。
感谢 Peter Cordes 和其他所有人,我的问题的正确(也是最漂亮)解决方案是
res = _mm256_testz_si256(_mm256_castpd_si256(a), _mm256_castpd_si256(a))