mirror of
https://github.com/uutils/awk.git
synced 2026-06-10 16:15:04 -07:00
interpreter: binary placing operations; expand IR
This commit is contained in:
+28
-12
@@ -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",
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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!(),
|
||||
|
||||
@@ -61,6 +61,7 @@ pub struct Identifier<'a> {
|
||||
pub literal: &'a str,
|
||||
}
|
||||
|
||||
#[repr(u16)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum Variable<'a> {
|
||||
User(Identifier<'a>),
|
||||
|
||||
Reference in New Issue
Block a user