2017-02-15 16 views
2

次のループは、整数行列を別の整数行列に変換します。興味深いことにコンパイルすると、結果が出力マトリックスに格納されるmovaps命令が生成されます。なぜgccですか?このSSE2プログラム(整数)がなぜmovaps(浮動小数点数)を生成するのですか?

データ:

int __attribute__((aligned(16))) t[N][M] 
    , __attribute__((aligned(16))) c_tra[N][M]; 

ループ:

.L39: 
    lea rcx, [rsi+rdx] 
    movdqa xmm1, XMMWORD PTR [rdx] 
    add rdx, 16 
    add rax, 2048 
    movdqa xmm6, XMMWORD PTR [rcx+rdi] 
    movdqa xmm3, xmm1 
    movdqa xmm2, XMMWORD PTR [rcx+r9] 
    punpckldq xmm3, xmm6 
    movdqa xmm5, XMMWORD PTR [rcx+r10] 
    movdqa xmm4, xmm2 
    punpckhdq xmm1, xmm6 
    punpckldq xmm4, xmm5 
    punpckhdq xmm2, xmm5 
    movdqa xmm5, xmm3 
    punpckhqdq xmm3, xmm4 
    punpcklqdq xmm5, xmm4 
    movdqa xmm4, xmm1 
    punpckhqdq xmm1, xmm2 
    punpcklqdq xmm4, xmm2 
    movaps XMMWORD PTR [rax-2048], xmm5 
    movaps XMMWORD PTR [rax-1536], xmm3 
    movaps XMMWORD PTR [rax-1024], xmm4 
    movaps XMMWORD PTR [rax-512], xmm1 
    cmp r11, rdx 
    jne .L39 

gcc -Wall -msse4.2 -masm="intel" -O2 -c -S skylake linuxmint

for(i=0; i<N; i+=4){ 
    for(j=0; j<M; j+=4){ 

     row0 = _mm_load_si128((__m128i *)&t[i][j]); 
     row1 = _mm_load_si128((__m128i *)&t[i+1][j]); 
     row2 = _mm_load_si128((__m128i *)&t[i+2][j]); 
     row3 = _mm_load_si128((__m128i *)&t[i+3][j]); 

     __t0 = _mm_unpacklo_epi32(row0, row1); 
     __t1 = _mm_unpacklo_epi32(row2, row3); 
     __t2 = _mm_unpackhi_epi32(row0, row1); 
     __t3 = _mm_unpackhi_epi32(row2, row3); 

     /* values back into I[0-3] */ 
     row0 = _mm_unpacklo_epi64(__t0, __t1); 
     row1 = _mm_unpackhi_epi64(__t0, __t1); 
     row2 = _mm_unpacklo_epi64(__t2, __t3); 
     row3 = _mm_unpackhi_epi64(__t2, __t3); 

     _mm_store_si128((__m128i *)&c_tra[j][i], row0); 
     _mm_store_si128((__m128i *)&c_tra[j+1][i], row1); 
     _mm_store_si128((__m128i *)&c_tra[j+2][i], row2); 
     _mm_store_si128((__m128i *)&c_tra[j+3][i], row3); 



    } 
} 

アセンブリコードを生成しました

-mavx2または-march=naticveは、VEXエンコーディング:vmovapsを生成します。

答えて

6

機能は同じです。 私は私のようにいくつかのリンクは、それを説明するようにコピー+他の人の文を貼り付けるのが好きではありません:

Difference between MOVDQA and MOVAPS x86 instructions?

https://software.intel.com/en-us/forums/intel-isa-extensions/topic/279587

http://masm32.com/board/index.php?topic=1138.0

https://www.gamedev.net/blog/615/entry-2250281-demystifying-sse-move-instructions/

ショートバージョン:

ほとんどの場合、 が、それらの レジスタで使用する操作に対応する移動命令を使用するようにしてください。しかし、追加の合併症があります。ロードおよび メモリとの間のストアは、整数 および浮動小数点ユニットとは別のポートで実行されます。したがって、メモリにロードしてレジスタまたはレジスタからメモリに格納する命令には、移動にアタッチするデータ型に関係なく、同じ遅延が発生します。 したがって、 の場合、movaps、movapd、およびmovdqaには、使用するデータが同じでない限り、 という遅延はありません。 movaps(とmovups)は バイナリ形式でエンコードされているため、 はデータ型に関係なくすべてのreg-memの移動に使用されます。

GCCの最適化です。

+1

実際にIntelとAMDが推奨するコード生成の練習です。実際のところ、最新のCPUの場合、アライメントされた/整列されていないロードでは、パフォーマンスに合わせた書き込みが同じであるため、常に「 '' movups''を使うことをお勧めします。 [Intel](http://www.intel.com/content/www/us/en/architecture-and-technology/64-ia-32-architectures-optimization-manual.html)および[AMD](http: //developer.amd.com/resources/developer-guides-manuals/)ソフトウェア最適化ガイド –

+0

@ChuckWalbourn 'movups'と' movaps'はNehalem以来同じ性能しか持っていません。しかし、 'movups'が操作を折り畳むことができないので、本当に' vmovaps'だけが時代遅れです。 IntelとAMDの推奨事項は確実ですか?あなたのハードウェアがそれをサポートしているならば、常に 'vmovups'を使うことを意味します。 –

+0

@ChuckWalbournあなたが指摘したインテルマニュアルを検索しましたが、あなたが言及した推奨事項が見つかりませんでした。どのセクションを参照していますか。私も 'vmovaps'を探していました。コードで何度か表示されていますので、Intelもそれを使っています。 –

関連する問題