6

最適化したいコードは基本的に単純ですが大きな算術式です。コードを自動的に分析して独立した乗算/加算を並列に計算するのはかなり簡単なはずですが、自動ベクトル化はループに対してのみ機能することを読みました。

ユニオンまたは他の方法を介したベクトル内の単一要素へのアクセスは絶対に避け、代わりに_mm_shuffle_pdに置き換える必要があることを何度も読みました(私はdoubleのみに取り組んでいます)...

__m128dベクトルのコンテンツを、ユニオンとしてアクセスせずにdoubleとして格納する方法がわからないようです。また、このような操作は、スカラーコードと比較した場合にパフォーマンスの向上をもたらしますか?

union {
  __m128d v;
  double d[2];
} vec;
union {
  __m128d v;
double d[2];
} vec2;

vec.v = index1;
vec2.v = index2;
temp1 = _mm_mul_pd(temp1, _mm_set_pd(bvec[vec.d[1]], bvec[vec2[1]]));

また、2つの組合はばかげて醜いように見えますが、

union dvec {
  __m128d v;
  double d[2];
} vec;

indexXをdvecとして宣言しようとすると、コンパイラはdvecが宣言されていないと文句を言いました。

4

3 に答える 3

7

残念ながら、MSDNを見ると、次のように表示されます。

__m128dフィールドに直接アクセスしないでください。ただし、これらのタイプはデバッガーで確認できます。タイプ__m128の変数は、XMM[0-7]レジスタにマップされます。

私はSIMDの専門家ではありませんが、これは、あなたがしていることが、設計されていないために機能しないことを示しています。

編集:

私はちょうどこれを見つけました、そしてそれは言います:

__m128、__ m128d、および__m128iは、割り当ての左側でのみ、戻り値として、またはパラメーターとして使用してください。「+」や「>>」などの他の算術式では使用しないでください。

それはまた言う:

ユニオン(たとえば、float要素にアクセスするため)や構造体などの集合体で__m128、__ m128d、および__m128iオブジェクトを使用します。

だから多分あなたはそれらを使うことができますが、それは組合でのみです。ただし、MSDNの内容と矛盾しているようです。

EDIT2:

これらのSIMDタイプの使用方法の例を説明する別の興味深いリソースがあります

上記のリンクには、次の行があります。

#include <math.h>
#include <emmintrin.h>
double in1_min(__m128d x)
{
    return x[0];
}

上記では、gcc 4.6の新しい拡張機能を使用して、インデックスを介して上位部分と下位部分にアクセスします。古いバージョンのgccでは、ユニオンを使用し、2つのdoubleの配列に書き込む必要があります。これは面倒で、最適化をオフにすると非常に遅くなります。

于 2012-09-19T13:22:25.677 に答える
1

_mm_cvtsd_f64+_mm_unpackhi_pd

ダブルスの場合:

#include <assert.h>

#include <x86intrin.h>

int main(void) {
    __m128d x = _mm_set_pd(1.5, 2.5);
    /* _mm_cvtsd_f64 + _mm_unpackhi_pd */
    assert(_mm_cvtsd_f64(x) == 2.5);
    assert(_mm_cvtsd_f64(_mm_unpackhi_pd(x, x)) == 1.5);
}

フロートについては、_mm_extract_ps SSEGCCinstrinc関数を使用して16進フロートをC/C++でフロートに変換する方法に次の例を投稿しました。

  • _mm_cvtss_f32+_mm_shuffle_ps
  • _MM_EXTRACT_FLOAT

intの場合、次を使用できます_mm_extract_epi32

#include <assert.h>

#include <x86intrin.h>

int main(void) {
    __m128i x = _mm_set_epi32(1, 2, 3, 4);
    assert(_mm_extract_epi32(x, 3) == 4);
    assert(_mm_extract_epi32(x, 2) == 3);
    assert(_mm_extract_epi32(x, 1) == 1);
    assert(_mm_extract_epi32(x, 0) == 1);
}

GitHubアップストリーム

次のコマンドを使用して例をコンパイルして実行します。

gcc -ggdb3 -O0 -std=c99 -Wall -Wextra -pedantic -o main.out main.c
./main.out

Ubuntu19.04amd64でテスト済み。

于 2019-06-01T06:35:28.793 に答える
0

2つのdoubleのsseベクトルの下位doubleにアクセスするために、「emmintrin.h」で定義されているdouble _mm_cvtsd_f64(__m128d a)関数があります。

インテル組み込み関数ガイドから:

あらすじ

  • ダブル_mm_cvtsd_f64(__m128d a)
  • 「emmintrin.h」を含める
  • 指示:movsd
  • CPUID機能フラグ:SSE2

説明:aの下位倍精度(64ビット)浮動小数点要素をdstにコピーします。

操作dst[63:0]:= a [63:0]

于 2013-09-27T13:35:39.343 に答える