|
Tips MMXプログラミング
|
MMXプログラミング
インテルMMXテクノロジーは、インテルPentiumIIプロセッサファミリーおよびMMXテクノロジーPentiumプロセッサ
でIA-32アーキテクチャーに導入されました。MMXテクノロジーはメディアや通信アプリケーションの処理を高速化
するSIMD(Single-Instruction, Multiple-Data)実行モデルがあります。
MMXテクノロジー概要
MMXテクノロジーは64ビットパックド整数データを処理SIMD実行モデルを定義しています。
SIMD実行モデルを導入することで、IA-32アーキテクチャーに以下の機能が追加されますが、
従来のIA-32アプリケーションやOSとの互換性を維持しています。
-
64ビットデータレジスター8個(MMXレジスター)
-
パックドデータ型3個
-
64ビットパックドバイト整数(符号付き/符号なし)
-
64ビットパックドワード整数(符号付き/符号なし)
-
64ビットパックドダブルワード整数(符号付き/符号なし)
-
新しいデータ型をサポート。
MMXテクノロジーの状態を管理する命令
-
CPUID命令
の拡張
MMXテクノロジーには、IA-32アーキテクチャーのすべての実行モード(プロテクティッドモード、
リアルモード、仮想8086モード)からアクセス可能です。MMXテクノロジーの導入で、新しい
実行モードの追加はありません。
MMXテクノロジーのプログラミング環境
MMXテクノロジーには次のような実行環境で実行します。
-
MMXテクノロジーレジスター
8 つのMMXレジスターを使用して、64 ビットパックド整数データの操作を実行します。
これらのレジスターはMM0 〜MM7と呼びます。
-
汎用レジスター
8 つの汎用レジスターと既存のIA-32 アドレス指定モードを組み合わせて、
メモリ内のオペランドをアドレス指定します。(MMXレジスターは、メモリの
アドレス指定には使用できません)。汎用レジスターは、MMX命令で、オペランドの
格納にも使用できます。汎用レジスターは、EAX、EBX、ECX、EDX、EBP、ESI、
EDI、ESP という名前で参照します。
MMXレジスター
MMXテクノロジーのレジスターは、8 つの64 ビットレジスターがあります。これらのレジスタを使用して、
MMXテクノロジーのパックド整数データ型の計算が実行できます。MMXレジスター内の値は、
メモリ内の64 ビットと同じフォーマットを持ちます。MMXレジスターには、64 ビットアクセスモードと
32 ビットアクセスモードの2 種類のデータアクセスモードがあります。
-
64 ビットアクセスモードの使用目的
-
64ビットメモリーアクセス
-
MMXレジスター間の64ビット転送
-
すべてのパック命令、論理演算命令、算術命令
-
アンパック命令
-
32ビットアクセスモードの使用目的
-
32ビットメモリーアクセス
-
汎用レジスターとMMXレジスター間の32ビット転送
-
アンパック命令
IA-32 アーキテクチャーではMMXレジスターを独立したレジスタとして定義していますが、
実際には
FPUデータレジスタスタック(R0 〜 R7)のレジスタ
に別名を付けて使用しています。
MMXテクノロジーのデータ型
MMXテクノロジーでは、以下の64 ビットデータ型がIA-32 アーキテクチャに追加されました。
-
64ビットパックドバイト整数
8個のパックドバイト
-
64ビットパックドワード整数
4個のパックドワード
-
64ビットパックドダブルワード整数
2個のパックドダブルワード
MMX命令は、64 ビットパックドデータ型(パックドバイト、パックドワード、パックド・ダブルワード)と
クワッドワードデータ型を、MMXレジスターとメモリの間またはMMXレジスター同士の間で64 ビット
ブロックで転送します。ただし、MMX命令は、パックドデータ型の算術演算または論理演算を実行する
場合、MMXレジスター内の個々のバイト、ワード、またはダブルワードを並列に処理します。
メモリー内のデータフォルト
メモリーに格納するとき、パックドデータ型のバイト、ワード、ダブルワードが連続したアドレスに
格納されます。最下位のバイト、ワード、ダブルワードが連続するアドレス領域の最下位アドレスに
格納され、最上位のバイト、ワード、ダブルワードが、上位アドレスに格納されます。バイト、ワード、
ダブルワードのメモリへの格納順は常にリトルエンディアン型で、下位アドレスにはデータの下位バイトが
入り、上位アドレスには上位バイトが入ります。
SIMD(Single-Instruction, Multiple-Data)
MMXテクノロジでは、1つの命令で、複数のデータを操作することができます。64ビットのMMXレジスターに
対するバイト、ワード、ダブルワードの算術演算および論理演算は次のような操作(AND、ORなど)を行います
例えば、
PADDSW命令は、第1オペランドの格納先オペランドの内4つの符号付きワード整数を、
読込元オペランド(第2オペランド)内の4つの符号付きワード整数に加算し、得られた4つのワード整数を
格納先(第1オペランド)に格納します。このようにSIMDは複数のデータ要素に対して同一演算を並列に行うので、
ソフトウェアの処理が効率的になります。MMXテクノロジでは、バイト、ワード、ダブルワードのデータ要素が
MMXレジスターに入っている場合のみ並列演算をサポートします
MMXテクノロジがサポートしているSIMD処理は、メディア、通信、グラフィック関係のアプリケーション用途に適しています
このようなアプリケーションでは、サイズの小さいデータ型(バイト、ワード、ダブルワード)に対して同一演算を膨大な
回数実行するような高度なアルゴリズムを使用しています。例えば、オーディオデータは16ビットのワード単位で
処理を行いますので、MMX命令を使用すれば、1命令で4つのワードデータの演算を同時に実行することができます
また、ビデオやグラフィックのデータは8ビット(バイト)単位のパレットで処理する場合が多くあります
この場合では、8つのバイトデータを同時に演算することができます
MMXの計算方式
整数算術演算を実行したときに、演算結果が範囲外になることがあります。演算結果が範囲外の場合、
データ型が小さくなるので格納先オペランドに格納することができません。例えば、符号付きワード整数の
算術演算実行時に、正のオーバーフローが発生し、符号付きの結果が16ビットより大きくなることがあります
MMXテクノロジは、以下の3つの方法で範囲外の結果を処理します
-
ラップアラウンド演算。
範囲外の結果は切り捨てます。(キャリービット、オーバーフロービットは無視され、
演算結果の下位ビットだけが格納先オペランドに格納されます)。ラップアラウンド演算は、
オペランドの範囲を制御して範囲外の結果を防ぐアプリケーションに適しています。しかし、
オペランドの範囲が制御されない場合は、ラップアランド算術によって大きな誤差が
生じることがあります。例えば、2つの大きな符号付き整数を加算すると、正のオーバーフローが
発生し、負の結果が得られることがあります
-
符号付き飽和演算。
符号付き飽和演算では、範囲外の結果は操作対象となる整数サイズで
表現できる符号付き整数の範囲に合わせます。例えば、符号付きワード整数を
操作したときに正のオーバーフローが発生した場合は、結果は
0x7FFF(16ビットの最大の整数)に丸められます。負のオーバーフローが発生した
場合には結果は0x8000に丸められます
-
符号なし飽和演算。
符号なし飽和演算では、範囲外の結果は操作対象となる整数サイズで
表現できる符号なし整数の範囲に合わせます。従って、符号なしバイト整数を
操作したときに正のオーバーフローが発生した場合には、0xFFに丸められます。
負のオーバーフローが発生した場合には0x00に丸められます
飽和算術演算のデータ範囲限界値
|
データ型
|
下限値
|
上限値
|
16進数
|
10進数
|
16進数
|
10進数
|
符号付きバイト
|
0x80
|
-128
|
0x7F
|
127
|
符号付きワード
|
0x8000
|
-32,768
|
0x7FFF
|
32,767
|
符号なしバイト
|
0x00
|
0
|
0xFF
|
255
|
符号なしワード
|
0x0000
|
0
|
0xFFFF
|
65,535
|
飽和算術は、多くのオーバーフローで自然な解が得られます。例えば、カラー計算で飽和算術を
使用すれば、色の反転は起こらないため、色は純粋な黒または白のままとなります。
また、読込元オペランドの範囲チェックをしない場合に、ラップアラウンドによる問題が計算に影響を
及ぼさなくなります。
MMX命令では、例外を発生したりEFLAGSレジスターのフラグをセットすることによってオーバーフローや
アンダーフローを通知することはありません
x87 FPUとの互換性
MMXテクノロジーの状態とはx87 FPU状態の別名で、MMXテクノロジーのサポートするIA-32 アーキテクチャ
のために追加された新規状態でも新規モードでもありません。x87 FPU状態の格納とリストアを行う
浮動小数点命令でもMMXテクノロジー状態を操作することができます。(例えば、コンテキスト
スイッチングの場合など)。MMXテクノロジーでも、x87 FPUとOSとのプログラミング(主にタスクスイッチングで
使用)と同じ技法を使用します。
MMX命令とx87 FPUタグワードの関係
MMX命令の実行後は、必ずx87 FPUタグワード全体が有効(00b)に設定されています。
EMMS命令
(MMXテクノロジー状態のクリア命令)を実行すると、
x87 FPUタグワード全体が空(11b)に設定されます
MMXテクノロジーを利用するアプリケーションの作成
MMXテクノロジーを使用したアプリケーションを作成するときのガイドラインとなります。
MMXテクノロジーがサポートされているかチェックする
アプリケーションは、MMX命令を使用する前に、プロセッサがMMXテクノロジーをサポートしているか
どうかを確認する必要があります。以下の手順でこのチェックを実行します。
-
CPUID命令
を実行して、プロセッサがCPUID命令をサポートしているかどうか
チェックします。プロセッサがCPUID命令をサポートしていない場合は、
無効オペコード例外(#UD)が発生します。
-
CPUID命令を使用して、MMXテクノロジー機能ビットをチェックし、
プロセッサがMMXテクノロジーをサポートしているかどうか確認します。
EAXレジスタの引き数を1 に設定してCPUID 命令を実行し、
ビット23(MMX テクノロジー)が1 にセットされていることを確認します。
-
制御レジスターCR0 内のEMビットが0 に設定されているかどうかチェック
します。これは、x87 FPU のエミュレーションが無効にされていることを示します。
プロセッサがサポートしていないMMX命令を実行しようとしたり、制御レジスターCR0 のEMビットが
1 に設定されているときにMMX命令を実行しようとすると、無効オペコード例外(#UD)が発生します。
次に、MMXテクノロジーを検出するCPUID命令の使用方法を示します。この例はCPUID命令の
詳細な使用手順ではなく、MMXテクノロジーがサポートされているかどうか検出のための概略です。
... ; CPUID命令がサポートされているか確認
...
... ; インテルプロセッサの識別
...
MOV EAX, 1 ; 機能フラグを要求します
CPUID ; 0x0F 0x0A2 CPUID命令
TEST EDX, 0x00800000 ; 機能フラグのIA MMXテクノロジービット
; (EDXのビット23)がセットされているテストします
JNZ MMX_Technology_Found
x87 FPU命令とMMX命令間の移行
1 つのアプリケーション内で、x87 浮動小数点命令とMMX命令の両方を使用できます。
ただし、MMXレジスターはx87 FPUレジスタスタックに対して別名参照されるため、x87 FPU命令と
MMX命令の間の移行を行う際は、コヒーレンシのない結果や予期しない結果が発生しないように、
十分に注意する必要があります。(EMMS命令以外の)MMX命令が実行されると、プロセッサは
x87 FPU状態を次のように変更します。
-
x87 FPUステータスレジスターのTOP(トップオブスタック)の値を0に設定します
-
x87 FPUタグレジスターを有効状態(すべてのフィールドを00bに)設定します
-
MMX命令がMMXレジスターへの書き込みを行うと、対応する浮動小数点レジスター
の指数部(ビット64 〜 79)に1(11b)が書き込まれます。
これらの処置の結果、MMX命令の実行以前のx87 FPU状態は、基本的にはすべて失われます。
x87 FPU命令が実行されるとき、プロセッサは、x87 FPUレジスタースタックおよび制御レジスターの
現在の状態が有効であると見なし、x87 FPU状態を変更することなく、x87 FPU命令を実行します。
アプリケーション内でx87 FPU浮動小数点命令とMMX命令の両方を使用する場合は、以下の
ガイドラインに従うことをお勧めします。
-
x87 FPU命令からMMX命令に移行する際は、後に使用することを考えて
保持しなければならないx87 FPUデータレジスターまたは制御レジスターの
状態をすべて保存しておきます。
FSAVE命令
と
FXSAVE命令
は、x87 FPU
状態
全体を保存します。
-
MMX命令からx87 FPU命令に移行する際は、以下の動作を実行します。
-
後で使用しなければならない、MMXレジスター内のデータをすべて保存します。
FSAVE命令とFXSAVE命令は、MMXレジスターの状態も保存します。
-
EMMS命令を実行して、x87 データレジスターおよび制御レジスターを、
クリアーして、MMXテクノロジー状態をクリアーします。
EMMS命令の使用方法
MMX命令が実行されると、x87 FPUタグレジスターは有効(00b)とマークされます。この状態で
x87 FPU命令を実行すると、x87 FPUレジスタースタックに有効なデータが入っていると見なされるため、
予期しないx87 FPU浮動小数点例外や誤った結果が発生します。EMMS命令は、クリアされている
ものとしてx87 FPUタグレジスターをマークするしますので、この問題を回避できます。
次のいずれかの場合には、必ずEMMS命令を実行しなければなりません。
-
x87 FPU命令を使用しているアプリケーションからMMXテクノロジーライブラリ
を呼び出す場合(MMXテクノロジーコードの最後でEMMS命令を実行します)。
-
MMX命令を使用しているアプリケーションからx87 FPU浮動小数点ライブラリ
を呼び出す場合(x87 FPUコードを呼び出す直前にEMMS命令を実行します)。
-
非プリエンプティブ(協調型)OSにおいて、あるタスクやスレッドのMMXテクノロジー
コードと他のタスクやスレッドの切り替えが行われる場合(ただし、x87 FPUコード
より前にMMX命令を実行することが明らかな場合は除きます)。
MMX命令と、SSE、SSE2、SSE3 を混在させる場合は、EMMS命令を使用する必要はありません。
MMX命令とx87 FPU命令の混在
1 つのアプリケーション内で、x87 FPU浮動小数点命令とMMX命令の両方を使用することができます。
ただし、プロセッサによってはパフォーマンスが低下するため、MMX命令とx87 FPU命令を頻繁に
切り替えることはお勧めしません。MMXテクノロジーコードとx87 FPUコードを混在させる場合は、
以下のガイドラインに従います。
-
MMXテクノロジーコードとx87 FPUコードは、別々のモジュール、プロシージャ、ルーチン内に
置きます。
-
x87 FPUコードのモジュールとMMXテクノロジーコードのモジュール間の移行の前後で、
レジスタの内容に依存しないようにします。
-
MMXテクノロジーコードからx87 FPUコードに移行する際は、(後にMMXレジスターの状態が
必要になる場合は)MMXレジスターの状態を保存し、EMMS命令を実行してMMXテクノロジー
ステートを空にしておきます。
-
x87 FPUコードからMMXテクノロジーコードに移行する際は、(後にx87 FPU状態
が必要になる場合は)x87 FPU状態を保存しておきます。
MMXテクノロジーコードのインターフェース
MMX命令を使用して、すべてのMMXレジスターに直接にアクセス可能です。つまり、プロセッサの
汎用レジスター(EAX、EBXなど)と同じインターフェイス規則が、MMXレジスターの使用時にも
適用されます。MMXテクノロジールーチンへの分岐は、MMXレジスターを使用するか、
または(スタックを介して)メモリーアドレスとMMXレジスターを組み合わせて、パラメータと戻り値を
渡します。MMXレジスターを使用してパラメータを渡す場合は、EMMS命令を使用したり、
MMX テクノロジーコードとx87 FPUコードを混在させてはなりません。MMXテクノロジーデータ型を
サポートしない高水準言語を使用する場合は、パックドデータ型を保持する64 ビット構造として、
MMXテクノロジーデータ型を定義できます。高水準言語でMMX命令をコーディングする場合は、
次のような他の手法が使用できます。
-
スタックを介しポインタを渡すことによって、MMXテクノロジールーチンにパラメータを渡します。
-
構造へのポインタを返すことによって、関数から値を返します。
マルチタスクOSでのMMXテクノロジーコードの使用
アプリケーションはどのようなマルチタスクOS上で実行されるかを考慮して作成します。
タスクスイッチが発生するときに各タスクはその状態をセーブしておかなければなりません。
プロセッサの状態(コンテキスト)は、汎用レジスタおよび浮動小数点/MMXレジスターで構成されます。
OSには次の2種類があります
-
非プリエンプティブ(協調的)マルチタスクOS
-
プリエンプティブマルチタスクOS
非プリエンプティブ・マルチタスクOSでは、コンテキストスイッチの際にFPU状態(または
MMXテクノロジー状態)を保存しません。そのため、直接あるいは間接に制御をOSに返す前に
アプリケーションが自分で必要な状態を保存する必要があります。プリエンプティブマルチタスク
OSでは、コンテキストスイッチの際にFPU状態(またはMMXテクノロジー状態)の保存と復帰を
行います。そのため、アプリケーションが自分でFPU状態(またはMMXテクノロジー状態)の
保存や復帰を行う必要はありません。
MMXテクノロジーコードでの例外処理
MMX命令で発生するメモリーアクセス例外は他のIA-32命令で発生する例外と同じで、
ページフォルト、セグメント不在、境界違反などがあります。MMXテクノロジーコードでは、
既存の例外ハンドラを修正せず使用でき、これらのタイプの例外を処理できます。
保留状態の浮動小数点例外がなければ、MMX命令で数値例外が発生することはありません。
したがって、数値例外を処理するために、既存の例外ハンドラを修正したり、新しい例外
ハンドラを追加する必要はありません。保留状態の浮動小数点例外があるときに、MMX命令を
実行すると数値エラー例外(割込み16 および/ またはFERR#ピンのアサート)が発生します。
例外ハンドラからふきすると、MMX命令が実行を再開します。
レジスターのマッピング
MMXレジスターとそのタグは、浮動小数点レジスタとそのタグにマッピングされています。
MMX命令に対する命令プリフィックスの影響
下記表はMMX命令に対する命令プリフィックスの影響をまとめたものです。予測不可能な動作は、
ある世代のIA-32 プロセッサでは予約済みの動作として扱われ、他の世代のプロセッサでは無効
オペコード例外を発生させることがあります。
MMX命令に対する命令プリフィックスの影響
|
プリフィックスのタイプ
|
MMX命令に対する影響
|
アドレスサイズプリフィックス
(0x67)
|
メモリーオペランドを持つ命令に影響します。
|
メモリーオペランドを持たない命令では予約済みであり、予測不可能な動作を
発生させます。
|
オペランドサイズ
(0x66)
|
予約済みであり、予測不可能な動作を発生させます。
|
セグメントオーバーライド
(0x2E, 0x36, 0x3E, 0x26, 0x64, 0x65)
|
メモリーオペランドを持つ命令に影響します。
|
メモリーオペランドを持たない命令では予約済みであり、予測不可能な動作を
発生させます。
|
リピートプリフィックス
(0xF3)
|
予約済みであり、予測不可能な動作を発生させます。
|
リピートNEプリフィックス
(0xF2)
|
予約済みであり、予測不可能な動作を発生させます。
|
ロックプリフィックス
(0xF0)
|
予約済みであり、無効オペコード(#UD)が発生します。
|
分岐ヒントプリフィックス
(0x2E, 0x3E)
|
予約済みであり、予測不可能な動作を発生させます。
|
命令プリフィックス
を参照してください。