私は特別な使用事例を念頭に置いていません。私はこれが本当にインテルの組み込み関数の設計上の瑕疵/制限であるのか、それとも何か不足しているのかどうかを尋ねています。コンパイラが上位要素をゼロにする命令を無駄にすることなく、スカラーをベクトルにマージする方法はありますか?インテルの組み込み関数の設計上の制限?
スカラー浮動小数点を既存のベクトルに結合する場合、インテルの組み込み関数を使用して、要素の高精度化やベクトルへのスカラーのブロードキャストを行わない方法はありません。私はGNU Cのネイティブベクトル拡張と関連する組み込み関数については調べていません。
余分な組み込み関数は最適化されていても、gcc(5.4または6.2)では最適化されていないと悪くありません。関連する理由から、その組み込み関数がベクトルargsだけを取るという理由で、pmovzx
またはinsertps
をロードとして使う良い方法もありません。 (とgccはASM命令にスカラー値>ベクトルロードを折るしません。)
__m128 replace_lower_two_elements(__m128 v, float x) {
__m128 xv = _mm_set_ss(x); // WANTED: something else for this step, some compilers actually compile this to a separate insn
return _mm_shuffle_ps(v, xv, 0); // lower 2 elements are both x, and the garbage is gone
}
のgcc 5.3 -march =のNehalemの-O3の出力を、そのインテルのCPUのためのSSE4.1とチューニングを可能にするために:(それはですさらに悪いことに、SSE4.1なしで、上位要素をゼロにするための複数の命令)。
insertps xmm1, xmm1, 0xe # pointless zeroing of upper elements. shufps only reads the low element of xmm1
shufps xmm0, xmm1, 0 # The function *should* just compile to this.
ret
TLは:DR:あなたが実際にこれを効率的に行うことができれば、この質問の残りの部分は、ちょうど求めているし、そうでない場合その理由ではありません。
打ち鳴らすのシャッフルオプティマイザはこの権利を取得し、高い要素(_mm_set_ss(x)
を)ゼロ、またはそれら(_mm_set1_ps(x)
)にスカラを複製する手順を無駄にしません。コンパイラが最適化しなければならないものを書くのではなく、最初にC言語で "効率的に"書く方法はありませんか?最近のgcc でさえ、を最適化していないので、これは実際の問題です。
__m256 _mm256_castps128_ps256 (__m128 a)
の> 128B同等のスカラー値があった場合、これは可能であろう。つまり、上位要素に定義されていないゴミを持つ__m128
を生成し、下位要素の浮動小数点を生成します。スカラーfloat/doubleが既にxmmレジスタにあった場合は、asm命令をゼロにコンパイルします。
次の組み込み関数はありませんが、である必要があります。
- 上記の通り
_mm256_castps128_ps256
のスカラー - > __ m128に相当します。スカラー・イン・レジスターの場合の最も一般的な解決策。 __m128 _mm_move_ss_scalar (__m128 a, float s)
:ベクトルa
の下位要素をスカラーs
に置き換えます。これは汎用スカラ - > __ m128(前の箇条書きの点)がある場合は実際には必要ありません。 (movss
のreg-reg形式は、ゼロのロード形式とは異なり、マージします。どちらの場合も、上位要素の値が0になるmovd
とは異なります。偽の依存関係のないスカラ浮動小数点を含むレジスタをコピーするには、movaps
を使用します)。不都合な安全な方法でgccを最適化しないため、__m128i _mm_loadzxbd (const uint8_t *four_bytes)
と他のサイズPMOVZX/PMOVSX:AFAICT, there's no good safe way to use the PMOVZX intrinsics as a loadがあります。__m128 _mm_insertload_ps (__m128 a, float *s, const int imm8)
。INSERTPSは、ロードとは異なる動作をします。imm8の上位2ビットは無視され、(メモリ内のベクトルからの要素ではなく)実効アドレスで常にスカラーをとります。これにより、マップされていないページの直前にある場合は、16Bで整列されていないアドレスでも動作し、エラーが発生していなくても動作します。float
PMOVZXと同様に、gccは上部要素ゼロ化
_mm_load_ss()
をINSERTPSのメモリオペランドに折りたたまない。 (imm8の上位2ビットが両方ともゼロでない場合、0xはinsertps xmm0,xmm0,foo
にコンパイルできます。src要素が実際にはMOVSSによってメモリから生成されたゼロの場合、vecの要素と異なるimm8がコンパイルされます。実際
__m128 float_to_vec(float a){ something(a); }
のようなインラインラッパー関数の後ろに置くことができる。
インテルがそのようなイントリンシックスを導入しない理由はありますか? _mm256_castps128_ps256
を追加すると同時に、未定義の上位要素を持つfloat - > __ m128を追加できました。 これはコンパイラの内部で実装するのが難しいのですか?具体的には、具体的にはICC内部? x86-64の上
主要な呼び出し規約(SysVのまたはMS __vectorcall
)がXMM0のArg最初のFPを取得し、未定義の上部要素と、XMM0にスカラーFPの引数を返します。 (ABIドキュメントについては、x86タグwikiを参照してください)。これは、コンパイラが未知の上位要素を持つレジスタにスカラーfloat/doubleを持つことは珍しくないことを意味します。これはベクター化された内部ループではまれであるため、これらの無駄な命令を避けることはほとんどがちょっとしたコードサイズを節約すると思います。
内部ループで使用する場合があります(たとえば、VPERMDシャッフルマスクのLUTの場合、キャッシュフットプリントに4倍の係数を保存する代わりに、メモリに32ビットを埋め込んだ各インデックスを保存するなど)。 )。
pmovzx-AS-負荷の問題は、今しばらくの間、私を悩ませてきた、とthe original version of this questionはXMMレジスタ内のスカラ浮動小数点を使用することの関連問題について考えて私を得ました。おそらくpmovzxの負荷としてスカラー - > __ m128よりも多くのユースケースがあります。
:
__m128 float_to_vec(float x){ return _mm_set_ss(x); }
がにコンパイルされます。 '_mm_load_ *'または '_mm_set_ *'の組み込み関数が得られると、本当に偽のコードを生成します。ここでの質問で与えられた例では、4つの命令(!)を得ることができます: 'movaps xmm2、xmm1; xorps xmm3、xmm3; movss xmm3、xmm2; shufps xmm0、xmm3、0'。私は基本的にあきらめました。メモリに流出しないアセンブリを生成することができれば、それを勝利と呼びます。 –