下面是 AVX2 中矩阵乘法的实现。我使用的机器仅支持 AVX,因此我尝试使用 AVX 实现相同的配置。
但是,我很难理解到底有什么区别,以及需要改变什么!此实现中哪些内容是 AVX2 特有的,无法与只能处理 AVX 的机器一起使用?
这是 AVX 和 AVX2 所有命令的链接 https://software.intel.com/sites/landingpage/IntrinsicsGuide/#techs=AVX
感谢您的任何见解!
for (uint64_t i = 0; i < M; i++)
{
for (uint64_t j = 0; j < N; j++)
{
__m256 X = _mm256_setzero_ps();
for (uint64_t k = 0; k < L; k+= 8) {
const __m256 AV = _mm256_load_ps(A+i*L+k);
const __m256 BV = _mm256_load_ps(B+j*L+k);
X = _mm256_fmadd_ps(AV,BV,X);
}
C[i*N+j] = hsum_avx(X);
}
}
您的代码使用 AVX1 + FMA 指令,而不是 AVX2。 例如,它可以在 AMD 打桩机上正常运行。 (假设 hsum 以合理的方式实现,提取高半部分,然后使用 128 位混洗。)。
如果您的仅 AVX CPU 也没有 FMA,则需要使用
_mm256_mul_ps
和 _mm256_add_ps
。
不幸的是即使是 VIA CPU 也有 AVX2 但没有 FMA
,否则 AVX2 意味着 FMA,除非您使用的是虚拟机或模拟器,故意具有真正的硬件没有的扩展组合。
MSVC /arch:AVX2
-march=x86-64-v3
都暗示 Haswell 功能级别,AVX2+FMA+BMI1/2。
(在一些 AMD CPU 中有一个 FMA4 扩展,有 4 个操作数(3 个输入和一个单独的输出),Bulldozer 到 Zen1,之后英特尔在 AMD 上进行了切换,为时已晚,他们无法更改其 Bulldozer 设计以支持 FMA3。这就是为什么有一个仅限 AMD 的 FMA4,以及为什么直到 Piledriver 后 AMD 才支持与 Intel 兼容的 FMA 扩展,但现在这已成为历史的一部分,所以通常我们只是说 FMA 来引用技术上称为 FMA3 的扩展。请参阅 Agner Fog 2009 年的博客停止指令集战争,以及
我如何知道我是否可以使用FMA指令集进行编译?)
AVX1:仅限 256 位 FP(除了vptest
vxorps ymm
这样的按位指令)。随机播放仅在通道内(例如 vshufps ymm
或新的 vpermilps
)或具有 128 位粒度(vperm2f128
或 vinsertf128
/
vextractf128
)。 AVX1 还提供所有 SSE1..4 指令(包括整数)的 VEX 编码,具有 3 操作数非破坏性。 例如vpsubb xmm0, xmm1, [rdi]
AVX2:整数 SSE 指令的 256 位版本,以及新的车道交叉洗牌,例如
vpermps
vpermd
和
vpermq / pd
,以及带有寄存器源的
vbroadcastss/sd ymm, xmm
(AVX1 仅具有 vbroadcastss ymm, [mem]
)。 也是一个高效的 vpblendd
立即整数混合指令,如
vblendps
FMA3:
vfmadd213ps x/ymm, x/ymm, x/ymm/mem
_mm256_fmadd_ps
将编译为某种形式的 vfmadd...ps
,具体取决于编译器要覆盖哪个输入操作数,以及要使用哪个操作数作为内存操作数。这种介绍顺序解释了内在命名的错误选择,例如
_mm256_permute_ps
_mm256_permutevar_ps
(矢量控制)是 AVX1
vpermilps
车道内排列,而 AVX2 则背负着
_mm256_permutexvar_ps
。 令人困惑的是,内在函数有一个用于车道交叉的
x
,而 asm 助记符却很简单。