Skip to content

VM: inline arithmetic opcodes for statically-known integer types #110

@timfennis

Description

@timfennis

Background

All arithmetic operators (+, -, <, etc.) are compiled as Call instructions. Even after issue #107 (single-candidate binding collapse), a call to -(n, 1) still goes through the full call machinery: push callee, push args, Call(2)resolve_calleedispatch_call_with_memo → native closure → pop args, push result.

For integer-only hot paths like fib, this is significant overhead for what amounts to a - b.

Proposed fix

Add typed arithmetic opcodes to OpCode:

pub enum OpCode {
    // ... existing ...
    AddInt,
    SubInt,
    MulInt,
    LtInt,
    LtEqInt,
    GtInt,
    GtEqInt,
    // etc.
}

The VM handles these inline with no function call overhead:

OpCode::SubInt => {
    let b = self.stack.pop().expect("stack underflow");
    let a = self.stack.pop().expect("stack underflow");
    match (a, b) {
        (Value::Int(x), Value::Int(y)) => self.stack.push(Value::Int(x - y)),
        (a, b) => return Err(VmError::new(
            format!("SubInt: expected (Int, Int), got ({}, {})", a.static_type(), b.static_type()),
            span,
        )),
    }
}

The compiler emits these when both operand types are statically known to be Int at the call site.

Prerequisite: improved type inference

This optimisation is currently blocked because unannotated parameters like fn fib(n) are inferred as Any, so the compiler cannot confirm that n is an Int and cannot safely emit SubInt.

Type inference would need to propagate call-site types into function bodies — e.g. fib(26) implies n: Int on the first call, and recursive calls fib(n-1) with n-1: Int perpetuate that. This is either inter-procedural type inference or requires explicit type annotations from the user.

Once type inference is improved, the compiler can emit SubInt / LtInt etc. for the hot paths in fib, eliminating ~4 function-call dispatches per non-leaf frame.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions