Por ejemplo, quiero crear una variable Vector256 con todos los elementos inicializados en un entero con signo específico, supuestamente mi sistema es compatible con Avx2. El documento de .NET dice que la transmisión de un scarlar con Avx2 usa las instrucciones _mm256_broadcastd_epi32 y _mm_broadcastd_epi32 .
¿Qué instrucción genera Vector256.Create ? ¿Es lo mismo que el anterior?
int value = -1; Vector256<int> v1 = Avx2.BroadcastScalarToVector256(&value); Vector256<int> v2 = Vector256.Create(-1); Debug.Assert(v1.Equals(v2)); // TrueTL/DR: utilice BroadcastScalarToVector256 cuando los datos de origen estén en la memoria y Vector256<int>.Create en todos los demás casos.
La documentación de BroadcastScalarToVector256 dice que se compila en este ensamblado: VPBROADCASTD ymm, m32 Esto es lo que desea cuando el escalar de origen está en la memoria, pero realiza un viaje de ida y vuelta a la memoria y viceversa si los datos de origen son un registro. Ese viaje de ida y vuelta es un poco más lento en términos de latencia, incluso si la memoria está en la pila, es decir, en la caché L1D.
La documentación de Vector256.Create( int ) no dice en qué se compila, solo dice que corresponde a _mm256_set1_epi32 intrínseco en C++. Esto significa que el compilador JIT es libre de hacer lo que sea más eficiente.
Si llama a Vector256<int>.Create( 0 ) , debería compilarse en vpxor ymm0, ymm0, ymm0 , porque esa instrucción es una forma rápida de poner a cero un vector.
Cuando llama a Vector256<int>.Create( -1 ) , debe compilarse en vpcmpeqd ymm0, ymm0, ymm0 o similar, nuevamente porque el compilador conoce el valor, vpcmpeqd no tiene dependencias de datos y hace el trabajo rápidamente.
Cuando pasa una variable allí, Create debe compilarse en un código como vmovd xmm0, eax; vpbroadcastd ymm0, xmm0 , son dos instrucciones, pero aún más rápido que el viaje de ida y vuelta a la memoria y viceversa.