pub enum Opcode {
Show 86 variants
IConst,
FConst,
Splat,
GlobalAddr,
BlockAddr,
Add,
Sub,
Mul,
SDiv,
UDiv,
SRem,
URem,
And,
Or,
Xor,
Shl,
LShr,
AShr,
FAdd,
FSub,
FMul,
FDiv,
FRem,
FNeg,
Fma,
ICmp,
FCmp,
Trunc,
SExt,
ZExt,
FPTrunc,
FPExt,
FPToSI,
FPToUI,
SIToFP,
UIToFP,
PtrToInt,
IntToPtr,
Bitcast,
Alloca,
Load,
Store,
PtrAdd,
Memcpy,
Memmove,
Memset,
AtomicLoad,
AtomicStore,
AtomicRmw,
Cmpxchg,
Fence,
Jump,
BrIf,
Switch,
IndirectBr,
Return,
Unreachable,
Call,
CallIndirect,
TailCall,
Ctlz,
Cttz,
Ctpop,
Bswap,
Bitreverse,
SAddOverflow,
UAddOverflow,
SSubOverflow,
USubOverflow,
SMulOverflow,
UMulOverflow,
Expect,
UnreachableHint,
Prefetch,
FrameAddress,
ReturnAddress,
VaStart,
VaArg,
VaEnd,
VaCopy,
StackSave,
StackRestore,
SetjmpMarker,
LongjmpMarker,
TargetIntrinsic,
InlineAsm,
}Expand description
One instruction of the IR.
The names are the textual form exactly, so Opcode::name and Opcode::from_name are
what the printer and the parser use, and neither carries a table of its own that could
drift from this one.
The enum is not non_exhaustive, deliberately. The set is closed, so a pass that matches
on every opcode should stop compiling when one is added rather than fall into a wildcard
arm that quietly does the wrong thing.
Variants§
IConst
An integer constant, iconst.i32 7.
FConst
A floating point constant, fconst.f64 0x1.8p+1.
Splat
A vector constant with every lane the same, splat.i8x16 0.
GlobalAddr
The address of a global or a function, global_addr @counter.
BlockAddr
The address of a block in this function, block_addr block3.
The one instruction that names a block without being a branch, which is what GNU’s
&&label is. Where it goes is Opcode::IndirectBr, and the two are only useful
together: an address on its own is a number that nothing can do anything with.
Add
Integer addition.
Sub
Integer subtraction.
Mul
Integer multiplication.
SDiv
Signed division.
UDiv
Unsigned division.
SRem
Signed remainder, with the sign of the dividend.
URem
Unsigned remainder.
And
Bitwise and.
Or
Bitwise or.
Xor
Bitwise exclusive or.
Shl
Shift left.
LShr
Logical shift right, shifting in zeroes.
AShr
Arithmetic shift right, shifting in the sign bit.
FAdd
Floating point addition.
FSub
Floating point subtraction.
FMul
Floating point multiplication.
FDiv
Floating point division.
FRem
Floating point remainder.
FNeg
Floating point negation, which flips the sign bit and is not 0 - x.
Fma
Fused multiply-add, rounded once.
ICmp
Integer comparison, producing i1 or a vector of i1.
FCmp
Floating point comparison, producing i1 or a vector of i1.
Trunc
Narrows an integer, discarding the high bits.
SExt
Widens an integer, copying the sign bit.
ZExt
Widens an integer, filling with zeroes.
FPTrunc
Narrows a floating point value.
FPExt
Widens a floating point value.
FPToSI
Floating point to signed integer.
FPToUI
Floating point to unsigned integer.
SIToFP
Signed integer to floating point.
UIToFP
Unsigned integer to floating point.
PtrToInt
An address to an integer of the same width.
IntToPtr
An integer to an address.
Bitcast
A reinterpretation of the same bits at the same width.
Alloca
A stack slot. In the entry block, or marked dynamic for a variable length array.
Load
A read.
Store
A write, producing no value.
PtrAdd
Address arithmetic: an address and a byte offset.
Memcpy
A copy of a known size between addresses that do not overlap.
Memmove
A copy of a known size between addresses that may overlap.
Memset
A fill of a known size with one byte.
AtomicLoad
An atomic read.
AtomicStore
An atomic write.
AtomicRmw
An atomic read-modify-write, carrying which operation in RmwOp.
Cmpxchg
An atomic compare and exchange, producing the old value and whether it succeeded.
Fence
A memory barrier.
Jump
An unconditional branch, jump block1(%a, %b).
BrIf
A two-way branch on an i1.
Switch
A multi-way branch on an integer, with a default.
IndirectBr
A branch to an address, indirect_br %0, block1, block2.
The targets are every block control can arrive at, which is what makes the edges of a
computed goto ordinary edges: nothing else in the compiler has to know that the
address decides which one it is. A target that is not listed is a branch that does not
happen, so a frontend that leaves one out has made a promise on the program’s behalf.
Return
A return, with the values the signature says.
Unreachable
A place control cannot reach, which the frontend emits after a noreturn call.
Call
A call to a named function.
CallIndirect
A call through an address, carrying the signature it is called with.
TailCall
A call in tail position that reuses the frame, which is a terminator.
Ctlz
Count leading zeroes.
Cttz
Count trailing zeroes.
Ctpop
Count set bits.
Bswap
Reverse the bytes.
Bitreverse
Reverse the bits.
SAddOverflow
Signed addition, producing the result and whether it overflowed.
UAddOverflow
Unsigned addition, producing the result and whether it overflowed.
SSubOverflow
Signed subtraction, producing the result and whether it overflowed.
USubOverflow
Unsigned subtraction, producing the result and whether it overflowed.
SMulOverflow
Signed multiplication, producing the result and whether it overflowed.
UMulOverflow
Unsigned multiplication, producing the result and whether it overflowed.
Expect
__builtin_expect, which is the value with a hint attached.
UnreachableHint
__builtin_unreachable as a hint on a path, distinct from the terminator.
Prefetch
__builtin_prefetch.
FrameAddress
__builtin_frame_address.
ReturnAddress
__builtin_return_address.
VaStart
The start of a variable argument list.
VaArg
One argument off a variable argument list, which moves the list on as it reads it. Two of these on one list are two arguments and never one argument read twice, so whatever decides which instructions may be folded together has to leave these alone.
VaEnd
The end of a variable argument list.
VaCopy
A copy of a variable argument list.
StackSave
The stack pointer, saved before a variable length array.
StackRestore
The stack pointer, restored after one.
SetjmpMarker
The marker a setjmp leaves, which pins everything live across it.
LongjmpMarker
The marker a longjmp leaves.
TargetIntrinsic
A target-specific intrinsic, named rather than enumerated, for the vector builtins.
InlineAsm
Inline assembly. A terminator when it has labels, which is asm goto.
Implementations§
Source§impl Opcode
impl Opcode
Sourcepub fn all() -> impl Iterator<Item = Self>
pub fn all() -> impl Iterator<Item = Self>
Every opcode, in the order they are declared.
The parser walks this rather than holding a second table, because a second table is a table that can disagree with the first one.
Sourcepub const fn is_terminator(self) -> bool
pub const fn is_terminator(self) -> bool
Whether this ends a block.
Opcode::InlineAsm is not here and is the one instruction whose answer depends on
the instruction rather than on the opcode: asm goto has successors and everything
else does not. Ask the instruction, not the opcode.
Sourcepub const fn is_commutative(self) -> bool
pub const fn is_commutative(self) -> bool
Whether the operands can be swapped without changing the result.
The floating point cases are commutative even under the strictest rounding, because swapping the operands of an addition does not change which of them is a NaN, and the sign of a NaN result is not something we promise anything about either way.
Sourcepub const fn has_effects(self) -> bool
pub const fn has_effects(self) -> bool
Whether this reads or writes memory, or has an effect the optimizer has to preserve.
An instruction that answers no can be deleted when nothing uses its result, moved across a call, and merged with another one computing the same thing. Everything else has to be argued about individually, so the conservative answer is the true one here and the list of exceptions is the part that is checked.
Sourcepub const fn results(self) -> Option<u8>
pub const fn results(self) -> Option<u8>
How many values this produces, for the opcodes where the count is fixed.
None means the count comes from somewhere else: a call takes it from its signature,
and inline assembly takes it from its output constraints. A tail call is not one of
them, because whatever it returns goes straight out of the function and there is no
instruction after it to use anything.
Sourcepub const fn extra_kind(self) -> ExtraKind
pub const fn extra_kind(self) -> ExtraKind
Which payload an instruction with this opcode carries.
The printer reads the payload it finds and does not need this. The parser has only the
opcode when it reaches the operands, so this is where the two of them agree on what
comes after them. An instruction carrying a payload of some other kind prints as text
the parser cannot read back, which is why the verifier checks it against
Extra::kind rather than leaving it to be found later.