深入理解計算機系統——第三章—3.11浮點代碼

3.11 浮點代碼

處理器的浮點體系結構包括多個方面,會影響對浮點數據操作的程序如何被映射到機器上,包括:
1) 如何存儲和訪問浮點數據。通常是通過某種寄存器方式來完成。
2) 對浮點數據操作的指令。
3) 想函數傳遞浮點數參數和從函數返回浮點數結構的規則。
4) 函數調用過程保持寄存器的規則——例如,一些寄存器被指定爲調用者保存,而其他的被指定爲被調用者保存

歷史回顧:

單指令多數據或SIMD(sim-dee),允許多個數據並行執行同一操作。

名字變遷過程:MMX    \impliesSSE(Streaming SIMD Extension,流式SIMD擴展)    \impliesAVX(Advanced Vector Extension,高級向量擴展)

每個擴展都是管理寄存器組中的數據:
MM寄存器    \impliedbyMMX64位;
XMM寄存器    \impliedbySSE128位;
YMM寄存器    \impliedbyAVX256位。

AVX浮點體系結構允許數據存儲在16個***YMM***寄存器中,它們的名字爲%ymm0~%ymm15。每個YMM寄存器都是256位(32位)。這些寄存器只保存浮點數,只使用低32位(float)或64位)(double)。每個SSE XMM寄存器對應YMM寄存器低32位。
這裏寫圖片描述

3.11.1 浮點傳送和轉換操作

引用內存的指令是標量指令,意味着它們只對單個而不是一組封裝好的數據值進行操作。

指令 目的 描述
vmovss M32M_{32} XX 傳送單精度數
vmovss XX M32M_{32} 傳送單精度數
vmovsd M64M_{64} XX 傳送雙精度數
vmovsd XX M64M_{64} 傳送雙精度數
vmovaps XX XX 傳送對齊的封裝好的單精度數
vmovapd XX XX 傳送對齊的封裝好的雙精度數

  346  \blue{圖\;3-46}\;浮點傳送指令。這些操作在內存和寄存器之間以及一對寄存器之間的傳送值

GCC只用標量傳送操作從內存傳送數據到XMM寄存器或從XMM寄存器傳送數據到內存。
對於兩個XMM寄存器之間傳送數據,GCC會使用兩種指令(vmovss傳送單精度或vmovsd傳送雙精度),兩者不會影響執行速度。
指令中的a表示.aligned的意思。當用於讀寫內存時如果地址不滿足16字節對齊,會導致異常。
示例:
這裏寫圖片描述
把浮點值轉換成整數時,指令會執行截斷(truncation),把值指向0進行舍入,這是C和大多數其他編程語言的要求。

指令 目的 描述
vcvttss2si X/M32X/M_{32} R32R_{32} 用截斷的方法把單精度數轉換成整數
vcvttsd2si X/M64X/M_{64} R64R_{64} 用截斷的方法把單雙度數轉換成整數
vcvttss2siq X/M32X/M_{32} R64R_{64} 用截斷的方法把單精度數轉換成四字整數
vcvttsd2siq X/M64X/M_{64} R64R_{64} 用截斷的方法把雙精度數轉換成四字整數

347    \blue {圖3-47}\qquad 雙操作數浮點指令。浮點數\implies整數

指令 1 2 目的 描述
vcvttsi2ss M32M_{32}/R32R_{32} XX XX 把整數轉換成單精度數
vcvttsi2sd M32M_{32}/R32R_{32} XX XX 把整數轉換成雙精度數
vcvttsi2ssq M64M_{64}/R64R_{64} XX XX 把四字整數轉換成單精度數
vcvttsi2sdq M64M_{64}/R64R_{64} XX XX 把四字整數轉換成雙精度數

348    \blue {圖3-48}\qquad 三操作數浮點指令。第一個源數據類型\implies目的的數據類型, 第二個源值對結果的低位字節沒有影響。
3-48中的指令把整數轉換成浮點數。第一個操作數讀自於內存或一個通用目的寄存器。第二個操作數只會影響結果的高位字節
例如如下指令:

vcvtsi2sdq    %rax, %xmm1, %xmm1

該指令從寄存器%rax讀出一個長整數,把它轉換成數據類型double,並把結果存放進XMM寄存器%xmm1的低字節中。
假設%xmm0的低位4字節保存着一個單精度值,使用如下指令:

vcvtss2sd    %xmm0, %xmm0, %xmm0

把它轉換成一個雙精度值,並將結果存儲在寄存器%xmm0的低8字節。
GCC生成的代碼:

Conversion from single to double precision
1    vunpcklps    %xmm0, %xmm0, %xmm0      `Replace first vector element`
2    vcvtps2pd    %xmm0, %xmm0             `Convert two element to double`

vunpcklps指令通常用來交叉放置來自兩個XMM寄存器的值,把它們存儲到第三個寄存器中(例如:源R1R_1 = [s3s_3, s2s_2, s1s_1, s0s_0], 源R2R_2 = [d3d_3, d2d_2, d1d_1, d0d_0],那麼目的寄存器R3R_3 = [s1s_1, d1d_1, s0s_0, d0d_0]。)。
對於使用三個相同寄存器%xmm0的,RR = [x3x_3, x2x_2, x1x_1, x0x_0]     \implies[x1x_1, x1x_1, x0x_0, x0x_0]。
對於指令vcvtps2pd\Downarrow
RR = [x3x_3, x2x_2, x1x_1, x0x_0]     \implies[x1x_1, x1x_1, x0x_0, x0x_0]
對於指令vunpcklps\Downarrow
[[x_1$, x1x_1, x0x_0, x0x_0]     \implies [dx0dx_0, dx0dx_0],這裏的dx0dx_0是將xx轉換成雙精度後的結果。

對於雙精度轉換爲單精度,·GCC會產生類似的代碼:

Conversion from double to single precsion
1    vmovddup    %xmm0, %xmm0      `Replicate first vector element`
2    vcvtpd2psx    %xmm0, %xmm0    `Convert two vector elements to single`

假設這些指令開始執行前寄存器%xmm0保存着兩個雙精度值[x1x_1, x2x_2]。然後vmovddup指令把它設置爲[x0x_0, x0x_0]。vcvtpd2psx指令把這兩個值轉換成單精度,再存放到該寄存器的低位一般中,並將高位一半置0,得到結果[0.0, 0.0, x0x_0, x0x_0]。
這裏寫圖片描述
**fcvt**的所有參數都是通過通用寄存器傳遞的,因爲它們既不是整數也不是指針。

浮點傳送和轉換操作指令彙總

指令 源1 源2 目的 描述
vmovss M32 NULL X 傳送單精度數
vmovss X NULL M32 傳送單精度數
vmovsd M64 NULL X 傳送雙精度數
vmovsd X NULL M64 傳送雙精度數
vmovaps X NULL X 傳送對齊的封裝好的單精度數
vmovapd X NULL X 傳送對齊的封裝好的雙精度數
vcvttss2si X/M32 NULL R32 用截斷的方法把單精度數轉換成整數
vcvttsd2si X/M64 NULL R32 用截斷的方法把雙精度數轉換成整數
vcvttss2siq X/M32 NULL R64 用截斷的方法把單精度數轉換成四字整數
vcvttsd2siq X/M64 NULL R64 用截斷的方法把雙精度數轉換成四字整數
vcvtsi2ss M32/R32 X X 把整數轉換成單精度數
vcvtsi2sd M32/R32 X X 把整數轉換成雙精度數
vcvtsi2ssq M64/R64 X X 把四字整數轉換成單精度數
vcvtsi2sdq M64/R64 X X 把四字整數轉換成雙精度數
vcvtps2pd X1 NULL X2 **X1中兩個低位單精度值擴展成X2中的兩個雙精度值
vunpcklps X1 X2 X3 交叉放置X1X2的值存儲到X3

注:NULL表示沒有該源。

練習鞏固:
在這裏插入圖片描述

答案:
在這裏插入圖片描述

3.11.2 過程中的浮點代碼

x86-64中,XMM寄存器用來向函數傳遞浮點參數,以及從函數返回浮點值。
1) XMM寄存器%xmm0~%xmm7最多可以傳遞8個浮點參數(額外的可以通過棧傳遞)。
2) 函數使用寄存器xmm0來返回浮點值
3) 所有的XMM寄存器都是調用者保存的。被調用者可以不用保存就覆蓋這些寄存器中任一個。
示例:
這裏寫圖片描述

練習鞏固:(易錯點:注意指針)
在這裏插入圖片描述
答案:
在這裏插入圖片描述

3.11.3 浮點運算操作

3-49描述了一組執行算術運算的標量AVX2浮點指令。

單精度 雙精度 效果 描述
vaddss vaddsd DS2+S1D\leftarrow S_2+S_1 浮點數加
vsubss vsubsd DS2S1D\leftarrow S_2-S_1 浮點數減
vmulss vmulsd DS2×S1D\leftarrow S_2\times S_1 浮點數乘
vdivss vdivsd DS2/S1D\leftarrow S_2/S_1 浮點數除
vmaxss vmaxsd Dmax(S2,S1)D\leftarrow max(S_2,S_1) 浮點數最大值
vminss vminsd Dmin(S2,S1)D\leftarrow min(S_2,S_1) 浮點數最小值
sqrtss sqrtsd DS1D\leftarrow \sqrt{S_1} 浮點數最大值

349\blue{圖3-49}\qquad 標量浮點算術運算。
示例:
在這裏插入圖片描述
在這裏插入圖片描述

練習鞏固:
在這裏插入圖片描述

3.11.4 定義和使用浮點常數

和整數運算操作不同,AVX浮點操作不能以立即數值作爲操作數。相反,編譯器必須爲所有的常量值分配和初始化存儲空間。
示例:
在這裏插入圖片描述

標號 4 4 數值
.LC2 .long 3435973837    \implies.long 0xcccc cccd .long 1073532108    \implies.long 0x3ffc cccc 1.8
.LC3 .long 0    \implies.long 0x0 .long 1077936128    \implies.long 0x4040 0000 32.0

具體編碼過程請使勁點擊它    \implies二進制小數編碼
簡述過程:
1.8編碼過程:
0x3ffc  cccc  cccc  cccd=0x0011  1111  1111  1010  1010  1010  1010  1010  1010  1010  1010  1010  1010  1010  1010  10110\text{x3ffc}\;\text{cccc}\;\text{cccc}\;\text{cccd} = 0\text{x}\red{0}\blue{011\;1111\;1111}\;1010\;1010\;1010\;1010\;1010\;1010\;1010\;1010\;1010\;1010\;1010\;1010\;1011,
s=0  exp=k=11  frac=n=52  s=0\;exp=k=11\;frac=n=52\;exp位不全爲零,屬於情況1,規格化的值,e=1023e=10238位藍色二進制的值。
V=(1)s×M×2E=(1)s×(1+f)×2eBias=(1)s×(1+f)×2e2k11=(1)0×(1+225179981368525281474976710655)×2102321111=1×(1+0.8)×20=1.8V=(-1)^s\times M \times 2^E=(-1)^s\times (1+f) \times 2^{e-Bias}=(-1)^s\times (1+f) \times 2^{e-2^{k-1}-1}\\[2ex]=(-1)^0\times (1+\frac{225179981368525}{281474976710655}) \times 2^{1023-2^{11-1}-1}=1\times(1+0.8)\times 2^0=1.8

32.0編碼過程:
0x4040  0000  0000  0000=0x0100  0000  0100  0000  0000  0000  0000  0000  0000  0000  0000  0000  0000  0000  0000  00000\text{x4040}\;\text{0000}\;0000\;0000 = 0\text{x}\red{0}\blue{100\;0000\;0100}\;0000\;0000\;0000\;0000\;0000\;0000\;0000\;0000\;0000\;0000\;0000\;0000\;0000,
s=0  exp=k=11  frac=n=52  s=0\;exp=k=11\;frac=n=52\;exp位不全爲零,屬於情況1,規格化的值,e=1028e=10288位藍色二進制的值。
V=(1)s×M×2E=(1)s×(1+f)×2eBias=(1)s×(1+f)×2e2k11=(1)0×(1+0281474976710655)×2102821111=1×(1+0)×25=32.0V=(-1)^s\times M \times 2^E=(-1)^s\times (1+f) \times 2^{e-Bias}=(-1)^s\times (1+f) \times 2^{e-2^{k-1}-1}\\[2ex]=(-1)^0\times (1+\frac{0}{281474976710655}) \times 2^{1028-2^{11-1}-1}=1\times(1+0)\times 2^5=32.0

3.11.5 在浮點代碼中使用位級操作

單精度 雙精度 效果 描述
vxorps vorps DS2D\leftarrow S_2 ^ S1S_1 位級異或(EXCLUSIVE-OR
vandps andpd DS2D\leftarrow S_2 & S1S_1 位級與(AND

350XMM128\blue{圖3-50} 對封裝數據的位級操作(這些指令對一個XMM寄存器中的所有128位進行布爾操作)
tips:
產生浮點數0.0的彙編:

vxorpd	%xmm0, %xmm0, %xmm0

3.11.6 浮點比較操作

AVX提供了兩條比較浮點值的指令(類似與CMP指令,但是操作數順序相反):

指令 基於 描述
ucomiss S1,S2S_1, S_2 S2S1S_2-S_1 比較單精度值
ucomisd S1,S2S_1, S_2 S2S1S_2-S_1 比較雙精度值

cmpq一樣,遵循以相反順序列出操作數的ATT格式慣例。參數S2S_2必須在XMM寄存器中。
浮點比較指令會設置三個條件碼:零標誌位 ZF、進位標誌位CF和奇偶標記位PF
兩個操作數中任意一個是NaN時,PF會置1
這裏寫圖片描述
當任一操作數爲NaN時,就會出現無序的情況。可以通過奇偶標誌位發現這種情況。通常jp(jump on parity)指令是條件跳轉,條件就是浮點比較得到一個無序的結果。
示例:
這裏寫圖片描述
解析如下圖
這裏寫圖片描述
練習鞏固:
在這裏插入圖片描述
答案:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章