● MMX コードとの併用
MMX は FPU のリソースを利用した機能なので、FPU による演算処理中に MMX を使用すると処理内容に干渉します。
- emms 以外の MMX 命令を使用すると、次のような変更が自動で行われます。
- ステータスレジスタのスタックトップポインタを 0 にセットします。
- タグレジスタ全体を 0 にセットします。
- MMX レジスタに書き込みを行うと、対応するレジスタスタックの LSB 〜 63 bit に値がセットされます。また、64 bit 〜 MSB を 1 で埋めます。
- emms 命令を実行すると、タグレジスタ全体を 11b にセットします。これには、MMX で使用したレジスタスタックをリセットする意味があります。
これらの結果、以前の浮動小数点情報は失われます。
floatex.dll の演算は、メモリを積極的に使用する形になりますので、演算過程がメモリに格納されている間は、FPU をどのように使用しても(そのメモリにアクセスしない限り)影響しません。しかし、安全に浮動小数点演算を行うために、本ライブラリでは原則として、MMX との併用を推奨しません。
どうしても MMX を使用しなければならない場合は、次の点に注意してください。
- できるだけ、浮動小数点演算と MMX 処理を区分けしてください。また、FPU 処理の内容に依存する MMX 処理、あるいは MMX 処理に依存する FPU 処理にしないでください。
- MMX の処理が終了次第、タグレジスタをリセットしてください。floatex.dll の関数は、正常な FPU 環境上で動作させる事を想定していますので、MMX の処理で使用した FPU は、浮動小数点演算が行える状態に戻す必要があります。
通常は emms 命令を使用しますが、floatex_reset や floatex_reset2 、floatex_stinit を使用する事もできます(タグの全リセットだけならば、emms 命令の方が高速です)。
- 独自処理の浮動小数点演算の最中に MMX を使用する必要が生じた場合は、FPU 環境を保護してください(参照:「FPU 環境の保護」)。
- コンパイラが MMX でコード生成を行うオプションを持っている場合は、そのオプションをなるべく使用しないでください。必要がある場合は、floatex.dll の関数を使用しているオブジェクトをコンパイル単位で分けて、コンパイラのコード生成が影響しないようにしてください。
実験.MMX が FPU 環境に与える影響
このプログラムでは MMX Pentium 以降が必要です。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <conio.h>
#include "floatex.h"
void print_reg(void); /* 「低水準操作」の「FPU 環境の保護」参照の事 */
void main(void)
{
UINT64 val_qword = 1234567689012345678ui64;
int i;
floatex_reset();
/* スタックトップを適当に変更しておきます */
srand((unsigned)time(NULL));
for(i = rand() % 7 + 1;i;i--)
_asm fincstp
/* レジスタスタックを全て使用 */
_asm{
mov ebx,dword ptr fex_const_8
fld tbyte ptr [ebx]
mov ebx,dword ptr fex_const_7
fld tbyte ptr [ebx]
mov ebx,dword ptr fex_const_6
fld tbyte ptr [ebx]
mov ebx,dword ptr fex_const_5
fld tbyte ptr [ebx]
mov ebx,dword ptr fex_const_4
fld tbyte ptr [ebx]
mov ebx,dword ptr fex_const_3
fld tbyte ptr [ebx]
mov ebx,dword ptr fex_const_2
fld tbyte ptr [ebx]
mov ebx,dword ptr fex_const_1
fld tbyte ptr [ebx]
}
print_reg(); /* 初期状態の表示 */
getch(); /* 一時停止:コンソール上で何かキーを押してください */
/*
MMX レジスタを使用。対応するレジスタスタックの内容が潰れる。
また、スタックトップが 0 にリセットされる。
*/
_asm{
movq mm0,val_qword
movq mm2,val_qword
movq mm4,val_qword
movq mm6,val_qword
}
print_reg();
getch();
/* emms 命令はタグワードを全て 11b (空)にする */
_asm{
emms
}
print_reg();
getch();
floatex_reset();
}
結果.初期スタックトップが R0 の場合
スタックトップ:R0
スタックフォルト:normal
ST(7):00 00 00 00 00 00 00 00:ST(0)
----------------------------------------------------
ST(0) : 1
ST(1) : 2
ST(2) : 3
ST(3) : 4
ST(4) : 5
ST(5) : 6
ST(6) : 7
ST(7) : 8
----------------------------------------------------
スタックトップ:R0
スタックフォルト:normal
ST(7):00 10 00 10 00 10 00 10:ST(0)
----------------------------------------------------
ST(0) : 特殊
ST(1) : 2
ST(2) : 特殊
ST(3) : 4
ST(4) : 特殊
ST(5) : 6
ST(6) : 特殊
ST(7) : 8
----------------------------------------------------
スタックトップ:R0
スタックフォルト:normal
ST(7):11 11 11 11 11 11 11 11:ST(0)
----------------------------------------------------
ST(0) : 空
ST(1) : 空
ST(2) : 空
ST(3) : 空
ST(4) : 空
ST(5) : 空
ST(6) : 空
ST(7) : 空
----------------------------------------------------