其他分享
首页 > 其他分享> > c – Intel AVX:256位版本的点积,用于双精度浮点变量

c – Intel AVX:256位版本的点积,用于双精度浮点变量

作者:互联网

英特尔高级矢量扩展指令集(AVX)在256位版本(YMM寄存器)中不提供双精度浮点变量的点积. “为什么?”问题已在另一个论坛(here)和Stack Overflow(here)上进行了简要处理.但我面临的问题是如何以有效的方式用其他AVX指令替换这条缺失的指令?

对于单精度浮点变量(reference here),存在256位版本的点积:

 __m256 _mm256_dp_ps(__m256 m1, __m256 m2, const int mask);

我们的想法是找到这个缺失指令的有效等价物:

 __m256d _mm256_dp_pd(__m256d m1, __m256d m2, const int mask);

更具体地说,我想从__m128(四个浮点数)转换为__m256d(4个双精度数)的代码使用以下指令:

   __m128 val0 = ...; // Four float values
   __m128 val1 = ...; //
   __m128 val2 = ...; //
   __m128 val3 = ...; //
   __m128 val4 = ...; //

   __m128 res = _mm_or_ps( _mm_dp_ps(val1,  val0,   0xF1),
                _mm_or_ps( _mm_dp_ps(val2,  val0,   0xF2),
                _mm_or_ps( _mm_dp_ps(val3,  val0,   0xF4),
                           _mm_dp_ps(val4,  val0,   0xF8) )));

此代码的结果是包含val1和val0,val2和val0,val3和val0,val4和val0之间的点积结果的四个浮点数的_m128向量.

也许这可以给出建议的提示?

解决方法:

我会使用4 *倍乘,然后是一个hadd(不幸的是,在上半部分和下半部分只添加2 * 2个浮点数),提取上半部分(一个shuffle应该同样工作,也许更快)并将其添加到下半部分.

结果是dotproduct的低64位.

__m256d xy = _mm256_mul_pd( x, y );
__m256d temp = _mm256_hadd_pd( xy, xy );
__m128d hi128 = _mm256_extractf128_pd( temp, 1 );
__m128d dotproduct = _mm_add_pd( (__m128d)temp, hi128 );

编辑:
在对Norbert P.的想法之后,我将这个版本扩展为一次做4个点产品.

__m256d xy0 = _mm256_mul_pd( x[0], y[0] );
__m256d xy1 = _mm256_mul_pd( x[1], y[1] );
__m256d xy2 = _mm256_mul_pd( x[2], y[2] );
__m256d xy3 = _mm256_mul_pd( x[3], y[3] );

// low to high: xy00+xy01 xy10+xy11 xy02+xy03 xy12+xy13
__m256d temp01 = _mm256_hadd_pd( xy0, xy1 );   

// low to high: xy20+xy21 xy30+xy31 xy22+xy23 xy32+xy33
__m256d temp23 = _mm256_hadd_pd( xy2, xy3 );

// low to high: xy02+xy03 xy12+xy13 xy20+xy21 xy30+xy31
__m256d swapped = _mm256_permute2f128_pd( temp01, temp23, 0x21 );

// low to high: xy00+xy01 xy10+xy11 xy22+xy23 xy32+xy33
__m256d blended = _mm256_blend_pd(temp01, temp23, 0b1100);

__m256d dotproduct = _mm256_add_pd( swapped, blended );

标签:c,performance,avx,simd
来源: https://codeday.me/bug/20191004/1851837.html