像_m128,_m128i,_m128d等變量類型主要是爲了保護您。它們確保您不試圖使用標準運算符(如+, - ,&,|,==,...),並確保編譯器在嘗試分配錯誤類型時會拋出錯誤。這些類型強制編譯器將自己加載到適當的寄存器(在這種情況下是XMM *),但仍然賦予編譯器自由選擇哪一個,或者如果採用了所有適當的寄存器,則將它們本地存儲在堆棧上。它們還確保在任何時候將它們存儲在堆棧中時,它們都保持正確的對齊方式(在這種情況下爲16字節對齊方式),因此依賴對齊方式的內在指令不會導致GPF。
您可以緊緊地,如果你配合這些變量中的一個物理寄存器像使用ASM構造:
__m128i myXMM1 asm("%xmm1");
但最好只讓編譯器做它的魔力,併爲您選擇寄存器以允許更好的優化。
任何數量的這些變量都可以聲明,甚至超量預訂XMM寄存器存儲可能不會導致使用堆棧空間,只要您的工作集寄存器保持較小。編譯器範圍界定通常會在不再使用某個值時實現,並允許優化器不將其存儲回堆棧。有時你可以通過創建自己的作用域堆棧幀幫助編譯出來:
__m128i storedVar;
{
__m128i tempVar1, tempVar2, tempVar3;
// do some operations with tempVar1 -> 3
storedVar = tempVar1;
}
{
__m128i tempVar4, tempVar5, tempVar6, tempVar7, tempVar8;
// do some operations with tempVar4 -> 8
storedVar = tempVar4;
}
return storedVar;
自變量超出範圍在封閉的大括號,編譯器看到的是它用來包含這些值的寄存器現在都被釋放因此它不需要超過可用XMM寄存器的總數。
如果你超配你的註冊商店,並且需要維護所有的值,那麼編譯器將在堆棧上分配合適的大小,並確保它正確對齊,並且XMM寄存器的值將被換出爲堆棧騰出空間來創造新的價值。請記住,堆棧空間的緩存很好,所以寫入和讀取並不像您預期的那樣有害。你採取的真正命中是額外的移動操作來交換它們的必要性。
根據寬度(64位,128位,256位,512位)有不同類型的物理寄存器,顯然與相應的C/C++內部數據類型相關聯。給定寬度(「__m128i」,「__m128d」,...)的不同「風格」實際上可以全部位於給定寬度的任何寄存器中。該類型強制您使用適當的固有類型(_mm_and_si128
與_mm_and_pd
,例如),這反過來又產生該指令的適當版本。
有點像「和」是一個很好的例子,因爲所得的操作將是相同的類型無關的 - 按位「和」。但是使用了錯誤類型可以根據我在英特爾文檔讀過招致延遲。的整數指令和浮點指令有單獨的執行隊列,並且無論何時數據必須從一個執行隊列移動到另一個,有一個懲罰。所以通常它是很好的做法,選擇,從而可以產生相應的說明適當的數據類型,並保持該數據類型的範疇。
就像與通用寄存器中,編譯器負責哪些物理寄存器保持該變量在任何特定時間的調度。使用太多的變量意味着它必須更多地將物體進出物理寄存器,因此編寫代碼的方式是有意義的,以限制在任何點處使用中的變量的數量...... – twalberg