LoginSignup
6
2

More than 3 years have passed since last update.

ARM SVE intrinsic命令のレジスタ操作関数

Last updated at Posted at 2021-01-27

ARM SVE intrinsic命令のレジスタ操作関数の図を以前作ったときのメモ。自分で使うことがありそうなものしかまとめていないので、その他は公式マニュアル参照。
https://developer.arm.com/documentation/100987/latest/

  • {type} には [int{8,16,32,64}_t, uint{8,16,32,64}_t, float{16,32,64}_t] が入る
  • {t} には [s{8,16,32,64}, u{8,16,32,64}, f{16,32,64}] が入る。[_{t}]部分は省略可能

例えば、TBL関数では

svfloat64_t svtbl_f64(svfloat64_t input1, svuint64_t indices)
svint16_t svtbl(svint16_t input1, svuint16_t indices)

のようにできる。

レジスタ要素移動系の関数

後ろに1が付く関数は偶数番目要素、2が付く関数は奇数番目の要素を移動させるので注意。

REV: Reverse the elements in a single input

レジスタ内で要素を反転。predicateなし。

sv{type} svrev[_{t}] (sv{type} input1)

sve_rev.png

TBL: Table lookup/permute using vector of indices

要素番号のテーブルを作ってレジスタ内の要素を任意に並べ替え。テーブルを作るコストがかかるため可能な限り下に紹介する並び替えを駆使する方がいい。即値を与えて任意に並べ替える方法はわからなかったのでいちいちテーブル配列のレジスタを作る方法しかわからない。svuint??_t indices??{type}のビット幅と同じ。predicateなし。

sv{type} svtbl[_{t}](sv{type} input1, svuint??_t indices)

sve_tbl.png

EXT: Extract vector from pair of vectors

2つのレジスタから図のように周期的に要素を選択。整数値immによってどれくらいずらすかを指定。
図の場合はimm=4。 predicateなし。

sv{type} svext[_{t}](sv{type} input1, sv{type} input2, uint64_t imm)

sve_ext.png

TRN1: Interleave even elements from two inputs

2つのレジスタから図のように偶数番目の要素を選択。predicateなし。

sv{type} svtrn1[_{t}](sv{type} input1, sv{type} input2)

sve_trn1.png

TRN2: Interleave odd elements from two inputs

2つのレジスタから図のように奇数番目の要素を選択。predicateなし。

sv{type} svtrn2[_{t}](sv{type} input1, sv{type} input2)

sve_trn2.png

UZP1: Select even elements from two inputs

2つのレジスタから図のように偶数番目の要素を選択。predicateなし。

sv{type} svuzp1[_{t}](sv{type} input1, sv{type} input2)

sve_uzp1.png

UZP2: Select odd elements from two inputs

2つのレジスタから図のように奇数番目の要素を選択。predicateなし。

sv{type} svuzp2[_{t}](sv{type} input1, sv{type} input2)

sve_uzp2.png

ZIP1: Interleave elements from low halves of two inputs

2つのレジスタから図のように下半分の要素を選択。predicateなし。

sv{type} svzip1[_{t}](sv{type} input1, sv{type} input2)

sve_zip1.png

ZIP2: Interleave elements from high halves of two inputs

2つのレジスタから図のように上半分の要素を選択。predicateなし。

sv{type} svzip2[_{t}](sv{type} input1, sv{type} input2)

sve_zip2.png

レジスタ要素変換系の関数

UNPKLO: Unpack and extend low half of an input

なぜか整数型のみ。レジスタの下半分の要素を一段階上のビット幅の型にキャスト。アウトプットの要素数は半分になる。predicateなし。
ここでの {type_n?}[int{8,16,32,64}_t, uint{8,16,32,64}_t]{type_n2}{type_n1} より一段階大きい。

sv{type_n2} svunpklo[_{t_n2}](sv{type_n1} input1)
: svuint64_t svunpklo[_u64](svuint32_t input1)

sve_unpklo.png

UNPKHI: Unpack and extend high half of an input

なぜか整数型のみ。レジスタの上半分の要素を一段階上のビット幅の型にキャスト。アウトプットの要素数は半分になる。predicateなし。
ここでの {type_n?}[int{8,16,32,64}_t, uint{8,16,32,64}_t]{type_n2}{type_n1} より一段階大きい。

sv{type_n2} svunpkhi[_{t_n2}](sv{type_n1} input1)
: svint16_t svunpkhi[_s16](svint8_t input1)

sve_unpkhi.png

CVT: Convert floating-point value to wider type

整数型も浮動小数点型もあり。図のように偶数番目の要素を一段階上のビット幅の型にキャスト。奇数番目の要素は無視。要素数は半分になる。predicateあり。

sv{type_n2} svcvt_{t2}[_{t1}]_x(svbool_t pg, sv{type_n1} input1)
: svfloat64_t svcvt_f64[_f32]_x(svbool_t pg, svfloat32_t input1)

sve_cvtw.png

CVT: Convert floating-point value to narrower type

整数型も浮動小数点型もあり。図のように一段階下のビット幅の型にキャスト。偶数番目の要素に値が入り、奇数番目の要素はゼロ埋め。要素数は2倍になる。predicateあり。

sv{type_n1} svcvt_{t1}[_{t2}}]_x(svbool_t pg, sv{type_n2} input1)
: svfloat32_t svcvt_f32[_f64]_x(svbool_t pg, svfloat64_t input1)

sve_cvtn.png

もう少し使いやすい関数を作る

ARM SVE intrinsic命令で使えそうなレジスタ操作関数はおそらく上記のものくらいしかないがいまいち使いにくいので上記の関数を組み合わせて変換関数を作っておく。predicateは32bit要素のレジスタが全部実行されるものを入れておかないとおかしくなると思う。

svfloat32_tの下半分をsvfloat64_tに変換

static inline svfloat64_t svcvt_f32lo_to_f64(svbool_t pg, svfloat32_t in32)
{
  svfloat64_t out64 = svcvt_f64_x(pg, svzip1(in32, in32));
  return out64;
}

svfloat32_tの上半分をsvfloat64_tに変換

static inline svfloat64_t svcvt_f32hi_to_f64(svbool_t pg, svfloat32_t in32)
{
  svfloat64_t out64 = svcvt_f64_x(pg, svzip2(in32, in32));
  return out64;
}

svfloat64_tをsvfloat32_tに変換し、下半分に入れる

svfloat32_tの上半分はゼロ埋め。

static inline svfloat32_t svcvt_f64_to_f32lo_z(svbool_t pg, svfloat64_t in64)
{
  svfloat32_t out32 = svcvt_f32_x(pg, in64);
  out32 = svuzp1(out32, svdup_f32(0.0f));
  return out32;
}

svfloat64_tをsvfloat32_tに変換し、上半分に入れる

svfloat32_tの下半分はゼロ埋め。

static inline svfloat32_t svcvt_f64_to_f32hi_z(svbool_t pg, svfloat64_t in64)
{
  svfloat32_t out32 = svcvt_f32_x(pg, in64);
  out32 = svuzp1(svdup_f32(0.0f), out32);
  return out32;
}

2つのsvfloat64_tをsvfloat32_tに変換し、上半分下半分にそれぞれ入れる

static inline svfloat32_t svcvt_2f64_to_f32(svbool_t pred, svfloat64_t in64lo, svfloat64_t in64hi)
{
  svfloat32_t out32a = svcvt_f32_x(pg, in64lo); // lo
  svfloat32_t out32b = svcvt_f32_x(pg, in64hi); // hi
  out32a = svuzp1(out32a, out32b);
  return out32a;
}
6
2
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
2