interpreter: hinted registers

This commit is contained in:
Guillem L. Jara
2026-05-22 12:01:37 +02:00
parent 368585ba0c
commit ebf56167ff
2 changed files with 57 additions and 32 deletions
+41 -17
View File
@@ -14,13 +14,10 @@
mod lower;
use std::{
fmt::{Debug, Display},
ops::Deref,
};
pub use lower::test_interpreter;
use std::fmt::{Debug, Display};
#[derive(Clone, Copy, Debug)]
#[repr(transparent)]
struct NonLocal(u16);
@@ -85,7 +82,7 @@ const _: () = const { assert!(size_of::<Instruction>() <= 8) };
#[repr(C, align(8))]
struct Instruction {
opcode: OpCode,
// hint: Hint,
hint: Hint,
args: Arguments,
}
@@ -104,30 +101,39 @@ union Arguments {
}
impl Instruction {
fn unary(opcode: impl Into<OpCode>, dest: Reg, src: &impl Deref<Target = Reg>) -> Self {
fn unary(opcode: impl Into<OpCode>, dest: Reg, src: &impl HintedReg) -> Self {
let opcode = opcode.into();
debug_assert!(opcode.is_unary());
Self {
opcode,
args: Arguments {
unary_local: (dest, **src),
unary_local: (dest, src.reg()),
},
hint: src.hint(),
}
}
fn binary(
opcode: impl Into<OpCode>,
dest: Reg,
lhs: &impl Deref<Target = Reg>,
rhs: &impl Deref<Target = Reg>,
lhs: &impl HintedReg,
rhs: &impl HintedReg,
) -> Self {
let opcode = opcode.into();
debug_assert!(opcode.is_binary());
let hint = match (lhs.hint(), rhs.hint()) {
// TODO: Remove once we get const folding.
(Hint::UnboxedFloat64, Hint::UnboxedFloat64) => Hint::UnboxedFloat64,
(_, Hint::UnboxedFloat64) => Hint::UnboxedRhsFloat64,
(Hint::UnboxedFloat64, _) => Hint::UnboxedLhsFloat64,
_ => Hint::None,
};
Self {
opcode,
args: Arguments {
binary_local: (dest, **lhs, **rhs),
binary_local: (dest, lhs.reg(), rhs.reg()),
},
hint,
}
}
@@ -139,6 +145,7 @@ impl Instruction {
args: Arguments {
load_store: (dest, src),
},
hint: Hint::None,
}
}
@@ -148,6 +155,7 @@ impl Instruction {
Self {
opcode,
args: Arguments { jump: to },
hint: Hint::None,
}
}
@@ -159,6 +167,7 @@ impl Instruction {
args: Arguments {
branch: (cond, true_to, false_to),
},
hint: Hint::None,
}
}
@@ -168,6 +177,7 @@ impl Instruction {
Self {
opcode,
args: Arguments { br_if: (cond, to) },
hint: Hint::None,
}
}
}
@@ -219,12 +229,19 @@ impl OpCode {
}
}
// #[derive(Clone, Copy)]
// #[repr(u8, align(1))]
// enum Hint {
// // Next instruction contains additional data; for use in pipes, etc.
// // Also allows us to move past (2^16 - 1) variables if we want to.
// }
#[repr(u8, align(1))]
#[derive(Clone, Copy, Debug)]
enum Hint {
None = 0,
UnboxedFloat64,
UnboxedLhsFloat64,
UnboxedRhsFloat64,
}
trait HintedReg {
fn reg(&self) -> Reg;
fn hint(&self) -> Hint;
}
impl Debug for Instruction {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
@@ -323,6 +340,13 @@ impl Display for Instruction {
write!(f, "{op} {label}")
}
_ => todo!(),
}?;
match self.hint {
Hint::UnboxedFloat64 if self.opcode.is_binary() => write!(f, " @ all_unboxedf64"),
Hint::UnboxedFloat64 => write!(f, " @ all_unboxedf64"),
Hint::UnboxedLhsFloat64 => write!(f, " @ lhs_unboxedf64"),
Hint::UnboxedRhsFloat64 => write!(f, " @ rhs_unboxedf64"),
Hint::None => Ok(()),
}
}
}
+16 -15
View File
@@ -6,15 +6,14 @@
use std::fmt::Display;
use std::hash::Hash;
use std::mem::forget;
use std::ops::Deref;
use indexmap::IndexSet;
use parser::{Atom, BinaryOperator, Expr, ExprNode, UnaryOperator};
use crate::ir::{Instruction, Label, NonLocal, OpCode, Reg};
use crate::ir::{Hint, HintedReg, Instruction, Label, NonLocal, OpCode, Reg};
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
struct Value(f64); // TODO: use NaN-boxing.
pub struct Value(f64); // TODO: use NaN-boxing.
#[derive(Debug)]
struct Code {
@@ -26,16 +25,15 @@ struct Code {
#[must_use]
#[derive(Debug)]
#[repr(transparent)]
struct LinearReg(Reg);
struct LinearReg(Reg, Hint);
impl Code {
fn lower_expr(&mut self, expr: &Expr) -> LinearReg {
let dest = self.alloc_reg();
self.lower_expr_into(expr, dest);
LinearReg(dest)
let hint = self.lower_expr_into(expr, dest);
LinearReg(dest, hint)
}
fn lower_expr_into(&mut self, expr: &Expr, dest: Reg) {
fn lower_expr_into(&mut self, expr: &Expr, dest: Reg) -> Hint {
match expr {
Expr::Leaf(atom) => match atom {
Atom::Variable(var) => {
@@ -47,6 +45,7 @@ impl Code {
let src = self.register_const(Value(n));
self.bc
.emit(Instruction::load_store(OpCode::LoadConst, dest, src));
return Hint::UnboxedFloat64;
}
_ => todo!(),
},
@@ -84,6 +83,7 @@ impl Code {
_ => todo!(),
},
}
Hint::None
}
fn alloc_reg(&mut self) -> Reg {
@@ -141,7 +141,7 @@ impl RegsState {
n_free_regs: code.free_regs.len(),
}
}
fn scope(self, code: &mut Code, f: impl FnOnce(&mut Code)) -> Self {
fn scope<T>(self, code: &mut Code, f: impl FnOnce(&mut Code) -> T) -> Self {
f(code);
let old = code.reg_pointer;
code.reg_pointer = self.reg_pointer;
@@ -151,7 +151,7 @@ impl RegsState {
n_free_regs: self.n_free_regs,
}
}
fn scope_hwm(self, code: &mut Code, f: impl FnOnce(&mut Code)) {
fn scope_hwm<T>(self, code: &mut Code, f: impl FnOnce(&mut Code) -> T) {
f(code);
code.reg_pointer = code.reg_pointer.max(self.reg_pointer);
code.free_regs.truncate(self.n_free_regs);
@@ -166,7 +166,6 @@ pub fn test_interpreter(expr: &Expr<'_>) -> impl Display {
free_regs: Vec::new(),
};
let result = c.lower_expr(expr);
dbg!(&c, &result);
forget(result);
c
}
@@ -254,11 +253,13 @@ impl LinearReg {
}
}
impl Deref for LinearReg {
type Target = Reg;
impl HintedReg for LinearReg {
fn reg(&self) -> Reg {
self.0
}
fn deref(&self) -> &Self::Target {
&self.0
fn hint(&self) -> Hint {
self.1
}
}