Skip to content

🐛 Verify modifier bodies at the dialect boundary - #2319

Open
simon1hofmann wants to merge 6 commits into
mainfrom
codex/2255-measurement-lifting-effects
Open

🐛 Verify modifier bodies at the dialect boundary#2319
simon1hofmann wants to merge 6 commits into
mainfrom
codex/2255-measurement-lifting-effects

Conversation

@simon1hofmann

@simon1hofmann simon1hofmann commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

🤖 AI text below 🤖

Description

Reject invalid operations at the QC and QCO modifier boundary instead of adding pass-local guardrails to measurement lifting.

Modifier bodies may contain operations implementing UnitaryOpInterface and pure, speculatable, qubit-free classical support computations. Effectful or unknown operations, register access, and non-unitary operations carrying qubits are rejected by the dialect verifiers. Measurement lifting can consequently assume valid IR and no longer needs its redundant memory-effect checks.

The QIR conversion also rejects controlled global phases before mutating or inlining the control region. This preserves the existing diagnostic for valid multi-block classical computations that produce a non-hoistable phase angle.

Part of #2255.

Validation

  • QC IR: 339/339 tests passed
  • QCO IR: 494/494 tests passed
  • QC-to-QIR adaptive: 149/149 tests passed
  • QCO optimizations: 194/194 tests passed
  • Total affected suites: 1,176/1,176 tests passed
  • nox -s lint
  • Changed-file C++ lint: zero clang-format and clang-tidy findings

Checklist

  • The pull request only contains commits that are focused and relevant to this change.
  • I have added appropriate tests that cover the new/changed functionality.
  • The QC and QCO modifier documentation describes the verifier contract.
  • No changelog entry is needed for this unreleased MLIR behavior; the skip-changelog label is applied.
  • No upgrade-guide migration instructions are needed.
  • The changes follow the project's style guidelines and introduce no new warnings.
  • The changes are fully tested and pass the CI checks. Local targeted, full-suite, and lint checks pass; CI is pending.
  • I have reviewed my own code changes.

If PR contains AI-assisted content:

  • Any agent that created, edited, or submitted GitHub content was explicitly authorized for that scope, as required by our AI Usage Guidelines.
  • Every agent-authored or agent-edited public text body begins with the visible disclosure 🤖 *AI text below* 🤖 (titles are exempt).
  • I have disclosed AI assistance in the PR description. Implementation, tests, and PR preparation were assisted by Codex.
  • I confirm that I have personally reviewed and understood all AI-generated content, and accept full responsibility for it.

@simon1hofmann simon1hofmann added c++ Anything related to C++ code code quality Code quality improvements fix Fix for something that isn't working MLIR Anything related to MLIR skip-changelog Changes that do not need to show up in the changelog labels Sep 1, 2026
@simon1hofmann simon1hofmann self-assigned this Sep 1, 2026
@codecov

codecov Bot commented Sep 1, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Measurement lifting could erase or move effectful support operations across a measurement. Refuse these rewrites when modifier bodies are not memory-effect free while retaining optimization for pure classical support computations.

Assisted-by: GPT-5.6 via Codex

@DRovara DRovara left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

That's an edge case I didn't think about, but I also have some concerns about it.

In particular, I'm not very convinced by the example test case. I assume the @observe function should represent a function that contains a measurement. But it's not really reasonable to invert a measurement.

In fact, I would say the contents of an qco.inv modifier should always be unitary. That means the only way to have actual memory effects in there is to have a gphase operation, because that adds a global phase with no targeted qubits (but actually, in that case, I don't even know if the inv modifier allows 0 target qubits.

Similarly, qco.ctrl also only makes sense for unitaries.

What are your thoughts on that?

@simon1hofmann

Copy link
Copy Markdown
Contributor Author

That's an edge case I didn't think about, but I also have some concerns about it.

In particular, I'm not very convinced by the example test case. I assume the @observe function should represent a function that contains a measurement. But it's not really reasonable to invert a measurement.

In fact, I would say the contents of an qco.inv modifier should always be unitary. That means the only way to have actual memory effects in there is to have a gphase operation, because that adds a global phase with no targeted qubits (but actually, in that case, I don't even know if the inv modifier allows 0 target qubits.

Similarly, qco.ctrl also only makes sense for unitaries.

What are your thoughts on that?

Thanks a lot for the review, you're right, the func.call example is invalid modifier content. I will retarget this PR to reject unknown/effectful non-unitary operations in both modifier verifiers while permitting pure classical support and UnitaryOpInterface operations.

The audit produced a lot of edge cases that are quite hypothetical.

Apply the review fix on the current verifier and test infrastructure.

Assisted-by: GPT-5.6 via Codex
Reject effectful, non-speculatable, and qubit-carrying non-unitary operations in QC and QCO modifier bodies while retaining pure classical support and all UnitaryOpInterface operations.

Reject unrepresentable controlled global phases before mutating the QIR conversion state, and let measurement lifting rely on verified IR.

Assisted-by: GPT-5.6 via Codex
@simon1hofmann simon1hofmann changed the title 🐛 Preserve modifier effects during measurement lifting 🐛 Verify modifier bodies at the dialect boundary Sep 3, 2026
Keep the shared recursive qubit-type predicate, but inline the helpers that each had a single caller into the QC and QCO modifier verification paths.

Assisted-by: GPT-5.6 via Codex
@mergify mergify Bot added the conflict label Sep 4, 2026

@DRovara DRovara left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Hi @simon1hofmann, thanks for the update! Looks quite reasonable, I think it's good to make these verifications in advance.

I do have some minor concerns on the correctness/completeness of the implementation though, but I'm not 100% sure on any of them.

Comment thread mlir/lib/Conversion/QCToQIR/QIRCommon/QIRCommon.cpp Outdated
Comment thread mlir/lib/Dialect/QC/IR/Modifiers/ModifierUtils.cpp Outdated
Comment thread mlir/lib/Dialect/QCO/IR/Modifiers/ModifierUtils.cpp Outdated
Comment thread mlir/lib/Dialect/QC/IR/Modifiers/ModifierUtils.cpp Outdated
Assisted-by: GPT-5.6 via Codex

# Conflicts:
#	mlir/lib/Dialect/QC/IR/Modifiers/ModifierUtils.cpp
#	mlir/lib/Dialect/QCO/IR/Modifiers/ModifierUtils.cpp
#	mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp
Exercise the control-reordering guard separately from the phase-erasure guard so either unsafe rewrite causes the regression to fail.

Assisted-by: GPT-5.6 via Codex
@mergify mergify Bot removed the conflict label Sep 5, 2026
@coderabbitai

coderabbitai Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Important

Approval pending

CodeRabbit has no unresolved comments, but it has not reviewed the latest commit.

Use the checkbox below to review the latest commit. CodeRabbit will approve the changes if it finds no blocking issues.

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

c++ Anything related to C++ code code quality Code quality improvements fix Fix for something that isn't working MLIR Anything related to MLIR skip-changelog Changes that do not need to show up in the changelog

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants