2026年9月1日(火)掲載 3,963本日 0
HN6022

90年代の衝撃!Intel Pentium MMXにおけるSIMDプログラミングの真髄

SIMD in the 90s: Programming Intel's Pentium MMX

ibobev18日前

議論

6
0ibobevスレ主6018日前

90年代、PCのマルチメディア性能を一気に引き上げたIntelの「MMX」テクノロジー。当時のエンジニアたちを熱狂させたSIMD(Single Instruction, Multiple Data)の原点に立ち返り、Pentium MMXのプログラミングがいかにして当時の限界を突破したのか、その技術的背景と実装の面白さを振り返ります。

1Const-me15日前

補足だけど、SSE1とSSE2は今やAMD64命令セットの必須項目だね。すべての64ビットPCプロセッサで両方のサポートが義務付けられてる。だから、最近のコンパイラは64ビットバイナリをビルドする際、x87 FPUを無視するようになってる。その代わり、floatやdoubleの演算はすべてSSE1やSSE2の命令にコンパイルされるんだ。

2ack_complete15日前

2000年代にオーディオやビデオコーデックのMMXやSSE2最適化をめちゃくちゃやった経験があるよ。MMXはかなり違いを生んだけど、とにかく大変だった。

MMXの最適化は実質アセンブリ言語が必須だったからね。Pentium MMXはインオーダーのデュアルパイプCPUで、コンパイラはMMX組み込み関数をサポートしてたけど、生成されるコードがひどいもんだった。例えばVisual C++ 6は、レジスタ間の移動ばかりで2/3が埋まるようなコードを吐き出して、ALU演算のたびに無駄に値をレジスタ間でやり取りしてたんだ。これはSSE/SSE2の組み込み関数でも同じ問題があった。一番ひどかったのは_mm_set_epi8()っていう組み込み関数で、16個の入力から128ビットのベクタを構築するものだったんだけど、定数で指定しても128ビットの定数ロードを生成するどころか、VS2008はバイト単位のロードを計算するのに80命令近くも生成してたんだ。マイクロソフトがこれを直したのはVS2010になってからだよ。

MMX命令のレイテンシとインオーダーのデュアルパイプアーキテクチャのせいで、アセンブリのループもかなり複雑だった。単純な操作は1サイクルで終わるけど、乗算は3サイクルかかるし、ストアはデータを前もって1サイクル余分に用意しなきゃいけないし、ロードやストアのアドレス計算も1サイクル前に必要だった。レジスタが8個しかないから2~4回のイテレーションを並列に回すっていう選択肢もなくて、結局関数ユニットでボトルネックになる。だから最高性能を出すには、ループの前後に入れ替え用の特殊なコードを挟むような工夫がよく必要だったんだ。

EMMSの問題については過小評価されてると思う。CPUがMMXに切り替わると、x87スタック全体が満杯としてマークされる。EMMS命令を忘れると、ただ奇妙な浮動小数点バグが起きるだけじゃなくて、次のx87の浮動小数点計算がFPスタックオーバーフローのせいでいきなりNaNを吐き出すようになるんだ。さらにそのNaNが伝播していくと、CPUがそれを処理するためにマイクロコードのアシストを必要としてしまう。プログラムがクラッシュしなくても、計算領域全体が汚染されて20倍くらい遅くなることもあったよ。

結局のところ、MMXを終わらせたのはSSE2じゃなくて、SSE、特に浮動小数点だと思う。MMXは浮動小数点に対応してないだけじゃなくて、16ビット符号付き整数と8ビット符号なし整数に特化しすぎてた。32ビット整数へのサポートは特に欠けてたし、パック/アンパック変換がボトルネックだった。3Dをやろうとしても固定小数点が必須で、MMXにはDSPやNEONみたいに丸め処理や暗黙のナロー/ワイド変換、あるいはスウィズル(レジスタ値の入れ替え)の機能がなかったから本当に苦しかった。一方でSSEはIEEE標準の自動丸め機能を持った正真正銘の浮動小数点演算で、スウィズルやinsert/extractみたいな重要な命令もあった。だから3Dが普及した時、MMXよりSSEの方が遥かに便利だったんだよね。

とはいえ、MMXはしばらく画像や信号処理には使えてた。SSE2は幅が倍になったけど、8x8ブロックの動き予測みたいにその幅を活かせないアルゴリズムには意味がなかったしね。それに当時のCPUには64ビットのデータパスしかないものもあって、SSE2演算を分割しなきゃいけなかったんだけど、4-1-1のデコードテンプレートのせいで1サイクルに1命令しかデコードできなかった。結果、MMXレジスタを使ったコードの方がSSEより明らかに速く動くこともあったんだ。これが64ビット版Windowsで混乱を招いて、マイクロソフトはロングモードでx87/MMXを使うべきじゃないと言いつつも、映像処理企業からの問い合わせを受けて、ユーザーモードコード用にx87/MMXレジスタが有効でコンテキストスイッチされることを文書化せざるを得なかったんだ。

3nojokepoke15日前

よく見落とされがちだけど、MMXの普及はめちゃくちゃ遅かったよ。何年もIntelコンパイラしか対応する組み込みデータ型を持ってなかったしね。大きな転機になったのは、Intelの既存ライブラリを使ったDirectX 3のオーディオドライバだった。SIMDが普及するまでに最低でも5年から10年はかかったけど、Intelは進化させるのをやめなかったな。で、結局GPU戦争で負けたわけだけどw Larrabeeにお悔やみを。

4theandrewbailey15日前

MMXレジスタは各64ビット幅です。内部的には、MMXレジスタはx87浮動小数点レジスタのエイリアスでした。

最初のPentium 3(Katmai)の構造のせいで、同じようにx87(とMMX)レジスタがXMMのSSEレジスタのエイリアスになってたけど、それはプログラムからは隠蔽されてたんだ。Coppermineリビジョン以降になって初めて、また別々のレジスタとして扱われるようになったよ。

5gustavopezzi15日前

著者です。共有してくれてありがとう。