2012-05-01 134 views
2

我正在編程一個JIT編譯器,並且我驚訝地發現在Win64調用約定中很多x86-64寄存器都是非易失性的(被保留的)。在我看來,非易失性寄存器在所有可以使用這些寄存器的函數中都具有更多的功能。這在數值計算中尤其如此,您希望在葉函數中使用多個寄存器,例如某種高度優化的矩陣乘法。但是,例如,16個SSE寄存器中只有6個是不穩定的,所以如果你需要使用更多的東西,你會有很多事情要做。在調用約定中使用非易失性寄存器有什麼好處?

所以是的,我不明白。這裏的折衷是什麼?

+3

這不是它的工作方式,你,讓你設置自己的規則生成自己的機器代碼。當你調用外部代碼時,你只需要觀察x64 abi。無論如何,這需要一個自定義編組器。 –

+0

@HansPassant哼,是的,我沒有想到。這是我第一個這樣的項目,我想調用外部代碼,所以對我來說,在任何地方使用Win64都會更簡單。但我知道我可以做其他事情。 – Trillian

+0

@HansPassant這是否意味着在Linux內核中可以選擇覆蓋這些規則,只要它堅持內部選擇的任何規則(因爲它們不是硬着頭皮或被硬件以任何方式嵌入)? – HighOnMeat

回答

4

如果寄存器是調用者保存的,則調用者總是必須在函數調用周圍保存或重新加載這些寄存器。但是,如果寄存器是被調用者保存的,那麼被調用者只需要保存它使用的寄存器,並且只有當它知道它們將要被使用時(即可能根本不在早退場景中)。 這個慣例的缺點是被調用者不知道調用者,因此它可能會保存已經死亡的寄存器,但我想這被視爲一個較小的問題。

+0

因此,只要你的一個被叫方不使用非易失性寄存器,你已經保存了一些溢出/加載。我想這是有道理的。謝謝。 – Trillian

0

具有nonvolatile寄存器的優點是:性能

移動的數據越少,CPU的效率就越高。

更多volatile寄存器,CPU需要的能量就越多。

0

只有6個call-clobbered xmm寄存器的Windows x86-64調用約定不是一個很好的設計,你是對的。大多數SIMD(和許多標量FP)循環都不包含任何函數調用,所以它們在通過調用保存的寄存器中獲取數據沒有任何好處。保存/恢復是純粹的缺點,因爲它比任何調用者都使用這種非易失性狀態更爲罕見。

在x86-64 System V中,所有向量寄存器都是調用阻塞的,這可能是另一種方式。在許多情況下,保留1或2個保存會很好,特別是對於進行一些數學庫函數調用的代碼。 (Use gcc -fno-math-errno to let simple ones inline better;有時他們不這樣做的唯一原因是,他們需要設置爲NaN errno

相關:how the x86-64 SysV calling convention was chosen:看代碼大小和指令計數的gcc編譯的SPECint/SPECfp的。


對於整數暫存器,有一些各自的絕對是好,一切「正常」調用約定(對所有架構,而不僅僅是x86)的做其實有一個組合。 這減少了在呼叫者和被呼叫者組合中溢出/恢復的工作總量。

強制調用者溢出/重新加載每個函數調用的所有內容都不利於代碼大小或性能。在函數的開始/結束處保存/恢復一些調用保留的寄存器可以讓非葉函數將某些事情保存在call的寄存器中。

考慮一些代碼,計算一對夫婦的事情,然後做cout << "result: " << a << "foo" << b*c << '\n';這4個功能調用std::ostream operator<<,他們一般不在線。保留地址cout和您剛剛在非易失性寄存器中計算的當地人意味着您只需要一些便宜的指令即可爲下一次調用設置參數。 (或者在棧參數調用約定中使用push)。

但具有可以不保存使用的一些調用破壞的寄存器也很重要。不需要所有架構寄存器的函數都可以使用調用破壞寄存器作爲臨時對象。這樣可以避免在調用者的依賴鏈的關鍵路徑(對於非常小的被調用者)中引入溢出/重新加載,以及保存指令。

有時一個複雜的功能將保存/恢復一些呼叫保留的寄存器只是爲了獲得更多的總寄存器(就像你用XMM看到了數字運算)。這通常是值得的;保存/恢復調用者的非易失性寄存器通常比溢出/重新加載你自己的局部變量到堆棧要好,尤其是當你不得不在任何循環中這樣做時。


的另一個原因是呼叫破壞寄的是,通常是一些你的價值觀是「死」的函數調用後:你只需要它們作爲參數傳遞給函數。在呼叫受阻寄存器中計算它們意味着您不必保存/恢復任何內容來釋放這些寄存器,但是您的被調用者也可以自由使用它們。在調用通過寄存器中的參數的約定中,這更好:您可以直接在arg傳遞寄存器中計算輸入。 (如果你在功能之後還需要它們,將任何複製到保存調用的寄存器或者將它們溢出到堆棧內存中。)

(我喜歡call-preserved與call-clobbered這兩個術語,而不是調用者保存與callee-saved。後面的術語暗示有人必須保存寄存器,而不是讓死亡值死掉。volatile/non-volatile並不差,但這些術語也具有其他技術含義,如C關鍵字,或者閃存vs 。DRAM)

相關問題