Carved Marker

SSE 介紹 [Page 5]

看了簡單的例子之後,我們現在列出一些 SSE 浮點運算指令所支援的一些基本的運算:

指令Intrinsic功能
addps/addss_mm_add_ps/_mm_add_ss加法
subps/subss_mm_sub_ps/_mm_sub_ss減法
mulps/mulss_mm_mul_ps/_mm_mul_ss乘法
divps/divss_mm_div_ps/_mm_div_ss除法
sqrtps/sqrtss_mm_sqrt_ps/_mm_sqrt_ss平方根
maxps/maxss_mm_max_ps/_mm_max_ss逐項取最大值
minps/minss_mm_min_ps/_mm_min_ss逐項取最小值

這些運算基本上都符合 IEEE 754 中的規範,根據其計算結果,設定適當的旗標(divide-by-zero、invalid 等等),或是產生 exception。這可以由一個 MXCSR 暫存器來設定。MXCSR 暫存器是一個 32 位元的旗標暫存器,可以設定是否要產生各種 exception,並會記錄上次的計算中,發生了哪些情況。下面是 MXCSR 暫存器的說明圖:

MXCSR

以下是 MXCSR 各欄位的說明:

欄位名稱Intrinsic 巨集說明
IEInvalid Operation Flag_MM_EXCEPT_INVALID運算中發生 invalid operation
DEDenormal Flag_MM_EXCEPT_DENORMA試圖載入 denormal value 或對 denormal value 進行運算
ZEDivide-by-Zero Flag_MM_EXCEPT_DIV_ZERO運算中發生 divide by zero
OEOverflow Flag_MM_EXCEPT_OVERFLOW運算中發生 overflow
UEUnderflow Flag_MM_EXCEPT_UNDERFLOW運算中發生 underflow
PEPrecision Flag_MM_EXCEPT_INEXACT運算結果不精確(inexact)
DAZDenormals Are ZerosN/A強制將 denormals 視為 0
IMInvalid Operation Mask_MM_MASK_INVALID關閉 invalid operation exception
DMDenormal Operation Mask_MM_MASK_DENORM關閉 denormal operation exception
ZMDivide-by-Zero Mask_MM_MASK_DIV_ZERO關閉 divide by zero exception
OMOverflow Mask_MM_MASK_OVERFLOW關閉 overflow exception
UMUnderflow Mask_MM_MASK_UNDERFLOW關閉 underflow exception
PMPrecision Mask_MM_MASK_INEXACT關閉 inexact exception
RCRounding ControlN/A設定捨去方式
FZFlush to ZeroN/A打開 Flush-to-zero 模式

上表中有幾個地方是需要特別注意的:

  1. DAZ 若設為 1,則會開啟 Denormals Are Zeros 模式。當此模式開啟時,若來源參數中有任何 denormals,都會被視為 0,而且不會設定 DE 或產生 denormal operation exception。這個模式和 IEEE 754 規範不相容,但是通常會得到更好的效率。另外 DAZ 目前只在 Intel Pentium 4 和 Intel Xeon 處理器上有支援。有關判斷 DAZ 是否支援的方式,請參考 IA-32 Intel Architecture Software Developer's Manual, Volume 1: Basic Architecture, Section 11.6.3。
  2. RC 可以設定成四種方式:00 為 Round to nearest (even),即將運算結果捨去至最接近數值。如果兩個數值同樣接近,則捨去至偶數。01 為 Round down,即往負無限大方向捨去。10 為 Round up,即往正無限大方向捨去。11 則是 Round toward zero (truncate),即往零的方向捨去。
  3. FZ 若設為 1,則會開啟 Flush-to-zero 模式。當此模式開啟,且 underflow exception 被關閉時,若在運算時發生 underflow,則結果為 0(符號同真正結果),且會設定 PE 和 UE。若 underflow exception 未關閉,則此模式無任何影響。注意此模式和 IEEE 754 規範不相容(規範要求 underflow 需產生 denormal 結果),但通常會得到更好的效率。

設定和讀取 MXCSR 同樣有 intrinsic 可以用,即 _mm_getcsr_mm_setcsr。不過,因為 MXCSR 基本上是由 bit field 組成,因此在 xmmintrin.h 裡面也定義了一些方便的巨集。這些巨集包括:

巨集功用
_MM_SET_EXCEPTION_STATE設定 exception 狀態(IE ~ PE)
_MM_GET_EXCEPTION_STATE取得 exception 狀態(IE ~ PE)
_MM_SET_EXCEPTION_MASK設定 exception mask(IM ~ PM)
_MM_GET_EXCEPTION_MASK取得 exception mask(IM ~ PM)
_MM_SET_ROUNDING_MODE設定捨去方式
_MM_GET_ROUNDING_MODE取得目前的捨去方式
_MM_SET_FLUSH_ZERO_MODE設定 Flush-to-zero 模式(_MM_FLUSH_ZERO_ON_MM_FLUSH_ZERO_OFF
_MM_GET_FLUSH_ZERO_MODE取得 Flush-to-zero 模式設定

捨去方式的設定包括:

_MM_ROUND_NEARESTRound to nearest (even)
_MM_ROUND_DOWNRound down
_MM_ROUND_UPRound up
_MM_ROUND_TOWARD_ZERORound toward zero (truncate)

在開機時,所有的 exception mask 都是設定為 1,也就是所有的 exception 都是關閉的。如果有需要的話,可以將其開啟。下面的程式片斷是一個例子:

  • _MM_ALIGN16 float test1[4] = { 0, 0, 0, 1 };
  • _MM_ALIGN16 float test2[4] = { 1, 2, 3, 0 };
  • _MM_ALIGN16 float out[4];
  • _MM_SET_EXCEPTION_MASK(0); // 打開所有的 exception
  • __try {
    • __m128 a = _mm_load_ps(test1);
    • __m128 b = _mm_load_ps(test2);
    • a = _mm_div_ps(a, b);
    • _mm_store_ps(out, a);
  • }
  • __except(EXCEPTION_EXECUTE_HANDLER) { // exception handler
    • if(_mm_getcsr() & _MM_EXCEPT_DIV_ZERO) {
      • cout << "Divide by zero" << endl;
    • }
    • return;
  • }
  • cout << out[3] << endl;

上面的程式在執行時,會產生 divide by zero 的 exception,並進入 exception handler。在 exception handler 中,因為 ZE 會被設定,因此會顯示出 "Divide by zero" 的錯誤訊息。如果把 _MM_SET_EXCEPTION_MASK(0); 這一行去掉,則不會產生 exception,而會直接輸出正無限大(1.#INF)的結果。

[Part 1] [Page 2] [Part 3] [Part 4] [Part 5] [Part 6] [Part 7] [Part 8]

11/7/2001, Ping-Che Chen


Sorry, Traditional Chinese only. This page is encoded in UTF-8.

Copyright© 2000, 2001 Ping-Che Chen