亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

GCC為什么不使用分寄存器?

GCC為什么不使用分寄存器?

GCC為什么不使用分寄存器?拆解write(1,"hi",3)在Linux上構建的gcc -s -nostdlib -nostartfiles -O3成果如下:ba03000000     mov edx, 3 ; thanks for the correction jester!bf01000000     mov edi, 131c0           xor eax, eax e9d8ffffff     jmp loc.imp.write我不喜歡編譯器開發,但是由于這些寄存器中的每個值都是常量且已知的編譯時,我很好奇為什么GCC不使用dl, dil,和al相反。有些人可能會說,這個特性在性能上不會有任何不同,但是在可執行文件的大小上有很大的差別。mov $1, %rax => b801000000和mov $1, %al => b001當我們談論一個程序中成千上萬的寄存器訪問時。這不僅是軟件優雅的一部分,而且對性能也有影響。有人能解釋一下為什么“GCC”決定不重要嗎?
查看完整描述

3 回答

?
湖上湖

TA貢獻2003條經驗 獲得超2個贊

在許多x86處理器上,部分寄存器會導致性能損失,因為在編寫時,它們被重命名為與整個寄存器不同的物理寄存器。(有關啟用無序執行的寄存器重命名的更多信息,請參見這個問答).

但是,當指令讀取整個寄存器時,CPU必須檢測一個事實,即它在單個物理寄存器中沒有正確的體系結構寄存器值。(這發生在問題/重命名階段,因為CPU準備將uop發送到無序調度程序中。)

這叫做部分寄存器失速阿格納·福格顯微建筑手冊很好地解釋了:

6.8部分登記冊檔位(PPRO/PII/PIII和Pentium-M)

部分寄存器失速是一個問題,當我們寫到32位寄存器的一部分,然后從整個寄存器或更大的一部分讀取。
例子:

; Example 6.10a. Partial register stall
mov al, byte ptr [mem8]mov ebx, eax ; Partial register stall

這樣可以延遲5-6個時鐘。..原因是臨時登記冊已分配給AL使它獨立于AH..執行單元必須等到寫到AL的值可以合并之前就已經退休了。AL的其他價值EAX.

不同CPU中的行為:

如果沒有部分寄存器重命名,則寫入的輸入依賴項為假的如果您從未讀取完整寄存器,則依賴項。這限制了指令級的并行性,因為對其他事情重用8或16位寄存器實際上并不是獨立于CPU的觀點(16位代碼可以訪問32位寄存器,因此它必須在上半部保持正確的值)。同時,它也使AL和AH不獨立。當Intel設計P6系列(PPRO于1993年發布)時,16位代碼仍然很常見,因此部分寄存器重命名是使現有機器代碼運行更快的一個重要特性。(實際上,許多二進制文件不會為新CPU重新編譯。)

這就是為什么編譯器大多避免寫字部分寄存器他們用movzx / movsx只要有可能,將窄值擴展到完全寄存器,以避免部分寄存器錯誤依賴(AMD)或暫存(Intel P6-系列)。因此,大多數現代機器代碼并不能從部分寄存器重命名中獲益,這就是最近Intel CPU正在簡化它們的部分寄存器重命名邏輯的原因。

@BeeOnRope的回答指出,編譯器仍然朗讀,閱讀部分寄存器,因為這不是問題。(閱讀AH/BH/CH/DH可以在Haswell/Skylake上增加額外的延遲周期,但請參閱關于Sandybridge-族最近成員的部分寄存器的早期鏈接。)


也請注意那,那個write獲取參數,對于通常配置為GCC的x86-64,需要完整的32位和64位寄存器,這樣就不能簡單地組裝到mov dl, 3..大小由類型的數據,而不是價值數據。

最后,在某些情況下,C默認參數提升要知道,雖然事實并非如此.
實際上,作為羅斯里奇指出,這個電話很可能是在沒有可見原型的情況下發出的。


正如杰斯特指出的那樣,你的拆卸是誤導人的。
例如mov rdx, 3實際上mov edx, 3,盡管兩者都有相同的效果-也就是說,將3放在整體中。rdx.
這是正確的,因為即時值3不需要符號擴展名和MOV r32, imm32隱式清除寄存器的上32位。


查看完整回答
反對 回復 2019-07-03
?
德瑪西亞99

TA貢獻1770條經驗 獲得超3個贊

事實上,GCC經常使用分式寄存器。..如果您查看生成的代碼,您將發現很多使用部分寄存器的情況。

簡短的回答你的特殊情況,是因為GCC在調用cabi函數時總是將參數符號或零擴展到32位。.

這個事實上SysV x 86和x86-64 abigccclang要求小于32位的參數為零或符號擴展為32位.有趣的是,它們不需要一直延伸到64位。

因此,對于64位平臺SysVABI平臺上的如下功能:

void foo(short s) {
 ...}

..爭論s傳入rdi而s的部分如下(但請參閱下面關于icc):

  bits 0-31:  SSSSSSSS SSSSSSSS SPPPPPPP PPPPPPPP
  bits 32-63: XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX  where:
  P: the bottom 15 bits of the value of `s`
  S: the sign bit of `s` (extended into bits 16-31)
  X: arbitrary garbage

密碼foo可以依賴于SP比特,但不是在X比特,這可能是任何東西。

同樣,對于foo_unsigned(unsigned short u),你會0第16-31段,否則就會是相同的。

注意我說過事實上-因為實際上并沒有真正記錄如何處理較小的返回類型,但是您可以看到彼得的回答詳情請到這里。我還問了一個相關的問題這里.

經過進一步的測試,我得出結論:icc實際上違反了這個事實上的標準。gccclang似乎很堅持,但是gcc只以保守的方式:什么時候呼叫函數,它將零/符號擴展參數擴展到32位,但在其函數實現中,依附在打電話的人身上。clang實現依賴于調用者將參數擴展到32位的函數。所以事實上clangicc即使對于普通C函數,如果它們的參數小于int.


查看完整回答
反對 回復 2019-07-03
?
鳳凰求蠱

TA貢獻1825條經驗 獲得超4個贊

在類似于最初的IBMPC上,如果已知AH包含0,并且有必要以0x34這樣的值加載AX,則使用“MOVAL,34H”通常需要8個周期,而不是“MOVAX,0034h”所需的12個周期-這是一個相當大的速度改進(如果預取的話,這兩條指令都可以在兩個周期內執行,但在實踐中,8088花費了大部分時間等待指令被以每字節四個周期的代價獲取)。然而,在當今通用計算機中使用的處理器上,獲取代碼所需的時間通常并不是影響總體執行速度的一個重要因素,代碼大小通常也不是一個特別關注的問題。

此外,處理器廠商試圖最大限度地提高人們可能運行的代碼類型的性能,而8位加載指令不太可能像現在32位加載指令那樣經常使用。處理器核心通常包括同時執行多個32位或64位指令的邏輯,但可能不包括與任何其他操作同時執行8位操作的邏輯。因此,盡管在8088上使用8位操作(如果可能的話)是對8088的一個有用的優化,但它實際上對新的處理器來說是一個嚴重的性能損耗。


查看完整回答
反對 回復 2019-07-03
  • 3 回答
  • 0 關注
  • 595 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號