-
Notifications
You must be signed in to change notification settings - Fork 13
feat: Normalize CFGs #2591
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: Normalize CFGs #2591
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #2591 +/- ##
==========================================
+ Coverage 82.99% 83.07% +0.07%
==========================================
Files 254 255 +1
Lines 48040 48422 +382
Branches 43550 43932 +382
==========================================
+ Hits 39873 40225 +352
- Misses 6098 6103 +5
- Partials 2069 2094 +25
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
This reverts commit 3050976.
hugr-passes/src/normalize_cfg.rs
Outdated
| /// The CFG was preserved, but the entry or exit blocks may have changed. | ||
| #[allow(missing_docs)] | ||
| CFGPreserved { | ||
| entry_changed: bool, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would like to add 'num blocks merged' here, I guess could do that by changing signature of merge_basic_blocks and then making the merge_bbs:: version (currently a re-export) just throw away this information
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps it'd be more useful to return the Option<Node> of the extracted DFGs rather than bools here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done both, taking the opportunity to sort out merge_basic_blocks by giving the "new" version a sensible interface with an error, and so deprecating only the old (uncalled) panicking version.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You might want me to move the inline module in hugr-passes/src/lib.rs out into merge_bbs.rs again, can do.
hugr-passes/src/normalize_cfg.rs
Outdated
| #[allow(clippy::match_result_ok)] // let Ok(...) without .ok() borrows `h` | ||
| if let Some(succ) = h.output_neighbours(entry).exactly_one().ok() { | ||
| if succ == exit { | ||
| // Any (basic-block) predecessors of `entry` are unreachable, so allow/ignore |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seemed a neat trick: less checks on our part, more optimization. However I'm starting to wonder: it requires its own test and makes ComposablePass::run much harder. Perhaps a better strategy would be to enhance DeadCodeElimination to remove unreachable blocks (currently it assumes all BBs are reachable if the CFG is!) and insist here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not quite as good as I hoped - one could still have entirely disconnected BBs that raise the same issue - but again, it seems more uniform. Raised #2597.
hugr-passes/src/normalize_cfg.rs
Outdated
| .filter(|n| hugr.get_optype(*n).is_cfg()) | ||
| .collect::<Vec<_>>(); | ||
| // Process inner CFGs first, in case they are removed | ||
| // (if they are in an unreachable block when the Entry node has only the Exit as successor) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sadly even this current behaviour means that you can get results saying what was done to a CFG that was later removed from the Hugr altogether as the whole thing was unreachable...see https://github.com/CQCL/hugr/pull/2591/files#r2390401557
aborgna-q
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed with removing the optimized special case, but the rest looks gtm
hugr-passes/src/normalize_cfg.rs
Outdated
| /// The CFG was preserved, but the entry or exit blocks may have changed. | ||
| #[allow(missing_docs)] | ||
| CFGPreserved { | ||
| entry_changed: bool, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps it'd be more useful to return the Option<Node> of the extracted DFGs rather than bools here?
|
This PR contains breaking changes to the public Rust API. cargo-semver-checks summary |
aborgna-q
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
hugr-passes/src/lib.rs
Outdated
| pub mod untuple; | ||
|
|
||
| /// Merge basic blocks. Subset of [normalize_cfgs], use the latter. | ||
| #[deprecated(note = "Use normalize_cfgs", since = "0.15.1")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mixed up the version with tket's
| #[deprecated(note = "Use normalize_cfgs", since = "0.15.1")] | |
| #[deprecated(note = "Use normalize_cfgs", since = "0.23.0")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lol, should have twigged that was low...15 was ages ago! This looks ahead/predicts the next number, right...
hugr-passes/src/lib.rs
Outdated
| /// If the `entrypoint` of `cfg` is not an [OpType::CFG] | ||
| /// | ||
| /// [OpType::CFG]: hugr_core::ops::OpType::CFG | ||
| #[deprecated(note = "Use version in normalize_cfgs", since = "0.15.1")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mixed up the version with tket's
| #[deprecated(note = "Use version in normalize_cfgs", since = "0.15.1")] | |
| #[deprecated(note = "Use version in normalize_cfgs", since = "0.23.0")] |
## 🤖 New release
* `hugr-model`: 0.22.4 -> 0.23.0 (✓ API compatible changes)
* `hugr-core`: 0.22.4 -> 0.23.0 (⚠ API breaking changes)
* `hugr-llvm`: 0.22.4 -> 0.23.0 (✓ API compatible changes)
* `hugr-passes`: 0.22.4 -> 0.23.0 (⚠ API breaking changes)
* `hugr-persistent`: 0.2.3 -> 0.3.0 (✓ API compatible changes)
* `hugr`: 0.22.4 -> 0.23.0 (✓ API compatible changes)
* `hugr-cli`: 0.22.4 -> 0.23.0 (✓ API compatible changes)
### ⚠ `hugr-core` breaking changes
```text
--- failure enum_variant_missing: pub enum variant removed or renamed ---
Description:
A publicly-visible enum has at least one variant that is no longer available under its prior name. It may have been renamed or removed entirely.
ref: https://doc.rust-lang.org/cargo/reference/semver.html#item-remove
impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.43.0/src/lints/enum_variant_missing.ron
Failed in:
variant PackageEncodingError::ExtensionVersion, previously in file /tmp/.tmp8eoQo1/hugr-core/src/envelope/package_json.rs:89
--- failure function_parameter_count_changed: pub fn parameter count changed ---
Description:
A publicly-visible function now takes a different number of parameters.
ref: https://doc.rust-lang.org/cargo/reference/semver.html#fn-change-arity
impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.43.0/src/lints/function_parameter_count_changed.ron
Failed in:
hugr_core::import::import_package now takes 3 parameters instead of 2, in /tmp/.tmpBTXSed/hugr/hugr-core/src/import.rs:187
--- failure struct_missing: pub struct removed or renamed ---
Description:
A publicly-visible struct cannot be imported by its prior path. A `pub use` may have been removed, or the struct itself may have been renamed or removed entirely.
ref: https://doc.rust-lang.org/cargo/reference/semver.html#item-remove
impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.43.0/src/lints/struct_missing.ron
Failed in:
struct hugr_core::extension::prelude::PRELUDE_REGISTRY, previously in file /tmp/.tmp8eoQo1/hugr-core/src/extension/prelude.rs:43
struct hugr_core::extension::PRELUDE_REGISTRY, previously in file /tmp/.tmp8eoQo1/hugr-core/src/extension/prelude.rs:43
struct hugr_core::std_extensions::logic::EXTENSION, previously in file /tmp/.tmp8eoQo1/hugr-core/src/std_extensions/logic.rs:134
struct hugr_core::extension::prelude::PRELUDE, previously in file /tmp/.tmp8eoQo1/hugr-core/src/extension/prelude.rs:43
struct hugr_core::extension::PRELUDE, previously in file /tmp/.tmp8eoQo1/hugr-core/src/extension/prelude.rs:43
struct hugr_core::std_extensions::ptr::EXTENSION, previously in file /tmp/.tmp8eoQo1/hugr-core/src/std_extensions/ptr.rs:112
struct hugr_core::std_extensions::arithmetic::int_types::EXTENSION, previously in file /tmp/.tmp8eoQo1/hugr-core/src/std_extensions/arithmetic/int_types.rs:209
struct hugr_core::std_extensions::arithmetic::conversions::EXTENSION, previously in file /tmp/.tmp8eoQo1/hugr-core/src/std_extensions/arithmetic/conversions.rs:174
struct hugr_core::std_extensions::collections::array::EXTENSION, previously in file /tmp/.tmp8eoQo1/hugr-core/src/std_extensions/collections/array.rs:93
struct hugr_core::std_extensions::arithmetic::int_types::INT_TYPES, previously in file /tmp/.tmp8eoQo1/hugr-core/src/std_extensions/arithmetic/int_types.rs:49
struct hugr_core::std_extensions::arithmetic::float_types::EXTENSION, previously in file /tmp/.tmp8eoQo1/hugr-core/src/std_extensions/arithmetic/float_types.rs:104
struct hugr_core::std_extensions::collections::static_array::EXTENSION, previously in file /tmp/.tmp8eoQo1/hugr-core/src/std_extensions/collections/static_array.rs:142
struct hugr_core::std_extensions::collections::list::EXTENSION, previously in file /tmp/.tmp8eoQo1/hugr-core/src/std_extensions/collections/list.rs:289
struct hugr_core::std_extensions::STD_REG, previously in file /tmp/.tmp8eoQo1/hugr-core/src/std_extensions.rs:35
struct hugr_core::std_extensions::collections::value_array::EXTENSION, previously in file /tmp/.tmp8eoQo1/hugr-core/src/std_extensions/collections/value_array.rs:99
struct hugr_core::std_extensions::collections::borrow_array::EXTENSION, previously in file /tmp/.tmp8eoQo1/hugr-core/src/std_extensions/collections/borrow_array.rs:290
struct hugr_core::std_extensions::arithmetic::float_ops::EXTENSION, previously in file /tmp/.tmp8eoQo1/hugr-core/src/std_extensions/arithmetic/float_ops.rs:115
struct hugr_core::std_extensions::arithmetic::int_ops::EXTENSION, previously in file /tmp/.tmp8eoQo1/hugr-core/src/std_extensions/arithmetic/int_ops.rs:254
```
### ⚠ `hugr-passes` breaking changes
```text
--- failure enum_missing: pub enum removed or renamed ---
Description:
A publicly-visible enum cannot be imported by its prior path. A `pub use` may have been removed, or the enum itself may have been renamed or removed entirely.
ref: https://doc.rust-lang.org/cargo/reference/semver.html#item-remove
impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.43.0/src/lints/enum_missing.ron
Failed in:
enum hugr_passes::non_local::NonLocalEdgesError, previously in file /tmp/.tmp8eoQo1/hugr-passes/src/non_local.rs:57
```
<details><summary><i><b>Changelog</b></i></summary><p>
## `hugr-model`
<blockquote>
##
[0.23.0](hugr-model-v0.22.4...hugr-model-v0.23.0)
- 2025-09-30
### Bug Fixes
- [**breaking**] Appease `cargo-audit` by replacing unmaintained
dependencies ([#2572](#2572))
### New Features
- Documentation and error hints
([#2523](#2523))
</blockquote>
## `hugr-core`
<blockquote>
##
[0.23.0](hugr-core-v0.22.4...hugr-core-v0.23.0)
- 2025-09-30
### Bug Fixes
- [**breaking**] Appease `cargo-audit` by replacing unmaintained
dependencies ([#2572](#2572))
- *(core)* check extension versions on model import
([#2580](#2580))
- [**breaking**] test extension version compatibility on ModelWithExts
([#2587](#2587))
- *(core)* check used extension versions against resolved extensions
([#2588](#2588))
- [**breaking**] model import loads Package extensions
([#2590](#2590))
### Miscellaneous Tasks
- [**breaking**] Cleanup deprecated definitions
([#2594](#2594))
### New Features
- add trait+funcs for linking Hugrs explicitly by Node
([#2521](#2521))
- Documentation and error hints
([#2523](#2523))
- Allow creating DFG builders from existing hugrs
([#2562](#2562))
- add_input/output for arbitrary DFGBuilders
([#2564](#2564))
- [**breaking**] Return error instead of panicking in
DFGWrapper::add_{in,out}put
([#2571](#2571))
- *(core)* inner acccesors for WithGenerator error
([#2583](#2583))
- Normalize CFGs ([#2591](#2591))
### Refactor
- [**breaking**] Replace lazy_static with std::sync::LazyLock
([#2567](#2567))
</blockquote>
## `hugr-llvm`
<blockquote>
##
[0.23.0](hugr-llvm-v0.22.4...hugr-llvm-v0.23.0)
- 2025-09-30
### Miscellaneous Tasks
- [**breaking**] Cleanup deprecated definitions
([#2594](#2594))
### Refactor
- [**breaking**] Replace lazy_static with std::sync::LazyLock
([#2567](#2567))
### Testing
- Add framework for LLVM execution tests involving panics
([#2568](#2568))
</blockquote>
## `hugr-passes`
<blockquote>
##
[0.23.0](hugr-passes-v0.22.4...hugr-passes-v0.23.0)
- 2025-09-30
### Bug Fixes
- DeadCodeElim keeps consumers of linear outputs
([#2560](#2560))
- [**breaking**] Appease `cargo-audit` by replacing unmaintained
dependencies ([#2572](#2572))
### Miscellaneous Tasks
- [**breaking**] Cleanup deprecated definitions
([#2594](#2594))
### New Features
- [**breaking**] DeadCodeElimPass reports error on non-existent
entry_points ([#2566](#2566))
- Normalize CFGs ([#2591](#2591))
### Refactor
- [**breaking**] Replace lazy_static with std::sync::LazyLock
([#2567](#2567))
</blockquote>
## `hugr-persistent`
<blockquote>
##
[0.3.0](hugr-persistent-v0.2.3...hugr-persistent-v0.3.0)
- 2025-09-30
### Miscellaneous Tasks
- [**breaking**] Cleanup deprecated definitions
([#2594](#2594))
### Refactor
- [**breaking**] Replace lazy_static with std::sync::LazyLock
([#2567](#2567))
</blockquote>
## `hugr`
<blockquote>
##
[0.23.0](hugr-v0.22.4...hugr-v0.23.0)
- 2025-09-30
### Bug Fixes
- DeadCodeElim keeps consumers of linear outputs
([#2560](#2560))
- [**breaking**] Appease `cargo-audit` by replacing unmaintained
dependencies ([#2572](#2572))
- *(core)* check extension versions on model import
([#2580](#2580))
- [**breaking**] test extension version compatibility on ModelWithExts
([#2587](#2587))
- *(core)* check used extension versions against resolved extensions
([#2588](#2588))
- [**breaking**] model import loads Package extensions
([#2590](#2590))
### Miscellaneous Tasks
- [**breaking**] Cleanup deprecated definitions
([#2594](#2594))
### New Features
- [**breaking**] DeadCodeElimPass reports error on non-existent
entry_points ([#2566](#2566))
- add trait+funcs for linking Hugrs explicitly by Node
([#2521](#2521))
- Documentation and error hints
([#2523](#2523))
- Allow creating DFG builders from existing hugrs
([#2562](#2562))
- add_input/output for arbitrary DFGBuilders
([#2564](#2564))
- [**breaking**] Return error instead of panicking in
DFGWrapper::add_{in,out}put
([#2571](#2571))
- *(core)* inner acccesors for WithGenerator error
([#2583](#2583))
- Normalize CFGs ([#2591](#2591))
### Refactor
- [**breaking**] Replace lazy_static with std::sync::LazyLock
([#2567](#2567))
</blockquote>
## `hugr-cli`
<blockquote>
##
[0.22.3](hugr-cli-v0.22.2...hugr-cli-v0.22.3)
- 2025-09-11
### New Features
- *(hugr-cli)* CliError::validate helper
([#2507](#2507))
</blockquote>
</p></details>
---
This PR was generated with
[release-plz](https://github.com/release-plz/release-plz/).
closes #945, closes #2556.
normalize_cfgsand a newmerge_basic_blocks(with improved API) withinmerge_basic_blocksas the interface is annoying (panicking, usingRootCheckable).Does not address: "inlining" arbitrary CFG into a BB (requires splitting the outer BB into parts before/after the inner CFG); emptying (but preserving) a branching entry block (if no predecessors).