3DNow!
3DNow!(據說是「3D No Waiting!」的縮寫)是由AMD開發的一套SIMD多媒體指令集,支援單精度浮點數的向量運算,用於增強x86架構的電腦在三維圖像處理上的效能。
歷史
1996年Intel首先推出了支援MMX的Pentium處理器,極大地提高了CPU處理多媒體數據的能力,被廣泛地應用於語音合成、語音辨識、音頻影片編解碼、圖像處理和串串流媒體等領域。但是MMX只支援整數運算,浮點數運算仍然要使用傳統的x87協處理器指令。由於MMX與x87的暫存器相互重疊,在MMX代碼中插入x87指令時必須先執行EMMS指令清除MMX狀態,頻繁地切換狀態將嚴重影響效能。這限制了MMX指令在需要大量浮點運算的程式,如三維幾何變換、裁剪和投影中的應用。
另一方面,由於x87古怪的堆疊式暫存器結構,使得硬件上將其管線化化和軟件上合理排程指令都很困難,這成為提高x86架構浮點效能的一個瓶頸。
為了解決以上這兩個問題,AMD公司於1998年推出了包含21條指令的3DNow!指令集,並在其K6-2處理器中實現。K6-2是第一個能執行浮點SIMD指令的x86處理器,也是第一個支援水平浮點暫存器模型的x86處理器。藉助3DNow!,K6-2實現了x86處理器上最快的浮點單元,在每個時鐘周期內最多可得到4個單精度浮點數結果,是傳統x87協處理器的4倍。許多遊戲廠商為3DNow!最佳化了程式,微軟的DirectX 7也為3DNow!做了最佳化,AMD處理器的遊戲效能第一次超過Intel,這大大提升了AMD在消費者心目中的地位。K6-2和隨後的K6-III成為市場上的熱門貨。
1999年,隨着Athlon處理器的推出,AMD為3DNow!增加了5條新的指令,用於增強其在DSP方面的效能,它們被稱為「擴充3DNow!」(Extended 3DNow!)。
為了對抗3DNow!,Intel公司於1999年推出了SSE指令集。SSE幾乎能提供3DNow!的所有功能,而且能在一條指令中處理兩倍多的單精度浮點數;同時,SSE完全支援IEEE 754,在處理單精度浮點數時可以完全代替x87。這迅速瓦解了3DNow!的優勢。
1999年後,隨着主流作業系統和軟件都開始支援SSE並為SSE最佳化,AMD在其2000年發佈的代號為「Thunderbird」的Athlon處理器中添加了對SSE的完全支援(「經典」的Athlon或K7只支援SSE中與MMX有關的部分,AMD稱之為「擴充MMX」即Extended MMX)。隨後,AMD致力於AMD64架構的開發;在SIMD指令集方面,AMD跟隨Intel,為自己的處理器添加SSE2和SSE3支援,而不再改進3DNow!。
2010年八月,AMD宣佈將在新一代處理器中取消除了兩條數據預取指令之外3DNow!指令的支援,並鼓勵開發者將3DNow!代碼重新用SSE實現。
支援檢測
支援3DNow!的CPU的CPUID擴充功能字(EAX=80000001h時執行CPUID指令得到的EDX的內容)的(從低位到高位)第31位元為1。支援擴充3DNow!的CPU的CPUID擴充功能字的(從低位到高位)第30位為1。
K6-2至K10之間AMD所有的x86處理器都支援3DNow!,包括Athlon 64、Opteron和Sempron處理器;AMD將3DNow!從Ryzen、AMD FX處理器移除;Cyrix等一些其他廠家生產的某些處理器也支援3DNow!;但Intel生產的所有處理器都不支援3DNow!。
執行環境
3DNow!指令的執行環境與MMX一樣,都是將8個x87暫存器ST0~ST7的低64位元重新命名為MMX暫存器MM0~MM7,並依平坦模式進行操作(即指令可以任意訪問這8個暫存器中的任何一個而不必使用堆疊)。
由於3DNow!使用的暫存器與x87暫存器重疊,工作切換時,儲存x87暫存器狀態的同時也儲存了3DNow!的狀態,所以3DNow!不需要作業系統的額外支援。只要CPU支援3DNow!,含有3DNow!代碼的程式可以在只考慮到x87狀態的原有的作業系統上不加修改地執行。
由於3DNow!依平坦模式訪問暫存器,對3DNow!浮點單元的管線化變得容易,這也利於編譯器生成高效的浮點代碼。
3DNow!指令集
3DNow!和擴充3DNow!的26條指令從功能上可以分為以下五類。
單精度浮點運算指令
此類指令的運算元均為64位元,其高32位元和低32位元分別是IEEE 754格式的單精度浮點數。大部分指令一次可接受兩個這樣的運算元,並得到兩個單精度浮點數的結果。它們的匯編語言輔助記憶碼都以PF開頭。
3DNow!還包含有計算單精度倒數和開方倒數的指令,並可以依程式需要,得到12位元精度和24位元精度的結果。這些指令一次只能處理一個單精度浮點數。
3DNow!的一個特色是可以將同一暫存器內的64位元運算元中的兩個單精度浮點數相加或相乘,這在複數運算和內積運算中非常有用。Intel直到最近才在SSE3指令集中增加了這項功能,稱之為「水平操作」。
為了保證與舊有作業系統的相容性,與MMX指令一樣,3DNow!指令不引發任何算術異常。3DNow!指令不會生成也不能正確處理NaN和非規格化數,也不支援指定捨入模式。因此3DNow!並不是IEEE 754的一個完整實現,即使是只涉及單精度浮點數時也不能完全代替x87。
增強的MMX指令
PAVGUSB用於求64位元緊縮位元組(8×8位元位元組)的平均值,可用於影片編碼中的像素平均和圖像縮放等。可能是意識到這個功能的重要性,Intel在SSE中添加了功能完全相同的PAVGB指令。
PMULHRW則用來補充MMX指令PMULHW的不足,在緊縮字(4×16位元字)相乘時可以得到比後者更準確的結果。Intel直到最近才在SSSE3中增加了功能相似的指令PMULHRSW。
PSWAPD指令用於交換緊縮雙字(2×32位元字)中兩個雙字數據的位置。
資料類型轉換指令
PF2ID、PI2FD等4條指令用於完成整數和單精度浮點數之間的相互轉換。
數據預取指令
PREFETCH/PREFETCHW指令用於把將要使用到的數據從主記憶體提前載入快取中,以減少訪問主記憶體的指令執行時的延遲。Intel在SSE中添加了類似的PREFETCHTx指令
快速退出MMX狀態指令
FEMMS指令與MMX中的EMMS功能相同,用於退出MMX狀態。在K6-2和K6-III處理器中,FEMMS比EMMS更快;在Athlon及更新的處理器中,FEMMS等同於EMMS。