AVXのシフト処理について

AVX intrinsics 関数を使ったプログラミングのシフト演算処理について解説していきます。
AVX-512はまだ使った事が無い為に扱いません。AVX～AVX2までの範囲が主です。

`__m256`レジスタには単精度浮動小数点数 (float) の場合は8個、倍精度浮動小数点数 (double) の場合は4個、格納されます。
`__m256i`レジスタには 1バイト型 (char, unsigned char) であれば32個、2バイト型 (short, unsigned short) であれば16個、4バイトの型 (int, unsigned int) であれば8個、8バイトの型 (long long) であれば4個格納されます。

それぞれの要素の単位のシフトではなく、レジスタ全体を単位にしたシフト処理を扱います。

# シフト量がコンパイル時に確定している場合

## __m128i
シフト量はバイト単位で指定出来ますが、コンパイル時に確定している必要があります。

### __m128i の 右シフト
組み込み関数 `_mm_srli_si128` を使うと 128ビットのXMMレジスタをまとめて右シフト出来ます。
シフトした事によって空いた左端には 0 が設定されます。

### __m128i の 左シフト
組み込み関数 `_mm_slli_si128` を使うと 128ビットのXMMレジスタをまとめて左シフト出来ます。
シフトした事によって空いた右端には 0 が設定されます。

### __m128i の ファネルシフト
組み込み関数 `_mm_alignr_epi8` を使って行う事が出来ます。

## __m256i

組み込み関数 `_mm256_srli_si256` で YMMレジスタの上位と下位のそれぞれの128ビットのレーンを右シフト、
組み込み関数 `_mm256_slli_si256` で YMMレジスタの上位と下位のそれぞれの128ビットのレーンを左シフト出来ますが、
256ビットのレジスタ全体をシフトしてくれる組み込み命令は有りません。

しかし組み込み関数を組み合わせる事によって実現が可能です。

シフトするレジスタは a とし、シフト量は N とします。

### __m256i の 右シフト


#### シフト量が 0 の場合
シフトをしない事と同等なので命令を呼び出す必要はありません。

```cpp
template<unsigned int N>
struct m256i_shift_right_impl<N, Range<N == 0>> {
    static __m256i doit(__m256i a) {
        return a;
    }
};
```

#### シフト量が 0 より大きく 16未満 の場合

```cpp
template<unsigned int N>
struct m256i_shift_right_impl<N, Range<(0 < N && N < 16)>> {
    static __m256i doit(__m256i a) {
        __m256i mask = _mm256_permute2x128_si256(a, a, 0x81);
        return _mm256_alignr_epi8(mask, a, N);
    }
};
```

#### シフト量が 16 の場合

```cpp
template<unsigned int N>
struct m256i_shift_right_impl<N, Range<N == 16>> {
    static __m256i doit(__m256i a) {
        return _mm256_permute2x128_si256(a, a, 0x81);
    }
};
```

#### シフト量が 16 より大きく 32未満の場合

```cpp
template<unsigned int N>
struct m256i_shift_right_impl<N, Range<(16 < N && N < 32)>> {
    static __m256i doit(__m256i a) {
        __m256i tmp = _mm256_srli_si256(a, N - 16);
        return _mm256_permute2x128_si256(tmp, tmp, 0x81);
    }
};
```

#### シフト量が 32 以上の場合
全部 0 になります。

```cpp
template<unsigned int N>
struct m256i_shift_right_impl<N, Range<N >= 32>> {
    static __m256i doit(__m256i a) {
        return _mm256_setzero_si256();
    }
};
```

### __m256i の 左シフト

#### シフト量が 0 の場合
シフトをしない事と同等なので命令を呼び出す必要はありません。

```cpp
template<unsigned int N>
struct m256i_shift_left_impl<N, Range<N == 0>> {
    static __m256i doit(__m256i a) {
        return a;
    }
};
```

#### シフト量が 0 より大きく 16未満 の場合

```cpp
template<unsigned int N>
struct m256i_shift_left_impl<N, Range<(0 < N && N < 16)>> {
    static __m256i doit(__m256i a) {
        __m256i mask = _mm256_permute2x128_si256(a, a, 0x08);
        return _mm256_alignr_epi8(a, mask, 16-N);
    }
};
```

#### シフト量が 16 の場合

```cpp
template<unsigned int N>
struct m256i_shift_left_impl<N, Range<N == 16>> {
    static __m256i doit(__m256i a) {
        return _mm256_permute2x128_si256(a, a, 0x08);
    }
};
```

#### シフト量が 16 より大きく 32未満の場合

```cpp
template<unsigned int N>
struct m256i_shift_left_impl<N, Range<(16 < N && N < 32)>> {
    static __m256i doit(__m256i a) {
        __m256i tmp = _mm256_slli_si256(a, N - 16);
        return _mm256_permute2x128_si256(tmp, tmp, 0x08);
    }
};
```

#### シフト量が 32 以上の場合
全部 0 になります。

```cpp
template<unsigned int N>
struct m256i_shift_left_impl<N, Range<N >= 32>> {
    static __m256i doit(__m256i a) {
        return _mm256_setzero_si256();
    }
};
```

### __m256i の 右ファネルシフト
シフトする元となるレジスタは b, a とします。シフト量は N です。

#### シフト量 0
シフト無しなので a

```cpp
template<unsigned int N>
struct m256i_funnel_shift_right_impl<N, Range<N == 0>> {
    static __m256i doit(__m256i a, __m256i b) {
        return a;
    }
};
```

#### シフト量 0 より大きく 16 未満

```cpp
template<unsigned int N>
struct m256i_funnel_shift_right_impl<N, Range<(0 < N && N < 16)>> {
    static __m256i doit(__m256i a, __m256i b) {
        __m256i mask = _mm256_permute2x128_si256(a, b, 0x21);
        return _mm256_alignr_epi8(mask, a, N);
    }
};
```

#### シフト量 16

```cpp
template<unsigned int N>
struct m256i_funnel_shift_right_impl<N, Range<N == 16>> {
    static __m256i doit(__m256i a, __m256i b) {
        return _mm256_permute2x128_si256(a, b, 0x21);
    }
};
```

#### シフト量 16 より大きく 32 未満

```cpp
template<unsigned int N>
struct m256i_funnel_shift_right_impl<N, Range<(16 < N && N < 32)>> {
    static __m256i doit(__m256i a, __m256i b) {
        __m256i mask = _mm256_permute2x128_si256(a, b, 0x21);
        return _mm256_alignr_epi8(b, mask, N-16);
    }
};
```

#### シフト量 32
b

```cpp
template<unsigned int N>
struct m256i_funnel_shift_right_impl<N, Range<N == 32>> {
    static __m256i doit(__m256i a, __m256i b) {
        return b;
    }
};
```

### __m256i の 左ファネルシフト
シフトする元となるレジスタは a, b とします。シフト量は N です。

#### シフト量 0
シフト無しなので a

```cpp
template<unsigned int N>
struct m256i_funnel_shift_left_impl<N, Range<N == 0>> {
    static __m256i doit(__m256i a, __m256i b) {
        return a;
    }
};
```

#### シフト量 0 より大きく 16 未満

```cpp
template<unsigned int N>
struct m256i_funnel_shift_left_impl<N, Range<(0 < N && N < 16)>> {
    static __m256i doit(__m256i a, __m256i b) {
        __m256i mask = _mm256_permute2x128_si256(b, a, 0x21);
        return _mm256_alignr_epi8(a,mask,16-N);
    }
};
```

#### シフト量 16

```cpp
template<unsigned int N>
struct m256i_funnel_shift_left_impl<N, Range<N == 16>> {
    static __m256i doit(__m256i a, __m256i b) {
        return _mm256_permute2x128_si256(b, a, 0x21);
    }
};
```

#### シフト量 16 より大きく 32 未満

```cpp
template<unsigned int N>
struct m256i_funnel_shift_left_impl<N, Range<(16 < N && N < 32)>> {
    static __m256i doit(__m256i a, __m256i b) {
        __m256i mask = _mm256_permute2x128_si256(b, a, 0x21);
        return _mm256_alignr_epi8(mask,b,32-N);
    }
};
```

#### シフト量 32
b

```cpp
template<unsigned int N>
struct m256i_funnel_shift_left_impl<N, Range<N == 32>> {
    static __m256i doit(__m256i a, __m256i b) {
        return b;
    }
};
```

## __m256

AVX2の組み込み関数を使わずに、AVXの組み込み関数でシフト処理を行う場合の処理です。
シフトするレジスタは x とします。

http://stackoverflow.com/q/19516585 を参考にしました。

### __m256 の 右シフト

#### シフト量 0
シフトをしない事と同等なので命令を呼び出す必要はありません。

```cpp
template <>
inline __m256 m256_shift_right<0>(__m256 x) {
    return x;
}
```

#### シフト量 4

http://stackoverflow.com/a/19532415/4699324 に方法が載っていました。

```cpp
template <>
inline __m256 m256_shift_right<4>(__m256 x) {
    // x  = (x7, x6, x5, x4, x3, x2, x1, x0)

    // t0 = (x4, x7, x6, x5, x0, x3, x2, x1)
    __m256 t0 = _mm256_permute_ps(x, _MM_SHUFFLE(0, 3, 2, 1));
    // t1 = (0, 0, 0, 0, x4, x7, x6, x5)
    __m256 t1 = _mm256_permute2f128_ps(t0, t0, 0x81);

    //      ( -, x7, x6, x5,  -, x3, x2, x1)
    //      ( 0,  -,  -,  -, x4,  -,  -,  -)
    // y  = ( 0, x7, x6, x5, x4, x3, x2, x1)
    __m256 y = _mm256_blend_ps(t0, t1, 0x88 /* 0b10001000 */ );
    return y;
}
```

#### シフト量 8
```cpp
template <>
inline __m256 m256_shift_right<8>(__m256 x) {
    // x  = (x7, x6, x5, x4, x3, x2, x1, x0)

    // t0 = (x5, x4, x7, x6, x1, x0, x3, x2)
    __m256 t0 = _mm256_permute_ps(x, _MM_SHUFFLE(1, 0, 3, 2));
    // t1 = (0, 0, 0, 0, x5, x4, x7, x6)
    __m256 t1 = _mm256_permute2f128_ps(t0, t0, 0x81);

    //      ( -,  -, x7, x6,  -,  -, x3, x2)
    //      ( 0,  0,  -,  -, x5, x4,  -,  -)
    // y  = ( 0,  0, x7, x6, x5, x4, x3, x2)
    __m256 y = _mm256_blend_ps(t0, t1, 0xCC /* 0b11001100 */ );
    return y;
}
```

#### シフト量 12

```cpp
template <>
inline __m256 m256_shift_right<12>(__m256 x) {
    // x  = (x7, x6, x5, x4, x3, x2, x1, x0)

    // t0 = (x6, x5, x4, x7, x2, x1, x0, x3)
    __m256 t0 = _mm256_permute_ps(x, _MM_SHUFFLE(2, 1, 0, 3));
    // t1 = ( 0,  0,  0,  0, x6, x5, x4, x7)
    __m256 t1 = _mm256_permute2f128_ps(t0, t0, 0x81);

    //      ( -,  -,  -, x7,  -,  -,  -, x3)
    //      ( 0,  0,  0,  -, x6, x5, x4,  -)
    // y  = ( 0,  0,  0, x7, x6, x5, x4, x3)
    __m256 y = _mm256_blend_ps(t0, t1, 0xEE /* 0b11101110 */ );
    return y;
}
```

#### シフト量 16

```cpp
template <>
inline __m256 m256_shift_right<16>(__m256 x)
{
    // x  = (x7, x6, x5, x4, x3, x2, x1, x0)

    // y  = ( 0,  0,  0,  0, x7, x6, x5, x4)
    __m256 y = _mm256_permute2f128_ps(x, x, 0x81);
    return y;
}
```

#### シフト量 20

```cpp
template <>
inline __m256 m256_shift_right<20>(__m256 x) {
    // x  = (x7, x6, x5, x4, x3, x2, x1, x0)

    // t0 = (x4, x7, x6, x5, x0, x3, x2, x1)
    __m256 t0 = _mm256_permute_ps(x, _MM_SHUFFLE(0, 3, 2, 1));
    // t1 = ( 0,  0,  0,  0, x4, x7, x6, x5)
    __m256 t1 = _mm256_permute2f128_ps(t0, t0, 0x81);

    //      ( -,  -,  -,  -,  -, x7, x6, x5)
    //      ( 0,  0,  0,  0,  0,  -,  -,  -)
    // y  = ( 0,  0,  0,  0,  0, x7, x6, x5)
    __m256 y = _mm256_blend_ps(t1, _mm256_setzero_ps(), 0xF8 /* 0b11111000 */ );
    return y;
}
```

#### シフト量 24

```cpp
template <>
inline __m256 m256_shift_right<24>(__m256 x) {
    // x  = (x7, x6, x5, x4, x3, x2, x1, x0)

    // t0 = (x5, x4, x7, x6, x1, x0, x3, x2)
    __m256 t0 = _mm256_permute_ps(x, _MM_SHUFFLE(1, 0, 3, 2));
    // t1 = ( 0,  0,  0,  0, x5, x4, x7, x6)
    __m256 t1 = _mm256_permute2f128_ps(t0, t0, 0x81);

    //      ( -,  -,  -,  -,  -,  -, x7, x6)
    //      ( 0,  0,  0,  0,  0,  0,  -,  -)
    // y  = ( 0,  0,  0,  0,  0,  0, x7, x6)
    __m256 y = _mm256_blend_ps(t1, _mm256_setzero_ps(), 0xFC /* 0b11111100 */ );
    return y;
}
```

#### シフト量 28

```cpp
template <>
inline __m256 m256_shift_right<28>(__m256 x) {
    // x  = (x7, x6, x5, x4, x3, x2, x1, x0)

    // t0 = (x6, x5, x4, x7, x2, x1, x0, x3)
    __m256 t0 = _mm256_permute_ps(x, _MM_SHUFFLE(2, 1, 0, 3));
    // t1 = ( 0,  0,  0,  0, x6, x5, x4, x7)
    __m256 t1 = _mm256_permute2f128_ps(t0, t0, 0x81);

    //      ( -,  -,  -,  -,  -,  -,  -, x7)
    //      ( 0,  0,  0,  0,  0,  0,  0,  -)
    // y  = ( 0,  0,  0,  0,  0,  0,  0, x7)
    __m256 y = _mm256_blend_ps(t1, _mm256_setzero_ps(), 0xFE /* 0b11111110 */ );
    return y;
}
```

#### シフト量 32

```cpp
template <>
inline __m256 m256_shift_right<32>(__m256 x) {
    return _mm256_setzero_ps();
}
```

### __m256 の 左シフト

#### シフト量 0
シフトをしない事と同等なので命令を呼び出す必要はありません。

```cpp
template <>
inline __m256 m256_shift_left<0>(__m256 x) {
    return x;
}
```

#### シフト量 4
http://stackoverflow.com/q/19516585 に書かれています。

```cpp
template <>
inline __m256 m256_shift_left<4>(__m256 x) {
    // x  = (x7, x6, x5, x4, x3, x2, x1, x0)

    // t0 = (x6, x5, x4, x7, x2, x1, x0, x3)
    __m256 t0 = _mm256_permute_ps(x, _MM_SHUFFLE(2, 1, 0, 3));
    // t1 = (x2, x1, x0, x3, 0, 0, 0, 0)
    __m256 t1 = _mm256_permute2f128_ps(t0, t0, 0x08);
    // y  = (x6, x5, x4, x3, x2, x1, x0, 0)
    __m256 y = _mm256_blend_ps(t0, t1, 0x11);
    return y;
}
```

#### シフト量 8

```cpp
template <>
inline __m256 m256_shift_left<8>(__m256 x) {
    // x  = (x7, x6, x5, x4, x3, x2, x1, x0)

    // t0 = (x5, x4, x7, x6, x1, x0, x3, x2)
    __m256 t0 = _mm256_permute_ps(x, _MM_SHUFFLE(1, 0, 3, 2));
    // t1 = (x1, x0, x3, x2, 0, 0, 0, 0)
    __m256 t1 = _mm256_permute2f128_ps(t0, t0, 0x08);
    // y  = (x5, x4, x3, x2, x1, x0, 0, 0)
    __m256 y = _mm256_blend_ps(t0, t1, 0x33 /* 0b00110011 */ );
    return y;
}
```

#### シフト量 12

```cpp
template <>
inline __m256 m256_shift_left<12>(__m256 x) {
    // x  = (x7, x6, x5, x4, x3, x2, x1, x0)

    // t0 = (x4, x7, x6, x5, x0, x3, x2, x1)
    __m256 t0 = _mm256_permute_ps(x, _MM_SHUFFLE(0, 3, 2, 1));
    // t1 = (x0, x3, x2, x1, 0, 0, 0, 0)
    __m256 t1 = _mm256_permute2f128_ps(t0, t0, 0x08);
    // y  = (x4, x3, x2, x1, x0, 0, 0, 0)
    __m256 y = _mm256_blend_ps(t0, t1, 0x77 /* 0b01110111 */ );
    return y;
}
```

#### シフト量 16

```cpp
template <>
inline __m256 m256_shift_left<16>(__m256 x) {
    // x  = (x7, x6, x5, x4, x3, x2, x1, x0)

    // y  = (x3, x2, x1, x0, 0, 0, 0, 0)
    __m256 y = _mm256_permute2f128_ps(x, x, 0x08);
    return y;
}
```

#### シフト量 20

```cpp
template <>
inline __m256 m256_shift_left<20>(__m256 x) {
    // x  = (x7, x6, x5, x4, x3, x2, x1, x0)

    // t0 = (x6, x5, x4, x7, x2, x1, x0, x3)
    __m256 t0 = _mm256_permute_ps(x, _MM_SHUFFLE(2, 1, 0, 3));
    // t1 = (x2, x1, x0, x3, 0, 0, 0, 0)
    __m256 t1 = _mm256_permute2f128_ps(t0, t0, 0x08);
    // y  = (x2, x1, x0, 0, 0, 0, 0, 0)
    __m256 y = _mm256_blend_ps(t1, _mm256_setzero_ps(), 0x10 /* 0b00010000 */ );
    return y;
}

```

#### シフト量 24

```cpp
template <>
inline __m256 m256_shift_left<24>(__m256 x) {
    // x  = (x7, x6, x5, x4, x3, x2, x1, x0)

    // t0 = (x5, x4, x7, x6, x1, x0, x3, x2)
    __m256 t0 = _mm256_permute_ps(x, _MM_SHUFFLE(1, 0, 3, 2));
    // t1 = (x1, x0, x3, x2, 0, 0, 0, 0)
    __m256 t1 = _mm256_permute2f128_ps(t0, t0, 0x08);
    // y  = (x1, x0, 0, 0, 0, 0, 0, 0)
    __m256 y = _mm256_blend_ps(_mm256_setzero_ps(), t1, 0xC0 /* 0b11000000 */ );
    return y;
}
```

#### シフト量 28

```cpp
template <>
inline __m256 m256_shift_left<28>(__m256 x) {
    // x  = (x7, x6, x5, x4, x3, x2, x1, x0)

    // t0 = (x4, x7, x6, x5, x0, x3, x2, x1)
    __m256 t0 = _mm256_permute_ps(x, _MM_SHUFFLE(0, 3, 2, 1));
    // t1 = (x0, x3, x2, x1, 0, 0, 0, 0)
    __m256 t1 = _mm256_permute2f128_ps(t0, t0, 0x08);
    // y  = (x0, 0, 0, 0, 0, 0, 0, 0)
    __m256 y = _mm256_blend_ps(_mm256_setzero_ps(), t1, 0x80 /* 0b10000000 */ );
    return y;
}
```

#### シフト量 32

```cpp
template <>
inline __m256 m256_shift_left<32>(__m256 x) {
    return _mm256_setzero_ps();
}
```


# シフト量が可変の場合

if文を使わずに実現する方法です。

http://homepage1.nifty.com/herumi/diary/1411.html#21
のやり方を応用しています。

まず下記のテーブルをメモリに用意します。

```cpp
static const unsigned char MIE_ALIGN(16) shiftPattern[] = {
    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
};
```

## __m128i のシフト
シフトするレジスタは v とします。対応するシフト量は -16 から +16 までの範囲です。

```cpp
inline __m128i m128i_shift(__m128i v, int shift)
{
    assert(-16 <= shift && shift <= 16);
    return _mm_shuffle_epi8(v, _mm_loadu_si128((const __m128i*)(shiftPattern + 32 + shift)));
}
```

## __m128i の右ファネルシフト

対応するシフト量は 0 から +16 までの範囲です。

```cpp
inline __m128i m128i_funnel_shift_right(__m128i a, __m128i b, int shift)
{
    assert(0 <= shift && shift <= 16);
    __m128i b0 = _mm_shuffle_epi8(b, _mm_loadu_si128((const __m128i*)(shiftPattern + 16 +shift)));
    __m128i a0 = _mm_shuffle_epi8(a, _mm_loadu_si128((const __m128i*)(shiftPattern + 32 + shift)));
    return _mm_or_si128(a0, b0);
}
```

## __m128i の左ファネルシフト

対応するシフト量は 0 から +16 までの範囲です。

```cpp
inline __m128i m128i_funnel_shift_left(__m128i a, __m128i b, int shift)
{
    assert(0 <= shift && shift <= 16);
    __m128i a0 = _mm_shuffle_epi8(a, _mm_loadu_si128((const __m128i*)(shiftPattern + 32 - shift)));
    __m128i b0 = _mm_shuffle_epi8(b, _mm_loadu_si128((const __m128i*)(shiftPattern + 48 - shift)));
    return _mm_or_si128(a0, b0);
}
```

## __m256i の右シフト

対応するシフト量は 0 から 32 までの範囲です。

```cpp
inline __m256i m256i_shift_right(__m256i v, int shift)
{
    assert(0 <= shift && shift <= 32);
    __m256i mask = _mm256_broadcastsi128_si256(_mm_loadu_si128((const __m128i*)(shiftPattern + 32 + shift)));
    __m256i a0 = _mm256_shuffle_epi8(v, mask);

    __m256i a1 = _mm256_castsi128_si256(_mm_shuffle_epi8(_mm256_extracti128_si256(v, 1), _mm_loadu_si128((const __m128i*)(shiftPattern + 16 + shift))));
    __m256i a2 = _mm256_permute2x128_si256(a1, a1, 0x80);

    return _mm256_or_si256(a0, a2);
}
```

## __m256i の左シフト

対応するシフト量は 0 から 32 までの範囲です。

```cpp
inline __m256i m256i_shift_left(__m256i v, int shift)
{
    assert(0 <= shift && shift <= 32);
    __m256i mask = _mm256_broadcastsi128_si256(_mm_loadu_si128((const __m128i*)(shiftPattern + 32 - shift)));
    __m256i a0 = _mm256_shuffle_epi8(v, mask);

    __m256i a1 = _mm256_castsi128_si256(_mm_shuffle_epi8(_mm256_castsi256_si128(v), _mm_loadu_si128((const __m128i*)(shiftPattern + 48 - shift))));
    __m256i a2 = _mm256_permute2x128_si256(a1, a1, 0x08);

    return _mm256_or_si256(a0, a2);
}
```

## __m256i の右ファネルシフト

対応するシフト量は 0 から 32 までの範囲です。

```cpp
inline __m256i m256i_funnel_shift_right(__m256i a, __m256i b, int shift) {
    assert(0 <= shift && shift <= 32);

    __m256i ma = _mm256_broadcastsi128_si256(_mm_loadu_si128((const __m128i*)(shiftPattern + 32 + shift)));
    __m256i a0 = _mm256_shuffle_epi8(a, ma);

    __m256i mb = _mm256_broadcastsi128_si256(_mm_loadu_si128((const __m128i*)(shiftPattern + shift)));
    __m256i b0 = _mm256_shuffle_epi8(b, mb);
    
    const __m256i pat = _mm256_broadcastsi128_si256(_mm_loadu_si128((const __m128i*)(shiftPattern + 16 + shift)));
    __m256i ab = _mm256_permute2x128_si256(a, b, 0x21);
    __m256i ab0 = _mm256_shuffle_epi8(ab, pat);

    return _mm256_or_si256(ab0, _mm256_or_si256(a0, b0));
}
```

## __m256i の左ファネルシフト

対応するシフト量は 0 から 32 までの範囲です。

```cpp
inline __m256i m256i_funnel_shift_left(__m256i a, __m256i b, int shift) {
    assert(0 <= shift && shift <= 32);

    __m256i mb = _mm256_broadcastsi128_si256(_mm_loadu_si128((const __m128i*)(shiftPattern + 64 - shift)));
    __m256i b0 = _mm256_shuffle_epi8(b, mb);

    __m256i ma = _mm256_broadcastsi128_si256(_mm_loadu_si128((const __m128i*)(shiftPattern + 32 - shift)));
    __m256i a0 = _mm256_shuffle_epi8(a, ma);
    
    const __m256i pat = _mm256_broadcastsi128_si256(_mm_loadu_si128((const __m128i*)(shiftPattern + 48 - shift)));
    __m256i ab = _mm256_permute2x128_si256(a, b, 0x03);
    __m256i ab0 = _mm256_shuffle_epi8(ab, pat);

    return _mm256_or_si256(ab0, _mm256_or_si256(a0, b0));
}
```

# ソースコード

avx_shift.x がこの記事で紹介した処理が載っているソースコードです。

呼び出しを楽にする為にmetaprogrammingを使っています。

```cpp:avx_shift.h

#include <intrin.h>
#include <type_traits>
#include <cassert>

#ifdef _MSC_VER
#define MIE_ALIGN(x) __declspec(align(x))
#else
#define MIE_ALIGN(x) __attribute__((aligned(x)))
#endif

template<bool> struct Range;

template<int n>
struct foobar : std::false_type
{ };

// constant shift amount

// AVX
// Byte Shift YMM Register Across 128-bit Lanes
// limitation : shift amount is immediate and is multiples of 4

template <int n>
inline __m256 m256_shift_left(__m256 a) {
    static_assert(foobar<n>::value, "unsupported shift amount");
    return a;
}

template <>
inline __m256 m256_shift_left<0>(__m256 x) {
    return x;
}

// http://stackoverflow.com/q/19516585
template <>
inline __m256 m256_shift_left<4>(__m256 x) {
    // x  = (x7, x6, x5, x4, x3, x2, x1, x0)

    // t0 = (x6, x5, x4, x7, x2, x1, x0, x3)
    __m256 t0 = _mm256_permute_ps(x, _MM_SHUFFLE(2, 1, 0, 3));
    // t1 = (x2, x1, x0, x3, 0, 0, 0, 0)
    __m256 t1 = _mm256_permute2f128_ps(t0, t0, 0x08);
    // y  = (x6, x5, x4, x3, x2, x1, x0, 0)
    __m256 y = _mm256_blend_ps(t0, t1, 0x11);
    return y;
}

// http://stackoverflow.com/q/19516585
template <>
inline __m256 m256_shift_left<8>(__m256 x) {
    // x  = (x7, x6, x5, x4, x3, x2, x1, x0)

    // t0 = (x5, x4, x7, x6, x1, x0, x3, x2)
    __m256 t0 = _mm256_permute_ps(x, _MM_SHUFFLE(1, 0, 3, 2));
    // t1 = (x1, x0, x3, x2, 0, 0, 0, 0)
    __m256 t1 = _mm256_permute2f128_ps(t0, t0, 0x08);
    // y  = (x5, x4, x3, x2, x1, x0, 0, 0)
    __m256 y = _mm256_blend_ps(t0, t1, 0x33 /* 0b00110011 */ );
    return y;
}

template <>
inline __m256 m256_shift_left<12>(__m256 x) {
    // x  = (x7, x6, x5, x4, x3, x2, x1, x0)

    // t0 = (x4, x7, x6, x5, x0, x3, x2, x1)
    __m256 t0 = _mm256_permute_ps(x, _MM_SHUFFLE(0, 3, 2, 1));
    // t1 = (x0, x3, x2, x1, 0, 0, 0, 0)
    __m256 t1 = _mm256_permute2f128_ps(t0, t0, 0x08);
    // y  = (x4, x3, x2, x1, x0, 0, 0, 0)
    __m256 y = _mm256_blend_ps(t0, t1, 0x77 /* 0b01110111 */ );
    return y;
}

template <>
inline __m256 m256_shift_left<16>(__m256 x) {
    // x  = (x7, x6, x5, x4, x3, x2, x1, x0)

    // y  = (x3, x2, x1, x0, 0, 0, 0, 0)
    __m256 y = _mm256_permute2f128_ps(x, x, 0x08);
    return y;
}

template <>
inline __m256 m256_shift_left<20>(__m256 x) {
    // x  = (x7, x6, x5, x4, x3, x2, x1, x0)

    // t0 = (x6, x5, x4, x7, x2, x1, x0, x3)
    __m256 t0 = _mm256_permute_ps(x, _MM_SHUFFLE(2, 1, 0, 3));
    // t1 = (x2, x1, x0, x3, 0, 0, 0, 0)
    __m256 t1 = _mm256_permute2f128_ps(t0, t0, 0x08);
    // y  = (x2, x1, x0, 0, 0, 0, 0, 0)
    __m256 y = _mm256_blend_ps(t1, _mm256_setzero_ps(), 0x10 /* 0b00010000 */ );
    return y;
}

template <>
inline __m256 m256_shift_left<24>(__m256 x) {
    // x  = (x7, x6, x5, x4, x3, x2, x1, x0)

    // t0 = (x5, x4, x7, x6, x1, x0, x3, x2)
    __m256 t0 = _mm256_permute_ps(x, _MM_SHUFFLE(1, 0, 3, 2));
    // t1 = (x1, x0, x3, x2, 0, 0, 0, 0)
    __m256 t1 = _mm256_permute2f128_ps(t0, t0, 0x08);
    // y  = (x1, x0, 0, 0, 0, 0, 0, 0)
    __m256 y = _mm256_blend_ps(_mm256_setzero_ps(), t1, 0xC0 /* 0b11000000 */ );
    return y;
}

template <>
inline __m256 m256_shift_left<28>(__m256 x) {
    // x  = (x7, x6, x5, x4, x3, x2, x1, x0)

    // t0 = (x4, x7, x6, x5, x0, x3, x2, x1)
    __m256 t0 = _mm256_permute_ps(x, _MM_SHUFFLE(0, 3, 2, 1));
    // t1 = (x0, x3, x2, x1, 0, 0, 0, 0)
    __m256 t1 = _mm256_permute2f128_ps(t0, t0, 0x08);
    // y  = (x0, 0, 0, 0, 0, 0, 0, 0)
    __m256 y = _mm256_blend_ps(_mm256_setzero_ps(), t1, 0x80 /* 0b10000000 */ );
    return y;
}

template <>
inline __m256 m256_shift_left<32>(__m256 x) {
    return _mm256_setzero_ps();
}

template <int n>
inline __m256 m256_shift_right(__m256 a)
{
    static_assert(foobar<n>::value, "unsupported shift amount");
    return a;
}

template <>
inline __m256 m256_shift_right<0>(__m256 x) {
    return x;
}

// http://stackoverflow.com/a/19532415/4699324
template <>
inline __m256 m256_shift_right<4>(__m256 x) {
    // x  = (x7, x6, x5, x4, x3, x2, x1, x0)

    // t0 = (x4, x7, x6, x5, x0, x3, x2, x1)
    __m256 t0 = _mm256_permute_ps(x, _MM_SHUFFLE(0, 3, 2, 1));
    // t1 = (0, 0, 0, 0, x4, x7, x6, x5)
    __m256 t1 = _mm256_permute2f128_ps(t0, t0, 0x81);

    //      ( -, x7, x6, x5,  -, x3, x2, x1)
    //      ( 0,  -,  -,  -, x4,  -,  -,  -)
    // y  = ( 0, x7, x6, x5, x4, x3, x2, x1)
    __m256 y = _mm256_blend_ps(t0, t1, 0x88 /* 0b10001000 */ );
    return y;
}

template <>
inline __m256 m256_shift_right<8>(__m256 x) {
    // x  = (x7, x6, x5, x4, x3, x2, x1, x0)

    // t0 = (x5, x4, x7, x6, x1, x0, x3, x2)
    __m256 t0 = _mm256_permute_ps(x, _MM_SHUFFLE(1, 0, 3, 2));
    // t1 = (0, 0, 0, 0, x5, x4, x7, x6)
    __m256 t1 = _mm256_permute2f128_ps(t0, t0, 0x81);

    //      ( -,  -, x7, x6,  -,  -, x3, x2)
    //      ( 0,  0,  -,  -, x5, x4,  -,  -)
    // y  = ( 0,  0, x7, x6, x5, x4, x3, x2)
    __m256 y = _mm256_blend_ps(t0, t1, 0xCC /* 0b11001100 */ );
    return y;
}

template <>
inline __m256 m256_shift_right<12>(__m256 x) {
    // x  = (x7, x6, x5, x4, x3, x2, x1, x0)

    // t0 = (x6, x5, x4, x7, x2, x1, x0, x3)
    __m256 t0 = _mm256_permute_ps(x, _MM_SHUFFLE(2, 1, 0, 3));
    // t1 = ( 0,  0,  0,  0, x6, x5, x4, x7)
    __m256 t1 = _mm256_permute2f128_ps(t0, t0, 0x81);

    //      ( -,  -,  -, x7,  -,  -,  -, x3)
    //      ( 0,  0,  0,  -, x6, x5, x4,  -)
    // y  = ( 0,  0,  0, x7, x6, x5, x4, x3)
    __m256 y = _mm256_blend_ps(t0, t1, 0xEE /* 0b11101110 */ );
    return y;
}

template <>
inline __m256 m256_shift_right<16>(__m256 x)
{
    // x  = (x7, x6, x5, x4, x3, x2, x1, x0)

    // y  = ( 0,  0,  0,  0, x7, x6, x5, x4)
    __m256 y = _mm256_permute2f128_ps(x, x, 0x81);
    return y;
}

template <>
inline __m256 m256_shift_right<20>(__m256 x) {
    // x  = (x7, x6, x5, x4, x3, x2, x1, x0)

    // t0 = (x4, x7, x6, x5, x0, x3, x2, x1)
    __m256 t0 = _mm256_permute_ps(x, _MM_SHUFFLE(0, 3, 2, 1));
    // t1 = ( 0,  0,  0,  0, x4, x7, x6, x5)
    __m256 t1 = _mm256_permute2f128_ps(t0, t0, 0x81);

    //      ( -,  -,  -,  -,  -, x7, x6, x5)
    //      ( 0,  0,  0,  0,  0,  -,  -,  -)
    // y  = ( 0,  0,  0,  0,  0, x7, x6, x5)
    __m256 y = _mm256_blend_ps(t1, _mm256_setzero_ps(), 0xF8 /* 0b11111000 */ );
    return y;
}

template <>
inline __m256 m256_shift_right<24>(__m256 x) {
    // x  = (x7, x6, x5, x4, x3, x2, x1, x0)

    // t0 = (x5, x4, x7, x6, x1, x0, x3, x2)
    __m256 t0 = _mm256_permute_ps(x, _MM_SHUFFLE(1, 0, 3, 2));
    // t1 = ( 0,  0,  0,  0, x5, x4, x7, x6)
    __m256 t1 = _mm256_permute2f128_ps(t0, t0, 0x81);

    //      ( -,  -,  -,  -,  -,  -, x7, x6)
    //      ( 0,  0,  0,  0,  0,  0,  -,  -)
    // y  = ( 0,  0,  0,  0,  0,  0, x7, x6)
    __m256 y = _mm256_blend_ps(t1, _mm256_setzero_ps(), 0xFC /* 0b11111100 */ );
    return y;
}

template <>
inline __m256 m256_shift_right<28>(__m256 x) {
    // x  = (x7, x6, x5, x4, x3, x2, x1, x0)

    // t0 = (x6, x5, x4, x7, x2, x1, x0, x3)
    __m256 t0 = _mm256_permute_ps(x, _MM_SHUFFLE(2, 1, 0, 3));
    // t1 = ( 0,  0,  0,  0, x6, x5, x4, x7)
    __m256 t1 = _mm256_permute2f128_ps(t0, t0, 0x81);

    //      ( -,  -,  -,  -,  -,  -,  -, x7)
    //      ( 0,  0,  0,  0,  0,  0,  0,  -)
    // y  = ( 0,  0,  0,  0,  0,  0,  0, x7)
    __m256 y = _mm256_blend_ps(t1, _mm256_setzero_ps(), 0xFE /* 0b11111110 */ );
    return y;
}

template <>
inline __m256 m256_shift_right<32>(__m256 x) {
    return _mm256_setzero_ps();
}

// AVX2
// Byte Shift YMM Register Across 128-bit Lanes
// limitation : shift amount is immediate

namespace {

// shift right impl

template<unsigned int N, typename = Range<true>>
struct m256i_shift_right_impl
{};

template<unsigned int N>
struct m256i_shift_right_impl<N, Range<N == 0>> {
    static __m256i doit(__m256i a) {
        return a;
    }
};

template<unsigned int N>
struct m256i_shift_right_impl<N, Range<(0 < N && N < 16)>> {
    static __m256i doit(__m256i a) {
        __m256i mask = _mm256_permute2x128_si256(a, a, 0x81);
        return _mm256_alignr_epi8(mask, a, N);
    }
};

template<unsigned int N>
struct m256i_shift_right_impl<N, Range<N == 16>> {
    static __m256i doit(__m256i a) {
        return _mm256_permute2x128_si256(a, a, 0x81);
    }
};

template<unsigned int N>
struct m256i_shift_right_impl<N, Range<(16 < N && N < 32)>> {
    static __m256i doit(__m256i a) {
        __m256i tmp = _mm256_srli_si256(a, N - 16);
        return _mm256_permute2x128_si256(tmp, tmp, 0x81);
    }
};

template<unsigned int N>
struct m256i_shift_right_impl<N, Range<N >= 32>> {
    static __m256i doit(__m256i a) {
        return _mm256_setzero_si256();
    }
};

// shift left impl

template<unsigned int N, typename = Range<true>>
struct m256i_shift_left_impl
{};

template<unsigned int N>
struct m256i_shift_left_impl<N, Range<N == 0>> {
    static __m256i doit(__m256i a) {
        return a;
    }
};

template<unsigned int N>
struct m256i_shift_left_impl<N, Range<(0 < N && N < 16)>> {
    static __m256i doit(__m256i a) {
        __m256i mask = _mm256_permute2x128_si256(a, a, 0x08);
        return _mm256_alignr_epi8(a, mask, 16-N);
    }
};

template<unsigned int N>
struct m256i_shift_left_impl<N, Range<N == 16>> {
    static __m256i doit(__m256i a) {
        return _mm256_permute2x128_si256(a, a, 0x08);
    }
};

template<unsigned int N>
struct m256i_shift_left_impl<N, Range<(16 < N && N < 32)>> {
    static __m256i doit(__m256i a) {
        __m256i tmp = _mm256_slli_si256(a, N - 16);
        return _mm256_permute2x128_si256(tmp, tmp, 0x08);
    }
};

template<unsigned int N>
struct m256i_shift_left_impl<N, Range<N >= 32>> {
    static __m256i doit(__m256i a) {
        return _mm256_setzero_si256();
    }
};

// funnel shift right impl

template<unsigned int N, typename = Range<true>>
struct m256i_funnel_shift_right_impl
{};

template<unsigned int N>
struct m256i_funnel_shift_right_impl<N, Range<N == 0>> {
    static __m256i doit(__m256i a, __m256i b) {
        return a;
    }
};

template<unsigned int N>
struct m256i_funnel_shift_right_impl<N, Range<(0 < N && N < 16)>> {
    static __m256i doit(__m256i a, __m256i b) {
        __m256i mask = _mm256_permute2x128_si256(a, b, 0x21);
        return _mm256_alignr_epi8(mask, a, N);
    }
};

template<unsigned int N>
struct m256i_funnel_shift_right_impl<N, Range<N == 16>> {
    static __m256i doit(__m256i a, __m256i b) {
        return _mm256_permute2x128_si256(a, b, 0x21);
    }
};

template<unsigned int N>
struct m256i_funnel_shift_right_impl<N, Range<(16 < N && N < 32)>> {
    static __m256i doit(__m256i a, __m256i b) {
        __m256i mask = _mm256_permute2x128_si256(a, b, 0x21);
        return _mm256_alignr_epi8(b, mask, N-16);
    }
};

template<unsigned int N>
struct m256i_funnel_shift_right_impl<N, Range<N == 32>> {
    static __m256i doit(__m256i a, __m256i b) {
        return b;
    }
};

// funnel shift left impl

template<unsigned int N, typename = Range<true>>
struct m256i_funnel_shift_left_impl
{};

template<unsigned int N>
struct m256i_funnel_shift_left_impl<N, Range<N == 0>> {
    static __m256i doit(__m256i a, __m256i b) {
        return a;
    }
};

template<unsigned int N>
struct m256i_funnel_shift_left_impl<N, Range<(0 < N && N < 16)>> {
    static __m256i doit(__m256i a, __m256i b) {
        __m256i mask = _mm256_permute2x128_si256(b, a, 0x21);
        return _mm256_alignr_epi8(a,mask,16-N);
    }
};

template<unsigned int N>
struct m256i_funnel_shift_left_impl<N, Range<N == 16>> {
    static __m256i doit(__m256i a, __m256i b) {
        return _mm256_permute2x128_si256(b, a, 0x21);
    }
};

template<unsigned int N>
struct m256i_funnel_shift_left_impl<N, Range<(16 < N && N < 32)>> {
    static __m256i doit(__m256i a, __m256i b) {
        __m256i mask = _mm256_permute2x128_si256(b, a, 0x21);
        return _mm256_alignr_epi8(mask,b,32-N);
    }
};

template<unsigned int N>
struct m256i_funnel_shift_left_impl<N, Range<N == 32>> {
    static __m256i doit(__m256i a, __m256i b) {
        return b;
    }
};

} // anonymous namespace

// interface

template <unsigned int N>
__m256i m256i_shift_right(__m256i a) {
    return m256i_shift_right_impl<N>::doit(a);
}

template <unsigned int N>
__m256i m256i_shift_left(__m256i a) {
    return m256i_shift_left_impl<N>::doit(a);
}

template <unsigned int N>
inline __m256i m256i_funnel_shift_right(__m256i a, __m256i b) {
    return m256i_funnel_shift_right_impl<N>::doit(a, b);
}

template <unsigned int N>
inline __m256i m256i_funnel_shift_left(__m256i a, __m256i b) {
    return m256i_funnel_shift_left_impl<N>::doit(a, b);
}

// variable shift amount

static const unsigned char MIE_ALIGN(16) shiftPattern[] = {
    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
};

// original : http://homepage1.nifty.com/herumi/diary/1411.html
inline __m128i m128i_shift(__m128i v, int shift)
{
    assert(-16 <= shift && shift <= 16);
    return _mm_shuffle_epi8(v, _mm_loadu_si128((const __m128i*)(shiftPattern + 32 + shift)));
}

inline __m128i m128i_funnel_shift_right(__m128i a, __m128i b, int shift)
{
    assert(0 <= shift && shift <= 16);
    __m128i b0 = _mm_shuffle_epi8(b, _mm_loadu_si128((const __m128i*)(shiftPattern + 16 +shift)));
    __m128i a0 = _mm_shuffle_epi8(a, _mm_loadu_si128((const __m128i*)(shiftPattern + 32 + shift)));
    return _mm_or_si128(a0, b0);
}

inline __m128i m128i_funnel_shift_left(__m128i a, __m128i b, int shift)
{
    assert(0 <= shift && shift <= 16);
    __m128i a0 = _mm_shuffle_epi8(a, _mm_loadu_si128((const __m128i*)(shiftPattern + 32 - shift)));
    __m128i b0 = _mm_shuffle_epi8(b, _mm_loadu_si128((const __m128i*)(shiftPattern + 48 - shift)));
    return _mm_or_si128(a0, b0);
}

inline __m256i m256i_shift_right(__m256i v, int shift)
{
    assert(0 <= shift && shift <= 32);
    __m256i mask = _mm256_broadcastsi128_si256(_mm_loadu_si128((const __m128i*)(shiftPattern + 32 + shift)));
    __m256i a0 = _mm256_shuffle_epi8(v, mask);

    __m256i a1 = _mm256_castsi128_si256(_mm_shuffle_epi8(_mm256_extracti128_si256(v, 1), _mm_loadu_si128((const __m128i*)(shiftPattern + 16 + shift))));
    __m256i a2 = _mm256_permute2x128_si256(a1, a1, 0x80);

    return _mm256_or_si256(a0, a2);
}

inline __m256i m256i_shift_left(__m256i v, int shift)
{
    assert(0 <= shift && shift <= 32);
    __m256i mask = _mm256_broadcastsi128_si256(_mm_loadu_si128((const __m128i*)(shiftPattern + 32 - shift)));
    __m256i a0 = _mm256_shuffle_epi8(v, mask);

    __m256i a1 = _mm256_castsi128_si256(_mm_shuffle_epi8(_mm256_castsi256_si128(v), _mm_loadu_si128((const __m128i*)(shiftPattern + 48 - shift))));
    __m256i a2 = _mm256_permute2x128_si256(a1, a1, 0x08);

    return _mm256_or_si256(a0, a2);
}

inline __m256i m256i_funnel_shift_right(__m256i a, __m256i b, int shift) {
    assert(0 <= shift && shift <= 32);

    __m256i ma = _mm256_broadcastsi128_si256(_mm_loadu_si128((const __m128i*)(shiftPattern + 32 + shift)));
    __m256i a0 = _mm256_shuffle_epi8(a, ma);

    __m256i mb = _mm256_broadcastsi128_si256(_mm_loadu_si128((const __m128i*)(shiftPattern + shift)));
    __m256i b0 = _mm256_shuffle_epi8(b, mb);
    
    const __m256i pat = _mm256_broadcastsi128_si256(_mm_loadu_si128((const __m128i*)(shiftPattern + 16 + shift)));
    __m256i ab = _mm256_permute2x128_si256(a, b, 0x21);
    __m256i ab0 = _mm256_shuffle_epi8(ab, pat);

    return _mm256_or_si256(ab0, _mm256_or_si256(a0, b0));
}

inline __m256i m256i_funnel_shift_left(__m256i a, __m256i b, int shift) {
    assert(0 <= shift && shift <= 32);

    __m256i mb = _mm256_broadcastsi128_si256(_mm_loadu_si128((const __m128i*)(shiftPattern + 64 - shift)));
    __m256i b0 = _mm256_shuffle_epi8(b, mb);

    __m256i ma = _mm256_broadcastsi128_si256(_mm_loadu_si128((const __m128i*)(shiftPattern + 32 - shift)));
    __m256i a0 = _mm256_shuffle_epi8(a, ma);
    
    const __m256i pat = _mm256_broadcastsi128_si256(_mm_loadu_si128((const __m128i*)(shiftPattern + 48 - shift)));
    __m256i ab = _mm256_permute2x128_si256(a, b, 0x03);
    __m256i ab0 = _mm256_shuffle_epi8(ab, pat);

    return _mm256_or_si256(ab0, _mm256_or_si256(a0, b0));
}


```

動作確認用のプログラムです。The Boost Preprocessing library を使っています。

```cpp:main.cpp

#include <stdio.h>
#include <stdint.h>
#include <intrin.h>
#include <boost/preprocessor.hpp>

#include "avx_shift.h"

inline static void lf() { printf("\n"); }
inline static void idx(int i) { printf("%3d: ", i); }

static
void print_m256_floats(__m256 floats)
{
    for (int i = 7; i >= 0; --i) {
        printf("%f ", ((float *)&floats)[i]);
    }
    lf();
}

static
void print_m128i_bytes(__m128i bytes)
{
    for (int i = 15; i >= 0; --i) {
        printf("%2d ", ((unsigned char *)&bytes)[i]);
    }
    lf();
}

static
void print_m256i_bytes(__m256i bytes)
{
    for (int i = 31; i >= 0; --i) {
        printf("%2d ",((unsigned char *)&bytes)[i]);
    }
    lf();
}

// test __m256 constant shift
static
void test0()
{
    const __m256 reg =  _mm256_set_ps(
        8,7,6,5,4,3,2,1
    );
    printf("m256_shift_right\n");
    #define GEN_CALL(z, i, j) idx(i); print_m256_floats(m256_shift_right<i*4>(reg));
    BOOST_PP_REPEAT(9, GEN_CALL, 0)
    #undef GEN_CALL
    lf();

    printf("m256_shift_left\n");
    #define GEN_CALL(z, i, j) idx(i); print_m256_floats(m256_shift_left<i*4>(reg));
    BOOST_PP_REPEAT(9, GEN_CALL, 0)
    #undef GEN_CALL
    lf();

    lf();
}

// test __m256i constant shift
static
void test1()
{
    const __m256i a = _mm256_setr_epi8(
        0, 1, 2, 3, 4, 5, 6, 7,
        8, 9, 10, 11, 12, 13, 14, 15,
        16, 17, 18, 19, 20, 21, 22, 23,
        24, 25, 26, 27, 28, 29, 30, 31
        );
    printf("m256i_shift_right\n");
    #define GEN_CALL(z, i, j) idx(i); print_m256i_bytes(m256i_shift_right<i>(a));
    BOOST_PP_REPEAT(33, GEN_CALL, 0)
    #undef GEN_CALL
    lf();

    printf("m256i_shift_left\n");
    #define GEN_CALL(z, i, j) idx(i); print_m256i_bytes(m256i_shift_left<i>(a));
    BOOST_PP_REPEAT(33, GEN_CALL, 0)
    #undef GEN_CALL
    lf();

    lf();
}

// test __m256i constant funnel shift
static
void test2()
{
    const __m256i a = _mm256_setr_epi8(
        0, 1, 2, 3, 4, 5, 6, 7,
        8, 9, 10, 11, 12, 13, 14, 15,
        16, 17, 18, 19, 20, 21, 22, 23,
        24, 25, 26, 27, 28, 29, 30, 31
        );
    const __m256i b = _mm256_setr_epi8(
        32, 33, 34, 35, 36, 37, 38, 39,
        40, 41, 42, 43, 44, 45, 46, 47,
        48, 49, 50, 51, 52, 53, 54, 55,
        56, 57, 58, 59, 60, 61, 62, 63
        );

    printf("m256i_funnel_shift_right\n");
    #define GEN_CALL(z, i, j) idx(i); print_m256i_bytes(m256i_funnel_shift_right<i>(a, b));
    BOOST_PP_REPEAT(33, GEN_CALL, 0)
    #undef GEN_CALL
    lf();

    printf("m256i_funnel_shift_left\n");
    #define GEN_CALL(z, i, j) idx(i); print_m256i_bytes(m256i_funnel_shift_left<i>(b, a));
    BOOST_PP_REPEAT(33, GEN_CALL, 0)
    #undef GEN_CALL
    lf();

    lf();
}

// test __m128i variable shift
static
void test3()
{
    const __m128i a = _mm_setr_epi8(
        1, 2, 3, 4, 5, 6, 7, 8,
        9, 10, 11, 12, 13, 14, 15, 16
        );
    const __m128i b = _mm_setr_epi8(
        17, 18, 19, 20, 21, 22, 23, 24,
        25, 26, 27, 28, 29, 30, 31, 32
        );
    
    printf("m128i_shift\n");
    for (int i = -16; i <= 16; ++i) {
        __m128i c = m128i_shift(a, i);
        idx(i);
        print_m128i_bytes(c);
    }
    lf();

    printf("m128i_funnel_shift_right\n");
    for (int i = 0; i <= 16; ++i) {
        __m128i c = m128i_funnel_shift_right(a, b, i);
        idx(i);
        print_m128i_bytes(c);
    }
    lf();

    printf("m128i_funnel_shift_left\n");
    for (int i = 0; i <= 16; ++i) {
        __m128i c = m128i_funnel_shift_left(b, a, i);
        idx(i);
        print_m128i_bytes(c);
    }
    lf();

    lf();
}

// test __m256i variable shift
static
void test4()
{
    const __m256i a = _mm256_setr_epi8(
         1,  2,  3,  4,  5,  6,  7,  8,
         9, 10, 11, 12, 13, 14, 15, 16,
        17, 18, 19, 20, 21, 22, 23, 24,
        25, 26, 27, 28, 29, 30, 31, 32
        );
    const __m256i b = _mm256_setr_epi8(
        33, 34, 35, 36, 37, 38, 39, 40,
        41, 42, 43, 44, 45, 46, 47, 48,
        49, 50, 51, 52, 53, 54, 55, 56,
        57, 58, 59, 60, 61, 62, 63, 64
        );

    printf("m256i_shift_right\n");
    for (int i = 0; i <= 32; ++i) {
        __m256i c = m256i_shift_right(a, i);
        idx(i);
        print_m256i_bytes(c);
    }
    lf();

    printf("m256i_shift_left\n");
    for (int i = 0; i <= 32; ++i) {
        __m256i c = m256i_shift_left(a, i);
        idx(i);
        print_m256i_bytes(c);
    }
    lf();

    printf("m256i_funnel_shift_right\n");
    for (int i = 0; i <= 32; ++i) {
        __m256i c = m256i_funnel_shift_right(a, b, i);
        idx(i);
        print_m256i_bytes(c);
    }
    lf();

    printf("m256i_funnel_shift_left\n");
    for (int i = 0; i <= 32; ++i) {
        __m256i c = m256i_funnel_shift_left(b, a, i);
        idx(i);
        print_m256i_bytes(c);
    }
    lf();

    lf();
}

int main(int argc, char* argv[])
{
    printf("constant shift routines\n");
    lf();
    test0();
    test1();
    test2();

    printf("variable shift routines\n");
    lf();
    test3();
    test4();

    return 0;
}

```

# 動作確認用プログラムの出力内容

```text
constant shift routines

m256_shift_right
  0: 8.000000 7.000000 6.000000 5.000000 4.000000 3.000000 2.000000 1.000000
  1: 0.000000 8.000000 7.000000 6.000000 5.000000 4.000000 3.000000 2.000000
  2: 0.000000 0.000000 8.000000 7.000000 6.000000 5.000000 4.000000 3.000000
  3: 0.000000 0.000000 0.000000 8.000000 7.000000 6.000000 5.000000 4.000000
  4: 0.000000 0.000000 0.000000 0.000000 8.000000 7.000000 6.000000 5.000000
  5: 0.000000 0.000000 0.000000 0.000000 0.000000 8.000000 7.000000 6.000000
  6: 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 8.000000 7.000000
  7: 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 8.000000
  8: 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000

m256_shift_left
  0: 8.000000 7.000000 6.000000 5.000000 4.000000 3.000000 2.000000 1.000000
  1: 7.000000 6.000000 5.000000 4.000000 3.000000 2.000000 1.000000 0.000000
  2: 6.000000 5.000000 4.000000 3.000000 2.000000 1.000000 0.000000 0.000000
  3: 5.000000 4.000000 3.000000 2.000000 1.000000 0.000000 0.000000 0.000000
  4: 4.000000 3.000000 2.000000 1.000000 0.000000 0.000000 0.000000 0.000000
  5: 3.000000 2.000000 1.000000 0.000000 0.000000 0.000000 0.000000 0.000000
  6: 2.000000 1.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000
  7: 1.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000
  8: 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000


m256i_shift_right
  0: 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0
  1:  0 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1
  2:  0  0 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2
  3:  0  0  0 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3
  4:  0  0  0  0 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4
  5:  0  0  0  0  0 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5
  6:  0  0  0  0  0  0 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6
  7:  0  0  0  0  0  0  0 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7
  8:  0  0  0  0  0  0  0  0 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8
  9:  0  0  0  0  0  0  0  0  0 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9
 10:  0  0  0  0  0  0  0  0  0  0 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10
 11:  0  0  0  0  0  0  0  0  0  0  0 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11
 12:  0  0  0  0  0  0  0  0  0  0  0  0 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12
 13:  0  0  0  0  0  0  0  0  0  0  0  0  0 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13
 14:  0  0  0  0  0  0  0  0  0  0  0  0  0  0 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14
 15:  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15
 16:  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16
 17:  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17
 18:  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 31 30 29 28 27 26 25 24 23 22 21 20 19 18
 19:  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 31 30 29 28 27 26 25 24 23 22 21 20 19
 20:  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 31 30 29 28 27 26 25 24 23 22 21 20
 21:  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 31 30 29 28 27 26 25 24 23 22 21
 22:  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 31 30 29 28 27 26 25 24 23 22
 23:  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 31 30 29 28 27 26 25 24 23
 24:  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 31 30 29 28 27 26 25 24
 25:  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 31 30 29 28 27 26 25
 26:  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 31 30 29 28 27 26
 27:  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 31 30 29 28 27
 28:  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 31 30 29 28
 29:  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 31 30 29
 30:  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 31 30
 31:  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 31
 32:  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0

m256i_shift_left
  0: 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0
  1: 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0  0
  2: 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0  0  0
  3: 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0  0  0  0
  4: 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0  0  0  0  0
  5: 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0  0  0  0  0  0
  6: 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0  0  0  0  0  0  0
  7: 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0  0  0  0  0  0  0  0
  8: 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0  0  0  0  0  0  0  0  0
  9: 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0  0  0  0  0  0  0  0  0  0
 10: 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0  0  0  0  0  0  0  0  0  0  0
 11: 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0  0  0  0  0  0  0  0  0  0  0  0
 12: 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0  0  0  0  0  0  0  0  0  0  0  0  0
 13: 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0
 14: 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
 15: 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
 16: 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
 17: 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
 18: 13 12 11 10  9  8  7  6  5  4  3  2  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
 19: 12 11 10  9  8  7  6  5  4  3  2  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
 20: 11 10  9  8  7  6  5  4  3  2  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
 21: 10  9  8  7  6  5  4  3  2  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
 22:  9  8  7  6  5  4  3  2  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
 23:  8  7  6  5  4  3  2  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
 24:  7  6  5  4  3  2  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
 25:  6  5  4  3  2  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
 26:  5  4  3  2  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
 27:  4  3  2  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
 28:  3  2  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
 29:  2  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
 30:  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
 31:  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
 32:  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0


m256i_funnel_shift_right
  0: 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0
  1: 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1
  2: 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2
  3: 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3
  4: 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4
  5: 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5
  6: 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6
  7: 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7
  8: 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8
  9: 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9
 10: 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10
 11: 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11
 12: 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12
 13: 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13
 14: 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14
 15: 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15
 16: 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16
 17: 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17
 18: 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18
 19: 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19
 20: 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20
 21: 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21
 22: 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22
 23: 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23
 24: 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24
 25: 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25
 26: 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26
 27: 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27
 28: 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28
 29: 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29
 30: 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30
 31: 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31
 32: 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32

m256i_funnel_shift_left
  0: 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32
  1: 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31
  2: 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30
  3: 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29
  4: 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28
  5: 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27
  6: 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26
  7: 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25
  8: 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24
  9: 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23
 10: 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22
 11: 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21
 12: 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20
 13: 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19
 14: 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18
 15: 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17
 16: 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16
 17: 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15
 18: 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14
 19: 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13
 20: 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12
 21: 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11
 22: 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10
 23: 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9
 24: 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8
 25: 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7
 26: 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6
 27: 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5
 28: 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4
 29: 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3
 30: 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2
 31: 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1
 32: 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0


variable shift routines

m128i_shift
-16:  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
-15:  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
-14:  2  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0
-13:  3  2  1  0  0  0  0  0  0  0  0  0  0  0  0  0
-12:  4  3  2  1  0  0  0  0  0  0  0  0  0  0  0  0
-11:  5  4  3  2  1  0  0  0  0  0  0  0  0  0  0  0
-10:  6  5  4  3  2  1  0  0  0  0  0  0  0  0  0  0
 -9:  7  6  5  4  3  2  1  0  0  0  0  0  0  0  0  0
 -8:  8  7  6  5  4  3  2  1  0  0  0  0  0  0  0  0
 -7:  9  8  7  6  5  4  3  2  1  0  0  0  0  0  0  0
 -6: 10  9  8  7  6  5  4  3  2  1  0  0  0  0  0  0
 -5: 11 10  9  8  7  6  5  4  3  2  1  0  0  0  0  0
 -4: 12 11 10  9  8  7  6  5  4  3  2  1  0  0  0  0
 -3: 13 12 11 10  9  8  7  6  5  4  3  2  1  0  0  0
 -2: 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0  0
 -1: 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0
  0: 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1
  1:  0 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2
  2:  0  0 16 15 14 13 12 11 10  9  8  7  6  5  4  3
  3:  0  0  0 16 15 14 13 12 11 10  9  8  7  6  5  4
  4:  0  0  0  0 16 15 14 13 12 11 10  9  8  7  6  5
  5:  0  0  0  0  0 16 15 14 13 12 11 10  9  8  7  6
  6:  0  0  0  0  0  0 16 15 14 13 12 11 10  9  8  7
  7:  0  0  0  0  0  0  0 16 15 14 13 12 11 10  9  8
  8:  0  0  0  0  0  0  0  0 16 15 14 13 12 11 10  9
  9:  0  0  0  0  0  0  0  0  0 16 15 14 13 12 11 10
 10:  0  0  0  0  0  0  0  0  0  0 16 15 14 13 12 11
 11:  0  0  0  0  0  0  0  0  0  0  0 16 15 14 13 12
 12:  0  0  0  0  0  0  0  0  0  0  0  0 16 15 14 13
 13:  0  0  0  0  0  0  0  0  0  0  0  0  0 16 15 14
 14:  0  0  0  0  0  0  0  0  0  0  0  0  0  0 16 15
 15:  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 16
 16:  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0

m128i_funnel_shift_right
  0: 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1
  1: 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2
  2: 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3
  3: 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4
  4: 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5
  5: 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6
  6: 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7
  7: 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8
  8: 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9
  9: 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10
 10: 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11
 11: 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12
 12: 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13
 13: 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14
 14: 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15
 15: 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16
 16: 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17

m128i_funnel_shift_left
  0: 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17
  1: 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16
  2: 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15
  3: 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14
  4: 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13
  5: 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12
  6: 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11
  7: 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10
  8: 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9
  9: 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8
 10: 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7
 11: 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6
 12: 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5
 13: 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4
 14: 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3
 15: 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2
 16: 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1


m256i_shift_right
  0: 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1
  1:  0 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2
  2:  0  0 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3
  3:  0  0  0 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4
  4:  0  0  0  0 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5
  5:  0  0  0  0  0 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6
  6:  0  0  0  0  0  0 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7
  7:  0  0  0  0  0  0  0 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8
  8:  0  0  0  0  0  0  0  0 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9
  9:  0  0  0  0  0  0  0  0  0 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10
 10:  0  0  0  0  0  0  0  0  0  0 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11
 11:  0  0  0  0  0  0  0  0  0  0  0 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12
 12:  0  0  0  0  0  0  0  0  0  0  0  0 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13
 13:  0  0  0  0  0  0  0  0  0  0  0  0  0 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14
 14:  0  0  0  0  0  0  0  0  0  0  0  0  0  0 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15
 15:  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16
 16:  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17
 17:  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18
 18:  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 32 31 30 29 28 27 26 25 24 23 22 21 20 19
 19:  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 32 31 30 29 28 27 26 25 24 23 22 21 20
 20:  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 32 31 30 29 28 27 26 25 24 23 22 21
 21:  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 32 31 30 29 28 27 26 25 24 23 22
 22:  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 32 31 30 29 28 27 26 25 24 23
 23:  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 32 31 30 29 28 27 26 25 24
 24:  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 32 31 30 29 28 27 26 25
 25:  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 32 31 30 29 28 27 26
 26:  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 32 31 30 29 28 27
 27:  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 32 31 30 29 28
 28:  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 32 31 30 29
 29:  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 32 31 30
 30:  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 32 31
 31:  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 32
 32:  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0

m256i_shift_left
  0: 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1
  1: 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0
  2: 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0  0
  3: 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0  0  0
  4: 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0  0  0  0
  5: 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0  0  0  0  0
  6: 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0  0  0  0  0  0
  7: 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0  0  0  0  0  0  0
  8: 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0  0  0  0  0  0  0  0
  9: 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0  0  0  0  0  0  0  0  0
 10: 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0  0  0  0  0  0  0  0  0  0
 11: 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0  0  0  0  0  0  0  0  0  0  0
 12: 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0  0  0  0  0  0  0  0  0  0  0  0
 13: 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0  0  0  0  0  0  0  0  0  0  0  0  0
 14: 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0
 15: 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
 16: 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
 17: 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
 18: 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
 19: 13 12 11 10  9  8  7  6  5  4  3  2  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
 20: 12 11 10  9  8  7  6  5  4  3  2  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
 21: 11 10  9  8  7  6  5  4  3  2  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
 22: 10  9  8  7  6  5  4  3  2  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
 23:  9  8  7  6  5  4  3  2  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
 24:  8  7  6  5  4  3  2  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
 25:  7  6  5  4  3  2  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
 26:  6  5  4  3  2  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
 27:  5  4  3  2  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
 28:  4  3  2  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
 29:  3  2  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
 30:  2  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
 31:  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
 32:  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0

m256i_funnel_shift_right
  0: 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1
  1: 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2
  2: 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3
  3: 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4
  4: 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5
  5: 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6
  6: 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7
  7: 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8
  8: 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9
  9: 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10
 10: 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11
 11: 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12
 12: 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13
 13: 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14
 14: 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15
 15: 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16
 16: 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17
 17: 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18
 18: 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19
 19: 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20
 20: 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21
 21: 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22
 22: 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23
 23: 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24
 24: 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25
 25: 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26
 26: 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27
 27: 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28
 28: 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29
 29: 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30
 30: 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31
 31: 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32
 32: 64 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33

m256i_funnel_shift_left
  0: 64 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33
  1: 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32
  2: 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31
  3: 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30
  4: 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29
  5: 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28
  6: 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27
  7: 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26
  8: 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25
  9: 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24
 10: 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23
 11: 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22
 12: 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21
 13: 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20
 14: 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19
 15: 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18
 16: 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17
 17: 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16
 18: 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15
 19: 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14
 20: 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13
 21: 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12
 22: 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11
 23: 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10
 24: 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9
 25: 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8
 26: 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7
 27: 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6
 28: 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5
 29: 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4
 30: 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3
 31: 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2
 32: 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1


続行するには何かキーを押してください . . .
```

# あとがき

https://software.intel.com/en-us/blogs/2015/01/13/programming-using-avx2-permutations
も参考にしました。

読んでくれた方ありがとうございます。非常に読みにくい記事ですみません…。