Dot-Net

為什麼 .NET 使用 SIMD 而不是 x87 進行並非 SIMD 固有的數學運算?

  • April 4, 2021

這是一個好奇的問題,比什麼都重要。我正在查看此程式碼反彙編(C#,64 位,發布模式,VS 2012 RC):

           double a = 10d * Math.Log(20d, 2d);
000000c8  movsd       xmm1,mmword ptr [00000138h] 
000000d0  movsd       xmm0,mmword ptr [00000140h] 
000000d8  call        000000005EDC7F50 
000000dd  movsd       mmword ptr [rsp+58h],xmm0 
000000e3  movsd       xmm0,mmword ptr [rsp+58h] 
000000e9  mulsd       xmm0,mmword ptr [00000148h] 
000000f1  movsd       mmword ptr [rsp+30h],xmm0 
           a = Math.Pow(a, 6d);
000000f7  movsd       xmm1,mmword ptr [00000150h] 
000000ff  movsd       xmm0,mmword ptr [rsp+30h] 
00000105  call        000000005F758220 
0000010a  movsd       mmword ptr [rsp+60h],xmm0 
00000110  movsd       xmm0,mmword ptr [rsp+60h] 
00000116  movsd       mmword ptr [rsp+30h],xmm0 

…並發現編譯器在這裡沒有對日誌使用 x87 指令(Power 使用日誌),這很奇怪。當然,我不知道呼叫位置的程式碼是什麼,但我知道 SIMD 沒有 Log 功能,這使得這個選擇更加奇怪。此外,這裡沒有任何東西是並行化的,那麼為什麼是 SIMD 而不是簡單的 x87?

順便說一句,我還發現沒有使用 x87 FYL2X指令很奇怪,該指令專為第一行程式碼中所示的情況而設計。

任何人都可以對此有所了解嗎?

這裡有兩個不同的點。首先,為什麼編譯器使用 SSE 寄存器而不是 x87 浮點堆棧作為函式參數,其次為什麼編譯器不只使用可以計算對數的單條指令。

不使用對數指令最容​​易解釋,x86 中的對數指令被定義為精確到 80 位,而您使用的是只有 64 位的雙精度指令。計算精度為 64 位而不是 80 位的對數要快得多,而且速度的提高足以彌補必須在軟體中而不是在矽片中進行的計算。

SSE 寄存器的使用更難以以令人滿意的方式解釋。簡單的答案是 x64 呼叫約定要求將函式的前四個浮點參數傳遞給xmm0through xmm3

下一個問題當然是為什麼呼叫約定告訴你這樣做而不是使用浮點堆棧。答案是本機 x64 程式碼根本很少使用 x87 FPU,而是使用 SSE 代替。這是因為 SSE 中的乘法和除法更快(又是 80 位與 64 位的問題),並且 SSE 寄存器的操作速度更快(在 FPU 中,您只能訪問堆棧頂部,並旋轉 FPU 堆棧通常是現代處理器上最慢的操作,實際上有些處理器專門為此目的增加了一個額外的流水線階段)。

引用自:https://stackoverflow.com/questions/12380017