Vector256.Create 和 Avx2.BroadcastScalarToVector 函数有什么区别?

问题描述

例如,我想创建一个 Vector256 变量,其中所有元素都初始化为指定的有符号整数,据说我的系统支持 Avx2。 .NET 文档说使用 Avx2 广播 Scarlar 使用 _mm256_broadcastd_epi32_mm_broadcastd_epi32 指令。

Vector256.Create 生成什么指令?和上面一样吗?

int value = -1;
Vector256<int> v1 = Avx2.broadcastScalarToVector256(&value);
Vector256<int> v2 = Vector256.Create(-1);
Debug.Assert(v1.Equals(v2)); // True

解决方法

TL/DR:当源数据在内存中时使用 BroadcastScalarToVector256,其他情况下使用 Vector256<int>.Create

BroadcastScalarToVector256 的文档说它编译成这个程序集: VPBROADCASTD ymm,m32 当源标量在内存中时,这是你想要的,但如果源数据是寄存器,则需要往返内存并返回.即使内存在堆栈上,即在 L1D 缓存上,往返的延迟也稍慢。

Vector256.Create( int ) 的文档没有说明它编译成什么,只说它对应于 C++ 中的 _mm256_set1_epi32 内在函数。这意味着 JIT 编译器可以自由地做任何最有效的事情。

如果您调用 Vector256<int>.Create( 0 ),它应该编译为 vpxor ymm0,ymm0,ymm0 指令,因为该指令是将向量归零的快速方法。

当您调用 Vector256<int>.Create( -1 ) 时,它应该编译为 vpcmpeqd ymm0,ymm0 指令或类似指令,同样因为编译器知道该值,vpcmpeqd 没有数据依赖性,并且可以快速完成工作。

当你在那里传递一个变量时,Create 应该编译成像 vmovd xmm0,eax; vpbroadcastd ymm0,xmm0 这样的代码,这是两条指令,但仍然比往返内存和返回速度更快。