Skip to main content

StackScheduler

Struct StackScheduler 

Source
pub struct StackScheduler {
    pub stack: StackModel,
    pub spills: SpillManager,
    /* private fields */
}
Expand description

Stack scheduler that generates stack manipulation operations.

Fields§

§stack: StackModel

Current stack state.

§spills: SpillManager

Spill manager for values beyond stack depth 16.

Implementations§

Source§

impl StackScheduler

Source

pub fn new() -> Self

Creates a new stack scheduler.

Source

pub fn clear_ops(&mut self)

Clears the scheduled operations (after emitting them).

Source

pub fn take_ops(&mut self) -> Vec<ScheduledOp>

Takes the scheduled operations.

Source

pub fn ensure_on_top( &mut self, value: ValueId, func: &Function, ) -> &[ScheduledOp]

Ensures a value is on top of the stack. Returns the operations needed to achieve this.

Source

pub fn ensure_operand_on_top( &mut self, value: ValueId, func: &Function, ) -> &[ScheduledOp]

Emits a fresh operand occurrence for a consuming instruction.

If value is already on top, ensure_on_top can claim that existing stack item. That is correct for a single use, but wrong for instructions that consume the same MIR value more than once, such as revert(x, x) or log1(x, x, x). In those cases every operand occurrence needs its own stack item, so a top-of-stack value must be duplicated.

Source

pub fn can_emit_value(&self, value: ValueId, func: &Function) -> bool

Checks if we can emit a value (it’s an immediate, arg, on stack, or spilled). Returns false for instruction results that aren’t tracked.

Source

pub fn ensure_on_top_many( &mut self, values: &[ValueId], func: &Function, ) -> Vec<ScheduledOp>

Ensures multiple values are on top of the stack in order. The first value will be at the top, second below it, etc.

Source

pub fn bring_to_top(&mut self, value: ValueId) -> Option<StackOp>

Brings a specific value to the top of the stack using SWAP. The value must already be on the stack within accessible range.

Source

pub fn instruction_executed( &mut self, consumed: usize, produced: Option<ValueId>, )

Records that an instruction consumed its operands and produced a result. This updates the stack model accordingly.

Source

pub fn instruction_executed_untracked(&mut self, consumed: usize)

Records that an instruction consumed inputs and produced an untracked output. The output is on the EVM stack but we don’t track which ValueId it corresponds to. This is used for MLOAD where the value may become stale in loops.

Source

pub fn has_untracked_on_top(&self) -> bool

Checks if there’s an untracked value on top of the stack.

Source

pub fn has_untracked_at_depth(&self, depth: usize) -> bool

Checks if there’s an untracked value at a specific depth.

Source

pub fn stack_swapped(&mut self)

Records that a SWAP1 was executed, updating the stack model.

Source

pub fn drop_dead_values( &mut self, liveness: &Liveness, block: BlockId, inst_idx: usize, ) -> Vec<StackOp>

Drops dead values from the stack. Returns operations (SWAPs and POPs) to remove dead values.

Source

pub fn spill_excess_values(&mut self) -> Vec<ScheduledOp>

Spills values to memory to make room on the stack. This is needed when stack depth exceeds 16.

Source

pub fn stack_depth(&self) -> usize

Returns the current stack depth.

Source

pub fn depth(&self) -> usize

Returns the current stack depth (alias for stack_depth).

Source

pub fn clear_stack(&mut self)

Clears the stack model (used at block boundaries).

Source

pub fn shuffle_to_layout(&mut self, target: &[TargetSlot]) -> ShuffleResult

Shuffles the current stack to match the target layout.

This uses the backward layout optimization approach:

  • Given a target layout (what we want the stack to look like)
  • Generate the minimal sequence of DUP/SWAP/POP operations

Returns the shuffle result containing the operations to emit.

Source

pub fn prepare_binary_op( &mut self, a: ValueId, b: ValueId, _func: &Function, ) -> ShuffleResult

Prepares the stack for a binary operation.

Given operands (a, b) where a should be on top and b below:

  • Computes the target layout [a, b, …rest]
  • Shuffles current stack to match
  • Returns operations to emit
Source

pub fn prepare_unary_op( &mut self, operand: ValueId, _func: &Function, ) -> ShuffleResult

Prepares the stack for a unary operation.

Given operand that should be on top:

  • Computes the target layout [operand, …rest]
  • Shuffles current stack to match
  • Returns operations to emit
Source

pub fn compute_binary_entry_layout( a: ValueId, b: ValueId, result: Option<ValueId>, exit_layout: &[TargetSlot], ) -> Vec<TargetSlot>

Computes the ideal entry layout for a binary operation given the exit layout.

For ADD(a, b) -> result, if exit layout is [result, x, y]:

  • Entry layout should be [a, b, x, y]
Source

pub fn compute_unary_entry_layout( operand: ValueId, result: Option<ValueId>, exit_layout: &[TargetSlot], ) -> Vec<TargetSlot>

Computes the ideal entry layout for a unary operation given the exit layout.

Source

pub fn set_block_entry_layout( &mut self, block: BlockId, layout: BlockStackLayout, )

Sets the entry layout for a block.

This is used to specify what the stack should look like when entering a block. Predecessors will shuffle their stacks to match this layout.

Source

pub fn get_block_entry_layout( &self, block: BlockId, ) -> Option<&BlockStackLayout>

Gets the entry layout for a block, if one has been set.

Source

pub fn record_block_exit_layout(&mut self, block: BlockId)

Records the exit layout for a block (current stack state).

This is called after generating a block’s instructions, before the terminator. The layout is used to determine what values are on the stack when exiting.

Source

pub fn get_block_exit_layout(&self, block: BlockId) -> Option<&BlockStackLayout>

Gets the exit layout for a block, if one has been recorded.

Source

pub fn compute_merge_layout( &self, predecessors: &[BlockId], live_in: impl IntoIterator<Item = ValueId>, ) -> BlockStackLayout

Computes the entry layout for a merge block from its predecessors’ exit layouts.

This is the key function for phi node handling. It finds a common stack layout that all predecessors can shuffle to with minimal cost.

The function also considers the live-in values for the block to ensure all needed values are on the stack.

Source

pub fn shuffle_to_block_entry(&mut self, target_block: BlockId) -> ShuffleResult

Shuffles the current stack to match a block’s entry layout.

Returns the shuffle operations needed. The caller is responsible for emitting the actual opcodes.

Source

pub fn init_from_block_entry_layout(&mut self, block: BlockId)

Initializes the stack from a block’s entry layout.

This is called when starting to generate a block that has an entry layout. It sets up the stack model to match the expected entry state.

Source

pub fn clear_block_layouts(&mut self)

Clears all block layout information.

Called when starting to generate a new function.

Source

pub fn has_block_entry_layout(&self, block: BlockId) -> bool

Returns true if a block has an entry layout set.

Source

pub fn stack_matches_entry_layout(&self, target_block: BlockId) -> bool

Checks if the current stack matches a block’s entry layout.

Returns true if the stack already matches the target layout (no shuffling needed).

Trait Implementations§

Source§

impl Default for StackScheduler

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T, R> CollectAndApply<T, R> for T

Source§

fn collect_and_apply<I, F>(iter: I, f: F) -> R
where I: Iterator<Item = T>, F: FnOnce(&[T]) -> R,

Equivalent to f(&iter.collect::<Vec<_>>()).

Source§

type Output = R

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more