interpreter: binary placing operations; expand IR

This commit is contained in:
Guillem L. Jara
2026-05-27 17:37:21 +02:00
parent 4615b760d3
commit ecc7dcced6
4 changed files with 130 additions and 22 deletions
+28 -12
View File
@@ -62,11 +62,15 @@ pub enum Instruction {
Concat(BinaryArg),
// Intrinsic operations
LoadUser(LoadStoreArg),
LoadBultin(LoadStoreArg),
LoadConst(LoadStoreArg),
StoreUser(LoadStoreArg),
StoreBuiltin(LoadStoreArg),
LoadUserScalar(MemScalarArg),
LoadUserArray(MemArrayArg),
LoadBuiltinScalar(MemScalarArg),
LoadBuiltinArray(MemArrayArg),
LoadConst(MemScalarArg),
StoreUserScalar(MemScalarArg),
StoreBuiltinScalar(MemScalarArg),
StoreUserArray(MemArrayArg),
StoreBuiltinArray(MemArrayArg),
IntrinsicCall(CallArgs),
UserCall(IndCallArgs),
IndirectCall(CallArgs),
@@ -79,7 +83,8 @@ const _: () = const { assert!(size_of::<Instruction>() <= 8) };
pub type UnaryArg = (Reg, Reg);
pub type BinaryArg = (Reg, Reg, Reg);
pub type LoadStoreArg = (Reg, NonLocal);
pub type MemScalarArg = (Reg, NonLocal);
pub type MemArrayArg = (Reg, Reg, NonLocal);
pub type JumpArg = Label;
pub type RetArg = Reg;
pub type BranchArg = (Reg, Label, Label);
@@ -133,15 +138,22 @@ impl Display for Instruction {
| Self::Modulo((dest, lhs, rhs)) => {
write!(f, "{dest} <- {op} {lhs}, {rhs}")
}
Self::LoadUser((dest, src)) | Self::StoreUser((dest, src)) => {
Self::LoadUserScalar((dest, src)) | Self::StoreUserScalar((dest, src)) => {
write!(f, "{dest} <- {op} user[{src}]")
}
Self::LoadUserArray((dest, src, place)) | Self::StoreUserArray((dest, src, place)) => {
write!(f, "{dest} <- {op} user[{place}[{src}]]")
}
Self::LoadConst((dest, src)) => {
write!(f, "{dest} <- {op} mem[{src}]")
}
Self::StoreBuiltin((dest, src)) | Self::LoadBultin((dest, src)) => {
Self::StoreBuiltinScalar((dest, src)) | Self::LoadBuiltinScalar((dest, src)) => {
write!(f, "{dest} <- {op} intrinsic[{src}]")
}
Self::LoadBuiltinArray((dest, src, place))
| Self::StoreBuiltinArray((dest, src, place)) => {
write!(f, "{dest} <- {op} intrinsic[{place}[{src}]]")
}
Self::Branch((cond, label_then, label_else)) => {
write!(f, "{op} {cond}, {label_then}, {label_else}")
}
@@ -185,11 +197,15 @@ impl Instruction {
Self::Divide(_) => "div",
Self::Raise(_) => "pow",
Self::Modulo(_) => "mod",
Self::LoadUser(_) => "vload",
Self::LoadBultin(_) => "iload",
Self::LoadUserScalar(_) => "vsload",
Self::LoadBuiltinScalar(_) => "isload",
Self::LoadUserArray(_) => "vaload",
Self::LoadBuiltinArray(_) => "iaload",
Self::LoadConst(_) => "cload",
Self::StoreUser(_) => "vstore",
Self::StoreBuiltin(_) => "istore",
Self::StoreUserScalar(_) => "vsstore",
Self::StoreBuiltinScalar(_) => "isstore",
Self::StoreUserArray(_) => "vastore",
Self::StoreBuiltinArray(_) => "iastore",
Self::Copy(_) => "cpy",
Self::IntrinsicCall(_) => "icall",
Self::UserCall(_) => "ucall",
+93 -6
View File
@@ -136,7 +136,7 @@ impl<'a> Code<'a> {
Expr::Leaf(atom) => match atom {
Atom::Variable(Variable::User(ident)) => {
let src = self.symbols.register_user_var(ident, self.arena);
self.bc.emit(Instruction::LoadUser((dest, src)));
self.bc.emit(Instruction::LoadUserScalar((dest, src)));
}
&Atom::Number(n) => {
let src = self.register_const(Value::Float(n));
@@ -202,19 +202,101 @@ impl<'a> Code<'a> {
let next = self.following_instr(0);
self.bc.nth(jump).set_label(next);
}
ExprNode::BinaryPlaceOperation(BinaryPlaceOperator::Assignment, place, expr) => {
ExprNode::BinaryPlaceOperation(op, place, expr) => {
self.lower_expr_into(expr, dest);
let Place::Variable(Variable::User(var)) = place else {
todo!()
let second_op = match op {
BinaryPlaceOperator::Assignment => {
self.store_place(place, dest);
return;
}
BinaryPlaceOperator::AddAssign => Instruction::Add,
BinaryPlaceOperator::SubAssign => Instruction::Subtract,
BinaryPlaceOperator::MulAssign => Instruction::Multiply,
BinaryPlaceOperator::DivAssign => Instruction::Divide,
BinaryPlaceOperator::PowAssign => Instruction::Raise,
BinaryPlaceOperator::ModAssign => Instruction::Modulo,
};
let var = self.symbols.register_user_var(var, self.arena);
self.bc.emit(Instruction::StoreUser((dest, var)));
let lhs = self.alloc_reg();
self.load_place(*lhs, place);
self.bc.emit(second_op((dest, *lhs, dest)));
self.store_place(place, dest);
self.free_reg(lhs);
}
_ => todo!(),
},
}
}
fn load_place(&mut self, dest: Reg, place: &Place<'_>) {
match place {
Place::Record(_) => {
todo!()
}
Place::Variable(Variable::User(ident)) => {
let src = self.symbols.register_user_var(ident, self.arena);
self.bc.emit(Instruction::LoadUserScalar((dest, src)));
}
Place::Variable(var) => {
self.bc
.emit(Instruction::LoadBuiltinScalar((dest, var_index(var))));
}
Place::Index(Variable::User(ident), index) => {
self.subsep_index(dest, index);
let src = self.symbols.register_user_var(ident, self.arena);
self.bc.emit(Instruction::LoadUserArray((dest, dest, src)));
}
Place::Index(var, index) => {
self.subsep_index(dest, index);
self.bc
.emit(Instruction::LoadBuiltinArray((dest, dest, var_index(var))));
}
}
}
fn store_place(&mut self, place: &Place<'_>, src: Reg) {
match place {
Place::Record(_) => todo!(),
Place::Variable(Variable::User(ident)) => {
self.bc.emit(Instruction::StoreUserScalar((
src,
self.symbols.register_user_var(ident, self.arena),
)));
}
Place::Variable(var) => {
self.bc
.emit(Instruction::StoreBuiltinScalar((src, var_index(var))));
}
Place::Index(Variable::User(ident), index) => {
let rhs = self.alloc_reg();
self.subsep_index(*rhs, index);
let place = self.symbols.register_user_var(ident, self.arena);
self.bc
.emit(Instruction::StoreUserArray((src, *rhs, place)));
self.free_reg(rhs);
}
Place::Index(var, index) => {
let rhs = self.alloc_reg();
self.subsep_index(*rhs, index);
self.bc
.emit(Instruction::StoreBuiltinArray((src, *rhs, var_index(var))));
self.free_reg(rhs);
}
}
}
fn subsep_index(&mut self, dest: Reg, index: &[Expr<'_>]) {
let rhs = self.alloc_reg();
self.lower_expr_into(&index[0], dest);
for i in &index[1..] {
self.lower_expr_into(i, *rhs);
self.bc.emit(Instruction::Concat((dest, dest, *rhs)));
}
self.free_reg(rhs);
}
fn alloc_reg(&mut self) -> LinearReg {
self.free_regs.pop().map(LinearReg).unwrap_or_else(|| {
let current = self.reg_pointer;
@@ -360,6 +442,11 @@ impl Deref for LinearReg {
}
}
fn var_index(var: &Variable<'_>) -> NonLocal {
// SAFETY: it is repr(u16).
unsafe { *<*const Variable>::from(var).cast::<NonLocal>() }
}
#[cfg(debug_assertions)]
impl Drop for LinearReg {
fn drop(&mut self) {
+8 -4
View File
@@ -169,20 +169,24 @@ impl Interpreter<'_> {
rhs.write_string(&mut buf);
self.registers.write(dest, Value::String(buf.into()));
}
Instruction::LoadUser((dest, src)) => {
Instruction::LoadUserScalar((dest, src)) => {
let val = self.symbols.lookup_user_scalar(src);
self.registers.write(dest, val.clone());
}
Instruction::LoadBultin((_dest, _src)) => todo!(),
Instruction::LoadUserArray((_dest, _src, _place)) => todo!(),
Instruction::LoadBuiltinScalar((_dest, _src)) => todo!(),
Instruction::LoadBuiltinArray((_dest, _src, _place)) => todo!(),
Instruction::LoadConst((dest, src)) => {
let val = self.consts.0.get_index(src.0 as _).unwrap().clone();
self.registers.write(dest, val);
}
Instruction::StoreUser((dest, src)) => {
Instruction::StoreUserScalar((dest, src)) => {
let val = self.registers.get(dest).clone();
self.symbols.write_user_val(src, val);
}
Instruction::StoreBuiltin((_dest, _src)) => todo!(),
Instruction::StoreUserArray((_dest, _src, _place)) => todo!(),
Instruction::StoreBuiltinScalar((_dest, _src)) => todo!(),
Instruction::StoreBuiltinArray((_dest, _src, _place)) => todo!(),
Instruction::IntrinsicCall((_dest, _code, _args)) => todo!(),
Instruction::UserCall((_dest, _code, _args)) => todo!(),
Instruction::IndirectCall((_dest, _code, _args)) => todo!(),
+1
View File
@@ -61,6 +61,7 @@ pub struct Identifier<'a> {
pub literal: &'a str,
}
#[repr(u16)]
#[derive(Clone, Copy)]
pub enum Variable<'a> {
User(Identifier<'a>),