【发布时间】:2020-10-12 08:22:17
【问题描述】:
我是使用 AVX512 指令编码的新手。我的机器是 Intel KNL 7250。我正在尝试使用 AVX512 指令来查找具有最大绝对值的元素的索引,它是数组的双精度和大小 % 8 = 0。但它每次都会打印一个输出索引 = 0。不知道哪里有问题,请帮帮我。 另外,__m512i 类型如何使用 printf?
谢谢。
代码:
void main()
{
int i;
int N=160;
double vec[N];
for(i=0;i<N;i++)
{
vec[i]=(double)(-i) ;
if(i==10)
{
vec[i] = -1127;
}
}
int max = avxmax_(N, vec);
printf("maxindex=%d\n", max);
}
int avxmax_(int N, double *X )
{
// return the index of element having maximum absolute value.
int maxindex, ix, i, M;
register __m512i increment, indices, maxindices, maxvalues, absmax, max_values_tmp, abs_max_tmp, tmp;
register __mmask8 gt;
double values_X[8];
double indices_X[8];
double maxvalue;
maxindex = 1;
if( N == 1) return(maxindex);
M = N % 8;
if( M == 0)
{
increment = _mm512_set1_epi64(8); // [8,8,8,8,8,8,8,8]
indices = _mm512_setr_epi64(0, 1, 2, 3, 4, 5, 6, 7);
maxindices = indices;
maxvalues = _mm512_loadu_si512(&X[0]);
absmax = _mm512_abs_epi64(maxvalues);
for( i = 8; i < N; i += 8)
{
// advance scalar indices: indices[0] + 8, indices[1] + 8,...,indices[7] + 8
indices = _mm512_add_epi64(indices, increment);
// compare
max_values_tmp = _mm512_loadu_si512(&X[i]);
abs_max_tmp = _mm512_abs_epi64(max_values_tmp);
gt = _mm512_cmpgt_epi64_mask(abs_max_tmp, absmax);
// update
maxindices = _mm512_mask_blend_epi64(gt, maxindices, indices);
absmax = _mm512_max_epi64(absmax, abs_max_tmp);
}
// scalar part
_mm512_storeu_si512((__m512i*)values_X, absmax);
_mm512_storeu_si512((__m512i*)indices_X, maxindices);
maxindex = indices_X[0];
maxvalue = values_X[0];
for(i = 1; i < 8; i++)
{
if(values_X[i] > maxvalue)
{
maxvalue = values_X[i];
maxindex = indices_X[i];
}
}
return(maxindex);
}
}
【问题讨论】:
-
不是你要问的那个bug,但是注意
abs之后的结果应该是无符号的,epu就像_mm512_cmpgt_epu64_mask和_mm512_max_epu64INT64_MIN的绝对值是如果你把它当作有符号的,仍然是负数,因为 2 的补码。等一下,您正在对 FP 位模式使用整数指令。这对于负数是不正确的,因为 FP 是符号/大小,而不是 2 的补码。 (指数偏差确实可以将位模式作为整数进行比较,只需对符号处理进行少量调整。在您的情况下,通过屏蔽高位来 abs) -
re: 打印:没有 printf 转换,您必须编写自己的打印函数:print a __m128i variable
-
我将epi替换为_mm512_abs_epu64、_mm512_cmpgt_epu64_mask和_mm512_max_epu64的epu。但是它有关于“不能将“int”类型的值分配给“__m512i”类型的实体的abs错误。我真的不明白你关于通过“屏蔽高位”来解决我的问题的意思。请帮我解释一下。
-
您忽略了早期关于未声明函数的编译器警告。
_mm512_abs_epu64不存在,所以它的隐式返回类型是int。abs接受有符号输入,因此它的内在函数称为epi64。abs_epu64将是无操作的,因此它不存在。与有符号与无符号最大值和 cmp 不同。 -
顺便说一句,您的函数返回 0,因为它将一个微小的
double位模式转换为整数。你_mm512_storeu_si512将 int64 索引向量转换为double indices_X[8],将其键入到double,然后在纯 C 中将该双精度转换为整数。 (我注意到 asm godbolt.org/z/zsfc36 中有一个神秘的vcvttsd2siFP-int 转换,同时将代码转换为初始化器旁边的 C99 样式变量声明。请注意,对于 FP 位模式使用正确的 abs,只需清除符号位,您就可以继续使用有符号整数比较。)
标签: c max instructions avx512