[英]ARMv6 Best Practices for Register Use in Function
在Assembly上的總n00b,但我覺得我已經掌握了。 但是我有一個關於在函數中使用寄存器的最佳實踐的問題。
據我了解:在ARM11上的13個可用通用寄存器中,按慣例,寄存器0-3用於傳遞參數(0和1也用於返回值),而4-12則用於傳遞參數。用於在功能持續時間內存儲工作值。
但是,我也看到了一些代碼示例,其中人們也使用寄存器0-3作為工作值,只要它們中的任何一個都可用,因為它們不需要將前一個值壓入並彈出到堆棧上。
盡管我能理解為什么有人可能想要避免執行多余的push&pop步驟,但似乎除了將值傳入和傳出函數之外,將r0-r3用於其他任何事情都可能會導致問題(因為您無法保證您調用的任何函數都會保留其值)。
那么,這里的最佳實踐是什么? 我什么時候(如果有的話)將寄存器0-3用於工作值,何時應該浸入寄存器4-12?
似乎除了將值傳入和傳出函數外,將r0-r3用於其他任何事情都可能會帶來問題(因為您無法保證調用的任何函數都會保留其值)。
這正是您可以使用r4-r11的時間,因為ABI指定被調用者必須保留這些值:)
寄存器r0-r3被調用者保存,因此調用者必須確保在函數調用之前保存了這些寄存器中存儲的所有重要值。 作為被呼叫者,您可以在這些寄存器上執行任何您想執行的操作。
...似乎除了將值傳入和傳出函數外,將r0-r3用於其他任何事情都可能會導致一系列問題(因為您無法保證所調用的任何函數都會保留其值)。
寄存器比內存快,寄存器比L2緩存快,寄存器比L1緩存快,寄存器快。 通過使用R4-R8,您將創建額外的存儲和負載。 在手工編碼的匯編器中,這將創建額外的指令。 對於ARM葉子匯編器功能,沒有序言,而結尾是bx lr
。 多么簡單。
您的聲明似乎對於許多算法和函數來說, 除了傳遞值外,將r0-r3用作其他方法似乎都是不正確的。 考慮實施GCD,
int gcd(int a, int b)
{
while(a!=b)
if(a>b)
a = a - b;
else
b = b - a;
return a;
}
參數a
和b
在算法期間不斷更新。 第一次迭代后就不再需要原始的a
和b
值。 在編譯器優化中,此事實稱為“ 靜態單分配形式” 。 寄存器被重新命名為A 0,A 1,等
因此,輸入參數通常不需要保持不變。 無需將它們復制到r4-r8並強制生成堆棧幀。 ARM編譯器將努力這樣做。 無需人工對此進行編碼。 如果有必要,除非您正在學習,否則最好讓編譯器生成代碼。 David Seal的ARM ARM的ARM gcd算法是,
gcd: cmp r0, r1
subgt r0, r0, r1
sublt r1, r1, r0
bne gcd
bx lr
該例程是五個指令。 如果保存了輸入參數,則例程的大小將增加一倍。
gcd:
stmfd sp!, {r4, r5} ; extra code plus two data
mov r4, r0 ; extra code
mov r5, r1 ; extra code
1: cmp r4, r5
subgt r4, r4, r5
sublt r5, r5, r4
bne 1b
mov r0, r4 ; extra code to setup return
ldmfd sp!, {r4, r5} ; extra code plus two data
bx lr
對於較小的輸入,您可以將執行時間增加三倍。 不用額外的代碼就可以更容易地理解匯編程序。 您永遠不要保存不使用的寄存器。 為了獲得高質量的產品,專業的代碼總是有意義地使用r1
到r3
並放棄將它們存儲在堆棧中。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.