为什么 _mm256_load_pd 编译为 MOVUPD 而不是 MOVAPD?
Why _mm256_load_pd compiled to MOVUPD instead of MOVAPD?
为什么以下代码会导致未对齐的 AVX 指令(MOVUPD 而不是 MOVAPD)?我在 Visual Studio 2015 年编译了这个。我如何告诉编译器我的数据确实对齐了?
const size_t ALIGN_SIZE = 64;
const size_t ARRAY_SIZE = 1024;
double __declspec(align(ALIGN_SIZE)) a[ARRAY_SIZE];
double __declspec(align(ALIGN_SIZE)) b[ARRAY_SIZE];
//Calculate the dotproduct
__m256d ymm0 = _mm256_set1_pd(0.0);
for (int i = 0; i < ARRAY_SIZE; i += 8)
{
__m256d ymm1 = _mm256_load_pd(a + i);
__m256d ymm2 = _mm256_load_pd(b + i);
__m256d ymm3 = _mm256_mul_pd(ymm1, ymm2);
ymm0 = _mm256_add_pd(ymm3, ymm0);
__m256d ymm4 = _mm256_load_pd(a + i + 4);
__m256d ymm5 = _mm256_load_pd(b + i + 4);
__m256d ymm6 = _mm256_mul_pd(ymm4, ymm5);
ymm0 = _mm256_add_pd(ymm6, ymm0);
}
Assembly of the loop:
00007FF7AC7A1400 vmovupd ymm1,ymmword ptr [rbp+rax*8+2020h]
00007FF7AC7A1409 vmulpd ymm3,ymm1,ymmword ptr [rbp+rax*8+20h]
00007FF7AC7A140F vmovupd ymm2,ymmword ptr [rbp+rax*8]
00007FF7AC7A1415 vmulpd ymm0,ymm2,ymmword ptr b[rax*8]
00007FF7AC7A141E add r8d,8
00007FF7AC7A1422 movsxd rax,r8d
00007FF7AC7A1425 vaddpd ymm1,ymm0,ymm4
00007FF7AC7A1429 vaddpd ymm4,ymm1,ymm3
00007FF7AC7A142D cmp rax,400h
00007FF7AC7A1433 jb main+70h (07FF7AC7A1400h)
有解决这个问题的方法(它允许使用指令 VMOVDQA(模拟 MOVAPD)而不是 MOVUPD):
inline __m256d Load(const double * p)
{
#ifdef _MSC_VER
return _mm256_castsi256_pd(_mm256_load_si256((__m256i*)p));
#else
return _mm256_load_pd(p);
#endif
}
float 类型的类似解决方案:
inline __m256 Load(const float * p)
{
#ifdef _MSC_VER
return _mm256_castsi256_ps(_mm256_load_si256((__m256i*)p));
#else
return _mm256_load_ps(p);
#endif
}
但是为了欺骗 Visual Studio 编译器,您必须使用动态分配的指针。否则编译器不使用 VMOVDQA 指令。
#include <immintrin.h>
int main()
{
float * ps = (float*)_mm_malloc(40, 32);
double * pd = (double*)_mm_malloc(40, 32);
__m256 s = Load(ps);
//00007FF79FF81325 vmovdqa ymm1,ymmword ptr [rdi]
__m256d d = Load(pd);
//00007FF79FF8132F vmovdqa ymm0,ymmword ptr [rax]
_mm256_storeu_ps(ps, s);
_mm256_storeu_pd(pd, d);
_mm_free(ps);
_mm_free(pd);
}
为什么以下代码会导致未对齐的 AVX 指令(MOVUPD 而不是 MOVAPD)?我在 Visual Studio 2015 年编译了这个。我如何告诉编译器我的数据确实对齐了?
const size_t ALIGN_SIZE = 64;
const size_t ARRAY_SIZE = 1024;
double __declspec(align(ALIGN_SIZE)) a[ARRAY_SIZE];
double __declspec(align(ALIGN_SIZE)) b[ARRAY_SIZE];
//Calculate the dotproduct
__m256d ymm0 = _mm256_set1_pd(0.0);
for (int i = 0; i < ARRAY_SIZE; i += 8)
{
__m256d ymm1 = _mm256_load_pd(a + i);
__m256d ymm2 = _mm256_load_pd(b + i);
__m256d ymm3 = _mm256_mul_pd(ymm1, ymm2);
ymm0 = _mm256_add_pd(ymm3, ymm0);
__m256d ymm4 = _mm256_load_pd(a + i + 4);
__m256d ymm5 = _mm256_load_pd(b + i + 4);
__m256d ymm6 = _mm256_mul_pd(ymm4, ymm5);
ymm0 = _mm256_add_pd(ymm6, ymm0);
}
Assembly of the loop:
00007FF7AC7A1400 vmovupd ymm1,ymmword ptr [rbp+rax*8+2020h]
00007FF7AC7A1409 vmulpd ymm3,ymm1,ymmword ptr [rbp+rax*8+20h]
00007FF7AC7A140F vmovupd ymm2,ymmword ptr [rbp+rax*8]
00007FF7AC7A1415 vmulpd ymm0,ymm2,ymmword ptr b[rax*8]
00007FF7AC7A141E add r8d,8
00007FF7AC7A1422 movsxd rax,r8d
00007FF7AC7A1425 vaddpd ymm1,ymm0,ymm4
00007FF7AC7A1429 vaddpd ymm4,ymm1,ymm3
00007FF7AC7A142D cmp rax,400h
00007FF7AC7A1433 jb main+70h (07FF7AC7A1400h)
有解决这个问题的方法(它允许使用指令 VMOVDQA(模拟 MOVAPD)而不是 MOVUPD):
inline __m256d Load(const double * p)
{
#ifdef _MSC_VER
return _mm256_castsi256_pd(_mm256_load_si256((__m256i*)p));
#else
return _mm256_load_pd(p);
#endif
}
float 类型的类似解决方案:
inline __m256 Load(const float * p)
{
#ifdef _MSC_VER
return _mm256_castsi256_ps(_mm256_load_si256((__m256i*)p));
#else
return _mm256_load_ps(p);
#endif
}
但是为了欺骗 Visual Studio 编译器,您必须使用动态分配的指针。否则编译器不使用 VMOVDQA 指令。
#include <immintrin.h>
int main()
{
float * ps = (float*)_mm_malloc(40, 32);
double * pd = (double*)_mm_malloc(40, 32);
__m256 s = Load(ps);
//00007FF79FF81325 vmovdqa ymm1,ymmword ptr [rdi]
__m256d d = Load(pd);
//00007FF79FF8132F vmovdqa ymm0,ymmword ptr [rax]
_mm256_storeu_ps(ps, s);
_mm256_storeu_pd(pd, d);
_mm_free(ps);
_mm_free(pd);
}