Summary
Replace the current "PUSH0 placeholder" codegen with a Venom-style stack scheduler that maps MIR values to explicit EVM stack operations, assuming ≤16 live values.
Parent issue: #687
Context
The EVM is a stack machine with a 16-slot visibility window (DUP1-16, SWAP1-16). Currently, codegen emits PUSH0 as a placeholder for non-immediate values—this produces broken bytecode.
We need an abstract stack model that:
- Tracks which MIR values are at which stack positions
- Emits DUP/SWAP sequences to arrange operands correctly before each instruction
- Drops dead values from the stack
This issue covers the simpler case: functions where we never exceed 16 live values simultaneously.
Tasks
Abstract stack machine model
Per-block linear scheduling
Integration with codegen
Limitation handling
Patterns to follow
From Venom:
- Abstract virtual stack state per instruction
ensure_on_top generating optimal DUP/SWAP instead of ad-hoc patterns
- Separation between scheduling pass and assembler emission
From Sonatina:
- Pass structure: implement as transformation/annotation pass over MIR
Example
MIR:
v0 = arg(0)
v1 = arg(1)
v2 = add(v0, v1)
v3 = mul(v2, v0)
return v3
Stack scheduling trace:
[v0, v1] ; after loading args
DUP2 ; copy v0 for later use
[v0, v1, v0]
ADD ; consumes top 2, produces v2
[v0, v2]
SWAP1 ; bring v0 to top for mul
[v2, v0]
DUP2 ; copy v2
[v2, v0, v2]
SWAP1
[v2, v2, v0]
MUL ; produces v3
[v2, v3]
SWAP1, POP ; drop v2
[v3]
RETURN
Acceptance Criteria
Estimated Complexity
Large - Core algorithm is manageable but many edge cases
Dependencies
Summary
Replace the current "PUSH0 placeholder" codegen with a Venom-style stack scheduler that maps MIR values to explicit EVM stack operations, assuming ≤16 live values.
Parent issue: #687
Context
The EVM is a stack machine with a 16-slot visibility window (DUP1-16, SWAP1-16). Currently, codegen emits
PUSH0as a placeholder for non-immediate values—this produces broken bytecode.We need an abstract stack model that:
This issue covers the simpler case: functions where we never exceed 16 live values simultaneously.
Tasks
Abstract stack machine model
StackSlotabstraction tracking whichValueIdis at which depthAbstractStackwith operations:push(value)- add value to toppop()- remove topensure_on_top(value) -> Vec<Opcode>- emit DUP/SWAP to bring value to TOSdrop(value)- remove value from stackget_depth(value) -> Option<usize>- find value positionPer-block linear scheduling
ensure_on_top(value), emit DUP/SWAPIntegration with codegen
PUSH0emissions with scheduler callsLimitation handling
Patterns to follow
From Venom:
ensure_on_topgenerating optimal DUP/SWAP instead of ad-hoc patternsFrom Sonatina:
Example
Acceptance Criteria
Estimated Complexity
Large - Core algorithm is manageable but many edge cases
Dependencies