部分暫存器暫停警告

Partial_Reg 是在靜態分析期間指出的一個警告。在靜態分析期間,“VTune(TM) 效能分析器”會檢測基本指令塊內的部分暫存器暫停。暫停由以下原因導致時,分析器還會檢測基本指令塊之間的部分暫存器暫停:一個指令塊包含對部分暫存器進行寫入操作的指令,後面所跟指令跳轉到的指令塊包含對較大暫存器的讀取。

為其發出 Partial_Reg 的指令在前面的某個指令寫入其部分暫存器(例如 AL、AH、AX)之後從較大的暫存器(例如 EAX)進行讀取。讀取指令將一直暫停到寫入指令失效,即使這些指令不相鄰。

這適用於以下方式組成的暫存器對:一個較大的暫存器及其任何部分暫存器,或同一組中的兩個部分暫存器。

較大的暫存器及其部分暫存器之一的示例有:AX 與 EAX、BL 與 BX 以及 SI 與 ESI。

同一組中的兩個部分暫存器的示例有:AL 與 AH 以及 CL 與 CH。

如果在讀取開始執行之前,寫入已經失效,則不發生暫停。(在靜態模擬中,沒有辦法知道寫入的確切失效時間。因此,讀取和寫入之間的固定距離只是出於模擬的目的。使用的固定距離通常遠到足以確保寫入已失效)。

在以下情況中,由於處理器在內部按 32 位操作(即使看起來是僅按 16 位操作),因此也會發生部分暫存器暫停:

mov ax, 7 movsx ebx, ax

 

mov ax, 7 mov ss, ax

 

建議

儘量避免使用部分暫存器。如果必須使用部分暫存器,仍可以採取以下辦法來避免懲罰:

示例:避免使用部分暫存器

原始程式碼

優化程式碼

mov ah, cl mov al, dl mov mem, ax

mov eax, ecx shl eax, 8 and edx, 0xFF or eax, edx mov mem, ax

這裡,第二條 MOV 指令只寫入 EAX 暫存器的低位部分,即 AL。第三條 MOV 指令讀取整個 AX 暫存器。這會導致部分暫停。

 

這裡,整個 ECX 暫存器複製到 EAX。shl 指令將 ECX 的低位部分 (CL) 移到 EAX 的高位部分 (AH)。通過使用 EDX 與 FF 進行“與”運算,將 EDX 的高位部分 (DH) 置零,只留下 DL 部分。EAX 同 EDX 進行“或”運算之後,CL 留在 EAX 的高位部分 (AH),DL 留在低位部分,即 AL。原始程式碼的語義保持不變,並且沒有部分暫停。

通過重新安排,還可以進一步優化程式碼。

示例:使用 XOR 避免部分暫存器暫停

在寫入部分暫存器之一以前,可以使用 XOR 與 SUB 指令清除較大暫存器的高位。使用此種辦法清除較大暫存器的高位之後,在寫入其部分暫存器之一以後進行讀取時,不會導致暫停。使用其它辦法清除較大暫存器的高位則無法避免暫停。

原始程式碼

優化程式碼

mov al, mem8 inc eax

xor eax, eax mov al, mem8 inc eax

INC 指令使用整個 EAX 暫存器。前面的 MOV 指令只使用 EAX 暫存器的低位部分,即 AL。這會導致部分暫停。

在讀取部分暫存器之前,使用 XOR 指令將 EAX 中所有的位清除為零,從而避免暫停。

示例:使用 SUB 避免部分暫存器暫停

在寫入部分暫存器之一以前,可以使用 SUB 與 XOR 指令清除較大暫存器的高位。使用此種辦法清除較大暫存器的高位之後,在寫入其部分暫存器之一以後進行讀取時,不會導致暫停。使用其它辦法清除較大暫存器的高位則無法避免暫停。

原始程式碼

優化程式碼

mov eax, 0 mov al, mem8 inc eax

sub eax, eax mov al, mem8 inc eax

第一行中的 MOV 清除 EAX。第二行中的 MOV 寫入部分暫存器 AL。第三行遞增 EAX,會導致暫停。

在讀取部分暫存器之前,使用 SUB 指令將 EAX 中所有的位清除為零,從而避免暫停。

影響的處理器