diff --git a/src/compile.rs b/src/compile.rs index 4face0db..161a7e0f 100644 --- a/src/compile.rs +++ b/src/compile.rs @@ -1,10 +1,12 @@ #![cfg(feature = "std")] +use alloc::collections::BTreeSet; + use crate::prelude::*; use crate::{ host::Host, - run::{Instruction, InterpretedDef, LabSet, Port, Tag}, + run::{Def, Instruction, InterpretedDef, LabSet, Port, Tag}, stdlib::HostedDef, }; use core::{fmt::Write, hash::Hasher}; @@ -25,39 +27,91 @@ fn _compile_host(host: &Host) -> Result { .map(|(raw_name, def)| (raw_name, sanitize_name(raw_name), def)); writeln!(code, "#![allow(non_upper_case_globals, unused_imports)]")?; - writeln!(code, "use crate::{{host::{{Host, DefRef}}, run::*, ops::{{TypedOp, Ty::*, Op::*}}}};")?; + writeln!( + code, + "use crate::{{host::{{Host, DefRef}}, stdlib::{{AsHostedDef, HostedDef}}, run::*, ops::{{TypedOp, Ty::*, Op::*}}}};" + )?; writeln!(code)?; - writeln!(code, "pub fn host() -> Host {{")?; - writeln!(code, " let mut host = Host::default();")?; - for (raw_name, name, _) in defs.clone() { - writeln!(code, r##" host.insert_def(r#"{raw_name}"#, DefRef::Static(unsafe {{ &*DEF_{name} }}));"##)?; - } - writeln!(code, " host")?; - writeln!(code, "}}\n")?; + writeln!(code, "pub fn insert_into_host(host: &mut Host) {{")?; - for (_, name, def) in defs.clone() { + // insert empty defs + for (hvmc_name, rust_name, def) in defs.clone() { let labs = compile_lab_set(&def.labs)?; writeln!( code, - "pub const DEF_{name}: *const Def = const {{ &Def::new({labs}, (call_{name}, call_{name})) }}.upcast();" + r##" host.insert_def(r#"{hvmc_name}"#, unsafe {{ HostedDef::::new({labs}) }});"## + )?; + } + writeln!(code)?; + + // hoist all unique refs present in the right hand side of some def + for hvmc_name in defs.clone().flat_map(|(_, _, def)| refs(host, &def.data.0.instr)).collect::>() { + let rust_name = sanitize_name(hvmc_name); + + writeln!(code, r##" let def_{rust_name} = Port::new_ref(&host.defs[r#"{hvmc_name}"#]);"##)?; + } + writeln!(code)?; + + // initialize each def with the refs it makes use of + for (hvmc_name, rust_name, def) in defs.clone() { + let refs = + refs(host, &def.data.0.instr).iter().map(|r| format!("def_{}", sanitize_name(r))).collect::>().join(", "); + + writeln!( + code, + r##" host.get_mut::>(r#"{hvmc_name}"#).data.0 = Def_{rust_name} {{ {refs} }};"## )?; } + writeln!(code, "}}")?; writeln!(code)?; - for (_, name, def) in defs { - compile_def(&mut code, host, &name, &def.data.0.instr)?; + for (_, rust_name, def) in defs.clone() { + compile_struct(&mut code, host, &rust_name, def)?; } Ok(code) } -fn compile_def(code: &mut String, host: &Host, name: &str, instr: &[Instruction]) -> fmt::Result { - writeln!(code, "pub fn call_{name}(net: &mut Net, to: Port) {{")?; - writeln!(code, " let t0 = Trg::port(to);")?; - for instr in instr { - write!(code, " ")?; +fn refs<'a>(host: &'a Host, instructions: &'a [Instruction]) -> BTreeSet<&'a str> { + let mut refs = BTreeSet::new(); + + for instr in instructions { + if let Instruction::Const { port, .. } | Instruction::LinkConst { port, .. } = instr { + if port.tag() == Tag::Ref { + refs.insert(host.back[&port.addr()].as_str()); + } + } + } + + refs +} + +fn compile_struct( + code: &mut String, + host: &Host, + rust_name: &str, + def: &Def>, +) -> fmt::Result { + let refs = refs(host, &def.data.0.instr) + .iter() + .map(|r| format!("def_{}: Port", sanitize_name(r))) + .collect::>() + .join(",\n "); + + writeln!(code, "#[derive(Default)]")?; + writeln!(code, "struct Def_{rust_name} {{")?; + writeln!(code, " {refs}")?; + writeln!(code, "}}")?; + writeln!(code)?; + + writeln!(code, "impl AsHostedDef for Def_{rust_name} {{")?; + writeln!(code, " fn call(slf: &Def, net: &mut Net, port: Port) {{")?; + writeln!(code, " let t0 = Trg::port(port);")?; + + for instr in &def.data.0.instr { + write!(code, " ")?; match instr { Instruction::Const { trg, port } => { writeln!(code, "let {trg} = Trg::port({});", compile_port(host, port)) @@ -85,8 +139,8 @@ fn compile_def(code: &mut String, host: &Host, name: &str, instr: &[Instruction] } }?; } + writeln!(code, " }}")?; writeln!(code, "}}")?; - code.write_char('\n')?; Ok(()) } @@ -96,11 +150,11 @@ fn compile_port(host: &Host, port: &Port) -> String { "Port::ERA".to_owned() } else if port.tag() == Tag::Ref { let name = sanitize_name(&host.back[&port.addr()]); - format!("Port::new_ref(unsafe {{ &*DEF_{name} }})") + format!("slf.data.def_{name}.clone()") } else if port.tag() == Tag::Int { format!("Port::new_int({})", port.int()) } else if port.tag() == Tag::F32 { - format!("Port::new_float({})", port.float()) + format!("Port::new_float({:?})", port.float()) } else { unreachable!() } diff --git a/src/gen.rs b/src/gen.rs index 6f81882b..e831b223 100644 --- a/src/gen.rs +++ b/src/gen.rs @@ -2,6 +2,4 @@ use crate::host::Host; -pub fn host() -> Host { - Host::default() -} +pub fn insert_into_host(_: &mut Host) {} diff --git a/src/host.rs b/src/host.rs index 7ea67829..440d68e1 100644 --- a/src/host.rs +++ b/src/host.rs @@ -91,10 +91,7 @@ impl Host { // each of the new defs. for (nam, net) in book.iter() { let data = self.encode_def(net); - match self.defs.get_mut(nam).unwrap() { - DefRef::Owned(def) => def.downcast_mut::>().unwrap().data.0 = data, - DefRef::Static(_) => unreachable!(), - } + self.get_mut::>(nam).data.0 = data; } } @@ -103,4 +100,12 @@ impl Host { self.back.insert(Port::new_ref(&def).addr(), name.to_owned()); self.defs.insert(name.to_owned(), def); } + + /// Returns a mutable [`Def`] named `name`. + pub fn get_mut(&mut self, name: &str) -> &mut Def { + match self.defs.get_mut(name).unwrap() { + DefRef::Owned(def) => def.downcast_mut().unwrap(), + DefRef::Static(_) => unreachable!(), + } + } } diff --git a/src/main.rs b/src/main.rs index 41a066ff..3e974608 100644 --- a/src/main.rs +++ b/src/main.rs @@ -54,8 +54,9 @@ fn main() { } } else { let cli = BareCli::parse(); - let host = hvmc::gen::host(); - run(Arc::new(Mutex::new(host)), cli.opts, cli.args); + let host = create_host(&Book::default()); + gen::insert_into_host(&mut host.lock()); + run(host, cli.opts, cli.args); } if cfg!(feature = "trace") { hvmc::trace::_read_traces(usize::MAX); diff --git a/src/stdlib.rs b/src/stdlib.rs index f3a2c848..39211932 100644 --- a/src/stdlib.rs +++ b/src/stdlib.rs @@ -141,6 +141,13 @@ impl AsDef for ArcDef { pub struct HostedDef(pub T, PhantomData<()>); impl HostedDef { + pub unsafe fn new(labs: LabSet) -> DefRef + where + T: Default, + { + Self::new_hosted(labs, T::default()) + } + pub unsafe fn new_hosted(labs: LabSet, data: T) -> DefRef { DefRef::Owned(Box::new(Def::new(labs, HostedDef(data, PhantomData)))) }