Skip to content

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

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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