Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

newyork IR reference

A per-operation reference for the newyork IR: textual syntax, operand and result types, purity, region and static-slot annotations, and examples.

How to read this reference

This reference page enumerates every operation the newyork IR supports. It is a lookup, not a walkthrough: each entry is self-contained and intended to be reachable by anchor.

Operations are grouped by function (memory and storage writes, pure expressions, control flow, and so on) rather than alphabetically. Jump to a specific operation from the operation index below, or use the sidebar.

Every operation appears in two places in the codebase. The canonical Rust definition is a variant of either Expression or Statement in ir.rs. The textual rendering used by debug dumps and by this reference page is produced by the printer in printer.rs.

Note

Treat the printed syntax as a debug surface, not a stable input language: there is no parser for it, and printer details change when passes add new annotations.

Entry format

Each operation entry has the same shape:

FieldWhat it shows
HeadingThe printed operation name (e.g. mstore) followed by the Expression or Statement variant it corresponds to in ir.rs.
DescriptionA short prose summary of what the operation does and any semantic notes worth knowing before reading the rest of the entry.
SyntaxThe literal printer output, including any optional debug annotations (region tags, static-slot comments). Anything inside /* ... */ is a debug-only annotation and is not part of the operation itself.
ExampleA minimal printed snippet, using the printer’s actual v0/v1/… naming.
OperandsOne row per input or structural participant in the printed syntax. Value operands list the narrowest type the operation guarantees (default i256; narrower widths only appear when type inference has narrowed an upstream definition). Vector-of-operands fields show Vec<…> as the type. Non-value participants such as nested regions are listed with an em-dash type to mark them as structural rather than as operands.
Result and purityThe type the operation produces (or none for statements that bind no value), followed by a purity label, either Pure or Effectful. Pure operations may be reordered, deduplicated, or eliminated by the simplifier; effectful ones may not. Effectful entries may carry a parenthetical describing the nature of the side effect when informative (e.g. “control flow”, “terminator”, or a note about revert/trap behavior).
AnnotationsOperation-specific fields the printer surfaces as /* ... */ comments in the dump (region tag for memory ops, static-slot hint for storage ops, type suffix for non-default widths). Listed here as a table of source fieldprinted form.

Syntax notation

Syntax templates in each entry use the following conventions:

NotationMeaning
add, mload, if, else, case, let, yield, …Literal printer tokens: bare lowercase identifiers and keywords that the printer emits verbatim.
$offset, $value, $key, $lhs, $rhs, …Role names ($-prefixed): placeholders for SSA value references the printer renders as v followed by a decimal id (v0, v1, …).
<type>, <region>, <hex>, <id>, <bits>, <func_name>, <N>, <length>, …Metavariables: stand for compile-time fields (type tags, hex values, identifier strings, integer counts), not SSA values. The concrete values they take are enumerated in the Annotations section of each entry or in the type system reference.
[…]Optional parts. Anything inside the brackets may or may not appear in any given dump, depending on the conditions described in the operation’s Annotations section.
[: <type>]Optional type suffix on a value reference. Suppressed when the value’s type is the default i256 integer; present otherwise (: i32, : ptr<heap>, …).
/* … */Debug-only annotations the printer attaches to certain operations (memory region tag, static-slot hint, etc.).
Repetition: “more entries of the same shape.” Used in vector operand lists ($arg_0, $arg_1, …) and in multi-line block bodies ({ … }).

For instance, this template:

let $result[: <type>] := and($lhs[: <type>], $rhs[: <type>])

prints as:

let v2: i8 := and(v0, v1: i8)

$result rendered as v2 with an i8 type suffix, $lhs as v0 at the default i256 (type suffix omitted), and $rhs as v1 with an i8 type suffix.

Note

A value’s printed width is use-driven. Type inference assigns each value a forward width from its definition, then widens it to satisfy its uses. The type suffix shown for a value in an example (such as i8) is therefore only illustrative — a short example may not show the uses that determine it, and the same operation can appear with a wider suffix, or none (it is omitted for the default i256), in another program.

For instance, a value used as a memory offset widens to i64; as an address (a call target, extcodesize) to i160; stored as a full word (an mstore/sstore value) to i256; and an add/mul operand up to the i64 register width.

Operation index

Pure expressions

Constants and variables
Arithmetic
Bit-width conversions
Hashing
Environment reads
Calldata, returndata, and code
Memory and storage loads
Linker
Function call

Memory and storage writes

Bulk copies

Bindings and wrappers

Structured control flow

External interaction

Termination

Type system

Every value in the IR carries a Type. The operation entries below refer to widths (i1i256), address spaces (ptr<heap>, etc.), and memory regions (scratch, etc.) by their printed form; this section is the reference for those names.

Type

The umbrella enum, with these variants:

VariantPrinted asDescription
Int(BitWidth)i1, i8, …, i256An integer at one of the BitWidth widths.
Ptr(AddressSpace)ptr<heap>, ptr<stack>, ptr<storage>, ptr<code>A pointer tagged with its address space; see AddressSpace.
VoidvoidUnit type. Used for statements that produce no value and for void-returning functions.

BitWidth

The rungs of integer width. Newly minted values default to I256; type inference narrows them down to one of the lower rungs when it can prove the upper bits are zero or unused.

VariantPrinted asTypical use
I1i1Boolean. Result type of every comparison and iszero.
I8i8Byte values. The narrowest meaningful integer.
I32i32PolkaVM pointer width (XLEN); minimum width for function parameters under the rv64e ABI.
I64i64PolkaVM native register width; most narrowed values land here.
I128i128Two registers; arithmetic that overflows i64 but doesn’t need full 256-bit emulation.
I160i160Ethereum addresses; result of caller, origin, mapping keys.
I256i256EVM word width. The default and conservative ceiling.

AddressSpace

The address space a pointer points into. Carried on every Ptr value so the codegen can lower loads and stores without a separate alias-analysis pass.

VariantPrinted asPoints intoEndianness
Heapptr<heap>Emulated EVM linear memory (the simulated mload/mstore region).Big-endian (by EVM contract).
Stackptr<stack>Native PolkaVM stack allocations.Little-endian (no swap).
Storageptr<storage>Contract storage; key/value with 256-bit slots.Big-endian on the wire.
Codeptr<code>Read-only code/data segment.Big-endian.

MemoryRegion

A refinement carried by every memory load and store on top of AddressSpace::Heap. The tag tells later passes what kind of heap address an offset is hitting, which drives both free-memory-pointer propagation and byte-swap elimination.

VariantAddress rangePrinted asMeaning
Scratch0x000x3f/* scratch */EVM scratch space; safe to touch without consulting the free memory pointer.
FreePointerSlotexactly 0x40/* free_ptr */Slot that stores the free memory pointer itself.
Dynamic0x80 and above/* dynamic */Real heap allocations.
Unknowneverything else (constants in 0x410x7f, plus all non-constant offsets)(suppressed)Conservative fallback used when the offset isn’t a constant or doesn’t slot cleanly.

Pure expressions

Pure expressions produce values without side effects. The simplifier may freely reorder, deduplicate, and eliminate them. They appear on the right-hand side of a let binding, or as operands of other expressions and effectful statements; the operand positions accept SSA value references only, so any pure expression that is consumed elsewhere is first bound by a let. Examples in this section wrap each expression in a let v := … to give it somewhere to land.

0x<hex>

(Expression::Literal)

Description

A compile-time constant value with a declared type. New literals minted by the translator default to Int(I256); passes that synthesize constants at narrower widths (e.g. a one-bit boolean from a constant comparison) attach the narrower type directly.

Syntax

0x<hex>[: <type>]

Example

let v0: i8 := 0x2a
let v1: i1 := 0x1           // boolean true
let v2: i64 := 0x80

Operands

None — literals are leaves.

Result and purity

ResultPurity
Same as the literal’s value_typePure

Annotations

Source fieldPrinted as
value: BigUint0x<hex> in the syntax position (not a comment annotation; it is the expression itself)
value_type: Type: <type> suffix when value_type is not the default Int(I256); suppressed otherwise

v<id>

(Expression::Var)

Description

A reference to an existing SSA value, used as the entire right-hand side of a let. In a typical dump this is rare because the simplifier collapses let v := v<id> into the consumers of v via copy propagation; expect to see it only in dumps taken before simplification has run.

Syntax

v<id>

Example

let v5 := v3                // copy; usually eliminated by simplify

Operands

None — the expression is the value reference itself.

Result and purity

ResultPurity
Same as the referenced value’s typePure

Annotations

None.

add

(Expression::Binary with BinaryOperation::Add)

Description

Modular addition. Wraps on overflow; per EVM, the result is (lhs + rhs) mod 2^N where N is the operand width.

Syntax

add($lhs[: <type>], $rhs[: <type>])

Example

let v2 := add(v0, v1)

Operands

NameTypeNotes
lhsi256
rhsi256

Result and purity

ResultPurity
widen_by_one(max(width(lhs), width(rhs))) — one tier above the wider operand to account for the carry bitPure

Annotations

None.

sub

(Expression::Binary with BinaryOperation::Sub)

Description

Modular subtraction. Wraps on underflow; the result is (lhs - rhs) mod 2^256 regardless of operand widths.

Syntax

sub($lhs[: <type>], $rhs[: <type>])

Example

let v2 := sub(v0, v1)

Operands

NameTypeNotes
lhsi256
rhsi256

Result and purity

ResultPurity
i256 — conservative; underflow on narrower operands could borrow into upper bitsPure

Annotations

None.

mul

(Expression::Binary with BinaryOperation::Mul)

Description

Modular multiplication. The result is (lhs * rhs) mod 2^256.

Syntax

mul($lhs[: <type>], $rhs[: <type>])

Example

let v2 := mul(v0, v1)

Operands

NameTypeNotes
lhsi256
rhsi256

Result and purity

ResultPurity
double_width(max(width(lhs), width(rhs))) — the tier holding twice the wider operand’s bits (skipping i160 at the i128i256 transition)Pure

Annotations

None.

div

(Expression::Binary with BinaryOperation::Div)

Description

Unsigned integer division. Per EVM, div(x, 0) = 0 (no trap on division by zero).

Syntax

div($lhs[: <type>], $rhs[: <type>])

Example

let v2 := div(v0, v1)

Operands

NameTypeNotes
lhsi256Dividend.
rhsi256Divisor; 0 yields a result of 0, not a trap.

Result and purity

ResultPurity
width(lhs) — the quotient cannot exceed the dividendPure

Annotations

None.

sdiv

(Expression::Binary with BinaryOperation::SDiv)

Description

Signed two’s-complement integer division. Per EVM, sdiv(x, 0) = 0; quotient is truncated toward zero.

Syntax

sdiv($lhs[: <type>], $rhs[: <type>])

Example

let v2 := sdiv(v0, v1)

Operands

NameTypeNotes
lhsi256Dividend, treated as signed.
rhsi256Divisor, treated as signed; 0 yields 0.

Result and purity

ResultPurity
max(width(lhs), width(rhs)) — a negative divisor can push the result to full widthPure

Annotations

None.

mod

(Expression::Binary with BinaryOperation::Mod)

Description

Unsigned modulo. Per EVM, mod(x, 0) = 0.

Syntax

mod($lhs[: <type>], $rhs[: <type>])

Example

let v2 := mod(v0, v1)

Operands

NameTypeNotes
lhsi256Dividend.
rhsi256Divisor; 0 yields 0.

Result and purity

ResultPurity
width(lhs)Pure

Annotations

None.

smod

(Expression::Binary with BinaryOperation::SMod)

Description

Signed modulo. Per EVM, smod(x, 0) = 0; the result takes the sign of the dividend.

Syntax

smod($lhs[: <type>], $rhs[: <type>])

Example

let v2 := smod(v0, v1)

Operands

NameTypeNotes
lhsi256Dividend, treated as signed.
rhsi256Divisor, treated as signed; 0 yields 0.

Result and purity

ResultPurity
width(lhs)Pure

Annotations

None.

exp

(Expression::Binary with BinaryOperation::Exp)

Description

Modular exponentiation: (base ^ exponent) mod 2^256. The most expensive arithmetic opcode in EVM (variable gas cost proportional to the byte length of exponent).

Syntax

exp($base[: <type>], $exponent[: <type>])

Example

let v2 := exp(v0, v1)

Operands

NameTypeNotes
basei256Base.
exponenti256Exponent.

Result and purity

ResultPurity
i256 — conservative; exponentiation can fill any widthPure

Annotations

None.

and

(Expression::Binary with BinaryOperation::And)

Description

Bitwise AND. The common idiom for type narrowing: a constant mask on the right lets forward analysis pick up a tight result width.

Syntax

and($lhs[: <type>], $rhs[: <type>])

Example

let v2 := and(v0, v1)
let v3: i8 := 0xff
let v4: i8 := and(v0, v3: i8)

Operands

NameTypeNotes
lhsi256
rhsi256

Result and purity

ResultPurity
min(width(lhs), width(rhs)) — AND can only clear bits, so the result fits in the narrower operandPure

Annotations

None.

or

(Expression::Binary with BinaryOperation::Or)

Description

Bitwise OR.

Syntax

or($lhs[: <type>], $rhs[: <type>])

Example

let v2 := or(v0, v1)

Operands

NameTypeNotes
lhsi256
rhsi256

Result and purity

ResultPurity
max(width(lhs), width(rhs))Pure

Annotations

None.

xor

(Expression::Binary with BinaryOperation::Xor)

Description

Bitwise XOR.

Syntax

xor($lhs[: <type>], $rhs[: <type>])

Example

let v2 := xor(v0, v1)

Operands

NameTypeNotes
lhsi256
rhsi256

Result and purity

ResultPurity
max(width(lhs), width(rhs))Pure

Annotations

None.

shl

(Expression::Binary with BinaryOperation::Shl)

Description

Logical left shift. Operand order follows EVM: shl(shift, value) computes value << shift. Shifts ≥ 256 produce 0.

Syntax

shl($shift[: <type>], $value[: <type>])

Example

let v2 := shl(v0, v1)

Operands

NameTypeNotes
shifti256Shift amount in bits.
valuei256Value to shift.

Result and purity

ResultPurity
i256 — conservative; bits may shift into any widthPure

Annotations

None.

shr

(Expression::Binary with BinaryOperation::Shr)

Description

Logical right shift. Operand order follows EVM: shr(shift, value) computes value >> shift with zero-fill from the left. Shifts ≥ 256 produce 0.

Syntax

shr($shift[: <type>], $value[: <type>])

Example

let v2 := shr(v0, v1)

Operands

NameTypeNotes
shifti256Shift amount in bits.
valuei256Value to shift.

Result and purity

ResultPurity
If shift is a known constant k: tier holding 256 - k bits (or i1 for k ≥ 256). Otherwise: width(value).Pure

Annotations

None.

sar

(Expression::Binary with BinaryOperation::Sar)

Description

Arithmetic (signed) right shift. Operand order follows EVM: sar(shift, value) shifts value right by shift bits, preserving the sign bit. Shifts ≥ 256 saturate to 0 for non-negative values and to -1 (all-ones) for negative values.

Syntax

sar($shift[: <type>], $value[: <type>])

Example

let v2 := sar(v0, v1)

Operands

NameTypeNotes
shifti256Shift amount in bits.
valuei256Value to shift, treated as signed.

Result and purity

ResultPurity
width(value) — unlike shr, sign-extension means a constant shift cannot narrow the resultPure

Annotations

None.

lt

(Expression::Binary with BinaryOperation::Lt)

Description

Unsigned less-than comparison. Returns 1 if lhs < rhs, else 0.

Syntax

lt($lhs[: <type>], $rhs[: <type>])

Example

let v2: i1 := lt(v0, v1)

Operands

NameTypeNotes
lhsi256Compared unsigned.
rhsi256Compared unsigned.

Result and purity

ResultPurity
i1Pure

Annotations

None.

gt

(Expression::Binary with BinaryOperation::Gt)

Description

Unsigned greater-than comparison. Returns 1 if lhs > rhs, else 0.

Syntax

gt($lhs[: <type>], $rhs[: <type>])

Example

let v2: i1 := gt(v0, v1)

Operands

NameTypeNotes
lhsi256Compared unsigned.
rhsi256Compared unsigned.

Result and purity

ResultPurity
i1Pure

Annotations

None.

slt

(Expression::Binary with BinaryOperation::Slt)

Description

Signed less-than comparison. Operands are treated as two’s complement.

Syntax

slt($lhs[: <type>], $rhs[: <type>])

Example

let v2: i1 := slt(v0, v1)

Operands

NameTypeNotes
lhsi256Compared signed.
rhsi256Compared signed.

Result and purity

ResultPurity
i1Pure

Annotations

None.

sgt

(Expression::Binary with BinaryOperation::Sgt)

Description

Signed greater-than comparison. Operands are treated as two’s complement.

Syntax

sgt($lhs[: <type>], $rhs[: <type>])

Example

let v2: i1 := sgt(v0, v1)

Operands

NameTypeNotes
lhsi256Compared signed.
rhsi256Compared signed.

Result and purity

ResultPurity
i1Pure

Annotations

None.

eq

(Expression::Binary with BinaryOperation::Eq)

Description

Equality comparison. Returns 1 if lhs == rhs, else 0. Signedness is irrelevant.

Syntax

eq($lhs[: <type>], $rhs[: <type>])

Example

let v2: i1 := eq(v0, v1)

Operands

NameTypeNotes
lhsi256
rhsi256

Result and purity

ResultPurity
i1Pure

Annotations

None.

byte

(Expression::Binary with BinaryOperation::Byte)

Description

Extract a single byte from a 256-bit word. byte(i, x) returns the i-th byte of x with byte 0 being the most significant. If i ≥ 32, the result is 0.

Syntax

byte($index[: <type>], $word[: <type>])

Example

let v2: i8 := byte(v0, v1)

Operands

NameTypeNotes
indexi256Byte position; 0 = most significant byte. Values ≥ 32 yield 0.
wordi256Source word.

Result and purity

ResultPurity
i8Pure

Annotations

None.

signextend

(Expression::Binary with BinaryOperation::SignExtend)

Description

Sign-extend an integer from a byte position. Per EVM, signextend(b, x) treats byte b of x as the most significant byte of a smaller signed integer and extends its sign through the upper bytes.

Syntax

signextend($byte_position[: <type>], $value[: <type>])

Example

let v2 := signextend(v0, v1)

Operands

NameTypeNotes
byte_positioni256Byte position of the sign byte (0–31).
valuei256Source value.

Result and purity

ResultPurity
i256 — the extended value occupies the full wordPure

Annotations

The width-targeted sign-extension primitive sext<i<bits>> (Expression::SignExtendTo) is a separate operation; see the bit-width conversions section.

addmod

(Expression::Ternary with BinaryOperation::AddMod)

Description

Ternary modular addition: (a + b) mod n, computed without intermediate overflow. Per EVM, n = 0 yields 0.

Syntax

addmod($a[: <type>], $b[: <type>], $n[: <type>])

Example

let v3 := addmod(v0, v1, v2)

Operands

NameTypeNotes
ai256First addend.
bi256Second addend.
ni256Modulus; 0 yields 0.

Result and purity

ResultPurity
i256 — conservativePure

Annotations

None.

mulmod

(Expression::Ternary with BinaryOperation::MulMod)

Description

Ternary modular multiplication: (a * b) mod n, computed without intermediate overflow. Per EVM, n = 0 yields 0.

Syntax

mulmod($a[: <type>], $b[: <type>], $n[: <type>])

Example

let v3 := mulmod(v0, v1, v2)

Operands

NameTypeNotes
ai256First factor.
bi256Second factor.
ni256Modulus; 0 yields 0.

Result and purity

ResultPurity
i256 — conservativePure

Annotations

None.

iszero

(Expression::Unary with UnaryOperation::IsZero)

Description

Returns 1 if the operand is 0, else 0. Also serves as the logical NOT for boolean values.

Syntax

iszero($operand[: <type>])

Example

let v1: i1 := iszero(v0)

Operands

NameTypeNotes
operandi256

Result and purity

ResultPurity
i1Pure

Annotations

None.

not

(Expression::Unary with UnaryOperation::Not)

Description

Bitwise complement. Inverts every bit; equivalent to xor(operand, 2^256 - 1).

Syntax

not($operand[: <type>])

Example

let v1 := not(v0)

Operands

NameTypeNotes
operandi256

Result and purity

ResultPurity
i256 — the complement fills the full word regardless of operand widthPure

Annotations

None.

clz

(Expression::Unary with UnaryOperation::Clz)

Description

Count leading zeros. Returns the number of leading zero bits in the operand, where a value of 0 returns 256 (the full width). Not an EVM opcode; reaches newyork as a Yul builtin (FunctionName::Clz) and is translated directly by the Yul-to-newyork translator.

Syntax

clz($operand[: <type>])

Example

let v1 := clz(v0)

Operands

NameTypeNotes
operandi256

Result and purity

ResultPurity
i256 — in practice the value fits in nine bits (max 256), so type inference often narrows furtherPure

Annotations

None.

truncate<i<bits>>

(Expression::Truncate)

Description

Reinterpret a wider integer as a narrower one by discarding the upper bits. The destination width is carried in the IR’s to: BitWidth field and is rendered inside the angle brackets of the printer mnemonic. Narrowing-only; the source width must be greater than or equal to the destination width.

Syntax

truncate<i<bits>>($value[: <type>])

Example

let v1: i64 := truncate<i64>(v0)
let v2: i8 := truncate<i8>(v1: i64)

Operands

NameTypeNotes
valuei256Source value; must be at least as wide as the destination.

Result and purity

ResultPurity
The destination width from the to fieldPure

Annotations

None. The destination width is part of the operation name, not a debug annotation.

zext<i<bits>>

(Expression::ZeroExtend)

Description

Reinterpret a narrower integer as a wider one by zero-filling the upper bits. The destination width is carried in the IR’s to: BitWidth field. Widening-only.

Syntax

zext<i<bits>>($value[: <type>])

Example

let v1 := zext<i256>(v0: i8)

Operands

NameTypeNotes
valuei256Source value; must be no wider than the destination.

Result and purity

ResultPurity
The destination width from the to fieldPure

Annotations

None.

sext<i<bits>>

(Expression::SignExtendTo)

Description

Reinterpret a narrower signed integer as a wider one by sign-extending the high bit. The destination width is carried in the IR’s to: BitWidth field. Distinct from signextend (Expression::Binary), which is the EVM byte-position primitive; this one specifies the destination width directly and is introduced by passes that produce a sign-extended value at a known target width.

Syntax

sext<i<bits>>($value[: <type>])

Example

let v1 := sext<i256>(v0: i64)

Operands

NameTypeNotes
valuei256Source value; must be no wider than the destination.

Result and purity

ResultPurity
The destination width from the to fieldPure

Annotations

None.

keccak256

(Expression::Keccak256)

Description

Compute the Keccak-256 hash of length bytes of emulated EVM linear memory starting at offset. The general-purpose hashing primitive; the specialized variants below cover the common scratch-space patterns more compactly.

Syntax

keccak256($offset[: <type>], $length[: <type>])

Example

let v2 := keccak256(v0, v1)

Operands

NameTypeNotes
offseti256Byte offset into linear memory; forward analysis widens to at least i64.
lengthi256Length of the region to hash, in bytes; forward analysis widens to at least i64.

Result and purity

ResultPurity
i256Pure — the hash is a deterministic function of the memory contents at evaluation time. Passes that hoist or dedupe must respect intervening memory writes.

Annotations

None.

keccak256_pair

(Expression::Keccak256Pair)

Description

Compound hash of two 256-bit words. Equivalent to mstore(0, word0); mstore(32, word1); keccak256(0, 64) but emitted as a single outlined call after mem_opt’s keccak fusion recognizes the pattern. The mapping-key idiom; see also mapping_sload.

Syntax

keccak256_pair($word0[: <type>], $word1[: <type>])

Example

let v2 := keccak256_pair(v0, v1)

Operands

NameTypeNotes
word0i256First word; the high 32 bytes of the hash input.
word1i256Second word; the low 32 bytes of the hash input.

Result and purity

ResultPurity
i256Pure

Annotations

None.

keccak256_single

(Expression::Keccak256Single)

Description

Compound hash of a single 256-bit word. Equivalent to mstore(0, word0); keccak256(0, 32) but emitted as a single outlined call after mem_opt’s keccak fusion.

Syntax

keccak256_single($word0[: <type>])

Example

let v1 := keccak256_single(v0)

Operands

NameTypeNotes
word0i256The word to hash.

Result and purity

ResultPurity
i256Pure

Annotations

None.

caller

(Expression::Caller)

Description

Address of the immediate caller of the current call frame.

Syntax

caller()

Example

let v0: i160 := caller()

Operands

None.

Result and purity

ResultPurity
i160Pure

Annotations

None.

callvalue

(Expression::CallValue)

Description

Value (wei) attached to the current call.

Syntax

callvalue()

Example

let v0 := callvalue()

Operands

None.

Result and purity

ResultPurity
i256Pure

Annotations

None.

origin

(Expression::Origin)

Description

Address of the original externally owned account that initiated the transaction.

Syntax

origin()

Example

let v0: i160 := origin()

Operands

None.

Result and purity

ResultPurity
i160Pure

Annotations

None.

address

(Expression::Address)

Description

Address of the contract executing the current call frame.

Syntax

address()

Example

let v0: i160 := address()

Operands

None.

Result and purity

ResultPurity
i160Pure

Annotations

None.

chainid

(Expression::ChainId)

Description

Chain identifier of the network the contract is executing on.

Syntax

chainid()

Example

let v0 := chainid()

Operands

None.

Result and purity

ResultPurity
i256Pure

Annotations

None.

gas

(Expression::Gas)

Description

Remaining gas at the point of evaluation. Modeled as a pure expression for IR purposes; in practice it changes between evaluations, so any simplifier that deduplicates pure expressions must respect gas as a barrier.

Syntax

gas()

Example

let v0: i64 := gas()

Operands

None.

Result and purity

ResultPurity
i64Pure (per IR; see Description)

Annotations

None.

msize

(Expression::MSize)

Description

Highest byte offset of emulated EVM linear memory that has been touched, rounded up to the next 32-byte boundary. Unlike gas, classified as side-effectful by the simplifier: unused msize() bindings are not eliminated, because the result depends on the program’s memory-access history and would change if the surrounding statements were reordered.

Syntax

msize()

Example

let v0: i64 := msize()

Operands

None.

Result and purity

ResultPurity
i64Effectful (see Description)

Annotations

None.

coinbase

(Expression::Coinbase)

Description

Address of the block’s coinbase (block author).

Syntax

coinbase()

Example

let v0: i160 := coinbase()

Operands

None.

Result and purity

ResultPurity
i160Pure

Annotations

None.

timestamp

(Expression::Timestamp)

Description

Block timestamp, as a Unix epoch second.

Syntax

timestamp()

Example

let v0: i64 := timestamp()

Operands

None.

Result and purity

ResultPurity
i64Pure

Annotations

None.

number

(Expression::Number)

Description

Current block number.

Syntax

number()

Example

let v0: i64 := number()

Operands

None.

Result and purity

ResultPurity
i64Pure

Annotations

None.

difficulty

(Expression::Difficulty)

Description

Pre-merge block difficulty. On post-merge chains this is the block’s prevrandao value.

Syntax

difficulty()

Example

let v0 := difficulty()

Operands

None.

Result and purity

ResultPurity
i256Pure

Annotations

None.

gaslimit

(Expression::GasLimit)

Description

Block gas limit.

Syntax

gaslimit()

Example

let v0: i64 := gaslimit()

Operands

None.

Result and purity

ResultPurity
i64Pure

Annotations

None.

basefee

(Expression::BaseFee)

Description

Current block’s EIP-1559 base fee per gas.

Syntax

basefee()

Example

let v0 := basefee()

Operands

None.

Result and purity

ResultPurity
i256Pure

Annotations

None.

blobbasefee

(Expression::BlobBaseFee)

Description

Current block’s EIP-4844 blob base fee per gas.

Syntax

blobbasefee()

Example

let v0 := blobbasefee()

Operands

None.

Result and purity

ResultPurity
i256Pure

Annotations

None.

blobhash

(Expression::BlobHash)

Description

Versioned hash of the blob at the given index in the current transaction’s blob list.

Syntax

blobhash($index[: <type>])

Example

let v1 := blobhash(v0)

Operands

NameTypeNotes
indexi256Blob index; forward analysis widens to at least i64.

Result and purity

ResultPurity
i256Pure

Annotations

None.

blockhash

(Expression::BlockHash)

Description

Hash of the block with the given number. Per EVM, valid only for the most recent 256 blocks; outside that range the result is 0.

Syntax

blockhash($number[: <type>])

Example

let v1 := blockhash(v0)

Operands

NameTypeNotes
numberi256Block number; forward analysis widens to i256.

Result and purity

ResultPurity
i256Pure

Annotations

None.

selfbalance

(Expression::SelfBalance)

Description

Balance (in wei) of the contract executing the current call frame. Cheaper than balance(address()).

Syntax

selfbalance()

Example

let v0 := selfbalance()

Operands

None.

Result and purity

ResultPurity
i256Pure

Annotations

None.

gasprice

(Expression::GasPrice)

Description

Effective gas price of the current transaction.

Syntax

gasprice()

Example

let v0 := gasprice()

Operands

None.

Result and purity

ResultPurity
i256Pure

Annotations

None.

calldataload

(Expression::CallDataLoad)

Description

Read 32 bytes from the current call’s calldata at the given offset. Reads past the end of calldata return zero bytes.

Syntax

calldataload($offset[: <type>])

Example

let v1 := calldataload(v0)

Operands

NameTypeNotes
offseti256Byte offset into calldata.

Result and purity

ResultPurity
i256Pure

Annotations

None.

calldatasize

(Expression::CallDataSize)

Description

Length of the current call’s calldata, in bytes.

Syntax

calldatasize()

Example

let v0: i64 := calldatasize()

Operands

None.

Result and purity

ResultPurity
i64Pure

Annotations

None.

returndatasize

(Expression::ReturnDataSize)

Description

Length of the most recently returned data buffer from a sub-call, in bytes. Modeled as pure per IR but reflects the last ExternalCall / Create result; consumers must respect that ordering.

Syntax

returndatasize()

Example

let v0: i64 := returndatasize()

Operands

None.

Result and purity

ResultPurity
i64Pure (per IR; see Description)

Annotations

None.

codesize

(Expression::CodeSize)

Description

Size of the currently executing code, in bytes.

Syntax

codesize()

Example

let v0: i64 := codesize()

Operands

None.

Result and purity

ResultPurity
i64Pure

Annotations

None.

extcodesize

(Expression::ExtCodeSize)

Description

Size of the code deployed at the given address, in bytes. Returns 0 for accounts with no deployed code.

Syntax

extcodesize($address[: <type>])

Example

let v1: i64 := extcodesize(v0: i160)

Operands

NameTypeNotes
addressi256Account address; forward analysis widens to at least i160.

Result and purity

ResultPurity
i64Pure

Annotations

None.

extcodehash

(Expression::ExtCodeHash)

Description

Keccak-256 hash of the code deployed at the given address. Returns 0 for non-existent accounts.

Syntax

extcodehash($address[: <type>])

Example

let v1 := extcodehash(v0: i160)

Operands

NameTypeNotes
addressi256Account address; forward analysis widens to at least i160.

Result and purity

ResultPurity
i256Pure

Annotations

None.

balance

(Expression::Balance)

Description

Balance (in wei) of the given account address. Use selfbalance for the contract executing the current call frame (cheaper).

Syntax

balance($address[: <type>])

Example

let v1 := balance(v0: i160)

Operands

NameTypeNotes
addressi256Account address; forward analysis widens to at least i160.

Result and purity

ResultPurity
i256Pure

Annotations

None.

mload

(Expression::MLoad)

Description

Read a 32-byte word from emulated EVM linear memory at offset. The word is read big-endian per EVM semantics. Pure per IR, but reads after writes return the new value; the memory passes track read/write dependencies separately.

Syntax

mload($offset[: <type>]) [/* <region> */]

Example

let v1 := mload(v0: i64)
let v2: i32 := mload(v3: i64) /* free_ptr */

Operands

NameTypeNotes
offseti256Byte offset into linear memory; forward analysis widens to at least i64.

Result and purity

ResultPurity
i32 when region is FreePointerSlot; i256 otherwisePure (per IR; see Description)

Annotations

Source fieldPrinted as
region: MemoryRegion/* scratch */ · /* free_ptr */ · /* dynamic */ (Unknown is suppressed)

Same tagging rules as mstore. The region also determines the result width: a load from FreePointerSlot produces an i32 since the FMP fits in a pointer-sized word.

sload

(Expression::SLoad)

Description

Read a 32-byte word from persistent contract storage at the given key. Pure per IR; reads after writes to the same slot return the new value.

Syntax

sload($key[: <type>]) [/* slot: 0x<hex> */]

Example

let v1 := sload(v0)
let v2 := sload(v3) /* slot: 0x0 */

Operands

NameTypeNotes
keyi256Storage slot.

Result and purity

ResultPurity
i256Pure (per IR; see Description)

Annotations

Source fieldPrinted as
static_slot: Option<BigUint>/* slot: 0x<hex> */ when set; suppressed otherwise

Same tagging rules as sstore. The printer renders the annotation whenever the field is Some and the deduplicator’s canonicalizer partitions signatures by slot; no pass currently writes Some(...), however, so in present-day dumps the annotation is dormant.

tload

(Expression::TLoad)

Description

Read a 32-byte word from transient storage at the given key. Transient storage is wiped at the end of the transaction; pair with tstore.

Syntax

tload($key[: <type>])

Example

let v1 := tload(v0)

Operands

NameTypeNotes
keyi256Transient storage slot.

Result and purity

ResultPurity
i256Pure (per IR; see Description)

Annotations

None. The IR does not track a static slot for tload.

mapping_sload

(Expression::MappingSLoad)

Description

Compound load for a Solidity mapping element. Equivalent to mstore(0, key); mstore(32, slot); sload(keccak256(0, 64)) but emitted as a single outlined call after the mapping_access_outlining pass recognizes the pattern (it fuses a keccak256_pair — itself produced by mem_opt’s keccak fusion — followed by an sload whose key has a single consumer). Only valid when the intermediate hash is used exclusively by this load.

Syntax

mapping_sload($key[: <type>], $slot[: <type>])

Example

let v2 := mapping_sload(v0: i160, v1)

Operands

NameTypeNotes
keyi256Mapping key; often narrowed to i160 for address keys.
sloti256The mapping’s declared storage slot.

Result and purity

ResultPurity
i256Pure (per IR; see Description)

Annotations

None. The fused statement’s effective storage slot is the keccak hash of the key and the declared slot, which is never a compile-time constant; no static_slot hint is surfaced.

dataoffset

(Expression::DataOffset)

Description

Offset of a named data segment within the deployed code. The identifier is a string carried in the IR’s id: String field; the linker resolves it to a concrete offset.

Syntax

dataoffset("<id>")

Example

let v0 := dataoffset("MyContract_deployed")

Operands

None — the identifier is a quoted string literal in the syntax position, not an operand.

Result and purity

ResultPurity
i256Pure

Annotations

Source fieldPrinted as
id: StringThe quoted identifier in the syntax position (not a comment annotation; it is the expression itself).

datasize

(Expression::DataSize)

Description

Size of a named data segment within the deployed code, in bytes. The identifier is resolved by the linker.

Syntax

datasize("<id>")

Example

let v0: i64 := datasize("MyContract_deployed")

Operands

None — the identifier is a quoted string literal in the syntax position, not an operand.

Result and purity

ResultPurity
i64Pure

Annotations

Source fieldPrinted as
id: StringThe quoted identifier in the syntax position.

loadimmutable

(Expression::LoadImmutable)

Description

Read the value of a named immutable variable. Immutables are written once during contract construction by SetImmutable and read afterwards via this expression.

Syntax

loadimmutable("<key>")

Example

let v0 := loadimmutable("MyContract.owner")

Operands

None — the key is a quoted string literal in the syntax position.

Result and purity

ResultPurity
i256Pure

Annotations

Source fieldPrinted as
key: StringThe quoted identifier in the syntax position.

linkersymbol

(Expression::LinkerSymbol)

Description

Address of an external library, resolved by the linker. The path encodes the library’s source location and identifier.

Syntax

linkersymbol("<path>")

Example

let v0: i160 := linkersymbol("contracts/Library.sol:L")

Operands

None — the path is a quoted string literal in the syntax position.

Result and purity

ResultPurity
i160Pure

Annotations

Source fieldPrinted as
path: StringThe quoted path in the syntax position.

<func_name>

(Expression::Call; the printer emits func_<id> when no function name is registered)

Description

Internal function call. Invokes a user-defined function declared earlier in the same object; the mnemonic is the function’s Yul-level name, or func_<id> if the printer has no name registered for the FunctionId. Distinct from call and the other EVM call-opcode statements, which cross the contract boundary.

Syntax

<func_name>([$argument_0[: <type>], $argument_1[: <type>], …])

Example

let v3 := abi_decode_uint256(v0, v1, v2)
let v4, v5 := returns_two(v0)           // multi-return via let multi-binding

Operands

NameTypeNotes
argumentsVec<Value>Zero or more argument values, in declaration order; each operand may carry a : <type> suffix.

Result and purity

ResultPurity
One or more values, widths taken from the callee’s declared return types (or the inferred return widths, narrowed via the interprocedural pass). Falls back to i256 when the callee’s returns are unknown to type inference.Effectful — the simplifier treats every call as side-effectful regardless of callee body, so unused call bindings are not DCE’d. The transitive purity of the callee is not tracked at the IR level.

Annotations

Source fieldPrinted as
function: FunctionIdThe callee’s name in the syntax position (or func_<id> if the printer has no name registered).

Memory and storage writes

The operations in this section all modify external state: emulated EVM linear memory, persistent storage, or transient storage. They are statements (not expressions) and they are never pure. Simplification and deduplication never reorder them with respect to each other or with respect to reverts; the memory passes treat them as the side-effect boundary for their analyses.

mstore

(Statement::MStore)

Description

Write a 32-byte word to emulated EVM linear memory at offset. The word is stored big-endian, matching EVM semantics; the codegen handles the byte swap on PolkaVM’s little-endian RISC-V target.

Syntax

mstore($offset[: <type>], $value[: <type>]) [/* <region> */]

Example

mstore(v0, v1)                    // Unknown region; no annotation printed
mstore(v2, v3) /* scratch */      // offset proven to land in 0x00..0x3f
mstore(v4, v5) /* free_ptr */     // offset is exactly 0x40

Operands

NameTypeNotes
offseti256Byte offset into linear memory; forward analysis widens to at least i64.
valuei256The 32-byte word to store. Narrower values are zero-extended at codegen time.

Result and purity

ResultPurity
NoneEffectful

Annotations

Source fieldPrinted as
region: MemoryRegion/* scratch */ · /* free_ptr */ · /* dynamic */ (Unknown is suppressed)

Assigned at translation time from the constant offset (if any); consumed by mem_opt, FMP propagation, and byte-swap mode selection.

mstore8

(Statement::MStore8)

Description

Write a single byte to emulated EVM linear memory at offset. The low 8 bits of value are stored; the upper bits are ignored. The operation is otherwise identical to mstore: same operand shape, same region tag, same side-effect classification.

Syntax

mstore8($offset[: <type>], $value[: <type>]) [/* <region> */]

Example

mstore8(v0, v1: i8)

Operands

NameTypeNotes
offseti256Byte offset into linear memory; forward analysis widens to at least i64.
valuei256Only the low 8 bits are stored. Often narrowed to i8 by type inference.

Result and purity

ResultPurity
NoneEffectful

Annotations

Source fieldPrinted as
region: MemoryRegion/* scratch */ · /* free_ptr */ · /* dynamic */ (Unknown is suppressed)

Same tagging rules as mstore. Most mstore8s carry an Unknown region in practice because single-byte writes typically target offsets the translator cannot prove constant.

mcopy

(Statement::MCopy)

Description

Copy length bytes from src to dest within emulated EVM linear memory. The Yul builtin mcopy maps directly onto this statement; unlike mstore, it does not carry a region tag because the source and destination ranges may straddle multiple regions.

Syntax

mcopy($dest[: <type>], $src[: <type>], $length[: <type>])

Example

mcopy(v0, v1, v2)

Operands

NameTypeNotes
desti256Destination byte offset in linear memory.
srci256Source byte offset in linear memory.
lengthi256Number of bytes to copy. Overlapping ranges follow EVM-defined memmove semantics.

Result and purity

ResultPurity
NoneEffectful

Annotations

None. mcopy carries no region tag because the source and destination ranges may straddle multiple regions, and no static-slot hint because the copy is not storage-bound.

sstore

(Statement::SStore)

Description

Write a 32-byte word to persistent contract storage at key. The operation is the durable counterpart of mstore: the value survives across transactions and is observable to subsequent calls to the contract.

Syntax

sstore($key[: <type>], $value[: <type>]) [/* slot: 0x<hex> */]

Example

sstore(v0, v1)
sstore(v2, v3) /* slot: 0x0 */

Operands

NameTypeNotes
keyi256Storage slot. May be a constant slot, a keccak-derived slot for mappings or dynamic arrays, or an arbitrary expression.
valuei256The 256-bit word to store.

Result and purity

ResultPurity
NoneEffectful

Annotations

Source fieldPrinted as
static_slot: Option<BigUint>/* slot: 0x<hex> */ when set; suppressed otherwise

The printer renders the annotation whenever the field is Some, and the deduplicator’s canonicalizer and mapping-fusion analyses consume it as part of the signature. No pass currently writes Some(...), so the annotation is dormant in present-day dumps; when absent, alias and dedup analyses fall back to the conservative “may alias any slot” assumption.

tstore

(Statement::TStore)

Description

Write a 32-byte word to transient storage at key. Transient storage is wiped at the end of the transaction, so tstore is the right primitive for per-transaction bookkeeping (reentrancy guards, cached results) without the gas cost of sstore on EVM. On PolkaVM the transient backing store is provided by pallet-revive.

Syntax

tstore($key[: <type>], $value[: <type>])

Example

tstore(v0, v1)

Operands

NameTypeNotes
keyi256Transient storage slot.
valuei256The 256-bit word to store.

Result and purity

ResultPurity
NoneEffectful

Annotations

None. Unlike sstore, the IR does not track a static slot for tstore: transient storage’s short-lived lifetime makes the slot-aware optimizations less valuable, and the translator does not produce the annotation.

mapping_sstore

(Statement::MappingSStore)

Description

Compound store for a Solidity mapping element. Equivalent to mstore(0, key); mstore(32, slot); sstore(keccak256(0, 64), value) but emitted as a single outlined statement after the mapping_access_outlining pass recognizes the pattern (it fuses a keccak256_pair followed by an sstore whose key has a single consumer). Only valid when the intermediate hash is not observed by any other statement.

Syntax

mapping_sstore($key[: <type>], $slot[: <type>], $value[: <type>])

Example

mapping_sstore(v0, v1, v2)

Operands

NameTypeNotes
keyi256Mapping key. The outlining pass force-widens it to i256, so it always prints at full width, even for address keys.
sloti256The mapping’s declared storage slot. Typically a small constant.
valuei256The value to store at the computed storage location.

Result and purity

ResultPurity
NoneEffectful

Annotations

None. mapping_sstore deliberately drops the static_slot annotation that the original sstore may have carried, because the fused statement’s effective slot is the keccak hash of the key and the declared slot, which is never a compile-time constant.

Bulk copies

Multi-byte memory copies from the EVM-accessible byte sources (code, external code, returndata, embedded data, and calldata) into emulated EVM linear memory. They all take the same shape: a destination memory offset, a source offset, and a length. They are effectful and act as opaque barriers to the memory passes.

codecopy

(Statement::CodeCopy)

Description

Copy length bytes from the currently executing code at offset into emulated EVM linear memory at dest. Reads past the end of code yield zero bytes.

Syntax

codecopy($dest[: <type>], $offset[: <type>], $length[: <type>])

Example

codecopy(v0, v1, v2)

Operands

NameTypeNotes
desti256Destination byte offset in linear memory.
offseti256Source byte offset in the executing code.
lengthi256Number of bytes to copy.

Result and purity

ResultPurity
NoneEffectful

Annotations

None.

extcodecopy

(Statement::ExtCodeCopy)

Description

Copy length bytes from the code at address starting at offset into emulated EVM linear memory at dest. Reads beyond the code yield zero bytes; non-existent accounts yield all zeros.

Syntax

extcodecopy($address[: <type>], $dest[: <type>], $offset[: <type>], $length[: <type>])

Example

extcodecopy(v0: i160, v1, v2, v3)

Operands

NameTypeNotes
addressi256Account whose code to read; forward analysis widens to at least i160.
desti256Destination byte offset in linear memory.
offseti256Source byte offset in the external code.
lengthi256Number of bytes to copy.

Result and purity

ResultPurity
NoneEffectful

Annotations

None.

returndatacopy

(Statement::ReturnDataCopy)

Description

Copy length bytes from the most recent sub-call’s return data starting at offset into emulated EVM linear memory at dest. Per EVM, reads past the return data’s end revert; the memory passes treat this as a potential trap site.

Syntax

returndatacopy($dest[: <type>], $offset[: <type>], $length[: <type>])

Example

returndatacopy(v0, v1, v2)

Operands

NameTypeNotes
desti256Destination byte offset in linear memory.
offseti256Source byte offset in the return-data buffer.
lengthi256Number of bytes to copy.

Result and purity

ResultPurity
NoneEffectful (may revert on out-of-range reads, per EVM)

Annotations

None.

datacopy

(Statement::DataCopy)

Description

Copy length bytes from an embedded data segment starting at offset into emulated EVM linear memory at dest. The source segment is resolved by the linker, typically used to pull constants compiled into the bytecode into runtime memory.

Syntax

datacopy($dest[: <type>], $offset[: <type>], $length[: <type>])

Example

datacopy(v0, v1, v2)

Operands

NameTypeNotes
desti256Destination byte offset in linear memory.
offseti256Source byte offset in the data segment.
lengthi256Number of bytes to copy.

Result and purity

ResultPurity
NoneEffectful

Annotations

None.

calldatacopy

(Statement::CallDataCopy)

Description

Copy length bytes from the current call’s calldata starting at offset into emulated EVM linear memory at dest. Reads past the end of calldata yield zero bytes.

Syntax

calldatacopy($dest[: <type>], $offset[: <type>], $length[: <type>])

Example

calldatacopy(v0, v1, v2)

Operands

NameTypeNotes
desti256Destination byte offset in linear memory.
offseti256Source byte offset in calldata.
lengthi256Number of bytes to copy.

Result and purity

ResultPurity
NoneEffectful

Annotations

None.

Bindings and wrappers

The statements that bind SSA values, hold loose expressions evaluated for their side effects, and write to immutable storage. Every pure expression in this reference’s earlier sections appears on the right-hand side of one of these statements (almost always let).

let

(Statement::Let)

Description

SSA binding: evaluate an expression and bind its result(s) to a list of fresh value ids. The let statement is the only mechanism by which pure expressions enter the value namespace; every v<id> in a dump was produced by a let (or by a value-yielding control-flow statement or by a parameter at function entry).

Syntax

let $binding_0[, $binding_1, …] := $expression

Example

let v3 := add(v0, v1)
let v4, v5 := if v2 [v0, v1] { … } else { … }   // multi-binding from a value-yielding If

Operands

NameTypeNotes
bindingsVec<ValueId>One or more fresh SSA ids to bind. Most expressions produce one value; control-flow statements may produce several.
valueExpressionThe right-hand side; see any of the Pure expression entries.

Result and purity

ResultPurity
None directly — the bound ids carry the expression’s result(s)Effectful (binding establishment); the right-hand side’s purity is independent

Annotations

None.

Expression statement

(Statement::Expression)

Description

Wraps an expression evaluated for its observable consequences but whose value is not bound. Typically a zero-return (void) user-defined function call (Expression::Call) evaluated for its side effects, or the discarded void result of a Yul builtin used as a statement (a value-producing expression is bound by a let instead). EVM external calls (call, delegatecall, etc.) and contract creation (create, create2) translate to dedicated Statement::ExternalCall and Statement::Create variants, not through this wrapper.

Syntax

$expression

Example

update_balance(v0)          // void function called for its side effects

Operands

NameTypeNotes
expressionExpressionAny expression; result is discarded.

Result and purity

ResultPurity
NoneEffectful (per its statement position)

Annotations

None.

setimmutable

(Statement::SetImmutable)

Description

Write an immutable variable during contract construction. Immutables are written once in the constructor and read later via loadimmutable. The key is a string identifier resolved by the linker.

Syntax

setimmutable("<key>", $value[: <type>])

Example

setimmutable("MyContract.owner", v0)

Operands

NameTypeNotes
valuei256The value to store; the key is a quoted string literal in the syntax position.

Result and purity

ResultPurity
NoneEffectful

Annotations

Source fieldPrinted as
key: StringThe quoted identifier in the syntax position.

Structured control flow

The IR’s control flow is structured: if, switch, and for are statements with explicit nested regions, each carrying input values and yielding output values. The jump-like statements (break, continue, leave) are scoped to their nearest enclosing construct. Nested blocks create lexical scope without otherwise changing control flow.

if

(Statement::If)

Description

Conditional execution with optional value yields. The then region runs when condition is non-zero; the else region runs otherwise. If outputs is non-empty, both regions must yield the same number of values and the statement is bound by a let.

Syntax

if $condition[: <type>] [[$input_0, $input_1, …]] { … } [else { … }]

Example

if v0: i1 {
    sstore(v1, v2)
}

let v5, v6 := if v3: i1 [v1, v2] {
    let v7: i64 := 0x1          // add widens its operands to the i64 register width
    let v8 := add(v2, v7: i64)
    yield v1, v8
} else {
    yield v1, v2
}

Operands

NameTypeNotes
conditioni256Branch selector; non-zero takes the then region. Often narrowed to i1.
inputsVec<Value>Values threaded into both regions, printed in square brackets after the condition.
(regions)The then_region is mandatory; the else_region is optional and, when absent, implicitly yields the inputs unchanged.

Result and purity

ResultPurity
None for the statement form; for the value-yielding form, one value per outputs binding, types taken from the yielded valuesEffectful (control flow)

Annotations

None.

switch

(Statement::Switch)

Description

Multi-way dispatch on a scrutinee value. Each case matches a specific constant and runs its region; an optional default region catches non-matching values. Like if, switch may yield values via outputs and accept thread-through values via inputs.

Syntax

switch $scrutinee[: <type>] [[$input_0, …]]
case 0x<hex> {
    …
}
[case 0x<hex> {
    …
} …]
[default {
    …
}]

Example

switch v0
case 0x0 {
    sstore(v1, v2)
}
case 0x1 {
    sstore(v1, v3)
}
default {
    invalid()
}

Operands

NameTypeNotes
scrutineei256The value to compare against each case.
inputsVec<Value>Values threaded into every case and default region.
casesVec<SwitchCase>Each case carries a constant value: BigUint and a region.
(default)Optional fall-through region.

Result and purity

ResultPurity
None for the statement form; one value per outputs binding for the value-yielding formEffectful (control flow)

Annotations

None.

for

(Statement::For)

Description

Structured loop with explicit loop-carried variables. Each iteration evaluates condition_statements followed by condition; if the condition is non-zero, the body region runs, then the post region runs, and the loop iterates. Loop-carried variables are passed as SSA values through each region. break exits the loop and continue jumps to the post region.

Syntax

for { $variable_0 := $initial_0[, …] }
    [// condition statements:
        …]
    condition: $condition
    post [($post_input_variable_0[, …])] {
        …
    }
    body {
        … body …
    }

Example

let v0: i1 := 0x0
let v6 := for { v1 := v0: i1 }
    // condition statements:
    let v2: i8 := 0xa
    condition: lt(v1, v2: i8)
    post (v3) {
        let v4: i64 := 0x1
        let v5 := add(v3, v4: i64)
        yield v5
    }
    body {
        sstore(v1, v1)
        0x0: void
        yield v1
    }

Operands

NameTypeNotes
initial_valuesVec<Value>Starting values for the loop-carried variables.
loop_variablesVec<ValueId>SSA ids visible inside condition, body, and post.
condition_statementsVec<Statement>Statements evaluated each iteration before the condition expression; emitted into the loop header block. Printed only when non-empty, behind a // condition statements: comment.
conditionExpressionRe-evaluated each iteration; non-zero continues, zero exits.
bodyRegionLoop body; yields current loop-carried values.
post_input_variablesVec<ValueId>Input SSA ids for the post region (one per loop-carried variable); receive the body’s yielded values merged with continue-site values via phi nodes in the LLVM codegen.
postRegionRuns after each body iteration (and after continue); yields updated loop-carried values.
outputsVec<ValueId>Final loop-carried values after exit.

Result and purity

ResultPurity
None for the statement form; one value per outputs binding for the value-yielding formEffectful (control flow)

Annotations

None.

break

(Statement::Break)

Description

Exit the innermost enclosing for loop. Carries the current values of loop-carried variables at the break point; these become the loop’s outputs.

Syntax

break

Example

if v0 { break [v1, v2] }

Operands

The loop-carried values: Vec<Value> print in brackets when non-empty (e.g. break [v1, v2]).

Result and purity

ResultPurity
NoneEffectful (control flow)

Annotations

None.

continue

(Statement::Continue)

Description

Skip to the post region of the innermost enclosing for loop. Like break, carries the current values of loop-carried variables internally.

Syntax

continue

Example

if v0 { continue [v1, v2] }

Operands

The loop-carried values print in brackets when non-empty (e.g. continue [v1, v2]).

Result and purity

ResultPurity
NoneEffectful (control flow)

Annotations

None.

leave

(Statement::Leave)

Description

Exit the current function, returning the listed values as the function’s return values. The Yul-level leave keyword translates directly to this statement; the inlining pass eliminates intra-function leaves where possible via the exit-flag transformation.

Syntax

leave [[$value_0[: <type>], $value_1[: <type>], …]]

Example

leave [v0, v1]              // returns v0 and v1 from the function
leave                       // returns nothing (void function)

Operands

NameTypeNotes
return_valuesVec<Value>Empty for void functions; otherwise one entry per declared return.

Result and purity

ResultPurity
NoneEffectful (control flow)

Annotations

None.

Nested block

(Statement::Block)

Description

A lexical scope without conditional or iterative behavior. The body is a region; control falls through after the region’s statements complete. Used to bound the visibility of inner bindings.

Syntax

{
    …
}

Example

{
    let v0 := add(v1, v2)
    sstore(v3, v0)
}                           // v0 is no longer in scope here

Operands

None — the body is a region, not an operand.

Result and purity

ResultPurity
NoneEffectful (per the body’s contents)

Annotations

None.

External interaction

Statements that cross the contract boundary: external calls, contract creation, and event log emission. All produce or rely on external state and act as barriers to memory and storage analyses.

call

(Statement::ExternalCall with CallKind::Call)

Description

Standard external call that may transfer value. Reads args_length bytes from emulated EVM linear memory at args_offset as calldata, executes the target, and writes up to ret_length bytes of return data into linear memory at ret_offset. The boolean result indicates success.

Syntax

let $result := call($gas[: <type>], $address[: <type>], $value[: <type>], $args_offset[: <type>], $args_length[: <type>], $ret_offset[: <type>], $ret_length[: <type>])

Example

let v8 := call(v0: i64, v1: i160, v2, v3: i64, v4: i64, v5: i64, v6: i64)

Operands

NameTypeNotes
gasi256Gas to forward to the target; forward analysis widens to at least i64.
addressi256Callee address; forward analysis widens to at least i160.
valuei256Wei to transfer with the call.
args_offseti256Calldata source offset in linear memory; forward analysis widens to at least i64.
args_lengthi256Calldata length in bytes; forward analysis widens to at least i64.
ret_offseti256Return-data destination offset in linear memory; forward analysis widens to at least i64.
ret_lengthi256Maximum return-data length; forward analysis widens to at least i64.

Result and purity

ResultPurity
i256 (success flag: 1 on success, 0 on revert/error; narrowable to i1)Effectful

Annotations

None.

callcode

(Statement::ExternalCall with CallKind::CallCode)

Description

Deprecated EVM opcode that executes the callee’s code in the caller’s context but with the callee’s storage. Not supported by the newyork backend (codegen rejects it); use delegatecall instead.

Syntax

let $result := callcode($gas[: <type>], $address[: <type>], $value[: <type>], $args_offset[: <type>], $args_length[: <type>], $ret_offset[: <type>], $ret_length[: <type>])

Example

let v8 := callcode(v0: i64, v1: i160, v2, v3: i64, v4: i64, v5: i64, v6: i64)

Operands

Same shape as call.

Result and purity

ResultPurity
i256 (success flag; narrowable to i1)Effectful

Annotations

None.

delegatecall

(Statement::ExternalCall with CallKind::DelegateCall)

Description

Execute the callee’s code in the caller’s context: same storage, same sender, same call value. The standard mechanism for library calls and proxy patterns. No value operand (the caller’s call value is inherited).

Syntax

let $result := delegatecall($gas[: <type>], $address[: <type>], $args_offset[: <type>], $args_length[: <type>], $ret_offset[: <type>], $ret_length[: <type>])

Example

let v7 := delegatecall(v0: i64, v1: i160, v2: i64, v3: i64, v4: i64, v5: i64)

Operands

Same shape as call minus the value operand.

Result and purity

ResultPurity
i256 (success flag; narrowable to i1)Effectful

Annotations

None.

staticcall

(Statement::ExternalCall with CallKind::StaticCall)

Description

Read-only external call. Any state modification in the callee (including nested calls) causes the call to revert. No value operand.

Syntax

let $result := staticcall($gas[: <type>], $address[: <type>], $args_offset[: <type>], $args_length[: <type>], $ret_offset[: <type>], $ret_length[: <type>])

Example

let v7 := staticcall(v0: i64, v1: i160, v2: i64, v3: i64, v4: i64, v5: i64)

Operands

Same shape as call minus the value operand.

Result and purity

ResultPurity
i256 (success flag; narrowable to i1)Effectful (no state writes, but still an external boundary and may revert)

Annotations

None.

create

(Statement::Create with CreateKind::Create)

Description

Deploy a new contract with the given init-code bytes, transferring value wei from the caller. The new contract’s address is derived from the caller’s address and nonce; on failure the result is 0.

Syntax

let $result := create($value[: <type>], $offset[: <type>], $length[: <type>])

Example

let v4 := create(v0, v1: i64, v2: i64)

Operands

NameTypeNotes
valuei256Wei to transfer to the new contract.
offseti256Linear-memory offset of the init code; forward analysis widens to at least i64.
lengthi256Length of the init code in bytes; forward analysis widens to at least i64.

Result and purity

ResultPurity
i256 (created address; narrowable to i160 on success, 0 on failure)Effectful

Annotations

None.

create2

(Statement::Create with CreateKind::Create2)

Description

Deploy a new contract with a deterministic address derived from the caller’s address, the salt, and the init-code hash. Same operand shape as create plus an additional salt.

Syntax

let $result := create2($value[: <type>], $offset[: <type>], $length[: <type>], $salt[: <type>])

Example

let v5 := create2(v0, v1: i64, v2: i64, v3)

Operands

Same as create plus salt: i256.

Result and purity

ResultPurity
i256 (created address; narrowable to i160 on success, 0 on failure)Effectful

Annotations

None.

log<N>

(Statement::Log)

Description

Emit an event log entry. The mnemonic suffix <N> is the number of indexed topics (0 through 4), determined by the length of the IR’s topics field. The data portion is read from length bytes of emulated EVM linear memory at offset.

Syntax

log<N>($offset[: <type>], $length[: <type>][, $topic_0[: <type>], …])

Example

log0(v0: i64, v1: i64)                    // no topics
log2(v0: i64, v1: i64, v2, v3)            // two topics

Operands

NameTypeNotes
offseti256Data source offset in linear memory; forward analysis widens to at least i64.
lengthi256Data length in bytes; forward analysis widens to at least i64.
topicsVec<Value>Zero to four indexed topic values; the length determines the mnemonic suffix.

Result and purity

ResultPurity
NoneEffectful

Annotations

None.

Termination

Statements that end the current call frame. Plain forms (return, revert, stop), unconditional traps (invalid, selfdestruct), and outlined revert variants (panic_revert, error_string_revert, custom_error_revert) that encode common Solidity error patterns into single nodes that can be deduplicated across call sites.

return

(Statement::Return)

Description

End the current call frame successfully, returning length bytes from emulated EVM linear memory at offset as the return data.

Syntax

return($offset[: <type>], $length[: <type>])

Example

return(v0: i64, v1: i64)

Operands

NameTypeNotes
offseti256Return-data source offset; forward analysis widens to at least i64.
lengthi256Return-data length; forward analysis widens to at least i64.

Result and purity

ResultPurity
None — terminates the call frameEffectful (terminator)

Annotations

None.

revert

(Statement::Revert)

Description

End the current call frame with a revert, undoing all state changes made during the call, and returning length bytes of revert data from emulated EVM linear memory at offset.

Syntax

revert($offset[: <type>], $length[: <type>])

Example

revert(v0: i64, v1: i64)

Operands

NameTypeNotes
offseti256Revert-data source offset; forward analysis widens to at least i64.
lengthi256Revert-data length; forward analysis widens to at least i64.

Result and purity

ResultPurity
None — terminates the call frameEffectful (terminator)

Annotations

None.

stop

(Statement::Stop)

Description

End the current call frame successfully with empty return data.

Syntax

stop()

Example

stop()

Operands

None.

Result and purity

ResultPurity
None — terminates the call frameEffectful (terminator)

Annotations

None.

invalid

(Statement::Invalid)

Description

Unconditional invalid-opcode trap. Consumes all remaining gas and reverts. Used for unreachable branches and assertion failures.

Syntax

invalid()

Example

invalid()

Operands

None.

Result and purity

ResultPurity
None — terminates the call frameEffectful (terminator)

Annotations

None.

selfdestruct

(Statement::SelfDestruct)

Description

End the current call frame and transfer the contract’s remaining balance to address. Post-Cancun, the contract storage is not deleted (selfdestruct is effectively deprecated; the opcode still exists for legacy compatibility).

Syntax

selfdestruct($address[: <type>])

Example

selfdestruct(v0: i160)

Operands

NameTypeNotes
addressi256Recipient of the contract’s balance; forward analysis widens to at least i160.

Result and purity

ResultPurity
None — terminates the call frameEffectful (terminator)

Annotations

None.

panic_revert

(Statement::PanicRevert)

Description

Outlined Solidity panic revert. Equivalent to writing the Panic(uint256) ABI encoding (selector 0x4e487b71 plus the panic code) into emulated EVM linear memory and reverting, but emitted as a single statement that lowers to one outlined helper call. Common panic codes: 0x01 assertion failure, 0x11 arithmetic overflow, 0x12 division by zero, 0x32 array-out-of-bounds, 0x41 memory overflow.

Syntax

panic_revert(0x<hex>)

Example

panic_revert(0x11)              // arithmetic overflow

Operands

None — the panic code is stored as a u8 field on the IR, not an SSA operand.

Result and purity

ResultPurity
None — terminates the call frameEffectful (terminator)

Annotations

Source fieldPrinted as
code: u8The panic code in 0x<hex> form (two hex digits, zero-padded).

error_string_revert

(Statement::ErrorStringRevert)

Description

Outlined Solidity Error(string) revert. Equivalent to writing the Error selector (0x08c379a0), the string offset and length, and up to four 32-byte data words into emulated EVM linear memory and reverting. The string length and the data words are stored as compile-time fields; no SSA operands.

Syntax

error_string_revert(<length>, <N>_words)

Example

error_string_revert(12, 1_words)        // 12-byte string in one 32-byte word

Operands

None — the string length and data are compile-time fields, not SSA operands.

Result and purity

ResultPurity
None — terminates the call frameEffectful (terminator)

Annotations

Source fieldPrinted as
length: u8The string length in bytes, in the first syntax position.
data: Vec<BigUint>The number of 32-byte data words (1–4), printed as <N>_words in the second syntax position. The actual data is stored separately and not shown in the printed form.

custom_error_revert

(Statement::CustomErrorRevert)

Description

Outlined Solidity custom-error revert. Encodes the error selector (left-shifted by 224 bits) and zero or more argument values into scratch memory and reverts. No FMP load is needed; the encoding uses the scratch region at offset 0.

Syntax

custom_error_revert(0x<hex>, [$arg_0, $arg_1, …])

Example

custom_error_revert(0xa28c4c11, [v0, v1])

Operands

NameTypeNotes
argumentsVec<Value>Zero or more argument values; the selector is a compile-time field.

Result and purity

ResultPurity
None — terminates the call frameEffectful (terminator)

Annotations

Source fieldPrinted as
selector: BigUintThe 4-byte error selector in hex, in the first syntax position. The selector is stored left-shifted by 224 bits; the printer right-shifts it back and prints the bare 4-byte value.