Skip to content

Commit

Permalink
fix: allow dominator edges in CFGBuilder
Browse files Browse the repository at this point in the history
  • Loading branch information
ss2165 committed Nov 7, 2023
1 parent 24a6144 commit 936ebeb
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 5 deletions.
17 changes: 12 additions & 5 deletions src/builder/build_traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::hugr::hugrmut::InsertionResult;
use crate::hugr::validate::InterGraphEdgeError;
use crate::hugr::views::HugrView;
use crate::hugr::{NodeMetadata, ValidationError};
use crate::ops::{self, LeafOp, OpTrait, OpType};
use crate::ops::{self, LeafOp, OpTag, OpTrait, OpType};
use crate::{IncomingPort, Node, OutgoingPort};

use std::iter;
Expand Down Expand Up @@ -668,6 +668,7 @@ fn wire_up<T: Dataflow + ?Sized>(
let base = data_builder.hugr_mut();

let src_parent = base.get_parent(src);
let src_parent_parent = src_parent.and_then(|src| base.get_parent(src));
let dst_parent = base.get_parent(dst);
let local_source = src_parent == dst_parent;
if let EdgeKind::Value(typ) = base.get_optype(src).port_kind(src_port).unwrap() {
Expand All @@ -689,7 +690,10 @@ fn wire_up<T: Dataflow + ?Sized>(
let Some(src_sibling) = iter::successors(dst_parent, |&p| base.get_parent(p))
.tuple_windows()
.find_map(|(ancestor, ancestor_parent)| {
(ancestor_parent == src_parent).then_some(ancestor)
(ancestor_parent == src_parent ||
// Dom edge - in CFGs
Some(ancestor_parent) == src_parent_parent)
.then_some(ancestor)
})
else {
let val_err: ValidationError = InterGraphEdgeError::NoRelation {
Expand All @@ -702,9 +706,12 @@ fn wire_up<T: Dataflow + ?Sized>(
return Err(val_err.into());
};

// TODO: Avoid adding duplicate edges
// This should be easy with https://github.com/CQCL-DEV/hugr/issues/130
base.add_other_edge(src, src_sibling)?;
if !OpTag::BasicBlock.is_superset(base.get_optype(src).tag())
&& !OpTag::BasicBlock.is_superset(base.get_optype(src_sibling).tag())
{
// Add a state order constraint unless one of the nodes is a CFG BasicBlock
base.add_other_edge(src, src_sibling)?;
}
} else if !typ.copyable() & base.linked_ports(src, src_port).next().is_some() {
// Don't copy linear edges.
return Err(BuildError::NoCopyLinear(typ));
Expand Down
28 changes: 28 additions & 0 deletions src/builder/cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -393,4 +393,32 @@ mod test {
cfg_builder.branch(&entry, 1, &exit)?;
Ok(())
}
#[test]
fn test_dom_edge() -> Result<(), BuildError> {
let mut cfg_builder = CFGBuilder::new(FunctionType::new(type_row![NAT], type_row![NAT]))?;
let sum_tuple_const =
cfg_builder.add_constant(ops::Const::unary_unit_sum(), ExtensionSet::new())?;
let sum_variants = vec![type_row![]];

let mut entry_b =
cfg_builder.entry_builder(sum_variants.clone(), type_row![], ExtensionSet::new())?;
let [inw] = entry_b.input_wires_arr();
let entry = {
let sum = entry_b.load_const(&sum_tuple_const)?;

entry_b.finish_with_outputs(sum, [])?
};
let exit = cfg_builder.exit_block();
let mut middle_b =
cfg_builder.simple_block_builder(FunctionType::new(type_row![], type_row![NAT]), 1)?;
let middle = {
let c = middle_b.load_const(&sum_tuple_const)?;
middle_b.finish_with_outputs(c, [inw])?
};
cfg_builder.branch(&entry, 0, &middle)?;
cfg_builder.branch(&middle, 0, &exit)?;
assert_matches!(cfg_builder.finish_prelude_hugr(), Ok(_));

Ok(())
}
}

0 comments on commit 936ebeb

Please sign in to comment.