実現したいこと
- コンパイラ(プログラミング言語)を作りたくアセンブラを勉強を始めました。
質問
アセンブラのソースコードを見ると、汎用レジスタ間でのmovが沢山に出てきますが、なぜレジスタ間でコピーする必要があるのでしょうか?単純にレジスタの値の上書きや変更はできないのでしょうか?
ソースコード例(ARM64)
.text .global _start _start: mov x2, #13 // x2 length adr x1, msg // x1 string address mov x0, #1 // x0 stdout mov x8, #64 svc #0 // sys_write mov x0, xzr mov x8, #93 svc #0 // exit msg: .asciz "hello, world\n"
その例示ソースにはレジスタ間でのコピーは一個もないように見受けられますが。(zxrは微妙)
mov命令は汎用レジスタの値を上書き・変更しますが、上書きや変更ではない「コピー」というのはどういうことを指しているのでしょうか。
> mov命令は汎用レジスタの値を上書き・変更します
レジスタの値を上書き・変更するって意味なんですね。ありがとうございます。
>上書きや変更ではない「コピー」というのはどういうことを指しているのでしょうか。
質問の意図としては、レジスタの値を変更できるのであれば、わざわざレジスタ間でコピーせずに該当のレジスタの値だけ更新した方が効率的かと思ったのですが、レジスタ間でコピーする処理が必要な場面があるってことなんですかね。
いまいち理解せずに質問してしまいすみません。ドキュメントにも「Move (register) copies the value in a source register to the destination register.」とありますね。
https://developer.arm.com/documentation/ddi0596/2021-12/Base-Instructions/MOV--register---Move--register---an-alias-of-ORR--shifted-register--
たとえば、ある変数x、y、z、wに値が入っていて、
(x + y) * (z + w)
を計算するようなプログラムを書くとしますね。それをコンパイラで機械語にするとどんな結果になるかを考えてみればいいんじゃないですか。
c言語でコンパイルしたアセンブラを見ると、宣言したタイミングでメモリにstoreし、変数を読み込むタイミングでメモリからロードしていますね。なるほど、Cのコンパイルの中身を見ると、かなり参考になりますね。
### c
#include <stdio.h>
int main(void) {
int x=1;
int y=2;
int z=3;
int w=4;
printf("%d\n", (x+y)*(z+w));
return 0;
}
### arm64
stp fp,lr,[sp,#-0x20]!
mov fp,sp
mov w8,#1
str w8,[sp,#0x10]
mov w8,#2
str w8,[sp,#0x14]
mov w8,#3
str w8,[sp,#0x18]
mov w8,#4
str w8,[sp,#0x1C]
ldr w9,[sp,#0x10]
ldr w8,[sp,#0x14]
add w10,w9,w8
ldr w9,[sp,#0x18]
ldr w8,[sp,#0x1C]
add w8,w9,w8
mul w1,w10,w8
mov w1,w1
adrp x8,|$SG5195|
add x0,x8,PageOffset(|$SG5195|)
bl printf
mov w0,#0
ldp fp,lr,[sp],#0x20
ret
### 自分が書いたアセンブラ
_start: mov x1, #1
mov x2, #2
mov x3, #3
mov x4, #4
add x1, x1, x2
add x3, x3, x4
mul x0, x1, x3
コンパイルに使用したサイト
https://gcc.godbolt.org/
使ったコンパイラがなんなのか分かりませんが、私の手元のARM64 clangの結果とほぼ同じようですね。
最適化オプション (例えば -Os) をつけると生成されるコードが変わります。最適化を考えないで汎用性を大事にすると、アセンブラで直接記述した (完璧に最適化された状態) ときより冗長なコードが生成されるでしょう。
回答2件
あなたの回答
tips
プレビュー