HIR (High-level Intermediate Representation) Specification
Overview
The Ora HIR bridges the AST and codegen phases. It models validated, effect-aware, and optimizable program structure.
Key Features
- Explicit effect tracking
- Memory region modeling
- Strong type system
- Formal verification support
- Optimizer-friendly
- Error union/result support
- Dynamic symbol tracking
Design Principles
- Explicit behavior modeling
- Immutable HIR nodes
- Must validate before codegen
- All effects are tracked
- Memory safety enforced
- Simplicity over complexity
- Accurate program behavior modeling
Memory Model
enum Region {
stack, memory, storage, tstore, const_, immutable
}
Region | Lifetime | Mutability | Gas Cost | Use Case |
---|---|---|---|---|
stack | Function | Variable | Low | Local vars |
memory | Transaction | Variable | Medium | Temporary buffers |
storage | Persistent | Variable | High | Contract state |
tstore | Transaction | Variable | Medium | Transient state |
const_ | Compile-time | Immutable | None | Constants |
immutable | Deployment | Immutable | Low | Init-only contract vars |
Type System
enum PrimitiveType {
u8, u16, u32, u64, u128, u256,
bool, address, string
}
union Type {
primitive: PrimitiveType,
mapping: MappingType,
slice: SliceType,
custom: CustomType,
error_union: ErrorUnionType,
result: ResultType
}
Node Structure
HIRProgram
struct HIRProgram {
version: string,
contracts: []Contract,
allocator: Allocator
}
Contract
struct Contract {
name: string,
storage: []StorageVariable,
functions: []Function,
events: []Event,
allocator: Allocator
}
Function
struct Function {
name: string,
visibility: Visibility,
parameters: []Parameter,
return_type: ?Type,
requires: []Expression,
ensures: []Expression,
body: Block,
state_effects: EffectSet,
observable_effects: EffectSet,
effects: FunctionEffects,
location: SourceLocation,
allocator: Allocator
}
FunctionEffects
struct FunctionEffects {
writes_storage: bool,
reads_storage: bool,
writes_transient: bool,
reads_transient: bool,
emits_logs: bool,
calls_other: bool,
modifies_state: bool,
is_pure: bool
}
Expressions
union Expression {
binary, unary, call, index, field, transfer, shift,
old, literal, identifier, try_expr, error_value, error_cast
}
Statements
union Statement {
variable_decl, assignment, compound_assignment, if_statement,
while_statement, return_statement, expression_statement,
lock_statement, unlock_statement, error_decl,
try_statement, error_return
}
Effect System
Effect
struct Effect {
type: EffectType,
path: AccessPath,
condition: ?Expression
}
AccessPath
struct AccessPath {
base: string,
selectors: []PathSelector,
region: Region
}
PathSelector
union PathSelector {
field: { name: string },
index: { index: Expression }
}
Effect Analysis
- Symbol tables are rebuilt per contract
- All expressions and statements are walked
- Effects are computed recursively
- Computed metadata:
modifies_state = writes_storage || writes_transient || emits_logs
is_pure = !(writes_storage || reads_storage || writes_transient || reads_transient || emits_logs || calls_other)
Validation Rules
- All expressions must be typed
- Assignments must be type-compatible
- Function args must match params
- Index ops must match container types
- All effects must be consistent with requires/ensures
- Return paths must be valid
- Invariants must be stated on loops
- Error branches must be handled or propagated
Optimization Framework
struct OptimizationPass {
name: string,
run: fn(*HIRProgram, Allocator) -> anyerror!void
}
Standard passes:
- Dead code elimination
- Constant folding
- Effect optimization
- Gas optimization
JSON Serialization
- HIR serializes to JSON for tooling/debugging
- Effects included as simple flags
- Example:
{
"name": "transfer",
"effects": {
"writes_storage": true,
"emits_logs": true,
"is_pure": false
}
}
Examples
Simple Function HIR
pub fn transfer(to: address, amount: u256) -> bool
requires(balances[std.transaction.sender] >= amount)
ensures(balances[std.transaction.sender] + balances[to] ==
old(balances[std.transaction.sender]) + old(balances[to]))
{
@lock(balances[to]);
balances from std.transaction.sender -> to : amount;
log Transfer(std.transaction.sender, to, amount);
return true;
}
HIR Effects:
writes_storage: true
(modifies balances)emits_logs: true
(emits Transfer event)is_pure: false
(has side effects)
Complex Expression HIR
let result = balances[sender] + balances[receiver];
AccessPath Analysis:
balances[sender]
→{base: "balances", selectors: [index(sender)], region: storage}
balances[receiver]
→{base: "balances", selectors: [index(receiver)], region: storage}
Implementation Notes
- All HIR nodes use allocators
- Every node includes source location
- Effects tracked both structurally and via summary flags
- Per-contract symbol isolation required
Extensions
- Future: cross-contract effects, verification output, gas metrics
- Lock/Transfer annotations may decorate functions with semantic guarantees
Usage in Compilation Pipeline
- AST → HIR: Convert abstract syntax tree to high-level IR
- HIR Validation: Ensure type safety and effect consistency
- HIR Optimization: Apply optimization passes
- HIR → Yul: Generate Yul code from optimized HIR
- Yul → Bytecode: Compile to EVM bytecode
The HIR serves as the central representation for analysis, optimization, and code generation in the Ora compiler.