Introduction
3DNow! came with AMD’s K6-2 in 1998, a year before Intel’s SSE. It does arithmetic on two single-precision (32-bit) floating-point numbers at once, held in the eight 64-bit MMX registers, mm0 to mm7. It was meant for the geometry stage of 3D games. The Athlon added five more instructions in 1999 (AMD calls them the 3DNow! extensions; they are often called Extended 3DNow!), together with integer instructions on MMX registers that match those of SSE. The IDT WinChip 2 and VIA’s early C3 processors also carried 3DNow!. Intel never did.
Because the MMX registers are the x87 registers underneath, a program ends a block of
3DNow! code with femms (or emms) before it uses the x87
unit again.
A program checks for 3DNow! with CPUID leaf 8000_0001h: EDX bit 31, and for the extensions with EDX bit 30.
Dropped. In August 2010 AMD said it would remove 3DNow! from its
processors, apart from prefetch and prefetchw. The
Bulldozer family (family 15h, 2011) and every AMD processor since lack it: CPUID
clears both bits, and the 0F 0F instructions raise #UD. The two prefetches are still
there, with a CPUID bit of their own; they are on the
cache and memory ordering
page.
Encoding
All but femms share one opcode, 0F 0F. The byte that
says which instruction it is comes last, after the ModRM byte and any SIB byte and
displacement, where an immediate would be:
0F 0F /r ib pfadd mm1, mm2/m64 0F 0F C1 9E pfadd mm0, mm1
Every one takes an MMX register in ModRM.reg as its destination and first source,
and an MMX register or a 64-bit memory operand in ModRM.r/m as its second source.
REX.W, REX.R and REX.B have no effect on them. In the tables the final byte is shown
after /r.
The instructions
The two values in a register are called low (bits 31:0) and high (bits 63:32).
Arithmetic
| Instruction | Forms | Encoding | What it does | Set |
|---|---|---|---|---|
pfadd | mm1, mm2/m64 | 0F 0F /r 9E | Adds the two pairs of single-precision values. | 3DNow! (AMD K6-2, 1998) |
pfsub | mm1, mm2/m64 | 0F 0F /r 9A | Subtracts the source values from the destination values. | 3DNow! (AMD K6-2, 1998) |
pfsubr | mm1, mm2/m64 | 0F 0F /r AA | Reverse subtraction: the destination values from the source values. | 3DNow! (AMD K6-2, 1998) |
pfmul | mm1, mm2/m64 | 0F 0F /r B4 | Multiplies the two pairs of values. | 3DNow! (AMD K6-2, 1998) |
pfmax | mm1, mm2/m64 | 0F 0F /r A4 | Keeps the larger value of each pair. | 3DNow! (AMD K6-2, 1998) |
pfmin | mm1, mm2/m64 | 0F 0F /r 94 | Keeps the smaller value of each pair. | 3DNow! (AMD K6-2, 1998) |
pfacc | mm1, mm2/m64 | 0F 0F /r AE | Horizontal add: the low result is the sum of the destination’s two values, the high result the sum of the source’s two values. | 3DNow! (AMD K6-2, 1998) |
pfnacc | mm1, mm2/m64 | 0F 0F /r 8A | Horizontal subtract: low result = destination low − destination high, high result = source low − source high. | Extended 3DNow! (AMD Athlon, 1999) |
pfpnacc | mm1, mm2/m64 | 0F 0F /r 8E | Mixed: low result = destination low − destination high, high result = source low + source high. | Extended 3DNow! (AMD Athlon, 1999) |
Reciprocal and square root
These give a fast approximation, then up to two Newton–Raphson steps refine it to full single precision. The first instruction takes the low value of its source and writes the result to both halves of the destination.
| Instruction | Forms | Encoding | What it does | Set |
|---|---|---|---|---|
pfrcp | mm1, mm2/m32 | 0F 0F /r 96 | Approximate reciprocal (1/x) of the source’s low value, to about 14 bits. | 3DNow! (AMD K6-2, 1998) |
pfrcpit1 | mm1, mm2/m64 | 0F 0F /r A6 | First Newton–Raphson step for the reciprocal: takes x in the destination and the approximation from pfrcp in the source. | 3DNow! (AMD K6-2, 1998) |
pfrsqrt | mm1, mm2/m32 | 0F 0F /r 97 | Approximate reciprocal square root (1/√x) of the source’s low value, to about 15 bits. | 3DNow! (AMD K6-2, 1998) |
pfrsqit1 | mm1, mm2/m64 | 0F 0F /r A7 | First Newton–Raphson step for the reciprocal square root (the destination holds the approximation squared, the source x). | 3DNow! (AMD K6-2, 1998) |
pfrcpit2 | mm1, mm2/m64 | 0F 0F /r B6 | Second and last step, for both the reciprocal and the reciprocal square root. | 3DNow! (AMD K6-2, 1998) |
Comparisons
| Instruction | Forms | Encoding | What it does | Set |
|---|---|---|---|---|
pfcmpeq | mm1, mm2/m64 | 0F 0F /r B0 | Sets each 32-bit result to all ones where destination = source, and to zero elsewhere. | 3DNow! (AMD K6-2, 1998) |
pfcmpge | mm1, mm2/m64 | 0F 0F /r 90 | The same, where destination ≥ source. | 3DNow! (AMD K6-2, 1998) |
pfcmpgt | mm1, mm2/m64 | 0F 0F /r A0 | The same, where destination > source. | 3DNow! (AMD K6-2, 1998) |
Conversions
| Instruction | Forms | Encoding | What it does | Set |
|---|---|---|---|---|
pi2fd | mm1, mm2/m64 | 0F 0F /r 0D | Converts two signed 32-bit integers to single precision. | 3DNow! (AMD K6-2, 1998) |
pf2id | mm1, mm2/m64 | 0F 0F /r 1D | Converts two single-precision values to signed 32-bit integers, truncating; out-of-range values saturate. | 3DNow! (AMD K6-2, 1998) |
pi2fw | mm1, mm2/m64 | 0F 0F /r 0C | Converts the signed 16-bit integer in the low half of each doubleword to single precision. | Extended 3DNow! (AMD Athlon, 1999) |
pf2iw | mm1, mm2/m64 | 0F 0F /r 1C | Converts two single-precision values to signed 16-bit integers, truncating and saturating, each sign-extended to 32 bits. | Extended 3DNow! (AMD Athlon, 1999) |
Integer and data movement
| Instruction | Forms | Encoding | What it does | Set |
|---|---|---|---|---|
pavgusb | mm1, mm2/m64 | 0F 0F /r BF | Averages eight pairs of unsigned bytes, rounding up: (a + b + 1) >> 1. SSE’s pavgb does the same. | 3DNow! (AMD K6-2, 1998) |
pmulhrw | mm1, mm2/m64 | 0F 0F /r B7 | Multiplies four pairs of signed 16-bit integers and keeps the high 16 bits of each 32-bit product, rounded (8000h is added first). | 3DNow! (AMD K6-2, 1998) |
pswapd | mm1, mm2/m64 | 0F 0F /r BB | Copies the source to the destination with its two doublewords swapped. | Extended 3DNow! (AMD Athlon, 1999) |
femms | – | 0F 0E | Fast exit from the MMX state: marks every x87 register empty, like emms, but leaves the register contents undefined, which made it faster on the K6-2. | 3DNow! (AMD K6-2, 1998) |
Notes
- Floating point. The 3DNow! instructions raise no floating-point exceptions and use neither MXCSR nor the x87 control word. They do not follow IEEE 754 in full; AMD’s manual gives how each one treats zeros, denormals, infinities and overflow.
- Prefixes. AMD gives F2 and F3 no meaning on 0F 0F. The disassembler, as LLVM does, takes them as part of the instruction and leaves them out of the text.
- Unknown suffixes. A final byte that is none of the 24 above is
shown as an invalid instruction. AMD’s Geode LX added two more,
pfrcpv(86) andpfrsqrtv(87); the disassembler does not decode them. - The MMX extensions. The integer instructions the Athlon added on
MMX registers (
pavgb,pshufw,pminuband the rest) are the same instructions as in SSE, and are on the SSE page.
Links
Reference
- AMD64 Architecture Programmer’s Manual, Volume 5 – AMD’s reference to the 64-bit media (MMX and 3DNow!) and x87 instructions
- AMD64 Architecture Programmer’s Manual, Volume 3 – AMD’s general-purpose instructions, with the 3DNow! opcode map in appendix A
- Intel 64 and IA-32 Architectures Software Developer’s Manuals – Intel’s manuals, for the MMX registers that 3DNow! shares
- x86 architecture 3DNow! opcodes – sandpile.org’s table of every 3DNow! suffix byte