「呼び出し元退避レジスター」および「呼び出し先退避レジスター」という用語は、関数の呼び出し元によって退避されるレジスターと、呼び出された関数によって退避されるレジスターをそれぞれ指します。プロセッサのアーキテクチャと「ABI」(Application Binary Interface)と呼ばれる仕様に依存するレジスタとは何ですか - これはプロセッサファミリごとに異なり、オペレーティングシステム間でも異なることがよくあります。しかし、基本的な原則は、コンパイラが生成するマシン コードは特定の期待に基づいて構築されているということです。どの関数も R0、R1、R2 を自由に使用でき、呼び出し元はこれらが呼び出しで変更されることを期待する必要があります。R3-R6 は呼び出された関数によって保存され、呼び出し元の関数が R7 または R8 を使用する場合、関数を呼び出す前にそれらを保存する必要があります。[これは「任意のプロセッサ」であり、
あなたの機能を分析するには...
最初にこの関数を分解しましょう:
int foo() {
int a = 1, b = 2, c = 3, w;
c = abs(c);
c = c + b + 7;
for (w = 0; w<10; w++) {
b += bar(b);
}
return c;
}
変数「a」は使用されていないため、削除できます。関数「abs」はコンパイル時に解決できるため、その行を削除できます。
c = c + b + 7;
は、コンパイル時に 2 + 3 + 7 = 12 として解決できます。定数 12 を return ステートメントに移動して、 を取り除くだけですc
。したがって、次のものが残ります。
int foo() {
int b = 2, w;
for (w = 0; w<10; w++) {
b += bar(b);
}
return 12;
}
これは、少なくとも 2 つのレジスタを使用します。
次の関数に対して同じことを行います:
int bar(int v) {
int a = 1, b = 2;
a += v + b;
printf(“v=%d\n”, v);
return v;
}
とは使用されていないため、a = 1, b = 2
とを削除できます。これは次のとおりです。a += v + b
a
b
int bar(int v) {
printf(“v=%d\n”, v);
return v;
}
さて、巧妙なコンパイラがbar
foo にインライン化すると、次のようになります。
int foo() {
int b = 2, w;
for (w = 0; w<10; w++) {
printf(“v=%d\n”, b);
b += b;
}
return 12;
}
現実的には、これは 2 つまたは 3 つのレジスタと、実行する必要があるものすべてで実行printf
できます (それが何であるかはわかりません...)。コンパイラーは別のステップに進み、ループを「展開」する可能性があります。その場合、おそらくもう 1 つのレジスターを削除できます。