Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

modify compilation strategy to allow for io defs #125

Merged
merged 5 commits into from
Apr 19, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 76 additions & 22 deletions src/compile.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand All @@ -24,40 +26,92 @@ fn _compile_host(host: &Host) -> Result<String, fmt::Error> {
.filter_map(|(name, def)| Some((name, def.downcast_ref::<HostedDef<InterpretedDef>>()?)))
.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, "#![allow(non_camel_case_types, unused_imports, unused_variables)]")?;
enricozb marked this conversation as resolved.
Show resolved Hide resolved
writeln!(
code,
"use crate::{{host::Host, 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::<Def_{rust_name}>::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::<BTreeSet<_>>() {
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::<Vec<_>>().join(", ");

writeln!(
code,
r##" host.get_mut::<HostedDef<Def_{rust_name}>>(r#"{hvmc_name}"#).data.0 = Def_{rust_name} {{ {refs} }};"##
enricozb marked this conversation as resolved.
Show resolved Hide resolved
)?;
}

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}<M: Mode>(net: &mut Net<M>, 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<HostedDef<InterpretedDef>>,
) -> fmt::Result {
let refs = refs(host, &def.data.0.instr)
.iter()
.map(|r| format!("def_{}: Port", sanitize_name(r)))
.collect::<Vec<_>>()
.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<M: Mode>(slf: &Def<Self>, net: &mut Net<M>, 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))
Expand Down Expand Up @@ -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(())
}
Expand All @@ -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!()
}
Expand Down
4 changes: 1 addition & 3 deletions src/gen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,4 @@

use crate::host::Host;

pub fn host() -> Host {
Host::default()
}
pub fn insert_into_host(_: &mut Host) {}
13 changes: 9 additions & 4 deletions src/host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<HostedDef<InterpretedDef>>().unwrap().data.0 = data,
DefRef::Static(_) => unreachable!(),
}
self.get_mut::<HostedDef<InterpretedDef>>(nam).data.0 = data;
}
}

Expand All @@ -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<T: Send + Sync + 'static>(&mut self, name: &str) -> &mut Def<T> {
match self.defs.get_mut(name).unwrap() {
DefRef::Owned(def) => def.downcast_mut().unwrap(),
DefRef::Static(_) => unreachable!(),
}
}
}
5 changes: 3 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
7 changes: 7 additions & 0 deletions src/stdlib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,13 @@ impl<T: AsArcDef> AsDef for ArcDef<T> {
pub struct HostedDef<T: AsHostedDef>(pub T, PhantomData<()>);

impl<T: AsHostedDef> HostedDef<T> {
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))))
}
Expand Down
Loading