From ecc7dcced6b994ae7f86b7ecb874677f13d83271 Mon Sep 17 00:00:00 2001 From: "Guillem L. Jara" <4lon3ly0@tutanota.com> Date: Wed, 27 May 2026 17:37:21 +0200 Subject: [PATCH] interpreter: binary placing operations; expand IR --- interpreter/src/ir.rs | 40 ++++++++++----- interpreter/src/ir/lower.rs | 99 ++++++++++++++++++++++++++++++++++--- interpreter/src/vm.rs | 12 +++-- parser/src/ast.rs | 1 + 4 files changed, 130 insertions(+), 22 deletions(-) diff --git a/interpreter/src/ir.rs b/interpreter/src/ir.rs index dc94fee..00927ac 100644 --- a/interpreter/src/ir.rs +++ b/interpreter/src/ir.rs @@ -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::() <= 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", diff --git a/interpreter/src/ir/lower.rs b/interpreter/src/ir/lower.rs index 42e5d2c..2f71f40 100644 --- a/interpreter/src/ir/lower.rs +++ b/interpreter/src/ir/lower.rs @@ -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::() } +} + #[cfg(debug_assertions)] impl Drop for LinearReg { fn drop(&mut self) { diff --git a/interpreter/src/vm.rs b/interpreter/src/vm.rs index 0ff8f44..6434aa0 100644 --- a/interpreter/src/vm.rs +++ b/interpreter/src/vm.rs @@ -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!(), diff --git a/parser/src/ast.rs b/parser/src/ast.rs index 00e620b..f435db7 100644 --- a/parser/src/ast.rs +++ b/parser/src/ast.rs @@ -61,6 +61,7 @@ pub struct Identifier<'a> { pub literal: &'a str, } +#[repr(u16)] #[derive(Clone, Copy)] pub enum Variable<'a> { User(Identifier<'a>),