Instruction
MOVZX
Copies an unsigned byte or word into a wider register, filling the upper bits with zeros.
- Extensions
- Forms
- 7 (7 Legacy)
- Data
- Intel XED v2026.08.23
MOVZX reads a byte or a word and writes it to a wider register with
zeros above it. It is how code loads unsigned char and
unsigned short values and widens them: GCC 14 at -O2 compiles a
read of *p, with p an unsigned char *, to
movzx eax, byte ptr [rdi]. MOVSX fills the upper
bits with copies of the sign bit instead.
Which destination size
Writing a 32-bit register already clears bits 63:32, so
movzx eax, byte ptr [rdi] leaves the same 64-bit value in RAX as the
REX.W form movzx rax, byte ptr [rdi], in one byte less, and
compilers use the 32-bit form for 64-bit results too. No MOVZX takes a
32-bit source: the zero-extension from 32 to 64 bits is a 32-bit
MOV. A 16-bit destination is
the odd one out, keeping bits 63:16 of its register like any other
16-bit write.
Instead of a byte or word MOV
mov al, [rdi] replaces only the low byte of RAX, so afterwards the
register mixes the new byte with what it held before, and every later
reader of RAX depends on both. MOVZX into a 32-bit register writes all
64 bits and leaves nothing of the old value.
The high-byte registers
MOVZX can read AH, CH, DH and BH, which makes bits 15:8 of a value two
instructions away: GCC 14 and Clang 23 both compile (x >> 8) & 0xff
to mov eax, edi and movzx eax, ah. Those four registers exist only
in instructions without a REX prefix; with one, the same register
numbers name SPL, BPL, SIL and DIL. So a MOVZX that reads AH must
write one of the eight original registers, and the 64-bit form, which
needs REX.W, cannot read them at all.
AT&T names
GNU’s AT&T syntax spells MOVZX with two size letters, source first:
movzbl (byte to 32 bits), movzwl (word to 32 bits), movzbw,
movzbq and movzwq. GCC writes movzbl and movzwl even for
64-bit results.
In the optimization guide
What the optimization guide says about MOVZX, a line per claim. Each links to the claim in the guide, with its sources and where they differ.
Out of order
- Move elimination: Intel’s list of moves eliminated from Ivy Bridge on includes
movzxfrom an 8-bit register other than AH, BH, CH and DH into a 32-bit or 64-bit one, which Agner Fog confirmed on Ivy Bridge, and LLVM’s Alder Lake model gives thatmovzxa latency of zero. sources differ - Partial register and flag writes: Writing whole registers avoids the question on every core: Intel advises working on 32-bit registers rather than 8-bit or 16-bit ones, loading bytes and words with
movzx, and choosing zero extension over sign extension where the value allows.
Skylake to Cooper Lake
- Integer execution:
xor,suband the vectorpxor,xorps,pandn,psubandpcmpgtof a register with itself zero it without an execution unit, four a cycle, for 32-bit and 64-bit and all vector registers.
Forms
| Instruction | Encoding | Requires |
|---|---|---|
MOVZX r16/32/64, m8
MOVZX_GPRv_MEMb | 0F B6 /r | Base instruction set |
MOVZX r16/32/64, m16 not in 64-bit mode
MOVZX_GPRv_MEMw | 0F B7 /r | Base instruction set |
MOVZX r64, m16 64-bit mode only
MOVZX_GPR64_MEMw | REX.W 0F B7 /r | Base instruction set |
MOVZX r16, m16 64-bit mode only
MOVZX_GPR16_MEMw | 66 0F B7 /r | Base instruction set |
MOVZX r32, m16 64-bit mode only
MOVZX_GPR32_MEMw | 0F B7 /r | Base instruction set |
MOVZX r16/32/64, r8
MOVZX_GPRv_GPR8 | 0F B6 /r | Base instruction set |
MOVZX r16/32/64, r16
MOVZX_GPRv_GPR16 | 0F B7 /r | Base instruction set |
Latency and throughput
| Model | r16, m8 | r32, m8r64, m8r64, m16r32, m16 | r16, r8 | r32, r8r64, r8 | r32, r16r64, r16 |
|---|---|---|---|---|---|
| Sandy Bridge | 5 / 0.5p23 | 5 / 0.5p23 | 1 / 0.33p015 | 1 / 0.33p015 | 1 / 0.33p015 |
| Haswell, Broadwell, Skylake, Skylake-SP, Ice Lake | 5 / 0.5p23 | 5 / 0.5p23 | 1 / 0.25p0156 | 1 / 0.25p0156 | 1 / 0.25p0156 |
| Alder Lake, Sapphire Rapids | 6 / 0.33p0 p1 p5 p6 p11 | 5 / 0.33p2 p3 p10 | 1 / 0.2p0 p1 p5 p6 p11 | 0 / 0.2p0 p1 p5 p6 p11 | 1 / 0.2p0 p1 p5 p6 p11 |
| Lunar Lake | 6 / 0.33p012345 | 4 / 0.33p20 p21 p22 | 1 / 0.33p135 | 0 / 0.17p012345 | 1 / 0.33p135 |
| Bonnell | 3 / 1.5p1 | 1 / 1p0 | 2 / 1p01 | 1 / 1p0 | 1 / 1p0 |
| Silvermont | 3 / 1MEC | 3 / 1MEC | 1 / 0.5IEC0 IEC1 | 1 / 0.5IEC0 IEC1 | 1 / 0.5IEC0 IEC1 |
| Piledriver | 5 / 1AGLU01 Load | 5 / 1AGLU01 Load | 1 / 1EX0 EX1 | 1 / 1EX0 EX1 | 1 / 1EX0 EX1 |
| Zen | 4 / 0.5AGU0 AGU1 | 4 / 0.5AGU0 AGU1 | 1 / 0.25ALU0 ALU1 ALU2 ALU3 | 1 / 0.25ALU0 ALU1 ALU2 ALU3 | 1 / 0.25ALU0 ALU1 ALU2 ALU3 |
| Zen 2 | 4 / 0.33AGU0 AGU1 AGU2 | 4 / 0.33AGU0 AGU1 AGU2 | 1 / 0.25ALU0 ALU1 ALU2 ALU3 | 1 / 0.25ALU0 ALU1 ALU2 ALU3 | 1 / 0.25ALU0 ALU1 ALU2 ALU3 |
| Zen 3, Zen 4 | 5 / 1AGU0 AGU1 AGU2 LSU Load | 5 / 0.33AGU0 AGU1 AGU2 LSU Load | 1 / 1ALU0 ALU1 ALU2 ALU3 | 1 / 0.25ALU0 ALU1 ALU2 ALU3 | 1 / 0.25ALU0 ALU1 ALU2 ALU3 |
| Jaguar | 3 / 1LAGU | 3 / 1LAGU | 1 / 0.5ALU0 ALU1 | 1 / 0.5ALU0 ALU1 | 1 / 0.5ALU0 ALU1 |
Operation
What the forms do, in pseudocode that our tests run against results recorded on real processors. How to read.
dest.write(src) # zero-extended to OSIZE: a 16-bit register
# keeps bits 63:16, a 32-bit one gets
# bits 63:32 cleared
Run on AMD Zen 5 (EPYC 9645) and an Intel processor under KVM (model hidden): 168 cases. The forms that 64-bit mode lacks were not run: the probe runs in 64-bit mode.
Operands
| Operand | Kind | Action |
|---|---|---|
MOVZX r16/32/64, r/m8 MOVZX r16/32/64, m16 not in 64-bit mode MOVZX r16, m16 64-bit mode only MOVZX r32, m16 64-bit mode only MOVZX r64, m16 64-bit mode only | ||
r16/32/64 | explicit | write |
r/m8, m16 | explicit | read |
MOVZX r16/32/64, r16 | ||
r16/32/64 | explicit | write |
r16 | explicit | read |
Flags
None: XED records no flag that the forms test or change.
CPUID and processors
Each form belongs to an XED ISA set. A form can be used when the processor reports every CPUID bit of one of its ISA set's alternatives.
| ISA set | CPUID | Processors |
|---|---|---|
I386 | No CPUID bit: part of the base instruction set. | Every x86-64 processor in XED’s model and Zen 3 to Zen 6 |
More General-purpose instructions
Sources
- Intel XED v2026.08.23 (commit
0bcb6237345c): forms, encodings, operands, flags, exception classes, attributes, ISA sets, CPUID bits and chip model. - The CPU data of x86-64.net: Zen 3 to Zen 6, from GCC’s
-marchfeature sets and AMD’s Processor Programming References, which the page of each processor cites. - LLVM 23.1.2's x86 scheduling models (commit
85ac56026243): the latency, reciprocal throughput and ports of each form, as llvm-mca reports them. - Intel 64 and IA-32 Architectures Software Developer's Manual, Volume 2 (325383-093, September 2026): Volume 2B, page 4-130 (MOVZX)
- Intel 64 and IA-32 Architectures Software Developer's Manual, Volume 1 (253665-093, September 2026)
The tables are derived from Intel XED, Copyright Intel Corporation, licensed under the Apache License 2.0; x86-64.net converted and reformatted them. The timings come from LLVM's scheduling models, part of the LLVM Project, licensed under the Apache License 2.0 with LLVM Exceptions. The text is our own.