Extensions
Mnemonics
XRSTOR, XRSTOR64
Forms
2 (2 Legacy)
Data
Intel XED v2026.08.23

XRSTOR loads state components back from an XSAVE area, the layout of which the XSAVE page describes. Which components it touches is the requested-feature bitmap, RFBM, XCR0 AND EDX:EAX. For each component i:

  • RFBM bit i clear: the component stays as it is;
  • RFBM bit i set and XSTATE_BV bit i set in the area’s header: the component is loaded from the area;
  • RFBM bit i set and XSTATE_BV bit i clear: the component is put in its initial state.

XRSTOR64 differs only in the format of the x87 pointers, as FXRSTOR64 does (FXRSTOR).

Initial states

The initial state is zero for the vector and mask registers and PKRU. For the x87 it is what FNINIT gives, control word 037FH and every register empty, but XRSTOR also zeroes the eight registers, which FNINIT leaves alone; Zen 5 did so. MXCSR is the odd one out. In the standard format it is loaded from the area whenever RFBM asks for SSE or AVX, even with SSE’s XSTATE_BV bit clear; in the compacted format only with SSE’s data, and an initialized SSE component gets 1F80H, as on Zen 5.

Faults

XRSTOR raises #GP for:

  • an address not aligned to 64 bytes (Zen 5: an address 16 bytes off);
  • in the standard format, an XSTATE_BV bit for a component not enabled in XCR0 (Zen 5: bit 3, MPX’s, with XCR0 = 2E7H), or nonzero header bytes 8 to 23;
  • in the compacted format, which bit 63 of XCOMP_BV selects, the same for XCOMP_BV, an XSTATE_BV bit outside XCOMP_BV, or nonzero header bytes 16 to 63;
  • an MXCSR value with a bit set that MXCSR_MASK does not allow.

The compacted format is what XSAVEC writes, and XRSTOR accepts it where CPUID leaf 0DH, sub-leaf 1, reports XSAVEC; Zen 5 restored the opmask registers and PKRU from such an area.

Tracking

A component that XRSTOR loaded then counts as in use, one it initialized as not (XINUSE, which XGETBV with ECX = 1 reads), and one outside RFBM as modified; XSAVEOPT uses this to skip work. On Zen 5, SSE stayed in use after an initialization while MXCSR was not 1F80H.

_xrstor(p, mask) and _xrstor64 need -mxsave; GCC 14 and Clang 23 at -O2 split the mask into EDX:EAX and emit one XRSTOR. AMD’s Zen 5 guide lists XRSTOR as microcoded.

Forms

Every encoding of XRSTOR that Intel XED knows, one row per XED instruction form (iform). How to read the notation.
InstructionEncodingRequires
XRSTOR mem XRSTOR_MEMmxsaveNP 0F AE /5XSAVE + OSXSAVE
XRSTOR64 mem XRSTOR64_MEMmxsaveREX.W 0F AE /5XSAVE + OSXSAVE

Operation

What the forms do, in pseudocode that our tests run against results recorded on real processors. How to read.

a = mem.address
if a % 64:
    fault(GP, 0)
rfbm = (edx << 32 | eax) & xcr0      # the components to restore
bv = load(a + 512, 64)               # XSTATE_BV
c = load(a + 520, 64)                # XCOMP_BV
std = c >> 63 == 0                   # the standard format
if std:                              # bytes 23:8 of the header zeros
    bad = bv & ~xcr0 or c
    bad = bad or load(a + 528, 64)
else:                                # the compacted one: 63:16 zeros
    bad = c & ~(xcr0 | 1 << 63) or bv & ~c
    bad = bad or load(a + 528, 384)
if bad:
    fault(GP, 0)
ld = rfbm & 6 if std else rfbm & bv & 2
mx = mxcsr
if ld:                               # MXCSR from the area: with SSE or
    mx = load(a + 24, 32)            # AVX in the standard format, with
    if mx & ~mxcsr_mask:             # SSE's data in the compacted
        fault(GP, 0)
elif rfbm & 2 and not std:
    mx = 0x1F80                      # initial, with SSE's registers
mxcsr = mx
if rfbm & bv & 1:                    # x87 state, as FXRSTOR loads it
    sw = load(a + 2, 16)
    t = sw >> 11 & 7                 # TOP from the area
    for i in range(8):
        v = load(a + 32 + 16 * i, 80)
        st[(t - top + i) % 8] = v
    tags = load(a + 4, 8)
    tw = 0
    for j in range(8):               # Rj empty where its bit is clear
        if not tags >> j & 1:
            tw |= 3 << 2 * j
    ftw = tw
    fcw = load(a, 16)
    fsw = sw
    fop = load(a + 6, 16)
    if OSIZE == 64:                  # REX.W: 64-bit offsets
        fip = load(a + 8, 64)
        fdp = load(a + 16, 64)
    else:
        fip = load(a + 8, 32)
        fcs = load(a + 12, 16)
        fdp = load(a + 16, 32)
        fds = load(a + 20, 16)
elif rfbm & 1:                       # x87 state initialized
    for i in range(8):
        st[i] = 0
    ftw = 0xFFFF                     # all empty
    fcw = 0x037F
    fsw = 0
    fop = fip = fcs = fdp = fds = 0
if rfbm & 2:                         # XMM0 to XMM15, or zeros
    b = a + 160
    for i in range(16):
        v = 0
        if bv & 2:
            v = load(b + 16 * i, 128)
        xmm[i] = v
if rfbm & 4:                         # AVX: bits 255:128
    b = a + xsave_offset(2, c)
    for i in range(16):
        v = 0
        if bv & 4:
            v = load(b + 16 * i, 128)
        ymm[i].dq[1] = v
if rfbm & 0x20:                      # AVX-512: k0 to k7
    b = a + xsave_offset(5, c)
    for i in range(8):
        v = 0
        if bv & 0x20:
            v = load(b + 8 * i, 64)
        opmask[i] = v
if rfbm & 0x40:                      # bits 511:256 of zmm0-15
    b = a + xsave_offset(6, c)
    for i in range(16):
        v = 0
        if bv & 0x40:
            v = load(b + 32 * i, 256)
        zmm[i].qq[1] = v
if rfbm & 0x80:                      # zmm16 to zmm31
    b = a + xsave_offset(7, c)
    for i in range(16):
        v = 0
        if bv & 0x80:
            v = load(b + 64 * i, 512)
        zmm[16 + i] = v
if rfbm & 0x200:                     # PKRU
    v = 0
    if bv & 0x200:
        v = load(a + xsave_offset(9, c), 32)
    pkru = v
# MPX's and AMX's components (3, 4, 17, 18) likewise
u = xinuse & ~rfbm | bv & rfbm       # XINUSE as Zen 5 keeps it, and
if mx != 0x1F80:                     # as XGETBV reads it: SSE in use
    u |= 2                           # while MXCSR is not 1F80H
xinuse = u

Run on AMD Zen 5 (EPYC 9645): 6 cases.

Operands

What each form reads and writes, as Intel XED records it: the operands of its syntax, in order, and the implicit ones that the syntax does not name. How to read.
OperandKindAction
XRSTOR mem XRSTOR64 mem
memexplicitread
EDXimplicitread
EAXimplicitread
XCR0implicitread

Flags

None: XED records no flag that the forms test or change.

Attributes

What else XED records about the forms. How to read.

All forms
aligned memory operand; may abort a TSX transaction

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.

CPUID requirements and processors of the XED ISA sets above. Alternatives are separated by “or”; processors follow XED’s chip model, whose AMD processors end with Zen 2, and the CPU data of this site for Zen 3 to Zen 6.

More XSAVE instructions

Sources

  1. Intel XED v2026.08.23 (commit 0bcb6237345c): forms, encodings, operands, flags, exception classes, attributes, ISA sets, CPUID bits and chip model.
  2. The CPU data of x86-64.net: Zen 3 to Zen 6, from GCC’s -march feature sets and AMD’s Processor Programming References, which the page of each processor cites.
  3. Intel 64 and IA-32 Architectures Software Developer's Manual, Volume 2 (325383-093, September 2026): Volume 2D, page 6-49 (XRSTOR)
  4. Intel 64 and IA-32 Architectures Software Developer's Manual, Volume 1 (253665-093, September 2026)
  5. Linux kernel documentation: Using XSTATE features in user space applications
  6. Intel Advanced Performance Extensions (Intel APX) Architecture Specification, revision 7.0 (July 2025)
  7. Software Optimization Guide for the AMD Zen5 Microarchitecture (58455, rev. 1.00, August 2024), Wayback Machine copy of AMD's ZIP

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 text is our own.