Extensions
Mnemonics
IRET, IRETD, IRETQ
Forms
3 (3 Legacy)
Data
Intel XED v2026.08.23

IRET returns from an interrupt or exception handler: it pops the return address, CS and RFLAGS that the event pushed, and in 64-bit mode RSP and SS as well, always, even when the privilege level does not change. A handler can thus resume the interrupted code wherever it was, user or kernel, 64-bit or compatibility mode.

The size of the frame

The operand size sets the size of each of the five slots: 8 bytes for IRETQ (48 CF), 4 for IRETD (CF), 2 with a 66 prefix. A 64-bit handler needs IRETQ, and the mnemonic decides: in our builds, a bare iret in Intel syntax became CF with a warning from the GNU assembler, and 66 CF, the 16-bit form, from Clang 23. Zen 5 ran that 16-bit form in 64-bit mode and loaded RIP and RSP from 2-byte slots, zero-extended: RIP 1234H and RSP 40H.

What it refuses

Zen 5 recorded #GP, with nothing changed, for a frame with a null CS, a CS of RPL 0 at CPL 3, a data segment as CS, a null SS or one of RPL 0 for a return to CPL 3, a code segment as SS, a non-canonical RIP, a RIP past the 4 GiB limit of a compatibility-mode segment, and for any IRET while NT was set, since IA-32e mode has no task to return to. It did load RSP = 8000000000000000H, which is not canonical, without a fault: IRET itself does not check it.

Flags it may not change

At CPL 3 with IOPL 0, IRET leaves IF and IOPL as they were whatever the frame says, as Zen 5 showed with a frame holding IOPL 3 and IF 0. The status flags, TF, DF and NT come from the frame, and AC and ID too except in the 16-bit form.

The manuals differ on RSP

Returning to compatibility mode, Intel’s manual loads all of RSP from the frame, AMD’s only ESP, zero-extended. Zen 5 followed AMD’s: a frame RSP of 1234567810000040H gave RSP 10000040H.

Serializing, and NMIs

Both vendors list IRET among the serializing instructions that need no privilege, as CPUID is. IRET also ends the blocking of NMIs that an NMI’s delivery starts. With FRED, events return through ERETU and ERETS, and an IRET that would change CPL raises #GP. AMD’s Zen 5 guide lists IRET as microcoded.

Forms

Every encoding of IRET that Intel XED knows, one row per XED instruction form (iform). How to read the notation.
InstructionEncodingRequires
IRET IRET66 CFBase instruction set
IRETD IRETDCFBase instruction set
IRETQ 64-bit mode only IRETQREX.W CFLM

Latency and throughput

What the scheduling models of LLVM 23.1.2 give for each form, not measurements: latency / reciprocal throughput in cycles, the ports under them. A row is a model, or models that agree; a dash, a form that its processors lack. Memory forms: latency from the address, ports without the load and store units. Which processors each model covers.
ModelIRET
IRETD
IRETQ
Sandy Bridge6 / 1p5 p23
Haswell, Broadwell, Skylake, Skylake-SP, Ice Lake, Alder Lake6 / 0.5p0236
Sapphire Rapids6 / 0.5p0 p2 p3 p6 p10
Lunar Lake6 / 0.33p0 p2 p4 p20 p21 p22
Bonnell1 / 1p01
Silvermont4 / 1IEC1 MEC
Piledriver5 / 1.5AGLU01 Branch EX1 Load
Zen, Zen 21 / 0.5ALU0 ALU3
Zen 3, Zen 45 / 0.5AGU0 AGU1 AGU2 ALU0 BRU1 LSU Load
Jaguar4 / 1ALU0 ALU1 LAGU

Operation

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

if nt:
    fault(GP, 0)                 # no task to return to in IA-32e mode
n = OSIZE // 8                   # a field: 8 bytes for IRETQ, 4 for
                                 # IRETD, 2 for IRET
t = load(rsp, OSIZE)             # the return address
c = load(rsp + n, OSIZE) & 0xFFFF
f = load(rsp + 2 * n, OSIZE)     # RFLAGS
new_sp = load(rsp + 3 * n, OSIZE)   # 64-bit mode pops RSP and SS
s = load(rsp + 4 * n, OSIZE) & 0xFFFF   # also when the CPL stays
pl = c & 3                       # the CPL to return to: CS's RPL
if c & ~3 == 0:
    fault(GP, 0)                 # a null CS
if pl < CPL:
    fault(GP, c & ~3)            # never to a more privileged level
d = descriptor(c)
if d >> 43 & 3 != 3:
    fault(GP, c & ~3)            # bits 44 and 43: not code
dpl = d >> 45 & 3
if d >> 42 & 1 and dpl > pl:
    fault(GP, c & ~3)            # conforming: a DPL up to the RPL
if not d >> 42 & 1 and dpl != pl:
    fault(GP, c & ~3)            # else the DPL is the RPL
if d >> 47 & 1 == 0:
    fault(NP, c & ~3)
wide = d >> 53 & 1               # L: 64-bit code; else compatibility
                                 # mode
lim = d & 0xFFFF | d >> 32 & 0xF0000
if d >> 55 & 1:
    lim = lim << 12 | 0xFFF      # G: in units of 4 KiB
if wide and not canonical(t):
    fault(GP, 0)
if not wide and t > lim:
    fault(GP, 0)
if s & ~3 == 0:
    if pl == 3 or not wide:
        fault(GP, 0)             # a null SS: only to 64-bit code at
                                 # CPL 0 to 2
else:
    if s & 3 != pl:
        fault(GP, s & ~3)
    e = descriptor(s)
    if e >> 41 & 0xD != 9:
        fault(GP, s & ~3)        # bits 44, 43 and 41: S set, code
                                 # clear, writable set
    if e >> 45 & 3 != pl:
        fault(GP, s & ~3)        # its DPL is the new CPL
    if e >> 47 & 1 == 0:
        fault(SS, s & ~3)
cf = f & 1                       # the status flags, TF, DF and NT at
pf = f >> 2 & 1                  # every operand size
af = f >> 4 & 1
zf = f >> 6 & 1
sf = f >> 7 & 1
tf = f >> 8 & 1
df = f >> 10 & 1
of = f >> 11 & 1
nt = f >> 14 & 1
rf = 0                           # IRET's image has no RF: cleared
if OSIZE != 16:
    rf = f >> 16 & 1             # IRETD and IRETQ load it from the
                                 # image: SDM Volume 3B, 20.3.1.1,
                                 # rev. 093; Zen 5 too (a breakpoint
                                 # at the return address did not
                                 # fire), though APM Volume 3, IRET,
                                 # rev. 3.36, clears it
if OSIZE != 16:
    ac = f >> 18 & 1
    id = f >> 21 & 1
if CPL <= iopl:
    if_ = f >> 9 & 1             # else IF stays
if CPL == 0:
    iopl = f >> 12 & 3
    if OSIZE != 16:
        vif = f >> 19 & 1
        vip = f >> 20 & 1
if not wide:
    if AMD:
        new_sp = low(new_sp, 32)     # into compatibility mode, ESP
                                     # alone, zero-extended: APM (RSP.s,
                                     # of the new stack size), Zen 5
rsp = new_sp                     # all of RSP on Intel's (SDM); IRETD's
                                 # and IRET's zero-extended
ss = s
cs = c                           # and CPL becomes pl
rip = t
# VM stays 0, the other bits of the image are ignored. To an outer
# level, ES, DS, FS and GS become null where the new CPL may not
# use their segments (data, or code that is not conforming, of a
# lower DPL). With FRED enabled, an IRET that would change CPL, or
# enter compatibility mode at CPL 0, raises #GP(c & ~3). IRET also
# ends the blocking of NMIs

Run on AMD Zen 5 (EPYC 9645): 53 cases. Its branches for Intel's processors were not run: no Intel processor ran these forms.

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
IRET IRETD IRETQ 64-bit mode only
stackimplicitread
rSPimplicitread, write
rIPimplicitwrite
RFLAGSimplicitread, write

Flags

T tested, P loaded from the stack; blank: not affected. How to read.
OFSFZFAFPFCFDFIFTFACIOPLNTRFVMVIFVIPID
All forms
PPPPPPPPPPTPTPPTPPPP

Attributes

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

All forms
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.
ISA setCPUIDProcessors
I86

No CPUID bit: part of the base instruction set.

Every x86-64 processor in XED’s model and Zen 3 to Zen 6
I386

No CPUID bit: part of the base instruction set.

Every x86-64 processor in XED’s model and Zen 3 to Zen 6
LONGMODE

LM
CPUID.80000001H:EDX[29] LM

Every x86-64 processor in XED’s model and Zen 3 to Zen 6

More General-purpose instructions

All 109 General-purpose 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. LLVM 23.1.2's x86 scheduling models (commit 85ac56026243): the latency, reciprocal throughput and ports of each form, as llvm-mca reports them.
  4. Intel 64 and IA-32 Architectures Software Developer's Manual, Volume 2 (325383-093, September 2026): Volume 2A, page 3-490 (IRET/IRETD/IRETQ)
  5. Intel 64 and IA-32 Architectures Software Developer's Manual, Volume 3 (325384-093, September 2026)
  6. AMD64 Architecture Programmer's Manual, Volume 2: System Programming (24593, rev. 3.46, October 2026)
  7. AMD64 Architecture Programmer's Manual, Volume 3: General-Purpose and System Instructions (24594, rev. 3.39, October 2026)
  8. 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 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.