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

feat!: Add monomorphization pass #1733

Merged
merged 72 commits into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
24bff91
Add {Dataflow,}OpTrait::substitute - compiles, no tests
acl-cqc Nov 26, 2024
341e537
WIP Add Hugr::substitute
acl-cqc Nov 26, 2024
6a96b2c
WIP monomorphize via mono_scan
acl-cqc Nov 26, 2024
7866a62
Use continue, match instead of if let |
acl-cqc Nov 26, 2024
871e796
WIP start copying edges...no not so simple
acl-cqc Nov 27, 2024
ac536c5
Break out is_polymorphic_funcdefn, tho only used once; remove obsolet…
acl-cqc Nov 27, 2024
ff04f13
Separate 'fn instantiate' to copy edges, add struct Instantiating; mv…
acl-cqc Nov 27, 2024
e5f665b
Use Instantiating::poly_func, drop is_polymorphic_funcdefn; and ..**inst
acl-cqc Nov 27, 2024
6c00ad0
mangle inner names, switch from impl HugrMut to &mut Hugr
acl-cqc Nov 27, 2024
b666dd5
two-level Instantiations, flatten in instantiate()
acl-cqc Nov 27, 2024
5a4a0f9
Add remove_polyfuncs, using remove_subtree
acl-cqc Nov 28, 2024
7de2c2b
comments
acl-cqc Nov 28, 2024
5bb0c57
name_mangle => mangle_name
acl-cqc Nov 28, 2024
b04e1cf
WIP tests
acl-cqc Nov 27, 2024
4aa6c79
refactor: let mut = Instantiating; use static_output_port
acl-cqc Dec 1, 2024
a7d6137
Fixes: monomorphize Call op; read static input from old_ch
acl-cqc Dec 1, 2024
48a6598
Test: use pair/triple not list
acl-cqc Dec 1, 2024
937a6d0
Implement mangle_name
acl-cqc Dec 1, 2024
f15f09f
fixup! Test: use pair
acl-cqc Dec 2, 2024
d5f15ff
fix edge handling
acl-cqc Dec 2, 2024
ad00327
clippy/lint, docs
acl-cqc Dec 2, 2024
c5a0f8d
test remove_polyfuncs
acl-cqc Dec 2, 2024
04d60b1
Shorten test a bit
acl-cqc Dec 2, 2024
3be790e
Factor out is_polymorphic_funcdefn, avoid root
acl-cqc Dec 2, 2024
4a9f7a2
remove_polyfuncs if non-module-rooted; implement mangle_inner_func
acl-cqc Dec 2, 2024
8178b5d
Fix monomorphized func -> Call edges
acl-cqc Dec 2, 2024
2090218
Test flattening (and multiple calls with different typeargs from one …
acl-cqc Dec 2, 2024
6ff4c3b
Merge remote-tracking branch 'origin/main' into acl/monomorphize
acl-cqc Dec 2, 2024
4429152
tidy
acl-cqc Dec 2, 2024
9fc3271
clippy
acl-cqc Dec 2, 2024
9f0b906
Make test_module also test recursion
acl-cqc Dec 3, 2024
1b7f9ee
fix doclink
acl-cqc Dec 3, 2024
8a52185
helper list_funcs
acl-cqc Dec 3, 2024
5d54ee3
Test part-flattening
acl-cqc Dec 3, 2024
bbcda39
fix tests for all-features
acl-cqc Dec 3, 2024
bdfdbbd
Merge remote-tracking branch 'origin/main' into acl/monomorphize
acl-cqc Dec 3, 2024
a26fa49
silence clippy
acl-cqc Dec 4, 2024
275b155
common up is_polymorphic
acl-cqc Dec 4, 2024
f7a6dca
Move monomorphize.rs into hugr-passes, pub Substitution::new
acl-cqc Dec 4, 2024
3e755d1
substitute(self) -> substitute(&self) calling subst_mut(&mut self)
acl-cqc Dec 4, 2024
41d0812
Revert subst_mut; substitute takes &self; OpTrait requires Clone
acl-cqc Dec 6, 2024
c0eae19
Merge remote-tracking branch 'origin/main' into acl/monomorphize
acl-cqc Dec 6, 2024
d4ab4aa
can't monomorphize array ops polymorphic in size because can't define…
acl-cqc Dec 9, 2024
565a78a
Revert "can't monomorphize array ops polymorphic in size because can'…
acl-cqc Dec 9, 2024
134bda4
A couple of test tidies
acl-cqc Dec 9, 2024
9f88f97
Remove remove_polyfuncs
acl-cqc Dec 9, 2024
5d0ca00
Tests in controlflow.rs
acl-cqc Dec 9, 2024
2fb8a92
Merge branch 'main' of gh:CQCL-DEV/hugr into acl/monomorphize
doug-q Dec 10, 2024
00c918c
Revert "Remove remove_polyfuncs"
doug-q Dec 10, 2024
43826be
wip
doug-q Dec 10, 2024
802d361
fix!: Replace `LoadFunction::signature` with `LoadFunction::instantia…
doug-q Dec 10, 2024
71253c8
Merge remote-tracking branch 'origin/doug/loadfunction-instantiation'…
doug-q Dec 10, 2024
afb6e17
Adjust flattening test to also check multiple typeargs and BoundedNats
acl-cqc Dec 9, 2024
5d2ff7d
wip
doug-q Dec 11, 2024
efc461a
Merge branch 'main' of gh:CQCL-DEV/hugr into acl/monomorphize
doug-q Dec 11, 2024
703004e
wip
doug-q Dec 11, 2024
43c2f3e
Revert "wip"
doug-q Dec 12, 2024
bc839b7
Merge branch 'main' of gh:CQCL-DEV/hugr into acl/monomorphize
doug-q Dec 12, 2024
0adb432
fix up merge
doug-q Dec 12, 2024
d933d59
Merge branch 'acl/monomorphize' of gh:CQCL-DEV/hugr into acl/monomorp…
doug-q Dec 12, 2024
5845706
fmt
doug-q Dec 12, 2024
6049889
add array extension to signatures
doug-q Dec 12, 2024
144fc47
fmt
doug-q Dec 12, 2024
becc847
lint
doug-q Dec 12, 2024
df38d88
docs + tweak name mangling
doug-q Dec 12, 2024
4bde01d
docs
doug-q Dec 12, 2024
d693c81
Update hugr-passes/src/monomorphize.rs
doug-q Dec 12, 2024
61afb2e
Update hugr-passes/src/monomorphize.rs
doug-q Dec 12, 2024
7618fa3
Update hugr-passes/src/monomorphize.rs
doug-q Dec 12, 2024
44a354c
Update hugr-passes/src/monomorphize.rs
doug-q Dec 12, 2024
821c68e
remove call_indirect helper
doug-q Dec 12, 2024
ae2b850
Merge branch 'acl/monomorphize' of gh:CQCL-DEV/hugr into acl/monomorp…
doug-q Dec 12, 2024
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
10 changes: 8 additions & 2 deletions hugr-core/src/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use std::borrow::Cow;

use crate::extension::simple_op::MakeExtensionOp;
use crate::extension::{ExtensionId, ExtensionRegistry, ExtensionSet};
use crate::types::{EdgeKind, Signature};
use crate::types::{EdgeKind, Signature, Substitution};
use crate::{Direction, OutgoingPort, Port};
use crate::{IncomingPort, PortIndex};
use derive_more::Display;
Expand Down Expand Up @@ -369,7 +369,7 @@ pub trait StaticTag {

#[enum_dispatch]
/// Trait implemented by all OpType variants.
pub trait OpTrait {
pub trait OpTrait: Sized + Clone {
/// A human-readable description of the operation.
fn description(&self) -> &str;

Expand Down Expand Up @@ -433,6 +433,12 @@ pub trait OpTrait {
}
.is_some() as usize
}

/// Apply a type-level substitution to this OpType, i.e. replace
/// [type variables](crate::types::TypeArg::new_var_use) with new types.
fn substitute(&self, _subst: &Substitution) -> Self {
self.clone()
}
}

/// Properties of child graphs of ops, if the op has children.
Expand Down
2 changes: 2 additions & 0 deletions hugr-core/src/ops/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ impl OpTrait for Const {
fn static_output(&self) -> Option<EdgeKind> {
Some(EdgeKind::Const(self.get_type()))
}

// Constants cannot refer to TypeArgs of the enclosing Hugr, so no substitute().
}

impl From<Const> for Value {
Expand Down
142 changes: 142 additions & 0 deletions hugr-core/src/ops/controlflow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,15 @@ impl DataflowOpTrait for TailLoop {
Signature::new(inputs, outputs).with_extension_delta(self.extension_delta.clone()),
)
}

fn substitute(&self, subst: &crate::types::Substitution) -> Self {
Self {
just_inputs: self.just_inputs.substitute(subst),
just_outputs: self.just_outputs.substitute(subst),
rest: self.rest.substitute(subst),
extension_delta: self.extension_delta.substitute(subst),
}
}
}

impl TailLoop {
Expand Down Expand Up @@ -111,6 +120,15 @@ impl DataflowOpTrait for Conditional {
.with_extension_delta(self.extension_delta.clone()),
)
}

fn substitute(&self, subst: &crate::types::Substitution) -> Self {
Self {
sum_rows: self.sum_rows.iter().map(|r| r.substitute(subst)).collect(),
other_inputs: self.other_inputs.substitute(subst),
outputs: self.outputs.substitute(subst),
extension_delta: self.extension_delta.substitute(subst),
}
}
}

impl Conditional {
Expand Down Expand Up @@ -140,6 +158,12 @@ impl DataflowOpTrait for CFG {
fn signature(&self) -> Cow<'_, Signature> {
Cow::Borrowed(&self.signature)
}

fn substitute(&self, subst: &crate::types::Substitution) -> Self {
Self {
signature: self.signature.substitute(subst),
}
}
}

#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
Expand Down Expand Up @@ -223,6 +247,15 @@ impl OpTrait for DataflowBlock {
Direction::Outgoing => self.sum_rows.len(),
}
}

fn substitute(&self, subst: &crate::types::Substitution) -> Self {
Self {
inputs: self.inputs.substitute(subst),
other_outputs: self.other_outputs.substitute(subst),
sum_rows: self.sum_rows.iter().map(|r| r.substitute(subst)).collect(),
extension_delta: self.extension_delta.substitute(subst),
}
}
}

impl OpTrait for ExitBlock {
Expand All @@ -248,6 +281,12 @@ impl OpTrait for ExitBlock {
Direction::Outgoing => 0,
}
}

fn substitute(&self, subst: &crate::types::Substitution) -> Self {
Self {
cfg_outputs: self.cfg_outputs.substitute(subst),
}
}
}

/// Functionality shared by DataflowBlock and Exit CFG block types.
Expand Down Expand Up @@ -311,6 +350,12 @@ impl OpTrait for Case {
fn tag(&self) -> OpTag {
<Self as StaticTag>::TAG
}

fn substitute(&self, subst: &crate::types::Substitution) -> Self {
Self {
signature: self.signature.substitute(subst),
}
}
}

impl Case {
Expand All @@ -324,3 +369,100 @@ impl Case {
&self.signature.output
}
}

#[cfg(test)]
mod test {
use crate::{
extension::{
prelude::{qb_t, usize_t, PRELUDE_ID},
ExtensionSet, PRELUDE_REGISTRY,
},
ops::{Conditional, DataflowOpTrait, DataflowParent},
types::{Signature, Substitution, Type, TypeArg, TypeBound, TypeRV},
};

use super::{DataflowBlock, TailLoop};

#[test]
fn test_subst_dataflow_block() {
use crate::ops::OpTrait;
let tv0 = Type::new_var_use(0, TypeBound::Any);
let dfb = DataflowBlock {
inputs: vec![usize_t(), tv0.clone()].into(),
other_outputs: vec![tv0.clone()].into(),
sum_rows: vec![usize_t().into(), vec![qb_t(), tv0.clone()].into()],
extension_delta: ExtensionSet::type_var(1),
};
let dfb2 = dfb.substitute(&Substitution::new(
&[
qb_t().into(),
TypeArg::Extensions {
es: PRELUDE_ID.into(),
},
],
&PRELUDE_REGISTRY,
));
let st = Type::new_sum(vec![vec![usize_t()], vec![qb_t(); 2]]);
assert_eq!(
dfb2.inner_signature(),
Signature::new(vec![usize_t(), qb_t()], vec![st, qb_t()])
.with_extension_delta(PRELUDE_ID)
);
}

#[test]
fn test_subst_conditional() {
let tv1 = Type::new_var_use(1, TypeBound::Any);
let cond = Conditional {
sum_rows: vec![usize_t().into(), tv1.clone().into()],
other_inputs: vec![Type::new_tuple(TypeRV::new_row_var_use(0, TypeBound::Any))].into(),
outputs: vec![usize_t(), tv1].into(),
extension_delta: ExtensionSet::new(),
};
let cond2 = cond.substitute(&Substitution::new(
&[
TypeArg::Sequence {
elems: vec![usize_t().into(); 3],
},
qb_t().into(),
],
&PRELUDE_REGISTRY,
));
let st = Type::new_sum(vec![usize_t(), qb_t()]); //both single-element variants
assert_eq!(
cond2.signature(),
Signature::new(
vec![st, Type::new_tuple(vec![usize_t(); 3])],
vec![usize_t(), qb_t()]
)
);
}

#[test]
fn test_tail_loop() {
let tv0 = Type::new_var_use(0, TypeBound::Copyable);
let tail_loop = TailLoop {
just_inputs: vec![qb_t(), tv0.clone()].into(),
just_outputs: vec![tv0.clone(), qb_t()].into(),
rest: vec![tv0.clone()].into(),
extension_delta: ExtensionSet::type_var(1),
};
let tail2 = tail_loop.substitute(&Substitution::new(
&[
usize_t().into(),
TypeArg::Extensions {
es: PRELUDE_ID.into(),
},
],
&PRELUDE_REGISTRY,
));
assert_eq!(
tail2.signature(),
Signature::new(
vec![qb_t(), usize_t(), usize_t()],
vec![usize_t(), qb_t(), usize_t()]
)
.with_extension_delta(PRELUDE_ID)
);
}
}
28 changes: 28 additions & 0 deletions hugr-core/src/ops/custom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,26 @@ impl DataflowOpTrait for ExtensionOp {
fn signature(&self) -> Cow<'_, Signature> {
Cow::Borrowed(&self.signature)
}

fn substitute(&self, subst: &crate::types::Substitution) -> Self {
let args = self
.args
.iter()
.map(|ta| ta.substitute(subst))
.collect::<Vec<_>>();
let signature = self.signature.substitute(subst);
debug_assert_eq!(
self.def
.compute_signature(&args, subst.extension_registry())
.as_ref(),
Ok(&signature)
);
Self {
def: self.def.clone(),
args,
signature,
}
}
}

/// An opaquely-serialized op that refers to an as-yet-unresolved [`OpDef`].
Expand Down Expand Up @@ -259,6 +279,14 @@ impl DataflowOpTrait for OpaqueOp {
fn signature(&self) -> Cow<'_, Signature> {
Cow::Borrowed(&self.signature)
}

fn substitute(&self, subst: &crate::types::Substitution) -> Self {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm surprised this isn't covered, it should be right?

Self {
args: self.args.iter().map(|ta| ta.substitute(subst)).collect(),
signature: self.signature.substitute(subst),
..self.clone()
}
}
}

/// Errors that arise after loading a Hugr containing opaque ops (serialized just as their names)
Expand Down
Loading
Loading