bamboo’s blog

Bambooの気まぐれブログ

即値もレジスタも自由に操作!バレルシフタの役割(Arm)

はじめに

 ArmをはじめとするRISCプロセッサは固定長命令であるため、32bitの即値をそのまま使用することはできない。Armの命令では、下位8bitが即値に割り当てられることが多い。
 「それだと8bitサイズの即値しか使えないじゃないか!!」そう思った方がいるかもしれない。そこで登場するのがバレルシフタである。

バレルシフタとは

 バレルシフタとは、データをシフト処理するデジタル回路のことである。レジスタのデータはALU(演算装置)に渡され、そこではじめて演算が行われる。バレルシフタは、命令に含まれるシフト情報を用いて、データがALUに渡される前にデータにシフト処理を行う。この機能により、8bitの即値を事前にシフトして大きくしたり、レジスタの値をシフト処理した状態で演算に使用したりできる。

即値の場合

 即値の場合は、8bitをシフト処理して表現可能な値であれば指定可能。実際には「8bit値を偶数回右ローテートして表現可能な値かどうか」をアセンブラが判断する。例えばmov r0, #0x80000000は1命令で実行できる。これは正確にはmov r0, #2, #2で、「2を2回右ローテートした値(=0x80000000)をr0に代入」という意味である。
 これがどういう意味かは機械語表現すると分かりやすい。mov r0, #0x80000000機械語表現すると0xE3A00102だが、この構造は以下の通りである。

f:id:bamboo_cpu:20210224005855p:plain

 まずMOV構造について簡単に説明。Iフラグは即値かどうか、Sフラグはcpsrに反映するかどうかを意味する。今回は即値指定でcpsrには反映しないため、I=1, S=0である。即値が指定されている場合は、シフト値×2回(偶数回)即値を右ローテートする。
 次に16進数の欄を見てみる。レジスタは0(r0)、シフト値は1、即値は2である。これを先程の規則に従って解釈すると、mov r0, #2, #2、すなわちmov r0, #0x80000000となる。

レジスタの場合

 レジスタの場合は論理左シフト(LSL)、論理右シフト(LSR)、算術右シフト(ASR)、右ローテート(ROR)が使用可能。例として、r1を2で割った値とr0を比較するコード(cmp r0, r1, lsr #1)をエンコードしてみる。これは機械語では0xE15000A1である。

f:id:bamboo_cpu:20210224025816p:plain

ID 種類 意味
00 LSL 論理左シフト
01 LSR 論理右シフト
10 ASR 算術右シフト
11 ROR 右ローテート

 今回は即値ではないためIフラグには0が設定される。Rnは第一オペランド、Rmは第二オペランド。種類の欄にはシフトのIDが対応する。Rn=0(r0)、シフト回数=1、ID=1(lsr)、Rm=1(r1)。よってcmp r0, r1, lsr #1となる。

まとめ

 バレルシフタを活用すれば、使用するレジスタを減らせたり、命令数を減らせたりと数々の恩恵を受けることができる。Armに触れる際はぜひ意識してみよう。