在Intel Haswell架構里引入了Gather特性。它使得CPU可以使用向量索引存儲器編址從存儲器取非連續的數據元素。這些gather指令引入了一種新的存儲器尋址形式,該形式由一個基地址寄存器(仍然是通用目的寄存器)和通過一個向量寄存器(XMM或YMM)所指定的多個索引構成。數據元素大小支持32位與64位,並且數據類型支持浮點型和整型。
我們先回顧一下普通的x86尋址方式:[<base register> + <index register> * <scale> + <offset>]
在AT&T形式下表達為:<offset>(<base register>, <index register>, <scale>)
其中,<base register>為基地址寄存器;<index register>為索引寄存器;<scale>為刻度因子,它是一個立即數,並僅支持0,1,2,4,8這幾個值;<offset>表示偏移量,它是一個立即數。
那么下面我們就先來談談上面所提到的向量存儲器尋址。
向量SIB(VSIB)存儲器尋址
在AVX2中,跟在ModR/M字節后面的SIB(S表示Scale;I表示Index;B表示Base)字節可以支持對一組線性地址的VSIB存儲器尋址。VSIB尋址僅在AVX2指令的子集中支持。VSIB存儲器尋址要求32位或64位的有效尋址。在32位模式下,當地址大小屬性被重載為16位時,VSIB尋址不被支持。在16位保護模式下,VSIB尋址是被允許的,若地址大小屬性被重載為32位的話。此外,VSIB存儲器尋址僅伴隨VEX前綴而被支持。
在VSIB存儲器尋址中,SIB字節由以下部分組成:
● 刻度域(位7:6)指定了刻度因子。
● 索引域(位5:3)指定了向量索引寄存器的寄存器編號,該向量存儲器中的每個元素都指定了一個索引。
● 基地址域(位2:0)指定了基地址寄存器的編號。
比如:
vgatherdpd %xmm0, 128(%rdi, %xmm2, 4), %xmm3
上述指令中,基地址寄存器為RDI,索引寄存器為XMM2,刻度因子是4,偏移量是128。而指令vgatherdpd是將索引寄存器的元素作為雙字(即4字節)進行划分,然后乘上刻度因子后加到基地址上。而偏移量則作用於每個基地址元素。
下面我們將提供一個比較完整的示例代碼來描述VGATHERDPD指令。
先看匯編指令:
_InstTest: // 設置索引寄存器的每個元素 mov $4, %eax // 前一個索引為4 movd %eax, %xmm2 mov $8, %eax // 后一個索引為8 pinsrd $1, %eax, %xmm2 // 將兩個double元素的mask全都置1 mov $0xffffffffffffffff, %rax movq %rax, %xmm0 punpcklqdq %xmm0, %xmm0 vgatherdpd %xmm0, 8(%rdi, %xmm2, 2), %xmm3 ret
這里,rdi寄存器作為第一個輸入參數,存放了基地址。
下面是C函數的調用:
int main(void) { extern void InstTest(void *p); unsigned __attribute__((aligned(64))) buffer[] = { 0x01020304, 0x05060708, 0x090a0b0c, 0x10121314, 0x15161718, 0x191a1b1c, 0x20212223, 0x24252627 }; InstTest(buffer); return 0; }
我們通過在return 0;這條語句設置斷點,然后通過lldb調試器可以發現XMM3寄存器的最后內容為:
xmm3 = {0x18 0x17 0x16 0x15 0x1c 0x1b 0x1a 0x19 0x23 0x22 0x21 0x20 0x27 0x26 0x25 0x24}
。
以上代碼的編譯環境為:OS X 10.9.3, Xcode 5.1, Apple LLVM 5.1
運行環境為:MacBook Air 2013版,Intel Core i7 4650U, 8GB DDR3。