2015-10-17 7 views
6

、 次のサンプルコードは、自動ベクトル化(assembly here)を-std=c99-O3、及び-mavx2を使用してGCC 5.2でコンパイル:GCCでストライドされた書き込みを自動ベクトル化する方法は?

#include <stdint.h> 

void test(uint32_t *restrict a, 
      uint32_t *restrict b) { 
    uint32_t *a_aligned = __builtin_assume_aligned(a, 32); 
    uint32_t *b_aligned = __builtin_assume_aligned(b, 32); 

    for (int i = 0; i < (1L << 10); i += 2) { 
    a_aligned[i] = 42 * b_aligned[i]; 
    a_aligned[i+1] = 3 * a_aligned[i+1]; 
    } 
} 

しかし、以下のサンプルコードは、自動ベクトル化(assembly here)ない:

#include <stdint.h> 

void test(uint32_t *restrict a, 
      uint32_t *restrict b) { 
    uint32_t *a_aligned = __builtin_assume_aligned(a, 32); 
    uint32_t *b_aligned = __builtin_assume_aligned(b, 32); 

    for (int i = 0; i < (1L << 10); i += 2) { 
    a_aligned[i] = 42 * b_aligned[i]; 
    a_aligned[i+1] = a_aligned[i+1]; 
    } 
} 

サンプル間の唯一の違いは、倍率がa_aligned[i+1]になることです。

これは、GCC 4.8,4.9、および5.1の場合も同様です。 をa_alignedの宣言に追加すると、自動ベクトル化は完全に禁止されます。最初のサンプルは一貫して2番目のサンプルよりも速く実行され、小さいタイプの場合はさらに高速化されました(たとえば、uint32_tの代わりにuint8_t)。

2番目のコードサンプルをGCCで自動ベクトル化する方法はありますか?

+0

唯一の違いは倍率(3対何もない)ですか?スケーリング係数として1を明示的に追加してみてください。それが解決すれば、それはコンパイラのバグです。 – Jeff

+0

また、文 'a_aligned [i + 1] = a_aligned [i + 1]'をコメントアウトするか、 'a_aligned [i + 1] * = 1'として書き直してみてください。コンパイラは、あなたが何を言っているかを正確に行う以外に、あなたのノーオペレーションの自己割り当てで何をすべきかを知らないかもしれません。 –

+0

@ Jeff実際、唯一の違いは倍率です。明示的な1を追加しても、2番目のコードサンプルは自動ベクトル化されません([assembly here](https://goo.gl/dnjSaQ))。 –

答えて

1

次のバージョンvectorisesていますが、-fopenmpでコンパイルするとtest(a, a, b)を呼び出すために...

#include <stdint.h> 

void test(uint32_t *a, uint32_t *aa, 
      uint32_t *restrict b) { 
    #pragma omp simd aligned(a,aa,b:32) 
    for (int i = 0; i < (1L << 10); i += 2) { 
    a[i] = 2 * b[i]; 
    a[i+1] = aa[i+1]; 
    } 
} 

を私に言わせれば、それは醜いです。

+0

このアプローチには2つの注意点があります。一つ目は、 'a'と' aa'で 'restrict'キーワードを忘れてしまい、必要以上に' aa'を読み返す可能性があります。提供されたサンプルコード(この場合、GCCは 'a'と' aa'エイリアスが面倒な方法で非ベクトル化されたコードに分岐します)が、一般的には必要以上に読み込みが行われる可能性があります。例えば、 'b'が' a'に置き換えられたとします。この場合、不要な多くの 'vmovdq'命令が生成されます。 –

+0

2番目は '-O3'で、GCCは' test() 'を自動インライン化します。これは 'test()'がインラインになる場所では、 'a'が' aa'であると認識し、自動ベクトル化に失敗することを意味します。これはGCCの '__attribute__((noinline)) 'で修正できますが、まだ不必要に関数呼び出しオーバーヘッドが発生しています。 –

関連する問題