For example, I want to create a Vector256 variable with all elements initialized to a specified signed integer, supposedly my system supports Avx2. The .NET Document says broadcasting a scarlar with Avx2 uses _mm256_broadcastd_epi32 and _mm_broadcastd_epi32 instructions.
What instruction does Vector256.Create generate? Is it the same as the above?
int value = -1;
Vector256<int> v1 = Avx2.BroadcastScalarToVector256(&value);
Vector256<int> v2 = Vector256.Create(-1);
Debug.Assert(v1.Equals(v2)); // True
TL/DR: use BroadcastScalarToVector256 when the source data is in memory, and Vector256<int>.Create in all other cases.
The documentation for BroadcastScalarToVector256 says it compiles into this assembly: VPBROADCASTD ymm, m32 This is what you want when the source scalar is in memory, but takes roundtrip to memory and back if the source data is a register. That roundtrip is slightly slower in terms of latency, even if the memory is on stack i.e. on L1D cache.
The documentation for Vector256.Create( int ) doesn’t say what it compiles into, only says that it corresponds to _mm256_set1_epi32 intrinsic in C++. This means JIT compiler is free to do whatever’s the most efficient.
If you call Vector256<int>.Create( 0 ) it should compile into vpxor ymm0, ymm0, ymm0 instruction, because that instruction is a fast way to zero out a vector.
When you call Vector256<int>.Create( -1 ) it should compile into vpcmpeqd ymm0, ymm0, ymm0 instruction or similar, again because the value is known to compiler, vpcmpeqd has no data dependencies, and does the job, fast.
When you pass a variable there, Create should compile into code like vmovd xmm0, eax; vpbroadcastd ymm0, xmm0, that’s two instructions, but still faster than roundtrip to memory and back.