LoginSignup
5
1

More than 1 year has passed since last update.

mov命令 -bit幅を広げたり狭めたり-

Last updated at Posted at 2020-12-18

はじめに

mov.png

$  grep -e ^vmovn -e vmovun -e ^vmovl -e ^vqmov /usr/lib/gcc/aarch64-linux-gnu/7.5.0/include/arm_neon.h
vmovl_high_s8 (int8x16_t a)
vmovl_high_s16 (int16x8_t a)
vmovl_high_s32 (int32x4_t a)
vmovl_high_u8 (uint8x16_t a)
vmovl_high_u16 (uint16x8_t a)
vmovl_high_u32 (uint32x4_t a)
vmovl_s8 (int8x8_t a)
vmovl_s16 (int16x4_t a)
vmovl_s32 (int32x2_t a)
vmovl_u8 (uint8x8_t a)
vmovl_u16 (uint16x4_t a)
vmovl_u32 (uint32x2_t a)
vmovn_high_s16 (int8x8_t a, int16x8_t b)
vmovn_high_s32 (int16x4_t a, int32x4_t b)
vmovn_high_s64 (int32x2_t a, int64x2_t b)
vmovn_high_u16 (uint8x8_t a, uint16x8_t b)
vmovn_high_u32 (uint16x4_t a, uint32x4_t b)
vmovn_high_u64 (uint32x2_t a, uint64x2_t b)
vmovn_s16 (int16x8_t a)
vmovn_s32 (int32x4_t a)
vmovn_s64 (int64x2_t a)
vmovn_u16 (uint16x8_t a)
vmovn_u32 (uint32x4_t a)
vmovn_u64 (uint64x2_t a)
vqmovn_high_s16 (int8x8_t a, int16x8_t b)
vqmovn_high_s32 (int16x4_t a, int32x4_t b)
vqmovn_high_s64 (int32x2_t a, int64x2_t b)
vqmovn_high_u16 (uint8x8_t a, uint16x8_t b)
vqmovn_high_u32 (uint16x4_t a, uint32x4_t b)
vqmovn_high_u64 (uint32x2_t a, uint64x2_t b)
vqmovun_high_s16 (uint8x8_t a, int16x8_t b)
vqmovun_high_s32 (uint16x4_t a, int32x4_t b)
vqmovun_high_s64 (uint32x2_t a, int64x2_t b)
vqmovn_s16 (int16x8_t __a)
vqmovn_s32 (int32x4_t __a)
vqmovn_s64 (int64x2_t __a)
vqmovn_u16 (uint16x8_t __a)
vqmovn_u32 (uint32x4_t __a)
vqmovn_u64 (uint64x2_t __a)
vqmovnh_s16 (int16_t __a)
vqmovns_s32 (int32_t __a)
vqmovnd_s64 (int64_t __a)
vqmovnh_u16 (uint16_t __a)
vqmovns_u32 (uint32_t __a)
vqmovnd_u64 (uint64_t __a)
vqmovun_s16 (int16x8_t __a)
vqmovun_s32 (int32x4_t __a)
vqmovun_s64 (int64x2_t __a)
vqmovunh_s16 (int16_t __a)
vqmovuns_s32 (int32_t __a)
vqmovund_s64 (int64_t __a)
  • 全般的に言えることなのだが、mov命令はx86系のmov命令とは全然ちがう
  • movnmovl及びqmovnqmovunがある
  • また、浮動小数点型用の命令は存在しない。全部整数型のみ

movn命令

  • ベクトルの各レーンのbit幅を、半分の幅に縮める
  • 要素の型で言うと、int32_tint16_tに、int16_tint8_tにする
    int16_t src[] = {130,256,257,103,-132,-126,-125,-124,};
    int16x8_t vsrc = vld1q_s16(src);
    int8x8_t vdst0 = vmovn_s16(vsrc);
  • 演算結果
0:-126
1:0
2:1
3:103
4:124
5:-126
6:-125
7:-124
  • レーン数はそのまま、要素のbit幅だけ縮めるので、結果的に引数が単体の128bit幅ベクトル、戻り値が64bit幅ベクトルとなる
  • bit幅を縮めてオーバーフローする場合は、add命令のように単純に出力幅分のbitだけ、LSBからマスキングして出力される
    • 例1:先程のベクトルの要素0番は130、16進数表記で0x0082である。符号あり8bitの正の最大値127を超えているが、結果は下位8bit0x82を符号あり8bit整数型として扱って、-126となっている
    • 例2:先程のベクトルの要素1番は256、16進数表記で0x0100である。符号あり8bitの正の最大値127を超えているが、結果は下位8bit0x00を符号あり8bit整数型として扱って、0となっている
    • 例3:先程のベクトルの要素4番は-132、16進数表記で0xff7cである。符号あり8bitの負の最大値-128を超えているが、結果は下位8bit0x7cを符号あり8bit整数型として扱って、-124となっている

qmovn命令

  • add命令のときと同じく、命令の先頭にqが付くと飽和演算になる
  • 先程のmovn命令は単純に下位nbitを抽出して狭い型の整数型として解釈していたが、qmovnは入力値が結果のbit幅で結果がオーバーフローする際、最大値もしくは最小値でクランプする
qmovn.cpp
    int16_t src[] = {130,256,257,103,-132,-126,-125,-124,};
    int16x8_t vsrc = vld1q_s16(src);
    int8x8_t vdst1 = vqmovn_s16(vsrc);
  • 演算結果
0:127
1:127
2:127
3:103
4:-128
5:-126
6:-125
7:-124
  • 要素の0番、1番、2番はそれぞれ127に、4番は-128にクランプされている

movn_high命令、qmovn_high命令

  • おなじみ、後ろにhighが付く派生形
  • 引数を2つ取り、第1引数は64bit幅ベクトル、第2引数が128bit幅ベクトル
  • 第2引数を狭めて64bit幅ベクトルを生成し、第1引数と連結して128bit幅ベクトルを返す
  • 縮める演算はhighがついてない基本形と全く同じ

movl命令

  • 狭める命令があれば、広げる命令もある。それがmovl命令
  • 引数が64bit幅ベクトルで出力が128bit幅ベクトル
  • 符号あり整数型を引数に取る場合は、負数のbit拡張をちゃんとやってくれる
    • 8bitの-1(0xff)を16bitの-1(0xffff)にしてくれる
  • 符号のありなしは引数と戻り値で共通

movl_high命令

  • 128bit幅ベクトルを取り、128bit幅ベクトルを返す
  • ただし、演算に使われるのは、入力ベクトルの後半、上位64bit分だけ

qmovun命令

  • qmovn命令に近いが、符号あり整数型を、符号なし整数型に縮める
    • int64x2_t型をuint32x2_t型に、int32x4_tuint16x4_t型に、int16x8_t型をuint8x8_t型に変換する
  • 引数は128bit幅ベクトル、戻り値は64bit幅ベクトル
qmovun.cpp
    int16_t src[] = {130,256,257,103,-132,-126,-125,-124,};
    int16x8_t vsrc = vld1q_s16(src);
    int8x8_t vdst2 = vqmovun_s16(vsrc);
  • 演算結果
0:130
1:255
2:255
3:103
4:0
5:0
6:0
7:0
  • 負数は全て0に、256以上の数字は255に丸められている
  • なお、やはりhighが末尾につく派生形もある

早見表

拡張/収縮 飽和演算 符号無し飽和演算 命令
拡張 - - movl
収縮 N - movn
収縮 Y N qmovn
収縮 Y Y qmovun

その他

  • 図では省略したが、単体用の命令もある
  • 単体の要素を取るmov_nmov_n_high命令は、調べた限りではdup_ndup_n_high命令のエイリアス

おわりに

  • 整数型のbit幅を変換する命令movnmovlとその仲間たちを紹介した。
  • 明日も手島の担当で、Arm v8.2の内積命令を紹介する予定
5
1
0

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
5
1