Extensions
Forms
1 (1 Legacy)
Data
Intel XED v2026.08.23

UIRET returns from the handler of a user interrupt. Delivery of a user interrupt happens only in 64-bit mode at CPL 3 and never enters the kernel: the processor moves RSP down by an amount the operating system chose, or switches to another stack, aligns it to 16 bytes and pushes four quadwords, the old RSP, RFLAGS, the return RIP and last the vector, a number from 0 to 63. It then clears UIF, which holds further user interrupts back, and jumps to the handler. UIRET pops RIP, RFLAGS and RSP in that order, so the handler must first drop the vector itself.

In compiled code

With -muintr, GCC 14 and Clang 23 at -O2 compile a function declared __attribute__((interrupt)) with the parameters (struct __uintr_frame *, unsigned long long vector) into such a handler: it saves the registers it uses, reads the vector from the stack, removes it with an ADD to RSP and ends with UIRET. GCC 14 refused the handler unless SSE was turned off for it, for example with -mgeneral-regs-only; Clang 23 compiled it as it was.

What it restores

Unlike IRET, UIRET loads no segment and keeps the privilege level, and it runs at any CPL. From the RFLAGS image it takes only the status flags, TF, DF, NT, RF, AC and ID: IF and IOPL stay as they are. It checks that the return address is canonical (#GP(0) otherwise) and, where shadow stacks are on, that it matches the one delivery pushed onto the shadow stack (#CP otherwise). It sets UIF again; on processors with UIRET_UIF (CPUID leaf 7, sub-leaf 1, EDX bit 17), UIF takes bit 1 of the RFLAGS image instead. Delivery always pushes that bit as 1, so a handler clears it in the frame to return with user interrupts still blocked. UIRET also ends any address monitoring armed by MONITOR or UMONITOR.

Where it runs

UIRET needs UINTR, CPUID leaf 7 EDX bit 5, and CR4.UINTR set by the operating system; otherwise, and outside 64-bit mode, it raises #UD. Intel’s manual lists UINTR on Sapphire Rapids, Sierra Forest and Arrow Lake H, among others; AMD’s manuals do not define it. This site’s Zen 5 does not report UINTR, and both recorded cases raised #UD.

Forms

Every encoding of UIRET that Intel XED knows, one row per XED instruction form (iform). How to read the notation.
InstructionEncodingRequires
UIRET 64-bit mode only UIRETF3 0F 01 ECUINTR

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.
ModelUIRET
Sapphire Rapids100 / 0.25p0156

Operation

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

if not cr4 >> 25 & 1:            # CR4.UINTR; clear without UINTR
    fault(UD)
t = load(rsp, 64)                # the frame that delivery pushed:
f = load(rsp + 8, 64)            # RIP on top, RFLAGS, RSP
s = load(rsp + 16, 64)
if not canonical(t):
    fault(GP, 0)
if cr4 >> 23 & 1:                # CR4.CET
    cet = u_cet if CPL == 3 else s_cet
    if cet & 1:                  # shadow stacks on: delivery pushed
        if ss_load(ssp, 64) != t:    # RIP there too, which must
            fault(CP, 2)         # match: #CP(FAR-RET/IRET)
        ssp = ssp + 8
rip = t                          # at any CPL, to the same one
cf = f & 1                       # of RFLAGS, the status flags and
pf = f >> 2 & 1                  # TF, DF, NT, RF, AC and ID; IF,
af = f >> 4 & 1                  # IOPL, VM, VIF and VIP stay
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 = f >> 16 & 1
ac = f >> 18 & 1
id = f >> 21 & 1
rsp = s
if cpuid_leaf(7, 1)[3] >> 17 & 1:
    uif = f >> 1 & 1             # UIRET_UIF: from bit 1 of the image
else:
    uif = 1
# a monitor that MONITOR or UMONITOR set up is cleared

Run on AMD Zen 5 (EPYC 9645): 2 cases. Its cases ran where CPUID reported no UINTR, and every one raised an exception.

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
UIRET 64-bit mode only
rIPimplicitwrite
stackimplicitread
rSPimplicitread, write
RFLAGSimplicitwrite

Flags

M modified; blank: not affected. How to read.
OFSFZFAFPFCF
All forms
MMMMMM

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
UINTR

UINTR
CPUID.(EAX=07H,ECX=0):EDX[5] UINTR

Arrow Lake, Panther Lake, Nova Lake, Sapphire Rapids, Emerald Rapids, Granite Rapids, Diamond Rapids, Sierra Forest, Clearwater Forest

More UINTR 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. LLVM 23.1.2's x86 scheduling models (commit 85ac56026243): the latency, reciprocal throughput and ports of each form, as llvm-mca reports them.
  3. Intel 64 and IA-32 Architectures Software Developer's Manual, Volume 2 (325383-093, September 2026): Volume 2B, page 4-738 (UIRET)
  4. Intel 64 and IA-32 Architectures Software Developer's Manual, Volume 1 (253665-093, September 2026)
  5. Intel 64 and IA-32 Architectures Software Developer's Manual, Volume 3 (325384-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.