3DNow! 使い方概説の概説

タグ: #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 で実装されている。
    • 例外として PF2IDPI2FD は実装によらず常に round-to-zero を使う。
  • 3DNow! は数値例外を生成せず、ステータスフラグも設定しない。
    • 計算結果が有効範囲に収まるのを保証するのはユーザの責任である。

femmsprefetch / prefetchw 以外の命令のエンコーディングは 0fh 0fh ModR/M [sib] [displacement] 3DNow!_suffix となっており、末尾の 8bit 即値 (3DNow!_suffix) によって命令を区別する。 メモリオペランドがある場合、セグメントオーバーライドプレフィックスとアドレスサイズオーバーライドプレフィックスが有効となる。 オペランドサイズオーバーライドプレフィックスと REP プレフィックスは無視される。 LOCK プレフィックスがあると例外送出される。 具体例としては以下の表のようになる(32bit アドレッシング)。

機械語解釈
0f 0f ca b4pfmul mm1, mm2 (mod=11b, reg=001b, r/m=010b)
0f 0f 0b b4pfmul mm1, [ebx] (mod=00b, reg=001b, r/m=011b)
0f 0f 4b 0a b4pfmul mm1, [ebx + 10]
26 0f 0f 0b 9epfadd mm1, es:[ebx]
0f 0f 4c 83 0a 9epfadd mm1, [ebx + 4 * eax + 10]

また、femmsprefetch / prefetchw のオペコードは以下の通り。

オペコード命令
0f 0efemms
0f 0dprefetch 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 を使う方が無難だろう。


一覧に戻る