Introduction
AVX-512 added eight opmask registers, k0 to k7. Each bit of a mask
belongs to one element of a vector. An EVEX instruction can name a mask in its
destination, {k1}, so that only the elements whose bits are set are
written; and the compare and test instructions write their results into a mask, one bit
per element. How masking, zeroing and the EVEX fields work is explained on the
AVX-512 Foundation page.
The registers are 64 bits wide. The instructions on this page work on 8, 16, 32 or 64 of those bits, named by the last letter of the mnemonic: b, w, d or q. A write clears every bit above the size it writes. The sizes came with different sets:
- AVX-512 F (Intel Xeon Phi Knights Landing, 2016) has the 16-bit forms (KANDW, KMOVW …), enough for the 16 dwords of a zmm register;
- AVX-512 DQ (Intel Skylake-SP, 2017) adds the 8-bit forms, KADDW and KTESTW;
- AVX-512 BW (Skylake-SP, 2017) adds the 32-bit and 64-bit forms, for the 64 bytes of a zmm register.
k0 is special only as a write mask: the EVEX encoding 000 in the mask field means
“no mask”, so {k0} cannot be written. The instructions on this page can read
and write k0 like any other mask register.
These instructions are VEX-encoded, in the 0F map (and 0F 3A for the shifts). Their register operands are all in ModRM.mod = 11 forms, except KMOV, which can load and store memory and move to and from the general registers. A program checks for them as for their sets: CPUID leaf 7, sub-leaf 0, EBX bit 16 (AVX-512 F), bit 17 (DQ) and bit 30 (BW). The operating system must also have enabled the opmask state, XCR0 bit 5, with the other AVX-512 state (bits 6 and 7), which XGETBV reads.
The general-register forms of KMOV also have an EVEX encoding, added by APX so that they can reach the registers r16 to r31. Those are on the APX page.
The instructions
In the Forms column, k1 is ModRM.reg, k2 is VEX.vvvv in the three-operand forms and ModRM.rm in the two-operand ones, and k3 is ModRM.rm.
Logic
| Instruction | Forms | Encoding | What it does | Set |
|---|---|---|---|---|
kandb | k1, k2, k3 | VEX.L1.66.0F.W0 41 /r | k1 = k2 AND k3, 8 bits. | AVX-512 DQ (Skylake-SP, 2017) |
kandw | k1, k2, k3 | VEX.L1.0F.W0 41 /r | k1 = k2 AND k3, 16 bits. | AVX-512 F (Knights Landing, 2016) |
kandd | k1, k2, k3 | VEX.L1.66.0F.W1 41 /r | k1 = k2 AND k3, 32 bits. | AVX-512 BW (Skylake-SP, 2017) |
kandq | k1, k2, k3 | VEX.L1.0F.W1 41 /r | k1 = k2 AND k3, 64 bits. | AVX-512 BW (Skylake-SP, 2017) |
kandnb | k1, k2, k3 | VEX.L1.66.0F.W0 42 /r | k1 = (NOT k2) AND k3, 8 bits. | AVX-512 DQ (Skylake-SP, 2017) |
kandnw | k1, k2, k3 | VEX.L1.0F.W0 42 /r | k1 = (NOT k2) AND k3, 16 bits. | AVX-512 F (Knights Landing, 2016) |
kandnd | k1, k2, k3 | VEX.L1.66.0F.W1 42 /r | k1 = (NOT k2) AND k3, 32 bits. | AVX-512 BW (Skylake-SP, 2017) |
kandnq | k1, k2, k3 | VEX.L1.0F.W1 42 /r | k1 = (NOT k2) AND k3, 64 bits. | AVX-512 BW (Skylake-SP, 2017) |
korb | k1, k2, k3 | VEX.L1.66.0F.W0 45 /r | k1 = k2 OR k3, 8 bits. | AVX-512 DQ (Skylake-SP, 2017) |
korw | k1, k2, k3 | VEX.L1.0F.W0 45 /r | k1 = k2 OR k3, 16 bits. | AVX-512 F (Knights Landing, 2016) |
kord | k1, k2, k3 | VEX.L1.66.0F.W1 45 /r | k1 = k2 OR k3, 32 bits. | AVX-512 BW (Skylake-SP, 2017) |
korq | k1, k2, k3 | VEX.L1.0F.W1 45 /r | k1 = k2 OR k3, 64 bits. | AVX-512 BW (Skylake-SP, 2017) |
kxnorb | k1, k2, k3 | VEX.L1.66.0F.W0 46 /r | k1 = NOT (k2 XOR k3), 8 bits. With k2 = k3 it sets every bit, the usual way to make an all-ones mask. | AVX-512 DQ (Skylake-SP, 2017) |
kxnorw | k1, k2, k3 | VEX.L1.0F.W0 46 /r | k1 = NOT (k2 XOR k3), 16 bits. | AVX-512 F (Knights Landing, 2016) |
kxnord | k1, k2, k3 | VEX.L1.66.0F.W1 46 /r | k1 = NOT (k2 XOR k3), 32 bits. | AVX-512 BW (Skylake-SP, 2017) |
kxnorq | k1, k2, k3 | VEX.L1.0F.W1 46 /r | k1 = NOT (k2 XOR k3), 64 bits. | AVX-512 BW (Skylake-SP, 2017) |
kxorb | k1, k2, k3 | VEX.L1.66.0F.W0 47 /r | k1 = k2 XOR k3, 8 bits. | AVX-512 DQ (Skylake-SP, 2017) |
kxorw | k1, k2, k3 | VEX.L1.0F.W0 47 /r | k1 = k2 XOR k3, 16 bits. | AVX-512 F (Knights Landing, 2016) |
kxord | k1, k2, k3 | VEX.L1.66.0F.W1 47 /r | k1 = k2 XOR k3, 32 bits. | AVX-512 BW (Skylake-SP, 2017) |
kxorq | k1, k2, k3 | VEX.L1.0F.W1 47 /r | k1 = k2 XOR k3, 64 bits. | AVX-512 BW (Skylake-SP, 2017) |
knotb | k1, k2 | VEX.L0.66.0F.W0 44 /r | k1 = NOT k2, 8 bits. | AVX-512 DQ (Skylake-SP, 2017) |
knotw | k1, k2 | VEX.L0.0F.W0 44 /r | k1 = NOT k2, 16 bits. | AVX-512 F (Knights Landing, 2016) |
knotd | k1, k2 | VEX.L0.66.0F.W1 44 /r | k1 = NOT k2, 32 bits. | AVX-512 BW (Skylake-SP, 2017) |
knotq | k1, k2 | VEX.L0.0F.W1 44 /r | k1 = NOT k2, 64 bits. | AVX-512 BW (Skylake-SP, 2017) |
Arithmetic, shifts and unpacking
| Instruction | Forms | Encoding | What it does | Set |
|---|---|---|---|---|
kaddb | k1, k2, k3 | VEX.L1.66.0F.W0 4A /r | k1 = k2 + k3, as 8-bit integers; the carry is lost. | AVX-512 DQ (Skylake-SP, 2017) |
kaddw | k1, k2, k3 | VEX.L1.0F.W0 4A /r | k1 = k2 + k3, as 16-bit integers. | AVX-512 DQ (Skylake-SP, 2017) |
kaddd | k1, k2, k3 | VEX.L1.66.0F.W1 4A /r | k1 = k2 + k3, as 32-bit integers. | AVX-512 BW (Skylake-SP, 2017) |
kaddq | k1, k2, k3 | VEX.L1.0F.W1 4A /r | k1 = k2 + k3, as 64-bit integers. | AVX-512 BW (Skylake-SP, 2017) |
kshiftlb | k1, k2, imm8 | VEX.L0.66.0F3A.W0 32 /r ib | k1 = k2 shifted left by imm8, in 8 bits; a count above 7 gives 0. | AVX-512 DQ (Skylake-SP, 2017) |
kshiftlw | k1, k2, imm8 | VEX.L0.66.0F3A.W1 32 /r ib | k1 = k2 shifted left by imm8, in 16 bits; a count above 15 gives 0. | AVX-512 F (Knights Landing, 2016) |
kshiftld | k1, k2, imm8 | VEX.L0.66.0F3A.W0 33 /r ib | k1 = k2 shifted left by imm8, in 32 bits; a count above 31 gives 0. | AVX-512 BW (Skylake-SP, 2017) |
kshiftlq | k1, k2, imm8 | VEX.L0.66.0F3A.W1 33 /r ib | k1 = k2 shifted left by imm8, in 64 bits; a count above 63 gives 0. | AVX-512 BW (Skylake-SP, 2017) |
kshiftrb | k1, k2, imm8 | VEX.L0.66.0F3A.W0 30 /r ib | k1 = k2 shifted right (logically) by imm8, in 8 bits. | AVX-512 DQ (Skylake-SP, 2017) |
kshiftrw | k1, k2, imm8 | VEX.L0.66.0F3A.W1 30 /r ib | k1 = k2 shifted right by imm8, in 16 bits. | AVX-512 F (Knights Landing, 2016) |
kshiftrd | k1, k2, imm8 | VEX.L0.66.0F3A.W0 31 /r ib | k1 = k2 shifted right by imm8, in 32 bits. | AVX-512 BW (Skylake-SP, 2017) |
kshiftrq | k1, k2, imm8 | VEX.L0.66.0F3A.W1 31 /r ib | k1 = k2 shifted right by imm8, in 64 bits. | AVX-512 BW (Skylake-SP, 2017) |
kunpckbw | k1, k2, k3 | VEX.L1.66.0F.W0 4B /r | k1 bits 7–0 = k3 bits 7–0, bits 15–8 = k2 bits 7–0. | AVX-512 F (Knights Landing, 2016) |
kunpckwd | k1, k2, k3 | VEX.L1.0F.W0 4B /r | k1 bits 15–0 = k3 bits 15–0, bits 31–16 = k2 bits 15–0. | AVX-512 BW (Skylake-SP, 2017) |
kunpckdq | k1, k2, k3 | VEX.L1.0F.W1 4B /r | k1 bits 31–0 = k3 bits 31–0, bits 63–32 = k2 bits 31–0. | AVX-512 BW (Skylake-SP, 2017) |
Tests
These two set the flags and write no register. OF, SF, AF and PF are cleared.
| Instruction | Forms | Encoding | What it does | Set |
|---|---|---|---|---|
kortestb | k1, k2 | VEX.L0.66.0F.W0 98 /r | ZF = 1 if k1 OR k2 is all zeros; CF = 1 if it is all ones (8 bits). | AVX-512 DQ (Skylake-SP, 2017) |
kortestw | k1, k2 | VEX.L0.0F.W0 98 /r | The same over 16 bits. | AVX-512 F (Knights Landing, 2016) |
kortestd | k1, k2 | VEX.L0.66.0F.W1 98 /r | The same over 32 bits. | AVX-512 BW (Skylake-SP, 2017) |
kortestq | k1, k2 | VEX.L0.0F.W1 98 /r | The same over 64 bits. | AVX-512 BW (Skylake-SP, 2017) |
ktestb | k1, k2 | VEX.L0.66.0F.W0 99 /r | ZF = 1 if k1 AND k2 is all zeros; CF = 1 if (NOT k1) AND k2 is all zeros (8 bits). | AVX-512 DQ (Skylake-SP, 2017) |
ktestw | k1, k2 | VEX.L0.0F.W0 99 /r | The same over 16 bits. | AVX-512 DQ (Skylake-SP, 2017) |
ktestd | k1, k2 | VEX.L0.66.0F.W1 99 /r | The same over 32 bits. | AVX-512 BW (Skylake-SP, 2017) |
ktestq | k1, k2 | VEX.L0.0F.W1 99 /r | The same over 64 bits. | AVX-512 BW (Skylake-SP, 2017) |
Moves
| Instruction | Forms | Encoding | What it does | Set |
|---|---|---|---|---|
kmovb | k1, k2/m8m8, k1k1, r32r32, k1 | VEX.L0.66.0F.W0 90 /rVEX.L0.66.0F.W0 91 /rVEX.L0.66.0F.W0 92 /rVEX.L0.66.0F.W0 93 /r | Moves 8 bits between mask registers, memory and the low byte of a general register. A move into r32 zero-extends. | AVX-512 DQ (Skylake-SP, 2017) |
kmovw | k1, k2/m16m16, k1k1, r32r32, k1 | VEX.L0.0F.W0 90 /rVEX.L0.0F.W0 91 /rVEX.L0.0F.W0 92 /rVEX.L0.0F.W0 93 /r | Moves 16 bits. | AVX-512 F (Knights Landing, 2016) |
kmovd | k1, k2/m32m32, k1k1, r32r32, k1 | VEX.L0.66.0F.W1 90 /rVEX.L0.66.0F.W1 91 /rVEX.L0.F2.0F.W0 92 /rVEX.L0.F2.0F.W0 93 /r | Moves 32 bits. | AVX-512 BW (Skylake-SP, 2017) |
kmovq | k1, k2/m64m64, k1k1, r64r64, k1 | VEX.L0.0F.W1 90 /rVEX.L0.0F.W1 91 /rVEX.L0.F2.0F.W1 92 /rVEX.L0.F2.0F.W1 93 /r | Moves 64 bits. Intel’s manual gives the general-register forms as valid in 64-bit mode only. | AVX-512 BW (Skylake-SP, 2017) |
Notes
- Only KORTEST and KTEST change the flags. The rest leave them alone.
- The register forms need ModRM.mod = 11, and only KMOV at 90 and 91 takes memory. Intel’s manual gives the three-operand forms with VEX.L = 1 and the others with VEX.L = 0; our decoder shows the other value as an invalid instruction.
- KMOV at 92 and 93 with VEX.W = 1 and no F2 prefix is not an instruction.
- The decoder’s text follows LLVM’s (llvm-objdump, Intel syntax) for every form here.
Links
Reference
- Intel 64 and IA-32 Architectures Software Developer’s Manuals – Intel’s manual; volume 1 describes the opmask registers, and volume 2 each K instruction
- AMD64 Architecture Programmer’s Manual, Volume 4 – AMD’s reference to the 128-bit, 256-bit and 512-bit media instructions
- x86 and amd64 instruction reference – Félix Cloutier’s copy of the instruction pages of Intel’s manual