[Arm64] シフト演算命令

シフト演算とは論理演算と同じようにビット列を操作する演算
単純な左右へのシフトの他に、複雑な動作をするビットフィールド移動命令がある

### シフト演算

.include        "debug.s"
.text
.global _start

num:    .quad   0x876543210fedcba9

_start:
        ldr     x2, num
        mov     x0, x2
        bl      PrintHex16
        bl      NewLine
        mov     x1, #22
        bl      PrintRight
        bl      NewLine
        
        lsl     x0, x2, #8

        bl      PrintHex16
        bl      NewLine
        mov     x1, #22
        bl      PrintRight
        bl      NewLine
        bl      Exit

$ ./test
876543210FEDCBA9
-8690466096661279831
6543210FEDCBA900
7296712173568108800

算術右シフトはASR x0, x2, #8
論理右シフトはLSR x0, x2, #8
右ローテートはROR x0, x2, #8
左ローテートは右ローテート(ROR)のシフト量を (64 – ビット数) とすることで左ローテートを実現

### アドレッシングモード
シフト演算命令には、シフト量を定数で指定するイミディエートとレジスタで指定するモードの2種類のアドレッシングモードがある

    LSR    Wd, Wn, #imm6
    LSR    Xd, Xn, #imm6

    LSR    Wd, Wn, Wm
    LSR    Xd, Xn, Xm

### ASR
ASR命令 (Arithmetic Shift Right) は算術右シフトを実行。算術右シフトはRn レジスタの内容を Rm レジスタで指定したビット数だけ右にシフト。

    ASR     Wd, Wn, Wm        // ASRV Wd, Wn, Wm と同じ
    ASR     Xd, Xn, Xm        // ASRV Xd, Xn, Xm と同じ

### LSR
LSR命令 (Logical Shift Right)は論理右シフトを実行。論理右シフトはレジスタ Rn の内容をレジスタ Rm で指定したビット数だけ右にシフトしてレジスタ Rd に返却。

    LSR    Wd, Wn, Wm          // LSRV Wd, Wn, Wm と同じ
    LSR    Xd, Xn, Xm          // LSRV Xd, Xn, Xm と同じ

    LSR    Wd, Wn, #shift      // UBFM Wd, Wn, #shift, #31
    LSR    Xd, Xn, #shift      // UBFM Xd, Xn, #shift, #63

### LSL
LSL命令 (Logical Shift Left)は論理左シフトを実行。論理左シフトはレジスタ Rn の内容をレジスタ Rm で指定したビット数だけ左にシフトしてレジスタ Rd に返却

    LSL    Wd, Wn, Wm          // LSLV   Wd, Wn, Wm と同じ
    LSL    Xd, Xn, Xm          // LSLV   Xd, Xn, Xm と同じ

    LSL     Wd, Wn, #shift     // UBFM Wd, Wn, #(-shift MOD 32), #(31-shift)
    LSL     Xd, Xn, #shift     // UBFM Xd, Xn, #(-shift MOD 64), #(63 - shift)

### ROR
レジスタ Rn の内容をレジスタ Rm で指定したビット数(レジスタのビット数で除算した剰余)でローテイトした値をレジスタ Rd に返却

    ROR    Wd, Wn, Wm          // RORV Wd, Wn, Wm と同じ
    ROR    Xd, Xn, Xm          // RORV Xd, Xn, Xm と同じ

    ROR    Wd, Ws, #shift      // EXTR Wd, Ws, Ws, #shift
    ROR    Xd, Xs, #shift      // EXTR Xd, Xs, Xs, #shift

### EXTR
レジスタ Wn とレジスタ Wm のペアを連結してデータのビット列を抽出。定数には抽出する最下位のビット位置を指定

    EXTR    Wd, Wn, Wm, #lsb
    EXTR    Xd, Xn, Xm, #lsb

実装例

num0:      .quad   0xabcdefabcdefabcd
num1:      .quad   0x1234567890123456
//
    ldr     x11, num0
    ldr     x12, num1
//
    extr    x0, X11, x12, #8    // CD12345678901234
    extr    x0, X11, x12, #16   // ABCD123456789012
    extr    x0, X11, x12, #24   // EFABCD1234567890

### ビットフィールドムーブ命令
レジスタ内の最下位のビットを含む連続したビット列(最も右側のビット列)を移動する命令。 移動先レジスタをゼロクリアして 移動するビット列の最上位を符号フラグとして移動先レジスタの 上位ビットに符号をコピーする SBFM 命令、 移動先のレジスタの内容の対応するビット列だけ上書きして元の内容を保持する BFM 命令、移動先レジスタをゼロクリアしてビット列だけ を書き込む UBFM 命令がある。

                            x2    : 923486789ABCDEF0
                            x3    : 0123456789ABCDEF (使われない)
 SBFM X3, X2, #40, #23 -->  x3    : FFFFBCDEF0000000

                            x2    : 923486789ABCDEF0
                            x3    : BBBBBBBBBBBBBBBB (保持される)
 BFM  X3, X2, #40, #23 -->  x3    : BBBBBCDEF0BBBBBB

                            x2    : 923486789ABCDEF0
                            x3    : 0123456789ABCDEF (使われない)
 UBFM X3, X2, #40, #23 -->  x3    : 0000BCDEF0000000

### SBFM
Signed Bitfield Move の略で、ソースレジスタ(Wn、Xn)の 下位ビット側の任意の桁数 (imms+1) を、転送先レジスタの右シフト (immr)するビット位置にコピー

  SBFM Wd, Wn, #immr, #imms
  SBFM Xd, Xn, #immr, #imms
 x2    : 823456789ABCDEF0
 x5    : 5555555555555555
 SBFM X5, X2, #60, #23 --> FFFFFFFFFBCDEF00
 SBFM X5, X2, #56, #23 --> FFFFFFFFBCDEF000
 SBFM X5, X2, #60, #47 --> 00056789ABCDEF00
 SBFM X5, X2, #56, #47 --> 0056789ABCDEF000
 SBFM X5, X2, #24, #47 --> 000000000056789A
 SBFM X5, X2, #16, #23 --> FFFFFFFFFFFFFFBC
 SBFM X5, X2,  #8, #23 --> FFFFFFFFFFFFBCDE

### ASR
ASR 命令 (Arithmetic Shift Right) は転送元レジスタの内容を定数で指定したビット数だけ右にシフトして転送先レジスタにコピー

    ASR Wd, Wn, #shift               // SBFM Wd, Wn, #shift, #31
    ASR Xd, Xn, #shift               // SBFM Xd, Xn, #shift, #63

### SBFIZ
SBFIZ (Signed Bitfield Insert in Zero) 命令は、転送元レジスタの最下位ビットのビット番号が lsb、幅 が width のビット列を転送先レジスタの下位にコピー

    SBFIZ    Xd, Xn, #lsb, #width    // SBFM Wd, Wn, #(-lsb MOD 32), #(width-1)
    SBFIZ    Wd, Wn, #lsb, #width    // SBFM Xd, Xn, #(-lsb MOD 64), #(width-1)

### SBFX
SBFX (Signed Bitfield Extract) 命令は、転送元レジスタの最下位ビットのビット番号が lsb、幅 が width のビット列を取り出して符号拡張して転送先レジスタにコピー

    SBFX     Wd, Wn, #lsb, #width    // SBFM Wd, Wn, #lsb, #(lsb+width-1)
    SBFX     Xd, Xn, #lsb, #width    // SBFM Xd, Xn, #lsb, #(lsb+width-1)

### SXTB
SXTB (Signed Extend Byte) 命令は転送元レジスタの下位8ビットを符号拡張して転送先レジスタにコピー

    SXTB     Wd, Wn                  // SBFM Wd, Wn, #0, #7
    SXTB     Xd, Wn                  // SBFM Xd, Xn, #0, #7

### SXTH
SXTH (Sign Extend Halfword) 命令は転送元レジスタの下位16ビットを符号拡張して転送先レジスタにコピー

    SXTH     Wd, Wn                  // SBFM Wd, Wn, #0, #15 
    SXTH     Xd, Wn                  // SBFM Xd, Xn, #0, #15

### SXTW
SXTW (Sign Extend Word) 命令は転送元レジスタの下位32ビットを符号拡張して転送先レジスタにコピー

    SXTW     Xd, Wn                  // SBFM Xd, Xn, #0, #31

### BFM
この命令は Bitfield Move の略で、ソースレジスタ(Wn、Xn)の 下位ビット側の任意の桁数 (imms+1) を、転送先レジスタの 右シフト(immr)したビット位置にコピー

    BFM     Wd, Wn, #imm6r, #imm6s    // sf = 0 && N = 0
    BFM     Xd, Xn, #imm6r, #imm6s    // sf = 1 && N = 1
 x2    : 823456789ABCDEF0
 x5    : 5555555555555555
 BFM  X5, X2, #60, #23 --> 555555555BCDEF05
 BFM  X5, X2, #56, #23 --> 55555555BCDEF055
 BFM  X5, X2, #60, #47 --> 55556789ABCDEF05
 BFM  X5, X2, #56, #47 --> 5556789ABCDEF055
 BFM  X5, X2, #24, #47 --> 555555555556789A
 BFM  X5, X2, #16, #23 --> 55555555555555BC
 BFM  X5, X2,  #8, #23 --> 555555555555BCDE

### BFI

                            <--- width --->
before     -----------------bbbbbbbbbbbbbbb
 
                       <--- width --->
                                     lsb
after      ------------bbbbbbbbbbbbbbb-----

    BFI    Wd, Wn, #lsb, #width    // BFM Wd, Wn, #(-lsb MOD 32), #(width-1)
    BFI    Xd, Xn, #lsb, #width    // BFM Xd, Xn, #(-lsb MOD 64), #(width-1)

### BFXIL
BFXIL命令 (Bitfield eXtract and Insert at Low end) は、転送元レジスタの最下位ビットのビット番号が lsb 幅 が width のビット列を転送先レジスタの下位にコピー

                        <--- width --->
                                      lsb
before      ------------bbbbbbbbbbbbbbb-----

                             <--- width --->
after       -----------------bbbbbbbbbbbbbbb

    BFXIL  Wd, Wn, #lsb, #width    // BFM Wd, Wn, #lsb, #(lsb+width-1)
    BFXIL  Xd, Xn, #lsb, #width    // BFM Xd, Xn, #lsb, #(lsb+width-1)

### UBFM

    UBFM Wd, Wn, #imm6r, #imm6s     // sf = 0 && N = 0
    UBFM Xd, Xn, #imm6r, #imm6s     // sf = 1 && N = 1

 x2    : 823456789ABCDEF0
 x5    : 5555555555555555
 UBFM X5, X2, #60, #23 --> 000000000BCDEF00
 UBFM X5, X2, #56, #23 --> 00000000BCDEF000
 UBFM X5, X2, #60, #47 --> 00056789ABCDEF00
 UBFM X5, X2, #56, #47 --> 0056789ABCDEF000
 UBFM X5, X2, #24, #47 --> 000000000056789A
 UBFM X5, X2, #16, #23 --> 00000000000000BC
 UBFM X5, X2,  #8, #23 --> 000000000000BCDE

### LSL

    LSL     Wd, Wn, #shift         // UBFM Wd, Wn, #(-shift MOD 32), #(31-shift)
    LSL     Xd, Xn, #shift         // UBFM Xd, Xn, #(-shift MOD 64), #(63-shift)

### LSR

    LSR     Wd, Wn, #shift         // UBFM Wd, Wn, #shift, #31
    LSR     Xd, Xn, #shift         // UBFM Xd, Xn, #shift, #63

### UBFIZ
UBFIZ (Unsigned Bitfield Insert in Zero) 命令は転送先レジスタを0にした後、転送元レジスタの最下位ビットのビット番号が lsb、幅 が width のビット列を転送先レジスタの下位にコピー

    UBFIZ   Wd, Wn, #lsb, #width   // UBFM Wd, Wn, #(-lsb MOD 32), #(width-1)
    UBFIZ   Xd, Xn, #lsb, #width   // UBFM Xd, Xn, #(-lsb MOD 64), #(width-1)

### UBFX
UBFX (Unsigned Bitfield Extract) 命令は転送先レジスタを0にした後、、転送元レジスタの最下位ビットのビット番号が lsb、幅 が width のビット列を転送先レジスタの下位にコピー。コピーするビット列をゼロ拡張して転送する動作となる

    UBFX    Wd, Wn, #lsb, #width   // UBFM Wd, Wn, #lsb, #(lsb+width-1)
    UBFX    Xd, Xn, #lsb, #width   // UBFM Xd, Xn, #lsb, #(lsb+width-1)

### UXTB
UXTB (Unsigned Extend Byte) 命令は転送元レジスタの下位8ビットをゼロ拡張して転送先レジスタにコピー

    UXTB    Wd, Wn                 // UBFM Wd, Wn, #0, #7

### UXTH
UXTH (Sign Extend Halfword) 命令は転送元レジスタの下位16ビットをゼロ拡張して転送先レジスタにコピー

    UXTH    Wd, Wn                 // UBFM Wd, Wn, #0, #15