Partial_Reg 是在靜態分析期間指出的一個警告。在靜態分析期間,“VTune(TM) 效能分析器”會檢測基本指令塊內的部分暫存器暫停。暫停由以下原因導致時,分析器還會檢測基本指令塊之間的部分暫存器暫停:一個指令塊包含對部分暫存器進行寫入操作的指令,後面所跟指令跳轉到的指令塊包含對較大暫存器的讀取。
為其發出 Partial_Reg 的指令在前面的某個指令寫入其部分暫存器(例如 AL、AH、AX)之後從較大的暫存器(例如 EAX)進行讀取。讀取指令將一直暫停到寫入指令失效,即使這些指令不相鄰。
這適用於以下方式組成的暫存器對:一個較大的暫存器及其任何部分暫存器,或同一組中的兩個部分暫存器。
較大的暫存器及其部分暫存器之一的示例有:AX 與 EAX、BL 與 BX 以及 SI 與 ESI。
同一組中的兩個部分暫存器的示例有:AL 與 AH 以及 CL 與 CH。
如果在讀取開始執行之前,寫入已經失效,則不發生暫停。(在靜態模擬中,沒有辦法知道寫入的確切失效時間。因此,讀取和寫入之間的固定距離只是出於模擬的目的。使用的固定距離通常遠到足以確保寫入已失效)。
在以下情況中,由於處理器在內部按 32 位操作(即使看起來是僅按 16 位操作),因此也會發生部分暫存器暫停:
MOV 指令寫入任何部分暫存器,隨後,MOVSX 或 MOVZX 指令讀取相同的部分暫存器。示例:
mov ax, 7 movsx ebx, ax
MOV 指令寫入任何部分暫存器,隨後部分暫存器的內容複製到任何段暫存器。示例:
mov ax, 7 mov ss, ax
儘量避免使用部分暫存器。如果必須使用部分暫存器,仍可以採取以下辦法來避免懲罰:
儘量避免在寫入部分暫存器之一以後使用較大的暫存器。
在寫入部分暫存器之一以前,先使用 XOR 或 SUB 指令清除較大暫存器的高位。使用此辦法清除較大暫存器的高位之後,在寫入其部分暫存器之一以後再進行讀取,不會導致暫停。使用其它辦法清除較大暫存器的高位則無法避免暫停。
預測失誤的分支會抵消 XOR 與 SUB 指令的效果。因此,要使用 XOR 或 SUB 指令避免此種暫停,請將 XOR 或 SUB 放在分支後面。
示例:避免使用部分暫存器
原始程式碼 |
優化程式碼 |
|
|
這裡,第二條 MOV 指令只寫入 EAX 暫存器的低位部分,即 AL。第三條 MOV 指令讀取整個 AX 暫存器。這會導致部分暫停。
|
這裡,整個 ECX 暫存器複製到 EAX。 通過重新安排,還可以進一步優化程式碼。 |
示例:使用 XOR 避免部分暫存器暫停
在寫入部分暫存器之一以前,可以使用 XOR 與 SUB 指令清除較大暫存器的高位。使用此種辦法清除較大暫存器的高位之後,在寫入其部分暫存器之一以後進行讀取時,不會導致暫停。使用其它辦法清除較大暫存器的高位則無法避免暫停。
原始程式碼 |
優化程式碼 |
|
|
INC 指令使用整個 EAX 暫存器。前面的 MOV 指令只使用 EAX 暫存器的低位部分,即 AL。這會導致部分暫停。 |
在讀取部分暫存器之前,使用 XOR 指令將 EAX 中所有的位清除為零,從而避免暫停。 |
示例:使用 SUB 避免部分暫存器暫停
在寫入部分暫存器之一以前,可以使用 SUB 與 XOR 指令清除較大暫存器的高位。使用此種辦法清除較大暫存器的高位之後,在寫入其部分暫存器之一以後進行讀取時,不會導致暫停。使用其它辦法清除較大暫存器的高位則無法避免暫停。
原始程式碼 |
優化程式碼 |
|
|
第一行中的 MOV 清除 EAX。第二行中的 MOV 寫入部分暫存器 AL。第三行遞增 EAX,會導致暫停。 |
在讀取部分暫存器之前,使用 SUB 指令將 EAX 中所有的位清除為零,從而避免暫停。 |