bamboo’s blog

Bambooの気まぐれブログ

命令の末尾に"s"をつけると・・・?(Arm)

はじめに

 皆さんはArm命令の末尾にsがついた命令を見たことがあるだろうか。見たことはあっても、通常の命令と何が違うのかイマイチ分からない、という方も多いかもしれない。今回はこのsがどのような意味を持つのか詳しく見てみよう。

sの意味

 末尾にsを付けると、演算結果をステータスフラグに反映してくれるようになる。具体的には、第一オペランドレジスタに入る値(演算結果)を元にステータスフラグが更新される。

ステータスフラグ

 ステータスフラグについておさらい。皆さんはcmp命令やtst命令について知っているだろうか。条件実行する際によく使用される命令である。これらは正確には「演算結果をステータスフラグに反映する命令」である。

f:id:bamboo_cpu:20210225132945p:plain

 ステータスフラグには上記のようなものがある。cmp命令は第一オペランドから第二オペランドを引いた値が、tst命令は第一オペランドと第二オペランド論理積が演算結果として反映される。

f:id:bamboo_cpu:20210225133235p:plain

 また、条件実行の概要については上記の通り。条件付き命令は、その時点でのステータスフラグの状態と条件が一致した場合に実行される。
 例えば以下のようなコードがあったとする。

mov r0, r1
cmp r0, r1
beq label

当然このコードはlabelへと分岐する。普通なら「r0とr1が同値だから・・・」でいいのだが、今回はもう少し掘り下げて考えてみる。
 先程述べた通り、cmp命令はオペランドの差分をステータスフラグに反映する。つまり今回の場合はr0-r1、すなわち0である。演算結果が0ということは、Zフラグが1に設定される。eqはZが1に設定されていることが実行条件であるため、beq labelは実行されるというわけである。

sを使ってみる

 本題に戻る。実はこのステータスフラグの概念を理解していると、cmp命令やtst命令を使わずに条件実行できる場合がある。例えば以下のようなコード。

mov r0, r1
cmp r0, #0
beq label

r1をr0に代入して、その値が0なのであればlabelに分岐するという処理である。一見なんの無駄も無いように思えるが、実はこのような命令は短縮できる。
 注目すべきはcmp r0, #0。これは「r0 - 0の演算結果をステータスフラグに反映しろ」という意味である。つまり、実際ステータスフラグに反映するのはr0の値。直前にmov r0, r1があるため、この時点でr0の値はステータスフラグに反映できる。よって、以下のようなコードに書き換えることができる。

movs r0, r1
beq label

これで1命令減らすことができた。

cmp命令やtst命令との違い

 では、cmp命令やtst命令とはどのように使い分ければよいだろうか。結論から言うと、sを用いることが可能であれば使用し、そうでなければcmp命令やtst命令を使えばよい。例えばldr命令にはsをつけることができないためcmp命令やtst命令を使用し、演算命令(movやaddなど)ではsを使うといった具合だ。

まとめ

 末尾sの役割は分かっていただけただろうか。ステータスフラグの概念を理解しこれらをうまく使い分ければ、よりコンパクトなコードが書けるようになる。積極的に活用してみよう。