HN 日本語サマリー

← 一覧へ戻る
プログラミング

90年代のSIMD:Intel Pentium MMXのプログラミング

SIMD in the 90s: Programming Intel's Pentium MMX (pikuma.com)

128 pointsby ibobev54 コメント

要約

この記事は、1990年代後半に登場したIntelのPentium MMXプロセッサにおけるSIMD(Single Instruction, Multiple Data)命令セットのプログラミングについて解説しています。MMXは、マルチメディア処理を高速化するために、複数の整数データを単一の命令で同時に処理する機能を提供しました。SIMDの概念自体はMMXより古く、ILLIAC IVなどのスーパーコンピュータにまで遡りますが、MMXはx86 PCにSIMDを普及させる上で重要な役割を果たしました。

全文翻訳

90年代のSIMD:Intel Pentium MMXのプログラミング 1990年代後半にPCをプログラミングしていたなら、おそらく「Intel Inside Pentium with MMX」というステッカーを覚えているでしょう。MMXはもちろん、大きなマーケティング上のバズワードでしたが、IntelがメインストリームのデスクトップCPUにSIMD(Single Instruction, Multiple Data)命令をもたらそうとした主要な試みでもありました。 Gustavo Pezzi 2026年8月12日 20分読書 私たちのソフトウェアレンダリングモジュールを完了したすべての学生にとって、SIMD(Single Instruction, Multiple Data)のトピックについて質問し、探求し始めるのは通過儀礼のようなものです。今日、私たちはAVX-512、NEON、SVE、そして数千コアを持つGPUを持っています。これらの最新のCPUと拡張機能は、長年の探求、学習、市場圧力の結果であり、それらはすべて多くの歴史やレトロ互換性のノイズをもたらします。いつものように、私は過去を振り返り、技術が始まったばかりの頃に何が起こっていたかを分析することで、さまざまな技術について議論するのが好きです。1990年代後半、多くのプログラマは、初めて手書きのアセンブリ言語を使って、Pentium MMXから数フレーム/秒を絞り出す方法を学んでいました。 Intel Pentium with MMX tech 1997年にタイムトラベルして、MMXのプログラミングがどのようなものだったかを見てみましょう! MMXとは? MMX(MultiMedia eXtensions)は、1997年にPentium MMXプロセッサとともに導入され、グラフィックス、デジタル信号処理、オーディオ、モデムソフトウェアを含むマルチメディア体験を向上させました。これは、パフォーマンスを向上させるためにPentiumチップに組み込まれた57の追加命令セットでした。CPUはMMXモードに切り替える必要があり、x86の8つの80ビット浮動小数点レジスタの最初の64ビットがMMXレジスタに変わりました。 Eight MMX registers (64 bits long) MMXの作成と使用を動機付けた考え方は単純でした。1度に1つの整数を処理する代わりに、CPUは単一の64ビットレジスタにパックされた複数の整数を同時に処理します。マルチメディアソフトウェア(画像処理、オーディオミキシング、ビデオ再生、ゲームなど)では、これにより大幅な高速化が得られる可能性があります。たとえば、8バイトを個別に加算する代わりに: 10 + 20 30 + 40 50 + 60 70 + 80 ... MMXを使用すると、これらすべての8回の加算を単一の命令で実行できます。それが並列処理です!そして、それがSIMDの背後にある主な考え方です。 SIMDとは? 「Single Instruction, Multiple Data」は、並列処理技術の一種です。これは、複数のデータポイントに対して同時に同じ操作を実行する複数の処理要素を持つコンピュータを指します。SIMDは内部的(ハードウェア設計の一部)であり、命令セットアーキテクチャ(ISA)を通じて直接アクセスできます。MMXの場合、Intelは新しいSIMD命令を含めるためにx86命令セットを拡張しました。 MMXは最初のSIMDだったか? いいえ、MMXは間違いなく最初のSIMDではありませんでしたが、x86 PCでSIMDを普及させる上で非常に重要でした。多くの進歩やイノベーションは、パーソナルコンピュータ時代に先行していることを覚えておく必要があります。SIMDも例外ではなく、IntelのMMXよりも何十年も前に遡ります。複数のデータ要素に作用する単一命令を使用するという一般的な考え方は、Pentiumよりもはるかに昔に遡ります。初期の有名な例の1つは、1960年代のILLIAC IVスーパーコンピュータプロジェクトです。ILLIAC IVは、最初の超並列コンピュータでした。このシステムは、当初、256個の64ビット浮動小数点ユニット(FPU)と、毎秒10億回の操作を実行できる4つの中央処理ユニット(CPU)を備えるように設計されていました。 ILLIAC IV photo by Sascha Pohlflepp CC-BY-2.0 要約すると、ILLIAC IVは単一の命令ストリームの下で多数の処理要素を動作させており、現代のSIMD/ベクトルアーキテクチャの重要な祖先となっています。 ILLIAC IV array overview 1960年代から1980年代にかけて、CDC、Crayなどの企業からもアレイ処理マシンが登場しました。 SIMDとアレイプロセッサの違い ベクトル処理とSIMDはまったく同じものではないことを指摘することが重要です。この区別は主に、複数のデータ要素がプロセッサにどのように提示され、ハードウェアがそれらをどのように実行するかにあります。SIMD操作は、基本的にレジスタの幅に結びついています。Cray-1(1976年)は、ベクトルプロセッサであることが特徴でした。8つの64要素ベクトルレジスタを持ち、それぞれが64ビット値を含んでいました。 Cray-1 supercomputer SIMDで見たものと同様に、Cray-1は64個の個別のADD命令を必要としませんでした。したがって、これが明らかにSIMDライクであるとすると、なぜそれを単にSIMDと呼ばないのでしょうか?アーキテクチャ上の区別のせいです。SIMDは固定幅レジスタで動作しますが、Cray-1のベクトルレジスタはシーケンスのコンテナのようなものでした。ベクトルプロセッサは通常、SET VECTOR SIZE命令の存在によって特徴付けられます。このベクトル機能ユニットは、複数のサイクルで要素を処理できます。Cray-1にはVL(ベクトル長)レジスタがあり、その長さを設定する命令がありました。ベクトル機能ユニットは、その後、その数の要素を複数のサイクルで処理しました。配列の残りの追加要素は、単に使用されなかった/サイクルされませんでした。Cray-1のVLレジスタは7ビットでしたが、アーキテクチャは64(2⁶)までの値しか使用しませんでした。これは、Cray-1のベクトルレジスタが最大64個の要素を含んでいたためです。また、言及する価値のある小さな詳細として、Cray-1はVL=0を64と解釈し、ベクトルレジスタの全64要素を処理していました。 MMXの真の意義 ご覧のとおり、SIMDはIntelによって発明されたものではありませんでした。その真の意義は、比較的アクセスしやすいSIMD命令セットをメインストリームのx86 PCに搭載したことでした。それは、私たち(パーソナルコンピュータ愛好家)のほとんどがこの種のテクノロジーを実際に体験できた最初の機会であり、それがMMXがレトロコンピューティングの議論でこれほど注目される理由です。SIMDの発明ではありませんでしたが、SIMDが専門的/高性能コンピューティングから通常のデスクトップソフトウェア開発へと移行した瞬間の一つでした。 MMXレジスタ 前述のように、巧妙な設計上の決定の1つは、Intelがまったく新しいレジスタファイルを​​追加しなかったことです。代わりに、MMXは浮動小数点スタックレジスタを再利用しました。 MM0 MM1 MM2 MM3 MM4 MM5 MM6 MM7 各MMXレジスタは64ビット幅です。内部的には、MMXレジスタはx87浮動小数点レジスタのエイリアスでした。これらの基盤となる浮動小数点レジスタは80ビット長でしたが、MMXは下位64ビットのみにアクセスしました。 Eight MMX registers (64 bits long) この決定はシリコンを節約しましたが、重要な制限も生み出しました。SIMDと浮動小数点演算は相互に排他的でした。MMXは基本的にx87浮動小数点レジスタを「乗っ取って」いるため、MMXマルチメディア演算と浮動小数点演算は共存できませんでした。また、重要なルールも生まれました。まずクリーンアップせずに、MMXとx87浮動小数点コードを混在させないでください。心配しないでください…これらの制限については、すぐにまた詳しく説明します。 Packed Integer Data 単一のMMXレジスタはさまざまなレイアウトを持つことができました。 The same register could represent any of these layouts depending on the instruction you used. 最初のMMXプログラム 8ピクセルをすべて加算したいとします(コンパイラの最適化がないと仮定): for (int i = 0; i < 8; i++) { dest[i] = src1[i] + src2[i]; } MMXバージョンは次のようになります。 movq mm0, [src1] ; loads eight bytes movq mm1, [src2] ; loads eight bytes paddb mm0, mm1 ; performs eight byte additions simultaneously movq [dst], mm0 ; store the result 1つの命令が8回の個別の加算を置き換えました! MMXによる飽和演算 MMXのもう1つの非常に優れた機能は、「飽和」演算を実行できる能力でした。2つの値を加算すると、通常の整数演算はラップアラウンドします。 250 + 20 // = 270, which wraps around to 14 上記の加算は255を超え、通常は14にラップアラウンドします。整数演算のこの「ラップアラウンド」性質は、特にグラフィックスを扱う際には扱いにくい場合があります。ピクセル値を加算する場合、最大輝度は最大輝度のままであってほしいのです!MMXは、このようなケースのために飽和を提供します。命令は単純です: paddusb mm0, mm1 us st