neural/rs/codegen/src/lir.rs

//! LIR types: virtual registers, labels, and the 3-address op set used by mir2lir.

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Reg(pub u32);

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Label(pub String);

impl Label {
    pub fn new(s: impl Into<String>) -> Self { Self(s.into()) }
}

#[derive(Debug, Clone)]
pub enum LIROp {
    // ── Control flow ──────────────────────────────────────────────────────
    Call(String),           // BL symbol
    CallIndirect(Reg),      // BLR xN  — vtable dispatch, fn-ptr, closure
    Return,
    Halt,
    Branch { cond: Reg, if_true: Label, if_false: Label },
    Jump(Label),

    // ── Program structure ─────────────────────────────────────────────────
    LabelDef(Label),
    FnStart(String),
    FnEnd,

    // ── Passthrough ───────────────────────────────────────────────────────
    Comment(String),
    Asm { lines: Vec<String> },

    // ── Data movement ─────────────────────────────────────────────────────
    LoadImm(Reg, u64),
    Move(Reg, Reg),
    LoadAddr { dst: Reg, symbol: String },

    // ── Integer arithmetic ────────────────────────────────────────────────
    Add(Reg, Reg, Reg),
    Sub(Reg, Reg, Reg),
    Mul(Reg, Reg, Reg),
    Div(Reg, Reg, Reg),     // unsigned divide
    SDiv(Reg, Reg, Reg),    // signed divide
    Rem(Reg, Reg, Reg),     // unsigned remainder (udiv + msub)
    Neg(Reg, Reg),
    Not(Reg, Reg),

    // ── Bitwise ───────────────────────────────────────────────────────────
    And(Reg, Reg, Reg),
    Or(Reg, Reg, Reg),
    Xor(Reg, Reg, Reg),
    Shl(Reg, Reg, Reg),     // logical shift left
    Shr(Reg, Reg, Reg),     // logical shift right (unsigned)
    Sar(Reg, Reg, Reg),     // arithmetic shift right (signed)

    // ── Comparisons (result is 0 or 1) ────────────────────────────────────
    Eq(Reg, Reg, Reg),
    Ne(Reg, Reg, Reg),
    Lt(Reg, Reg, Reg),      // unsigned <
    Le(Reg, Reg, Reg),      // unsigned <=
    Gt(Reg, Reg, Reg),      // unsigned >
    Ge(Reg, Reg, Reg),      // unsigned >=
    SLt(Reg, Reg, Reg),     // signed <
    SLe(Reg, Reg, Reg),     // signed <=
    SGt(Reg, Reg, Reg),     // signed >
    SGe(Reg, Reg, Reg),     // signed >=

    // ── Type conversion ───────────────────────────────────────────────────
    ZeroExt { dst: Reg, src: Reg, from_bits: u8 },  // zero-extend from N bits to 64
    SignExt { dst: Reg, src: Reg, from_bits: u8 },   // sign-extend from N bits to 64

    // ── Memory (64-bit) ───────────────────────────────────────────────────
    Load  { dst: Reg, base: Reg, offset: i32 },
    Store { src: Reg, base: Reg, offset: i32 },

    // ── Memory (sized) ────────────────────────────────────────────────────
    LoadSize  { dst: Reg, base: Reg, offset: i32, size: u8 }, // 1/2/4/8-byte zero-ext load
    StoreSize { src: Reg, base: Reg, offset: i32, size: u8 }, // 1/2/4/8-byte store

    // ── Atomics (acquire-release) ─────────────────────────────────────────
    AtomicLoad  { dst: Reg, ptr: Reg },               // LDAR
    AtomicStore { src: Reg, ptr: Reg },               // STLR
    AtomicXchg  { dst: Reg, src: Reg,  ptr: Reg },    // LDAXR/STLXR loop
    AtomicFetchAdd  { dst: Reg, delta: Reg, ptr: Reg },
    AtomicFetchSub  { dst: Reg, delta: Reg, ptr: Reg },
    AtomicFetchAnd  { dst: Reg, val: Reg, ptr: Reg },
    AtomicFetchOr   { dst: Reg, val: Reg, ptr: Reg },
    AtomicFetchXor  { dst: Reg, val: Reg, ptr: Reg },
    AtomicFetchNand { dst: Reg, val: Reg, ptr: Reg },
    AtomicFetchMax  { dst: Reg, val: Reg, ptr: Reg },  // signed
    AtomicFetchMin  { dst: Reg, val: Reg, ptr: Reg },  // signed
    AtomicFetchUMax { dst: Reg, val: Reg, ptr: Reg },  // unsigned
    AtomicFetchUMin { dst: Reg, val: Reg, ptr: Reg },  // unsigned
    AtomicCas  { old: Reg, new: Reg, ptr: Reg, ok: Reg },
    Fence,                                              // DMB ISH
}

Graph