Arm SVE intrinsic load/store編

この記事は前の記事の続きのつもりです。
「ロード」とか「ストア」とかの言葉は知っている人向け。

# はじめに

SVEを用いて配列の計算を処理しようとすると(別にSVEに限らずAVXとかでもそうですが…)、

 - 通常の配列(```double```など)をSVE型にload
 - SVE型どうしの演算
 - SVE型を通常の配列にstore

という処理をする事になります。
ので、loadとstore命令を書かなくてはならないわけです。
ここにはSVEでのload/store命令のうち、代表的な物を書いておきます。

以下のサンプルコードでは、基本的に倍精度浮動小数点```src```を一回SVEレジスタにloadして、```dst```にstoreする、すなわちコピーを行う事を想定しておきます。
倍精度ではない値をやり取りしたいとかそういう場合は64を32に頭の中で入れ替えたりしてください。

前置きとして、プレディケータとして、

```cpp
const svbool_t pg = svwhilelt_b64(i, N);
```
という物が定義されているものとします。
また、SIMD幅の中に存在する倍精度浮動小数点の数を```N```としておきます。

## スカラー値 load/store
srcポインタからSIMD幅分のデータを読み、SVE型に格納する。

```cpp
const svfloat64_t data = svld1(pg, &src[i]);
svst1(pg, &dst[i], data);
```
```svld1```で```src[i]```から```src[i + N - 1]```までの要素を```data```に格納し、
```svld1```でその値を```dst[i]```から```dst[i + N - 1]```に書き戻している。

## スカラー値 load/store、間隔vnum
srcポインタからSIMD幅分のデータを間隔```vnum```個開けて読み、SVE型に格納する。

```cpp
const uint64_t vnum = 0;
const svfloat64_t data = svld1_vnum(pg, &src[i], vnum);
svst1_vnum(pg, &dst[i], data, vnum);
```
```svld1_vnum```で```src[i + N*vnum]```から```src[i + N*vnum + N - 1]```までの要素を```data```に格納し、
```svst1_vnum```でその値を```dst[i + N*vnum]```から```dst[i + N*vnum + N - 1]```に書き戻している。

## ベクトル値 load/store
srcポインタのベクトルに指定された位置からデータを読み、SVE型に格納する。

```cpp
const svuint64_t src_base_ptrs = svindex_u64((uint64_t)(&src[i]), sizeof(float64_t));
svuint64_t dst_base_ptrs = svindex_u64((uint64_t)(&dst[i]), sizeof(float64_t));
const svfloat64_t data = svld1_gather_f64(pg, src_base_ptrs);
svst1_scatter(pg, dst_base_ptrs, data);
```
まず、```svindex_u64```で```src[i]```へのポインタを```uint64_t```にキャストした値を頭にし、```sizeof(float64_t)```のstepsizeを持つ```uint64_t```型のベクトル型を作っている。
つまり、

```cpp
{(uint64_t)(&src[i]), (uint64_t)(&src[i]) + sizeof(float64_t), (uint64_t)(&src[i]) + 2 * sizeof(float64_t), ...}
```
というベクトル型を作っている。
```svld1_gather```で```src_base_ptrs[i]```から```src_base_ptrs[i + N - 1]```までの要素を```data```に格納し、
```svst1_scatter```でその値を```dst[i]```から```dst[i + N - 1]```に書き戻している。

## 続きそのうち書く

## スカラー値 load/store、ベクトル値オフセット
srcポインタに指定された位置からoffsetベクトルに指定されたバイト数だけ間隔を開けてデータを読み、SVE型に格納する。

```cpp
const svuint64_t byte_offsets = svindex_u64(0, sizeof(float64_t));
const svfloat64_t data = svld1_gather_offset(pg, &src[i], byte_offsets);
svst1_scatter_offset(pg, &dst[i], byte_offsets, data);
```
```svld1_gather_offset```で、```(float64_t*)((uint64_t)(&src[i]) + offset[i])```の値を```data[i]```に格納し、
```svst1_scatter_offset```でその値を```(float64_t*)((uint64_t)(&dst[i]) + offset[i])```に書き戻している。

#おまけCPP
```cpp
for(uint64_t i = 0 ; i < N ; i += stride){
    const svbool_t pg = svwhilelt_b64(i, N);
    const float64_t* const src_base_ptr = &src[i];
    float64_t* const dst_base_ptr = &dst[i];
    //const svfloat64_t data = svld1(pg, src_base_ptr);
    //svst1(pg, dst_base_ptr, data);

    //const uint64_t vnum = 0;
    //const svfloat64_t data = svld1_vnum(pg, src_base_ptr, vnum);
    //svst1_vnum(pg, dst_base_ptr, vnum, data);

    //const svuint64_t src_base_ptrs = svindex_u64((uint64_t)(src_base_ptr), sizeof(float64_t));
    //svuint64_t dst_base_ptrs = svindex_u64((uint64_t)(dst_base_ptr), sizeof(float64_t));
    //const svfloat64_t data = svld1_gather_f64(pg, src_base_ptrs);
    //svst1_scatter(pg, dst_base_ptrs, data);

    //const svuint64_t byte_offsets = svindex_u64(0, sizeof(float64_t));
    //const svfloat64_t data = svld1_gather_offset(pg, src_base_ptr, byte_offsets);
    //svst1_scatter_offset(pg, dst_base_ptr, byte_offsets, data);

    //const uint64_t byte_offset = 0;
    //const svuint64_t src_base_ptrs = svindex_u64((uint64_t)(src_base_ptr), sizeof(float64_t));
    //svuint64_t dst_base_ptrs = svindex_u64((uint64_t)(dst_base_ptr), sizeof(float64_t));
    //const svfloat64_t data = svld1_gather_offset_f64(pg, src_base_ptrs, byte_offset);
    //svst1_scatter_offset(pg, dst_base_ptrs, byte_offset, data);

    const uint64_t base_index = 0;
    const uint64_t step = 1;
    const svuint64_t indices = svindex_u64(base_index, step);
    const svfloat64_t data = svld1_gather_index(pg, src_base_ptr, indices);
    svst1_scatter_index(pg, dst_base_ptr, indices, data);
}
```