1. 程式人生 > >Intel Sandy Bridge/Ivy Bridge微架構(6) - 流水線快三原始碼搭建前端微熔合/巨集熔合

Intel Sandy Bridge/Ivy Bridge微架構(6) - 流水線快三原始碼搭建前端微熔合/巨集熔合

微熔合將來快三原始碼搭建q-2747044651自於同一條x86指令的多條微指令熔合成單條複雜的微指令.這條複雜的微指令可以被分發到亂序執行核任意多次,就好象沒有進行過微熔合一樣(即亂序執行核並不能感知到微熔合機制的存在【征途原始碼論壇https://0x9.me/WV9jI】)。

微熔合機制使得程式設計師可以使用“儲存器到暫存器”這樣的操作方式(這種操作在複雜指令集計算機中很常見),來編寫程式而不需擔心會損失前端譯碼頻寬。微熔合可以整體提升指令從譯碼到退役的頻寬,同時節省電力。

過多的使用單微指令的x86指令來編寫程式會增加程式碼長度,降低傳統譯碼流水線的取指頻寬。

下面是一些微熔合的示例,可以被所有的譯碼器處理。

所有的寫存操作,包括寫立即數到儲存器。在處理器內部,寫存操作是兩個獨立的操作:儲存目標地址,和儲存資料。
例如,MOV [5000H], 1234H,這條指令將立即數1234H寫到儲存器地址5000H中(假設基地址是0)。沒有微熔合機制的情況下,這條指令會對應兩條微指令,儲存目標地址5000H,儲存資料1234H。有了微熔合機制,這條指令譯碼後只對應單條的複雜微指令。TODO:這個理解是否正確。

所有的讀存加計算操作型別(load + op)都可以微熔合為一條微指令,例如
ADDPS XMM9, OWORD PTR [RSP+40]; todo: how long for OWORD PTR?

FADD DOUBLE PTR [RDI+RSI*8];

XOR RAX, QWORD PTR [RBP+32];

所有的讀存加跳轉操作型別(load + jump),例如
JMP [RDI+200]

RET ; load instruction pointer and jump

 

CMP/TEST指令使用儲存器定址和立即數
例如,CMP [5000H], 1234H

使用RIP相對定址的指令在如下的情況下無法進行微熔合:

有一個額外的立即數,例如
CMP [RIP+400], 27

MOV [RIP+3000], 142

控制流指令使用間接目標且目標是RIP相對定址方式,例如
JMP [RIP+500000000];

對於不能實施微熔合的情況,x86指令只能由複雜譯碼器進行譯碼,生成兩條微指令;這樣會稍微降低譯碼頻寬。

在64位程式碼中,RIP相對定址方式經常用於定址全域性資料。由於沒有微熔合機制,當移植32位程式到64位上時,頻繁訪問全域性資料的程式碼效能可能會有所下降。

Macro-Fusion

巨集熔合可以將兩條x86指令熔合,譯碼後只生成單條微指令。在Intel Core微架構中,這個硬體優化機制是有較大限制的,只能針對符合特定條件的指令對進行熔合。

第一條指令修改標誌暫存器且滿足一定條件(參下):
Nehalem微架構:CMP, TEST
Sandy Bridge微架構:CMP, TEST, ADD, SUB, AND, INC, DEC
具備巨集熔合條件的上述指令必須符合以下格式
第一個源/目標運算元是暫存器
注:TEST指令只有兩個源運算元;ADD指令第一個是目的運算元,第二個是源運算元;INC只有一個目的運算元。

第二個源運算元(如果存在)是以下任一:立即數,暫存器數,非RIP相對定址的儲存器數
第二條指令是條件轉移指令。下表描述了每條指令可以與之熔合的分支指令。
Instructions (2nd↓ \  1st →)

TEST

AND

CMP

ADD

SUB

INC

DEC

JO/JNO

Y

Y

N

N

N

N

N

JC/JB/JAE/JNB

Y

Y

Y

Y

Y

N

N

JE/JZ/JNE/JNZ

Y

Y

Y

Y

Y

Y

Y

JNA/JBE/JA/JNBE

Y

Y

Y

Y

Y

N

N

JS/JNS/JP/JPE/JNP/JPO

Y

Y

N

N

N

N

N

JL/JNGE/JGE/JNL/JNG/JG/JNLE

Y

Y

Y

Y

Y

Y

Y

 

如果第一條指令結束於快取行的63位元組上(即快取行行尾),第二條條件分支指令起始於下一個快取行的0位元組上(即快取行行首),這兩條指令不可以做巨集熔合。

由於符合巨集熔合條件的指令對在各種型別的程式中都很常見,所以即便不重新編譯程式,巨集熔合機制也能帶來效能收益。

巨集熔合後的指令都只需要一次分發即可投入執行(因為只生成一條微指令)。這樣既降低了執行延遲,也節省了執行資源。同時,還可以獲得更高的重新命名和指令退役頻寬,增加虛擬儲存容量(即更高的儲存密度),以及用更少的位元位表示更多的操作,從而更加節能。