3.11 浮點代碼
處理器的浮點體系結構
包括多個方面,會影響對浮點數據操作的程序如何被映射到機器上,包括:
1) 如何存儲和訪問浮點數據。通常是通過某種寄存器方式來完成。
2) 對浮點數據操作的指令。
3) 想函數傳遞浮點數參數和從函數返回浮點數結構的規則。
4) 函數調用過程保持寄存器的規則——例如,一些寄存器被指定爲調用者保存
,而其他的被指定爲被調用者保存
。
歷史回顧:
單指令多數據或SIMD(sim-dee)
,允許多個數據並行執行同一操作。
名字變遷過程:MMX
SSE(Streaming SIMD Extension,流式SIMD擴展)
AVX(Advanced Vector Extension,高級向量擴展)
。
每個擴展都是管理寄存器組中的數據:
MM
寄存器MMX
,64
位;
XMM
寄存器SSE
,128
位;
YMM
寄存器AVX
。256
位。
AVX
浮點體系結構允許數據存儲在16
個***YMM
***寄存器中,它們的名字爲%ymm0~%ymm15
。每個YMM
寄存器都是256
位(32
位)。這些寄存器只保存浮點數,只使用低32
位(float
)或64
位)(double
)。每個SSE XMM
寄存器對應YMM
寄存器低32
位。
3.11.1 浮點傳送和轉換操作
引用內存的指令是標量
指令,意味着它們只對單個而不是一組封裝好的數據值進行操作。
指令 | 源 | 目的 | 描述 |
---|---|---|---|
vmovss |
傳送單精度數 | ||
vmovss |
傳送單精度數 | ||
vmovsd |
傳送雙精度數 | ||
vmovsd |
傳送雙精度數 | ||
vmovaps |
傳送對齊的封裝好的單精度數 | ||
vmovapd |
傳送對齊的封裝好的雙精度數 |
GCC
只用標量傳送操作從內存傳送數據到XMM
寄存器或從XMM
寄存器傳送數據到內存。
對於兩個XMM
寄存器之間傳送數據,GCC
會使用兩種指令(vmovss
傳送單精度或vmovsd
傳送雙精度),兩者不會影響執行速度。
指令中的a
表示.aligned
的意思。當用於讀寫內存時如果地址不滿足16
字節對齊,會導致異常。
示例:
把浮點值轉換成整數時,指令會執行截斷(truncation)
,把值指向0
進行舍入,這是C
和大多數其他編程語言的要求。
指令 | 源 | 目的 | 描述 |
---|---|---|---|
vcvttss2si |
用截斷的方法把單精度數轉換成整數 | ||
vcvttsd2si |
用截斷的方法把單雙度數轉換成整數 | ||
vcvttss2siq |
用截斷的方法把單精度數轉換成四字整數 | ||
vcvttsd2siq |
用截斷的方法把雙精度數轉換成四字整數 |
指令 | 源1 |
源2 |
目的 | 描述 |
---|---|---|---|---|
vcvttsi2ss |
/ | 把整數轉換成單精度數 | ||
vcvttsi2sd |
/ | 把整數轉換成雙精度數 | ||
vcvttsi2ssq |
/ | 把四字整數轉換成單精度數 | ||
vcvttsi2sdq |
/ | 把四字整數轉換成雙精度數 |
圖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
寄存器的值,把它們存儲到第三個寄存器中(例如:源 = [, , , ], 源 = [, , , ],那麼目的寄存器 = [, , , ]。)。
對於使用三個相同寄存器%xmm0
的, = [, , , ] [, , , ]。
對於指令vcvtps2pd
= [, , , ] [, , , ]
對於指令vunpcklps
x_1$, , , ] [, ],這裏的是將轉換成雙精度後的結果。
對於雙精度轉換爲單精度,·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
保存着兩個雙精度值[, ]。然後vmovddup
指令把它設置爲[, ]。vcvtpd2psx
指令把這兩個值轉換成單精度,再存放到該寄存器的低位一般中,並將高位一半置0
,得到結果[0.0
, 0.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 |
交叉放置 X1和 X2的值存儲到 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 |
浮點數加 | |
vsubss |
vsubsd |
浮點數減 | |
vmulss |
vmulsd |
浮點數乘 | |
vdivss |
vdivsd |
浮點數除 | |
vmaxss |
vmaxsd |
浮點數最大值 | |
vminss |
vminsd |
浮點數最小值 | |
sqrtss |
sqrtsd |
浮點數最大值 |
示例:
練習鞏固:
3.11.4 定義和使用浮點常數
和整數運算操作不同,AVX
浮點操作不能以立即數值作爲操作數。相反,編譯器必須爲所有的常量值分配和初始化存儲空間。
示例:
標號 | 低4 位 |
高4 位 |
數值 |
---|---|---|---|
.LC2 |
.long 3435973837 .long 0xcccc cccd |
.long 1073532108 .long 0x3ffc cccc |
1.8 |
.LC3 |
.long 0 .long 0x0 |
.long 1077936128 .long 0x4040 0000 |
32.0 |
具體編碼過程請使勁點擊它二進制小數編碼
簡述過程:
1.8
編碼過程:
,
exp
位不全爲零,屬於情況1
,規格化的值, 是8
位藍色二進制的值。
32.0
編碼過程:
,
exp
位不全爲零,屬於情況1
,規格化的值, 是8
位藍色二進制的值。
3.11.5 在浮點代碼中使用位級操作
單精度 | 雙精度 | 效果 | 描述 |
---|---|---|---|
vxorps |
vorps |
^ | 位級異或(EXCLUSIVE-OR ) |
vandps |
andpd |
& | 位級與(AND ) |
tips
:
產生浮點數0.0
的彙編:
vxorpd %xmm0, %xmm0, %xmm0
3.11.6 浮點比較操作
AVX
提供了兩條比較浮點值的指令(類似與CMP
指令,但是操作數順序相反):
指令 | 基於 | 描述 |
---|---|---|
ucomiss |
比較單精度值 | |
ucomisd |
比較雙精度值 |
與cmpq
一樣,遵循以相反順序列出操作數的ATT
格式慣例。參數必須在XMM
寄存器中。
浮點比較指令會設置三個條件碼:零標誌位 ZF
、進位標誌位CF
和奇偶標記位PF
。
兩個操作數中任意一個是NaN
時,PF
會置1
。
當任一操作數爲NaN
時,就會出現無序的情況。可以通過奇偶標誌位發現這種情況。通常jp(jump on parity)
指令是條件跳轉,條件就是浮點比較得到一個無序的結果。
示例:
解析如下圖
練習鞏固:
答案: