3DNow! 使い方概説の概説
2024-09-14
タグ: #asm興味で 3DNow! の使い方を調べたので簡単に纏める。 本当にざっくりなので「概説の概説」ということで。
いきなりコードを出してしまうが、基本的には、MMX 命令か 3DNow! 付属の整数浮動小数点数変換命令を使ってデータを移動させて、適宜 3DNow! 命令を使って演算をすればいいという話である。
.686
.MMX
.K3D ; 3DNow! を使うときには .K3D が必要
CODE SEGMENT
ASSUME cs:CODE, ds:CODE
ALIGN 4
val_0 dd 1.1
val_1 dd 2.2
val_2 dd 3.3
val_3 dd 4.4
val_4 dd 0 ; val_0 + val_2
val_5 dd 0 ; val_1 + val_3
test_3dnow PROC
movq mm0, qword ptr [val_0]
pfadd mm0, qword ptr [val_2] ; packed floating-point addition
movq qword ptr [val_4], mm0
femms
ret
test_3dnow ENDP
CODE ENDS
END
注意したほうが良さそうな仕様として以下のような点がある(AMD 技術文書 21928 より抜粋)。
- 丸めモードは round-to-nearest か round-to-zero のどちらか1種類しかサポートしない。
- どちらをサポートするかは CPU の実装による。
- AMD の CPU は round-to-nearest で実装されている。
- 例外として
PF2ID
とPI2FD
は実装によらず常に round-to-zero を使う。
- 3DNow! は数値例外を生成せず、ステータスフラグも設定しない。
- 計算結果が有効範囲に収まるのを保証するのはユーザの責任である。
femms
と prefetch
/ prefetchw
以外の命令のエンコーディングは 0fh 0fh ModR/M [sib] [displacement] 3DNow!_suffix
となっており、末尾の 8bit 即値 (3DNow!_suffix
) によって命令を区別する。
メモリオペランドがある場合、セグメントオーバーライドプレフィックスとアドレスサイズオーバーライドプレフィックスが有効となる。
オペランドサイズオーバーライドプレフィックスと REP プレフィックスは無視される。
LOCK プレフィックスがあると例外送出される。
具体例としては以下の表のようになる(32bit アドレッシング)。
機械語 | 解釈 |
---|---|
0f 0f ca b4 | pfmul mm1, mm2 (mod=11b, reg=001b, r/m=010b) |
0f 0f 0b b4 | pfmul mm1, [ebx] (mod=00b, reg=001b, r/m=011b) |
0f 0f 4b 0a b4 | pfmul mm1, [ebx + 10] |
26 0f 0f 0b 9e | pfadd mm1, es:[ebx] |
0f 0f 4c 83 0a 9e | pfadd mm1, [ebx + 4 * eax + 10] |
また、femms
と prefetch
/ prefetchw
のオペコードは以下の通り。
オペコード | 命令 |
---|---|
0f 0e | femms |
0f 0d | prefetch mem8 / prefetchw mem8 |
あとは AMD の技術文書 21928『3DNow! Technology Manual』、22466『AMD Extensions to the 3DNow! and MMX Instruction Sets Manual』 あたりを読んで頑張る。
3DNow! の出番だが、K6-2 から XP より前の Athlon までの CPU には SSE 互換の浮動小数点数 SIMD 命令が入っていないらしい。 よって、これらの CPU を対象にした浮動小数点数演算の高速化では 3DNow! が輝く(筈)。 浮動小数点数演算ユニットの設計などを調べていないので、Athlon XP 以降の CPU では 3DNow! と SSE でどの程度速度差があるかわからないが、互換性の広さ的に SSE を使う方が無難だろう。