2016-07-13 6 views
3

こんにちは私はAVX2組み込み関数に奇妙な問題があります。私はint64_t *キャストで_m256iベクトルへのポインタを作成します。次に、ポインタの逆参照によって値を割り当てます。奇妙なことは、ベクトル変数の後ろにいくつかのcout文を実行しない限り、値がベクトル変数には見られないということです。ポインタとベクタは同じメモリアドレスを持ち、ポインタの逆参照は正しい値を生成しますが、ベクタは正しくありません。私は何が欠けていますか?int64_t内在のAVX2へのキャストポインタ_m256i

// Vector Variable 
__m256i R_A0to3 = _mm256_set1_epi32(0xFFFFFFFF); 

int64_t *ptr = NULL; 
for(int m=0; m<4; m++){ 
    // Cast pointer to vector type 
    ptr = (int64_t*)&R_A0to3; 

    cout<<"ptr_ADDRESS:  "<<ptr<<endl; 
    cout<<"&R_A0to3_ADDRESS: "<<&R_A0to3<<endl; 

    // access 
    ptr[m] = (int64_t) m_array[m]; 

    // generic function that prints out register 
    print_mm256_reg<int64_t>(R_A0to3, "R_A0to3"); 
    cout<<"m_array: "<< m_array[m]<<std::ends; 

    // Additional print statements 
    cout<<"ptr[m]: "<< ptr[m]<<std::endl; 
    cout<<"ptr[0]: "<< ptr[0]<<std::endl; 
    cout<<"ptr[1]: "<< ptr[1]<<std::endl; 
    cout<<"ptr[2]: "<< ptr[2]<<std::endl; 
    cout<<"ptr[3]: "<< ptr[3]<<std::endl; 
    print_mm256_reg<int64_t>(R_A0to3, "R_A0to3"); 
} 

Output: 
ptr_ADDRESS  0x7ffd9313e880 
&R_A0to3_ADDRESS 0x7ffd9313e880 
m_array: 8 
printing reg - R_C0to3 -1| -1| -1| -1| 
printing reg - R_D0to3 -1| -1| -1| -1| 

Output with Additional print statements: 
ptr_ADDRESS  0x7ffd36359e20 
&R_A0to3_ADDRESS 0x7ffd36359e20 
printing reg - R_A0to3  -1| -1| -1| -1| 
m_array: 8 

ptr[0]: 8 
ptr[1]: -1 
ptr[2]: -1 
ptr[3]: -1 
printing reg - R_A0to3  8| -1| -1| -1| 
+2

これはどのコンパイラですか?私はこれがGCCのコーナーケースの1つであると信じています。厳密なエイリアス違反が実際には起こらないかもしれないにもかかわらず実際に問題を引き起こすでしょう。 (SIMD型は '__may_alias__'と宣言されています)厳密なエイリアスを無効にしようとしましたか? '-Wstrict-aliasing'はそれを不平にしますか? – Mysticial

+1

@Mysticial:おそらく、プログラムが未定義の振る舞いをしているので、コンパイラは変数を一貫して保つことをあきらめますか? m = 4..9では 'ptr [m]'は '__m256i R_A0to3'の外側からアクセスします。いずれにせよ、これはベクトルを使うばかげた方法です。これをしないでください。実際にバッファに格納してベクトルを変更する場合は、それを行うコードを記述し、その後にベクトルを再読み込みします。あるいは、おそらくユニオンを使用します。ポインタキャストによる型打ちは良いイディオムではありません。 –

+0

@PeterCordes Aha、そうだよ!私はそれが限界を超えているのを見ていませんでした。 – Mysticial

答えて

2

私はあなたが個々の要素への臨時のアクセスを必要とするとき_mm256_extract_epi64_mm256_insert_epi64組み込み関数を使用することをお勧め。ベクトルからすべての要素にアクセスする必要がある場合は、_mm256_store_si256_mm256_lddqu_si256を使用して、格納してロードしてください。これらの組み込み関数は、未定義のビヘイビアに依存する可能性が低く、生成されるマシン命令(したがってパフォーマンス)に関して透過的です。

+0

すべての要素が別々のスカラとして必要な場合、ローカル配列に格納することは悪い選択ではありません。あなたはおそらく抽出物よりも良いコードを得るでしょう。あるいは、ポインタキャスティングの代わりに型打ちのための共用体を使用してください。なぜなら、IIRC、GNU Cは共用体ベースの型打ちを保証しているからです。 (私はGNU C拡張もサポートしていない他のx86コンパイラでは安全だと思います) –

+0

"IIRCのために、ポインタキャストの代わりに型打ち用の共用体を使用すると、GNU Cは、 (私はGNU C拡張をサポートしていない他のx86コンパイラでも安全だと思います) "この場合、コンパイラがどのように実装するのかはほとんど考えていないと思います私は間違っているかもしれませんが。それはあなたが望むものかもしれません。 –

+0

[gccストア/リロード、clangは抽出手順を使用します](https://godbolt.org/g/oqFjDE)。これはgccの欠落した最適化です。 IDKはどのくらいの間それを修正するのだろうか。明らかにいずれの方法もかなり低いパフォーマンス(特にstore/modify/reload store-forwarding failure)であるため、debug-printのようなものに主に使用するべきです。 ['vpextrq'](http://www.felixcloutier.com/x86/PEXTRB:PEXTRD:PEXTRQ.html)がそうでないので、私は' _mm256_extract_epi64'が上位の要素に存在している/働いていたことを認識していませんでした。また、 '_mm256_lddqu_si256'は意味がありません。単に 'loadu'を使用してください。 (または整列されている場合は 'load'、私は推測します)。 –

関連する問題