ARM NEONの使い方 加算編
四則演算編の予定でしたが、量が多いので分割することにしました
今回は加算編です
加算
サンプル
符号付き16bit整数のベクタvaとvbをvadd_s16()で足してみます
#include <stdio.h> #include <stdint.h> #include <arm_neon.h> int main() { int16_t a[4] = { 1, -1, 1, -1 }; int16_t b[4] = { 1, -1, 32767, -32768 }; int16x4_t va = vld1_s16(a); int16x4_t vb = vld1_s16(b); int16x4_t vc = vadd_s16(va, vb); int16_t c[4]; vst1_s16(c, vc); for (int i = 0; i < 4; i++) printf("c[%d]: %d\n", i, c[i]); return 0; }
実行結果
c[0]: 2 c[1]: -2 c[2]: -32768 c[3]: 32767
3,4番目のレーンはオーバーフローしました
符号拡張+加算(long add)
サンプル
符号付き16bit整数のベクタvaとvbをvaddl_s16()で足してみます
#include <stdio.h> #include <stdint.h> #include <arm_neon.h> int main() { int16_t a[4] = { 1, -1, 1, -1 }; int16_t b[4] = { 1, -1, 32767, -32768 }; int16x4_t va = vld1_s16(a); int16x4_t vb = vld1_s16(b); int32x4_t vc = vaddl_s16(va, vb); int32_t c[4]; vst1q_s32(c, vc); for (int i = 0; i < 4; i++) printf("c[%d]: %d\n", i, c[i]); return 0; }
実行結果
c[0]: 2 c[1]: -2 c[2]: 32768 c[3]: -32769
各レーンが32bitに拡張され、オーバーフローしなくなりました
飽和加算(saturating add)
vqadd[q]_<type>(va, vb)
64bit(qが付く場合は128bit)のベクタvaとvbを足します
演算結果がオーバーフローする場合は最大値/最小値で飽和させます
戻り値のサイズは入力のサイズと同じです
サンプル
符号付き16bit整数のベクタvaとvbをvqadd_s16()で足してみます
#include <stdio.h> #include <stdint.h> #include <arm_neon.h> int main() { int16_t a[4] = { 1, -1, 1, -1 }; int16_t b[4] = { 1, -1, 32767, -32768 }; int16x4_t va = vld1_s16(a); int16x4_t vb = vld1_s16(b); int16x4_t vc = vqadd_s16(va, vb); int16_t c[4]; vst1_s16(c, vc); for (int i = 0; i < 4; i++) printf("c[%d]: %d\n", i, c[i]); return 0; }
実行結果
c[0]: 2 c[1]: -2 c[2]: 32767 c[3]: -32768
3,4番目のレーンは最大値/最小値で飽和しました
その他の加算
個人的にあまり使わなそうだと思ったものですが
簡単に触れておきます
wide add: vaddw_<type>(va, vb)
サイズが違うもの同士を足す場合に使うようです
例えばvaddw_s16(va, vb)はvaがint32x4_tでvbがint16x4_tです
add high half: vaddhn_<type>(va, vb)
各レーンの上位ビット同士を足すようです
例えば、各レーンが32bitなら上位16bit同士を足します
どこで使うんだろう…
#include <stdio.h> #include <stdint.h> #include <arm_neon.h> int main() { int a[4] = { 0, 1, 2, 3 }; int b[4] = { 0, 1, 2, 3 }; for (int i = 0; i < 4; i++) { a[i] = a[i] << 16; b[i] = b[i] << 16; } int32x4_t va = vld1q_s32(a); int32x4_t vb = vld1q_s32(b); int16x4_t vc = vaddhn_s32(va, vb); // { 0, 2, 4, 6 } return 0; }
rounding add high half: vraddhn_<type>(va, vb)
これ、よく分かりませんw
(知ってたら教えて下さい)
次回
次回は減算編の予定です
ARM NEONの使い方 減算編