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

SENDUIPI interrupts another thread without a system call. Its one operand is a 64-bit register holding an index into the sending thread’s user-interrupt target table (UITT), whatever operand size a prefix asks for. The operating system builds that table and points the IA32_UINTR_TT MSR at it; each 16-byte entry has a valid bit, a user-interrupt vector from 0 to 63 and the address of the receiver’s user posted-interrupt descriptor (UPID). The program only chooses the index, so it can reach exactly the receivers the kernel has set up for it.

What it does

SENDUIPI checks the index against the table’s highest index, in IA32_UINTR_MISC, and the entry for its valid bit and reserved bits, raising #GP(0) on any failure. It then updates the UPID atomically: it sets the bit of the vector in the 64-bit field of posted requests, and if neither the outstanding-notification bit (ON) nor the suppress-notification bit (SN) was set, it sets ON and sends an ordinary IPI, with the notification vector and destination APIC ID that the UPID holds. A second SENDUIPI to the same receiver before it has taken the first only adds its vector to the posted bits: ON keeps it from sending another IPI. SN lets the operating system have the requests posted without any IPI.

Its reads and writes of the table and the UPID count as a supervisor’s, so both can live in pages the program itself cannot read or write.

The receiving end

On the receiving core, an interrupt with the vector the OS named in IA32_UINTR_MISC is a user-interrupt notification: the processor moves the posted bits into its request register and, once the receiver runs at CPL 3 in 64-bit mode with UIF set, delivers the highest vector to the receiver’s handler, which returns with UIRET. CLUI and STUI hold delivery back and allow it again.

In compiled code and on Zen 5

With -muintr, GCC 14 and Clang 23 at -O2 compile _senduipi(i) to senduipi rdi, the argument’s register. Without UINTR (CPUID leaf 7, EDX bit 5), with CR4.UINTR clear, or while bit 0 of IA32_UINTR_TT says that the thread has no table, it raises #UD. This site’s Zen 5 reports no UINTR, and both recorded cases, with indices 0 and 1, raised #UD.

Forms

Every encoding of SENDUIPI that Intel XED knows, one row per XED instruction form (iform). How to read the notation.
InstructionEncodingRequires
SENDUIPI r64 64-bit mode only SENDUIPI_GPR64u32F3 0F C7 /6UINTR

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.
Modelr64
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)
if not uintr_tt & 1:             # no valid target table
    fault(UD)
i = src.read()                   # 64 bits, whatever a 66 says
if i > uintr_misc & 0xFFFFFFFF:  # past UITTSZ, the highest index
    fault(GP, 0)
e = uintr_tt & ~0xF              # the table, 16 bytes an entry
lo = load(e + 16 * i, 64)        # V (bit 0), the user vector UV in
upid = load(e + 16 * i + 8, 64)  # bits 15:8, the UPID's address
if not lo & 1 or lo & ~0x3F01:
    fault(GP, 0)                 # not valid, or reserved bits set
if upid & 0x3F:
    fault(GP, 0)                 # the UPID not 64-byte aligned
v = lo >> 8 & 0x3F
d = load(upid, 64)               # ON (bit 0), SN (1), the vector NV
pir = load(upid + 8, 64)         # (23:16) and destination NDST
                                 # (63:32); PIR: one bit a vector
if d & 0xFF00FFFC:
    fault(GP, 0)                 # reserved bits set
notify = d & 3 == 0              # neither outstanding nor suppressed
store(upid + 8, 64, pir | 1 << v)
store(upid, 64, d | 1 if notify else d)
                                 # locked, the read and the writes
if notify:
    nv = d >> 16 & 0xFF
    if msr[0x1B] >> 10 & 1:      # IA32_APIC_BASE.EXTD: x2APIC
        send_ipi(nv, d >> 32)
    else:
        send_ipi(nv, d >> 40 & 0xFF)
# its accesses to the table and the UPID are a supervisor's, at any
# CPL

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
SENDUIPI r64 64-bit mode only
r64explicitread

Flags

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

Intrinsics

The C intrinsics of Clang 23.1.2 that compile to SENDUIPI, each with the form it compiles to and the Clang options it needs. The forms come from compiling every intrinsic and decoding the result with Intel XED; all intrinsics A–Z explains the method.

IntrinsicCompiles to
_senduipi void _senduipi(unsigned long long __a)

SENDUIPI r64 Legacy -muintr

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. Clang's x86 intrinsic headers, LLVM 23.1.2 (commit 85ac56026243): the intrinsics, their signatures and doc comments, and the Clang of that release, which compiled each of them.
  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 2B, page 4-620 (SENDUIPI)
  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 intrinsics and their signatures come from Clang and the timings from LLVM's scheduling models, both part of the LLVM Project, licensed under the Apache License 2.0 with LLVM Exceptions. The text is our own.