fixing deprecated stuff, i hate this

This commit is contained in:
mlokr 2024-02-14 11:45:58 +01:00
parent 34d1bf415e
commit 9ddc336ecd
4 changed files with 262 additions and 157 deletions

View file

@ -1,4 +1,4 @@
use rhai::{CustomType, Engine, ImmutableString}; use rhai::{CustomType, Engine, FuncRegistration, ImmutableString};
use { use {
crate::{object::SymbolRef, SharedObject}, crate::{object::SymbolRef, SharedObject},
@ -10,38 +10,39 @@ macro_rules! gen_data_insertions {
let (module, obj) = ($module, $obj); let (module, obj) = ($module, $obj);
$({ $({
let obj = ::std::rc::Rc::clone(obj); let obj = ::std::rc::Rc::clone(obj);
let hash = module.set_native_fn(stringify!($ty), move |arr: ::rhai::Array| {
let obj = &mut *obj.borrow_mut();
let symbol = obj.symbol($crate::object::Section::Data);
obj.sections FuncRegistration::new(stringify!($ty))
.data .with_namespace(rhai::FnNamespace::Global)
.reserve(arr.len() * ::std::mem::size_of::<$ty>()); .set_into_module::<_, 1, false, _, true, _>(module, move |arr: ::rhai::Array| {
let obj = &mut *obj.borrow_mut();
let symbol = obj.symbol($crate::object::Section::Data);
for item in arr { obj.sections
obj.sections.data.extend( .data
match item.as_int() { .reserve(arr.len() * ::std::mem::size_of::<$ty>());
Ok(num) => $ty::try_from(num).map_err(|_| "i64".to_owned()),
Err(ty) => Err(ty.to_owned()),
}
.map_err(|err| {
::rhai::EvalAltResult::ErrorMismatchDataType(
stringify!($ty).to_owned(),
err,
::rhai::Position::NONE,
)
})?
.to_le_bytes(),
);
}
Ok(DataRef { for item in arr {
symbol, obj.sections.data.extend(
len: obj.sections.data.len() - symbol.0, match item.as_int() {
}) Ok(num) => $ty::try_from(num).map_err(|_| "i64".to_owned()),
}); Err(ty) => Err(ty.to_owned()),
}
.map_err(|err| {
::rhai::EvalAltResult::ErrorMismatchDataType(
stringify!($ty).to_owned(),
err,
::rhai::Position::NONE,
)
})?
.to_le_bytes(),
);
}
module.update_fn_namespace(hash, ::rhai::FnNamespace::Global); Ok(DataRef {
symbol,
len: obj.sections.data.len() - symbol.0,
})
});
})* })*
}}; }};
} }
@ -63,10 +64,12 @@ impl CustomType for DataRef {
pub fn module(engine: &mut Engine, obj: SharedObject) -> Module { pub fn module(engine: &mut Engine, obj: SharedObject) -> Module {
let mut module = Module::new(); let mut module = Module::new();
gen_data_insertions!(&mut module, &obj, [i8, i16, i32, i64]); gen_data_insertions!(&mut module, &obj, [i8, i16, i32, i64]);
{ FuncRegistration::new("str")
let hash = module.set_native_fn("str", move |s: ImmutableString| { .with_namespace(rhai::FnNamespace::Global)
.set_into_module::<_, 1, false, _, true, _>(&mut module, move |s: ImmutableString| {
let obj = &mut *obj.borrow_mut(); let obj = &mut *obj.borrow_mut();
let symbol = obj.symbol(crate::object::Section::Data); let symbol = obj.symbol(crate::object::Section::Data);
@ -77,9 +80,6 @@ pub fn module(engine: &mut Engine, obj: SharedObject) -> Module {
}) })
}); });
module.update_fn_namespace(hash, rhai::FnNamespace::Global);
}
engine.build_type::<DataRef>(); engine.build_type::<DataRef>();
module module
} }

View file

@ -1,6 +1,6 @@
use { use {
crate::object::Object, crate::object::Object,
rhai::{FnNamespace, Module}, rhai::{FuncRegistration, Module},
std::{cell::RefCell, rc::Rc}, std::{cell::RefCell, rc::Rc},
}; };
@ -137,21 +137,27 @@ pub mod generic {
})* })*
macro_rules! gen_ins_fn { macro_rules! gen_ins_fn {
$(($obj:expr, $opcode:expr, [<$($ty)*>]) => { $(
move |$($name: $crate::ins::rity::$ty),*| { ($obj:expr, $opcode:expr, [<$($ty)*>]) => {
$crate::ins::generic::[<$($ty:lower)*>]( move |$($name: $crate::ins::rity::$ty),*| {
&mut *$obj.borrow_mut(), $crate::ins::generic::[<$($ty:lower)*>](
$opcode, &mut *$obj.borrow_mut(),
$( $opcode,
$crate::ins::generic::convert_op::< $(
_, $crate::ins::generic::convert_op::<
$crate::ins::optypes::$ty _,
>($name)? $crate::ins::optypes::$ty
),* >($name)?
)?; ),*
Ok(()) )?;
} Ok(())
};)* }
};
(@arg_count [<$($ty)*>]) => {
{ ["", $(stringify!($ty)),*].len() - 1 }
};
)*
($obj:expr, $opcode:expr, N) => { ($obj:expr, $opcode:expr, N) => {
move || { move || {
@ -159,6 +165,10 @@ pub mod generic {
Ok(()) Ok(())
} }
}; };
(@arg_count N) => {
{ 0 }
};
} }
} }
}; };
@ -198,21 +208,21 @@ pub mod generic {
macro_rules! instructions { macro_rules! instructions {
( (
($module:expr, $obj:expr $(,)?) ($module:expr, $obj:expr $(,)?)
{ $($opcode:expr, $mnemonic:ident, $ops:ident, $doc:literal;)* } { $($opcode:expr, $mnemonic:ident, $ops:tt, $doc:literal;)* }
) => {{ ) => {{
let (module, obj) = ($module, $obj); let (module, obj) = ($module, $obj);
$({ $({
let obj = Rc::clone(&obj); let obj = Rc::clone(&obj);
let hash = module.set_native_fn( FuncRegistration::new(stringify!([<$mnemonic:lower>]))
paste::paste!(stringify!([<$mnemonic:lower>])), .with_namespace(rhai::FnNamespace::Global)
generic::gen_ins_fn!( .set_into_module::<_, { generic::gen_ins_fn!(@arg_count $ops) }, false, _, true, _>(
obj, module,
$opcode, generic::gen_ins_fn!(
$ops obj,
) $opcode,
); $ops
)
module.update_fn_namespace(hash, FnNamespace::Global); );
})* })*
}}; }};
} }

View file

@ -1,6 +1,6 @@
use { use {
crate::SharedObject, crate::SharedObject,
rhai::{Engine, ImmutableString, Module}, rhai::{Engine, FuncRegistration, ImmutableString, Module},
}; };
macro_rules! shdm_fns { macro_rules! shdm_fns {
@ -9,25 +9,24 @@ macro_rules! shdm_fns {
shared: $shared:expr => $shname:ident; shared: $shared:expr => $shname:ident;
$( $(
$vis:ident fn $name:ident($($params:tt)*) $(-> $ret:ty)? $blk:block $vis:ident fn $name:ident($($param_name:ident: $param_ty:ty),*) $(-> $ret:ty)? $blk:block
)* )*
) => {{ ) => {{
let module = $module; let module = $module;
let shared = $shared; let shared = $shared;
$({ $({
let $shname = SharedObject::clone(&shared);
let hash = module.set_native_fn(
stringify!($name),
move |$($params)*| $(-> $ret)? {
let mut $shname = $shname.borrow_mut();
$blk
},
);
module.update_fn_namespace( let $shname = SharedObject::clone(&shared);
hash,
paste::paste!(rhai::FnNamespace::[<$vis:camel>]) FuncRegistration::new(stringify!($name))
); .with_namespace(rhai::FnNamespace::Global)
.set_into_module::<_, { ["", $(stringify!($param_name)),*].len() - 1 }, false, _, true, _>(
module,
move |$($param_name: $param_ty),*| $(-> $ret)? {
let mut $shname = $shname.borrow_mut();
$blk
}
);
})* })*
}}; }};
} }

View file

@ -1,10 +1,18 @@
use std::{iter::Cycle, mem::offset_of, ops::Range}; use std::{iter::Cycle, ops::Range, usize};
use crate::{ use crate::{
lexer::{self, Ty}, lexer::{self, Ty},
parser::{Exp, Function, Item, Literal, Struct, Type}, parser::{Exp, Function, Item, Literal, Struct, Type},
}; };
type Reg = u8;
type Offset = i32;
type Pushed = bool;
type SlotIndex = usize;
type Label = usize;
type Data = usize;
type Size = usize;
//| Register | Description | Saver | //| Register | Description | Saver |
//|:-----------|:--------------------|:-------| //|:-----------|:--------------------|:-------|
//| r0 | Hard-wired zero | N/A | //| r0 | Hard-wired zero | N/A |
@ -16,8 +24,6 @@ use crate::{
//| r254 | Stack pointer | Callee | //| r254 | Stack pointer | Callee |
//| r255 | Thread pointer | N/A | //| r255 | Thread pointer | N/A |
const STACK_POINTER: Reg = 254;
struct RegAlloc { struct RegAlloc {
pub regs: Box<[Option<usize>; 256]>, pub regs: Box<[Option<usize>; 256]>,
pub used: Box<[bool; 256]>, pub used: Box<[bool; 256]>,
@ -25,7 +31,11 @@ struct RegAlloc {
} }
impl RegAlloc { impl RegAlloc {
fn alloc_return(&mut self, slot: SlotId) -> Option<Reg> { const STACK_POINTER: Reg = 254;
const ZERO: Reg = 0;
const RETURN_ADDRESS: Reg = 31;
fn alloc_return(&mut self, slot: usize) -> Option<Reg> {
self.regs[1..2] self.regs[1..2]
.iter_mut() .iter_mut()
.position(|reg| { .position(|reg| {
@ -39,7 +49,7 @@ impl RegAlloc {
.map(|reg| reg as Reg + 1) .map(|reg| reg as Reg + 1)
} }
fn alloc_general(&mut self, slot: SlotId) -> Option<Reg> { fn alloc_general(&mut self, slot: usize) -> Option<Reg> {
self.regs[32..254] self.regs[32..254]
.iter_mut() .iter_mut()
.zip(&mut self.used[32..254]) .zip(&mut self.used[32..254])
@ -63,23 +73,33 @@ impl RegAlloc {
self.regs[reg as usize].is_some() self.regs[reg as usize].is_some()
} }
fn spill(&mut self, for_slot: SlotId) -> (Reg, Option<SlotId>) { fn spill(&mut self, for_slot: usize) -> (Reg, Option<usize>) {
let to_spill = self.spill_cycle.next().unwrap(); let to_spill = self.spill_cycle.next().unwrap();
let slot = self.spill_specific(to_spill, for_slot); let slot = self.spill_specific(to_spill, for_slot);
(to_spill as Reg + 32, slot) (to_spill as Reg + 32, slot)
} }
fn spill_specific(&mut self, reg: Reg, for_slot: SlotId) -> Option<SlotId> { fn spill_specific(&mut self, reg: Reg, for_slot: usize) -> Option<usize> {
self.regs[reg as usize].replace(for_slot) self.regs[reg as usize].replace(for_slot)
} }
fn restore(&mut self, reg: Reg, slot: SlotId) -> SlotId { fn restore(&mut self, reg: Reg, slot: usize) -> usize {
self.regs[reg as usize].replace(slot).unwrap() self.regs[reg as usize].replace(slot).unwrap()
} }
fn alloc_specific(&mut self, reg: u8, to: usize) { fn alloc_specific(&mut self, reg: u8, to: usize) {
assert!(self.regs[reg as usize].replace(to).is_none()); assert!(self.regs[reg as usize].replace(to).is_none());
} }
fn alloc_specific_in_reg(&mut self, reg: InReg, to: usize) {
match reg {
InReg::Single(r) => self.alloc_specific(r, to),
InReg::Pair(r1, r2) => {
self.alloc_specific(r1, to);
self.alloc_specific(r2, to);
}
}
}
} }
pub struct ParamAlloc { pub struct ParamAlloc {
@ -90,19 +110,23 @@ pub struct ParamAlloc {
impl ParamAlloc { impl ParamAlloc {
fn new() -> Self { fn new() -> Self {
Self { Self {
stack: 16, stack: 8, // return adress is in callers stack frame
reg_range: 2..12, reg_range: 2..12,
} }
} }
fn alloc(&mut self, size: usize) -> Value { fn alloc(&mut self, size: usize) -> SlotValue {
match self.try_alloc_regs(size) { match self.try_alloc_regs(size) {
Some(reg) => reg, Some(reg) => reg,
None => panic!("Too many arguments o7"), None => {
let stack = self.stack;
self.stack += size as Offset;
SlotValue::Stack(stack)
}
} }
} }
fn try_alloc_regs(&mut self, size: usize) -> Option<Value> { fn try_alloc_regs(&mut self, size: usize) -> Option<SlotValue> {
let mut needed = size.div_ceil(8); let mut needed = size.div_ceil(8);
if needed > 2 { if needed > 2 {
needed = 1; // passed by ref needed = 1; // passed by ref
@ -116,12 +140,12 @@ impl ParamAlloc {
1 => { 1 => {
let reg = self.reg_range.start; let reg = self.reg_range.start;
self.reg_range.start += 1; self.reg_range.start += 1;
Some(Value::Reg(reg, None, 0)) Some(SlotValue::Reg(InReg::Single(reg)))
} }
2 => { 2 => {
let reg = self.reg_range.start; let reg = self.reg_range.start;
self.reg_range.start += 2; self.reg_range.start += 2;
Some(Value::Reg(reg, Some(reg + 1), 0)) Some(SlotValue::Reg(InReg::Pair(reg, reg + 1)))
} }
_ => unreachable!(), _ => unreachable!(),
} }
@ -140,14 +164,39 @@ impl Default for RegAlloc {
struct Variable { struct Variable {
name: String, name: String,
location: SlotId, location: usize,
} }
type SlotId = usize; #[derive(Clone, Copy)]
struct SlotId {
// index into slot stack
index: SlotIndex,
// temorary offset carried over when eg. accessing fields
offset: Offset,
// this means we can mutate the value as part of computation
owned: bool,
}
impl SlotId {
fn base(location: usize) -> Self {
Self {
index: location,
offset: 0,
owned: true,
}
}
fn borrowed(self) -> Self {
Self {
owned: false,
..self
}
}
}
struct Slot { struct Slot {
ty: Type, ty: Type,
value: Value, value: SlotValue,
} }
#[repr(transparent)] #[repr(transparent)]
@ -171,43 +220,54 @@ impl hbbytecode::Buffer for InstBuffer {
} }
} }
type Reg = u8;
type Offset = i32;
type Pushed = bool;
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
enum Value { enum InReg {
Reg(Reg, Option<Reg>, Offset), Single(Reg),
Stack(Offset, Pushed), // if one of the registes is allocated, the other is too, ALWAYS
Imm(u64), // with the same slot
Spilled(Reg, SlotId, Option<Reg>, Option<SlotId>, Offset), Pair(Reg, Reg),
DoubleSpilled(SlotId, Offset, Option<SlotId>),
} }
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
enum NormalizedValue { enum Spill {
Reg(Reg, Option<Reg>, Offset), Reg(InReg),
Stack(Offset), // relative to frame end (rsp if nothing was pushed)
}
#[derive(Clone, Copy)]
enum SlotValue {
Reg(InReg),
Stack(Offset), // relative to frame start (rbp)
Imm(u64),
Spilled(Spill, SlotIndex),
}
pub struct Value {
store: ValueStore,
offset: Offset,
}
#[derive(Clone, Copy)]
enum ValueStore {
Reg(InReg),
Stack(Offset, Pushed), Stack(Offset, Pushed),
Imm(u64), Imm(u64),
} }
impl From<Value> for NormalizedValue { impl From<SlotValue> for ValueStore {
fn from(value: Value) -> Self { fn from(value: SlotValue) -> Self {
match value { match value {
Value::Reg(reg, secondary, offset) => NormalizedValue::Reg(reg, secondary, offset), SlotValue::Reg(reg) => ValueStore::Reg(reg),
Value::Stack(offset, pushed) => NormalizedValue::Stack(offset, pushed), SlotValue::Stack(offset) => ValueStore::Stack(offset, false),
Value::Imm(imm) => NormalizedValue::Imm(imm), SlotValue::Imm(imm) => ValueStore::Imm(imm),
Value::Spilled(reg, _, secondary, _, offset) => { SlotValue::Spilled(spill, _) => match spill {
NormalizedValue::Reg(reg, secondary, offset) Spill::Reg(reg) => ValueStore::Reg(reg),
} Spill::Stack(offset) => ValueStore::Stack(offset, true),
Value::DoubleSpilled(_, offset, _) => NormalizedValue::Stack(offset, false), },
} }
} }
} }
type Label = usize;
type Data = usize;
pub struct LabelReloc { pub struct LabelReloc {
pub label: Label, pub label: Label,
pub offset: usize, pub offset: usize,
@ -225,10 +285,12 @@ pub struct Frame {
} }
enum Instr { enum Instr {
BinOp(lexer::Op, NormalizedValue, NormalizedValue), BinOp(lexer::Op, Value, Value),
Move(usize, NormalizedValue, NormalizedValue), Move(Size, Value, Value),
Push(Reg),
Jump(Label), Jump(Label),
JumpIfZero(NormalizedValue, Label), Call(String),
JumpIfZero(Value, Label),
} }
#[derive(Default)] #[derive(Default)]
@ -237,8 +299,8 @@ pub struct Generator<'a> {
func_labels: Vec<(String, Label)>, func_labels: Vec<(String, Label)>,
stack_size: usize, stack_size: Offset,
pushed_size: usize, pushed_size: Offset,
regs: RegAlloc, regs: RegAlloc,
variables: Vec<Variable>, variables: Vec<Variable>,
@ -275,7 +337,9 @@ impl<'a> Generator<'a> {
let param_size = self.size_of(&param.ty); let param_size = self.size_of(&param.ty);
let value = param_alloc.alloc(param_size); let value = param_alloc.alloc(param_size);
let slot = self.add_slot(param.ty.clone(), value); let slot = self.add_slot(param.ty.clone(), value);
self.allocate_value_regs(value, slot); if let SlotValue::Reg(reg) = value {
self.regs.alloc_specific_in_reg(reg, slot);
}
self.add_variable(param.name.clone(), slot); self.add_variable(param.name.clone(), slot);
} }
@ -288,22 +352,17 @@ impl<'a> Generator<'a> {
self.pop_frame(frame); self.pop_frame(frame);
} }
fn allocate_value_regs(&mut self, value: Value, to: SlotId) {
if let Value::Reg(primary, secondary, _) = value {
self.regs.alloc_specific(primary, to);
if let Some(secondary) = secondary {
self.regs.alloc_specific(secondary, to);
}
}
}
fn generate_expr(&mut self, expected: Option<Type>, expr: &Exp) -> Option<SlotId> { fn generate_expr(&mut self, expected: Option<Type>, expr: &Exp) -> Option<SlotId> {
let value = match expr { let value = match expr {
Exp::Literal(lit) => match lit { Exp::Literal(lit) => SlotId::base(match lit {
Literal::Int(i) => self.add_slot(expected.clone().unwrap(), Value::Imm(*i)), Literal::Int(i) => self.add_slot(expected.clone().unwrap(), SlotValue::Imm(*i)),
Literal::Bool(b) => self.add_slot(Type::Builtin(Ty::Bool), Value::Imm(*b as u64)), Literal::Bool(b) => {
}, self.add_slot(Type::Builtin(Ty::Bool), SlotValue::Imm(*b as u64))
Exp::Variable(ident) => self.lookup_variable(ident).unwrap().location, }
}),
Exp::Variable(ident) => {
SlotId::base(self.lookup_variable(ident).unwrap().location).borrowed()
}
Exp::Call { name, args } => self.generate_call(expected.clone(), name, args), Exp::Call { name, args } => self.generate_call(expected.clone(), name, args),
Exp::Ctor { name, fields } => todo!(), Exp::Ctor { name, fields } => todo!(),
Exp::Index { base, index } => todo!(), Exp::Index { base, index } => todo!(),
@ -325,7 +384,7 @@ impl<'a> Generator<'a> {
}; };
if let Some(expected) = expected { if let Some(expected) = expected {
let actual = self.slots[value].ty.clone(); let actual = self.slots[value.index].ty.clone();
assert_eq!(expected, actual); assert_eq!(expected, actual);
} }
@ -344,33 +403,68 @@ impl<'a> Generator<'a> {
self.set_temporarly(arg_slot, param_slot); self.set_temporarly(arg_slot, param_slot);
} }
self.instrs.push(Instr::Call(name.to_owned()));
todo!() todo!()
} }
fn set_temporarly(&mut self, from: SlotId, to: Value) { fn set_temporarly(&mut self, from: SlotId, to: SlotValue) {
match to { let to = self.make_mutable(to, from.index);
Value::Reg(dst, secondary, offset) => { let to_slot = self.add_slot(self.slots[from.index].ty.clone(), to);
let other_slot = secondary.and_then(|s| self.regs.spill_specific(s, usize::MAX)); self.emit_move(from, SlotId::base(to_slot));
if let Some(slot) = self.regs.spill_specific(dst, usize::MAX) { }
self.slots[slot].value =
Value::Spilled(dst, slot, secondary, other_slot, offset); fn make_mutable(&mut self, target: SlotValue, by: SlotIndex) -> SlotValue {
} else if let Some(slot) = other_slot { match target {
self.slots[slot].value = SlotValue::Reg(in_reg) => {
Value::Spilled(secondary.unwrap(), slot, Some(dst), None, offset); self.regs.alloc_specific_in_reg(in_reg, by);
} target
}
SlotValue::Spilled(Spill::Reg(in_reg), slot) => {
let new_val = SlotValue::Spilled(
match in_reg {
InReg::Single(reg) => Spill::Stack(self.emmit_push(reg)),
InReg::Pair(r1, r2) => {
self.emmit_push(r2);
Spill::Stack(self.emmit_push(r1))
}
},
slot,
);
let new_slot = self.add_slot(self.slots[slot].ty.clone(), new_val);
SlotValue::Spilled(Spill::Reg(in_reg), new_slot)
} }
_ => unreachable!(), _ => unreachable!(),
}; }
let size = self.size_of(&self.slots[from].ty);
self.emit_move(size, self.slots[from].value, to);
} }
fn emit_move(&mut self, size: usize, from: Value, to: Value) { fn emmit_push(&mut self, reg: Reg) -> Offset {
self.instrs.push(Instr::Move(size, from.into(), to.into())); self.pushed_size += 8;
self.instrs.push(Instr::Push(reg));
self.pushed_size
} }
fn size_of(&self, ty: &Type) -> usize { fn emit_move(&mut self, from: SlotId, to: SlotId) {
let size = self.size_of(&self.slots[from.index].ty);
let other_size = self.size_of(&self.slots[to.index].ty);
assert_eq!(size, other_size);
self.instrs.push(Instr::Move(
size,
self.slot_to_value(from),
self.slot_to_value(to),
));
}
fn slot_to_value(&self, slot: SlotId) -> Value {
let slot_val = &self.slots[slot.index];
Value {
store: slot_val.value.into(),
offset: slot.offset,
}
}
fn size_of(&self, ty: &Type) -> Size {
match ty { match ty {
Type::Builtin(ty) => match ty { Type::Builtin(ty) => match ty {
Ty::U8 | Ty::I8 | Ty::Bool => 1, Ty::U8 | Ty::I8 | Ty::Bool => 1,
@ -388,12 +482,14 @@ impl<'a> Generator<'a> {
Type::Pinter(_) => 8, Type::Pinter(_) => 8,
} }
} }
}
fn add_variable(&mut self, name: String, location: SlotId) { impl<'a> Generator<'a> {
fn add_variable(&mut self, name: String, location: usize) {
self.variables.push(Variable { name, location }); self.variables.push(Variable { name, location });
} }
fn add_slot(&mut self, ty: Type, value: Value) -> SlotId { fn add_slot(&mut self, ty: Type, value: SlotValue) -> usize {
let slot = self.slots.len(); let slot = self.slots.len();
self.slots.push(Slot { ty, value }); self.slots.push(Slot { ty, value });
slot slot