2016-04-19 10 views
5

次のコードは、アラインメントのないAVX命令(MOVAPDではなくMOVUPD)を生成するのはなぜですか?私はVisual Studio 2015でこれをコンパイルしました。データが本当に整列していることをコンパイラにどのように伝えることができますか?_mm256_load_pdがMOVAPDではなくMOVUPDにコンパイルされるのはなぜですか?

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) 
+2

それは本当に問題ではありません - 現代のCPUで整列されたデータを非整列ロードを使用するための事実上のペナルティはありませんが - コンパイラの作家はおそらく常に使用する時期を決定するために追加のロジックを持つのではなく、非整列ロードを使用することにしましたアライメントされていないロードに対して –

+0

FWIW gcc *らは正しいことをしているので、これはマイクロソフト固有の癖にすぎません。 –

+3

@PaulR、なぜ仮想という言葉を使用しますか?私が気づいているすべてのペナルティはありません。 'vmovapd'は時代遅れです。 'mvovapd'は' movupd'が他の操作で折り畳むことができないのでネールハムではまだ有用ですが、これは実際には大きな違いがあるのではないかと疑います。たぶんそれはあなたが仮想で意味したものですが、その場合はNehalemにのみ適用され、この答えはNehalem用にはっきりとは作成されていません。 –

答えて

0

この問題を解決する方法は、(それが代わりMOVUPDの命令VMOVDQA(MOVAPDのアナログ)を使用することを可能にする)がある:float型用

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 
} 

類似液:

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); 
} 
関連する問題