diff --git a/Cargo.lock b/Cargo.lock index b3e60b9..def36c1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -351,6 +351,7 @@ dependencies = [ "lazy_static", "llvm-sys", "petgraph", + "portgraph", "rstest", ] diff --git a/Cargo.toml b/Cargo.toml index c4ec546..c8de63f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,13 +16,14 @@ hugr = "0.5.1" anyhow = "1.0.83" itertools = "0.12.1" delegate = "0.12.0" -petgraph = "*" -lazy_static = "*" +petgraph = "0.6.5" +lazy_static = "1.4.0" downcast-rs= "1.2.1" [dev-dependencies] insta = "1.39.0" rstest = "0.19.0" +portgraph = "0.12.1" [profile.dev.package] insta.opt-level = 3 diff --git a/src/emit.rs b/src/emit.rs index 3093328..0428216 100644 --- a/src/emit.rs +++ b/src/emit.rs @@ -3,13 +3,13 @@ use delegate::delegate; use hugr::{ ops::{FuncDecl, FuncDefn, NamedOp as _, OpType}, types::PolyFuncType, - HugrView, Node, NodeIndex, + HugrView, Node, }; use inkwell::{ context::Context, module::{Linkage, Module}, types::{BasicTypeEnum, FunctionType}, - values::{BasicValueEnum, FunctionValue}, + values::FunctionValue, }; use std::{collections::HashSet, hash::Hash, rc::Rc}; @@ -21,72 +21,15 @@ use crate::{ types::{LLVMSumType, TypeConverter}, }; -use self::func::{EmitFuncContext, RowPromise}; +use self::func::EmitFuncContext; +pub mod args; pub mod func; +pub mod namer; mod ops; -/// A type used whenever emission is delegated to a function -pub struct EmitOpArgs<'c, OT, H> { - /// This [HugrView] and [Node] we are emitting - pub node: FatNode<'c, OT, H>, - /// The values that should be used for all Value input ports of the node - pub inputs: Vec>, - /// The results of the node should be put here - pub outputs: RowPromise<'c>, -} - -impl<'c, OT, H> EmitOpArgs<'c, OT, H> { - /// Get the internal [FatNode] - pub fn node(&self) -> FatNode<'c, OT, H> { - self.node.clone() - } -} - -impl<'c, H: HugrView> EmitOpArgs<'c, OpType, H> { - /// Attempt to specialise the internal [FatNode]. - pub fn try_into_ot(self) -> Result, Self> - where - &'c OpType: TryInto<&'c OT>, - { - let EmitOpArgs { - node, - inputs, - outputs, - } = self; - match node.try_into_ot() { - Some(new_node) => Ok(EmitOpArgs { - node: new_node, - inputs, - outputs, - }), - None => Err(EmitOpArgs { - node, - inputs, - outputs, - }), - } - } - - /// Specialise the internal [FatNode]. - /// - /// Panics if `OT` is not the `get_optype` of the internal [Node]. - pub fn into_ot<'b, OTInto: PartialEq + 'c>(self, ot: &'b OTInto) -> EmitOpArgs<'c, OTInto, H> - where - for<'a> &'a OpType: TryInto<&'a OTInto>, - { - let EmitOpArgs { - node, - inputs, - outputs, - } = self; - EmitOpArgs { - node: node.into_ot(ot), - inputs, - outputs, - } - } -} +pub use args::EmitOpArgs; +pub use namer::Namer; /// A trait used to abstract over emission. /// @@ -111,39 +54,9 @@ impl EmitOp<'_, OT, H> for NullEmitLlvm { } } -/// A type with features for mangling the naming of symbols. -/// -/// TODO This is mostly a placeholder -#[derive(Clone)] -pub struct Namer { - prefix: String, -} - -impl Namer { - /// Create a new `Namer` that for each symbol: - /// * prefix `prefix` - /// * postfixes ".{node.index()}" - pub fn new(prefix: impl Into) -> Self { - Self { - prefix: prefix.into(), - } - } - - /// Mangle the the name of a [FuncDefn] or [FuncDecl]. - pub fn name_func(&self, name: impl AsRef, node: Node) -> String { - format!("{}{}.{}", &self.prefix, name.as_ref(), node.index()) - } -} - -impl Default for Namer { - fn default() -> Self { - Self::new("_hl.") - } -} - pub struct EmitModuleContext<'c, H: HugrView> { module: Module<'c>, - extension_context: Rc>, + extensions: Rc>, typer: Rc>, namer: Rc, } @@ -174,13 +87,13 @@ impl<'c, H: HugrView> EmitModuleContext<'c, H> { pub fn new( module: Module<'c>, namer: Rc, - extension_context: Rc>, + extensions: Rc>, typer: Rc>, ) -> Self { Self { module, namer, - extension_context, + extensions, typer, } } @@ -194,7 +107,7 @@ impl<'c, H: HugrView> EmitModuleContext<'c, H> { /// Returns a reference to the inner [CodegenExtsMap]. pub fn extensions(&self) -> Rc> { - self.extension_context.clone() + self.extensions.clone() } /// Returns a [TypingSession] constructed from it's members. @@ -328,8 +241,6 @@ impl<'c, H> Clone for Emission<'c, H> { /// Emits [HugrView]s into an LLVM [Module]. pub struct EmitHugr<'c, H: HugrView> { - // funcs: HashMap>, - // globals: HashMap>, emitted: EmissionSet<'c, H>, module_context: EmitModuleContext<'c, H>, } @@ -348,19 +259,19 @@ impl<'c, H: HugrView> EmitHugr<'c, H> { /// Creates a new `EmitHugr`. We take ownership of the [Module], and return it in [Self::finish]. pub fn new( - iw_context: &'c Context, + context: &'c Context, module: Module<'c>, - exts: Rc>, + namer: Rc, + extensions: Rc>, ) -> Self { - assert_eq!(iw_context, &module.get_context()); + assert_eq!(context, &module.get_context()); Self { - // todos: Default::default(), emitted: Default::default(), module_context: EmitModuleContext::new( module, - Default::default(), - exts, - TypeConverter::new(iw_context), + namer, + extensions, + TypeConverter::new(context), ), } } diff --git a/src/emit/args.rs b/src/emit/args.rs new file mode 100644 index 0000000..bd9ca04 --- /dev/null +++ b/src/emit/args.rs @@ -0,0 +1,69 @@ +use hugr::{ops::OpType, HugrView}; +use inkwell::values::BasicValueEnum; + +use crate::fat::FatNode; + +use super::func::RowPromise; + +/// A type used whenever emission is delegated to a function, for example in +/// [crate::emit::EmitOp]. +pub struct EmitOpArgs<'c, OT, H> { + /// This [HugrView] and [Node] we are emitting + pub node: FatNode<'c, OT, H>, + /// The values that should be used for all Value input ports of the node + pub inputs: Vec>, + /// The results of the node should be put here + pub outputs: RowPromise<'c>, +} + +impl<'c, OT, H> EmitOpArgs<'c, OT, H> { + /// Get the internal [FatNode] + pub fn node(&self) -> FatNode<'c, OT, H> { + self.node.clone() + } +} + +impl<'c, H: HugrView> EmitOpArgs<'c, OpType, H> { + /// Attempt to specialise the internal [FatNode]. + pub fn try_into_ot(self) -> Result, Self> + where + &'c OpType: TryInto<&'c OT>, + { + let EmitOpArgs { + node, + inputs, + outputs, + } = self; + match node.try_into_ot() { + Some(new_node) => Ok(EmitOpArgs { + node: new_node, + inputs, + outputs, + }), + None => Err(EmitOpArgs { + node, + inputs, + outputs, + }), + } + } + + /// Specialise the internal [FatNode]. + /// + /// Panics if `OT` is not the `get_optype` of the internal [Node]. + pub fn into_ot(self, ot: &OTInto) -> EmitOpArgs<'c, OTInto, H> + where + for<'a> &'a OpType: TryInto<&'a OTInto>, + { + let EmitOpArgs { + node, + inputs, + outputs, + } = self; + EmitOpArgs { + node: node.into_ot(ot), + inputs, + outputs, + } + } +} diff --git a/src/emit/namer.rs b/src/emit/namer.rs new file mode 100644 index 0000000..6f59a62 --- /dev/null +++ b/src/emit/namer.rs @@ -0,0 +1,54 @@ +use hugr::{Node, NodeIndex as _}; + +/// A type with features for mangling the naming of symbols. +#[derive(Clone)] +pub struct Namer { + prefix: String, + postfix_node: bool, +} + +impl Namer { + /// The [Default] impl of `Namer` uses this as a prefix. + pub const DEFAULT_PREFIX: &'static str = "_hl."; + + /// Create a new `Namer` that for each symbol: + /// * prefixes `prefix` + /// * if post_fix_node is true, postfixes ".{node.index()}" + /// + /// # Example + /// + /// ``` + /// use hugr_llvm::emit::Namer; + /// use hugr::Node; + /// let node = Node::from(portgraph::NodeIndex::new(7)); + /// let namer = Namer::default(); + /// assert_eq!(namer.name_func("name", node), "_hl.name.7"); + /// + /// let namer = Namer::new("prefix.", false); + /// assert_eq!(namer.name_func("name", node), "prefix.name") + /// ``` + pub fn new(prefix: impl Into, postfix_node: bool) -> Self { + Self { + prefix: prefix.into(), + postfix_node, + } + } + + /// Mangle the the name of a [FuncDefn] or [FuncDecl]. + pub fn name_func(&self, name: impl AsRef, node: Node) -> String { + let prefix = &self.prefix; + let name = name.as_ref(); + let postfix = if self.postfix_node { + format!(".{}", node.index()) + } else { + String::new() + }; + format!("{prefix}{name}{postfix}") + } +} + +impl Default for Namer { + fn default() -> Self { + Self::new(Self::DEFAULT_PREFIX, true) + } +} diff --git a/src/fat.rs b/src/fat.rs index fff3a35..189d439 100644 --- a/src/fat.rs +++ b/src/fat.rs @@ -35,7 +35,6 @@ where impl<'c, OT: 'c, H: HugrView + ?Sized> FatNode<'c, OT, H> where - // FatNode<'c,OpType,H>: TryInto>, &'c OpType: TryInto<&'c OT>, { /// Create a `FatNode` from a [HugrView] and a [Node]. @@ -56,10 +55,10 @@ where } } - // Tries to create a `FatNode` from a [HugrView] and a [Node]. - // - // If the node is invalid, or if it's `get_optype` is not `OT`, returns - // `None`. + /// Tries to create a `FatNode` from a [HugrView] and a [Node]. + /// + /// If the node is invalid, or if it's `get_optype` is not `OT`, returns + /// `None`. pub fn try_new(hugr: &'c H, node: Node) -> Option { (hugr.valid_node(node)).then_some(())?; Some(Self::new( @@ -69,34 +68,34 @@ where )) } - // Get's the [OpType] of the `FatNode`. + /// Get's the [OpType] of the `FatNode`. pub fn get(&self) -> &'c OT { self.hugr.get_optype(self.node).try_into().ok().unwrap() } } impl<'c, OT, H> FatNode<'c, OT, H> { - // Get's the [Node] of the `FatNode`. + /// Get's the [Node] of the `FatNode`. pub fn node(&self) -> Node { self.node } - // Get's the [HugrView] of the `FatNode`. + /// Get's the [HugrView] of the `FatNode`. pub fn hugr(&self) -> &'c H { self.hugr } } impl<'c, H: HugrView + ?Sized> FatNode<'c, OpType, H> { - // Creates a new general `FatNode` from a [HugrView] and a [Node]. - // - // Panics if the node is not valid in the [Hugr]. + /// Creates a new general `FatNode` from a [HugrView] and a [Node]. + /// + /// Panics if the node is not valid in the [Hugr]. pub fn new_optype(hugr: &'c H, node: Node) -> Self { assert!(hugr.valid_node(node)); FatNode::new(hugr, node, hugr.get_optype(node)) } - // Tries to downcast a genearl `FatNode` into a specific `OT`. + /// Tries to downcast a genearl `FatNode` into a specific `OT`. pub fn try_into_ot(&self) -> Option> where &'c OpType: TryInto<&'c OT>, @@ -104,9 +103,13 @@ impl<'c, H: HugrView + ?Sized> FatNode<'c, OpType, H> { FatNode::try_new(self.hugr, self.node) } - // Creates a specific `FatNode` from a general `FatNode`. - // - // Panics if the node's `get_optype` is not `OT`. + /// Creates a specific `FatNode` from a general `FatNode`. + /// + /// Panics if the node is not valid in the `Hugr` or if it's `get_optype` is + /// not an `OT`. + /// + /// Note that while we do check that the type of the node's `get_optype`, we do + /// not verify that it is actually equal to `ot`. pub fn into_ot(self, ot: &OT) -> FatNode<'c, OT, H> where for<'a> &'a OpType: TryInto<&'a OT>, diff --git a/src/test.rs b/src/test.rs index 231ece2..7c7f435 100644 --- a/src/test.rs +++ b/src/test.rs @@ -116,7 +116,8 @@ impl TestContext { self.with_context(|ctx| { let m = ctx.create_module("test_context"); let exts = self.extensions(); - let (r, ectx) = f(EmitHugr::new(ctx, m, exts)); + let namer = Namer::default(); + let (r, ectx) = f(EmitHugr::new(ctx, m, namer.into(), exts)); (r, ectx.finish()) }) }