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。