Skip to content

🐛 Preserve structured state in QC-to-QCO conversion#1935

Merged
burgholzer merged 10 commits into
mainfrom
agent/1910-qctoqco-structured
Jul 24, 2026
Merged

🐛 Preserve structured state in QC-to-QCO conversion#1935
burgholzer merged 10 commits into
mainfrom
agent/1910-qctoqco-structured

Conversation

@burgholzer

@burgholzer burgholzer commented Jul 24, 2026

Copy link
Copy Markdown
Member

🤖 AI text below 🤖

Summary

  • Preserve existing classical iteration arguments and results when the QC-to-QCO conversion appends explicit QCO and QTensor state to scf.for and scf.while.
  • Preserve the distinct input and result signatures of type-changing scf.while operations, including reordered scf.condition arguments.
  • Lower affected structured terminators in a second conversion phase so their operands use the final region state instead of depending on dialect-conversion traversal order.
  • Teach QCO mapping to distinguish classical loop state from qubit state, preserve classical terminator operands during hot routing, and extend type-changing scf.while regions with the correct before/after signatures.
  • Add focused pure-QC conversion regressions and mixed-state mapping regressions for for and while.
  • Add this general conversion fix to the existing MLIR infrastructure changelog entry.

Context

This conversion gap was found while working on OpenQASM control flow in #1910. The fix is independent of that frontend: any QC producer can create valid scf.for or scf.while operations whose existing classical values must survive conversion while quantum state is made explicit.

Scope

This PR is limited to stable scf.for and scf.while state preservation. It intentionally does not add classical results to qco.if or qco.index_switch, and it introduces no scratch allocations, stores, or loads. Classical qco.if results are being designed separately as an SSA-based extension.

Validation

  • QC-to-QCO conversion tests: 132 passed
  • QCO mapping tests: 13 passed
  • Focused structured-control-flow conversion regressions: 4 passed
  • Focused mixed-state mapping regressions: 2 passed
  • uvx nox -s lint
  • git diff --check

@denialhaag denialhaag changed the title 🐛 Preserve structured state in QC-to-QCO 🐛 Preserve structured state in QC-to-QCO conversion Jul 24, 2026
@denialhaag denialhaag added fix Fix for something that isn't working MLIR Anything related to MLIR labels Jul 24, 2026
@denialhaag denialhaag added this to the MLIR Support milestone Jul 24, 2026
@mergify mergify Bot added the conflict label Jul 24, 2026
Assisted-by: GPT-5.6 via Codex
Assisted-by: GPT-5.6 via Codex
Assisted-by: GPT-5.6 via Codex
@burgholzer
burgholzer force-pushed the agent/1910-qctoqco-structured branch from 9f0ec01 to 80b0e86 Compare July 24, 2026 16:07
@mergify mergify Bot removed the conflict label Jul 24, 2026
@codecov

codecov Bot commented Jul 24, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 99.00000% with 2 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
mlir/lib/Conversion/QCToQCO/QCToQCO.cpp 98.5% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

burgholzer and others added 7 commits July 24, 2026 19:59
Signed-off-by: Lukas Burgholzer <burgholzer@me.com>
Signed-off-by: Lukas Burgholzer <burgholzer@me.com>
Keep the stable SCF for/while state preservation and terminator-order
fixes while deferring classical conditional results to a dedicated QCO
operation change.

Assisted-by: GPT-5.6 via Codex
Assisted-by: GPT-5.6 via Codex
Teach QCO mapping to route only qubit-valued SCF state while preserving classical operands and type-changing while signatures. Add mixed-state for and while mapping regressions.

Assisted-by: GPT-5.6 via Codex
Assisted-by: GPT-5.6 via Codex
@burgholzer
burgholzer marked this pull request as ready for review July 24, 2026 20:12
@burgholzer

Copy link
Copy Markdown
Member Author

@MatthiasReumann @denialhaag for awareness. Follow-up for IfOp is coming.
If you spot any refinements, feel free to follow-up 😌

@burgholzer
burgholzer merged commit 7451496 into main Jul 24, 2026
29 checks passed
@burgholzer
burgholzer deleted the agent/1910-qctoqco-structured branch July 24, 2026 20:28
@denialhaag

Copy link
Copy Markdown
Member
  • Lower affected structured terminators in a second conversion phase so their operands use the final region state instead of depending on dialect-conversion traversal order.

Opus 4.8 brought up a similar point while I was working on #1927. I still have to understand whether there is really no form of a guaranteed conversion order. If that were the case, the QC-to-QCO conversion at large could fall apart at any moment. We heavily rely on the fact that each program is converted from top to bottom. 🤔

@burgholzer

Copy link
Copy Markdown
Member Author
  • Lower affected structured terminators in a second conversion phase so their operands use the final region state instead of depending on dialect-conversion traversal order.

Opus 4.8 brought up a similar point while I was working on #1927. I still have to understand whether there is really no form of a guaranteed conversion order. If that were the case, the QC-to-QCO conversion at large could fall apart at any moment. We heavily rely on the fact that each program is converted from top to bottom. 🤔

Yeah, me too. I was skeptical at first. But the regression tests in this PR did not pass without the changes to the pass, and the changes themselves feel sound.
Feel free to keep the investigation for that on some todo list 👍🏻

burgholzer added a commit that referenced this pull request Jul 25, 2026
🤖 *AI text below* 🤖

## Summary

- Allow `qco.if` and `qco.index_switch` to return ordinary classical SSA
values
  before their existing linear quantum results.
- Preserve result-bearing `scf.if` and `scf.index_switch` operations
through
  QC-to-QCO and QCO-to-QC conversion without introducing scratch memory.
- Update verification, parsing and printing, RegionBranch interfaces,
tied-value helpers, builders, mapping, tensor traversal, module
equivalence,
  and affected optimizations for the segmented result model.
- Keep unsupported Jeff lowering explicit without constraining the
standard
  QC → QCO → QC → QIR pipeline.

## Motivation

This capability was identified while working on the OpenQASM integration
in
#1910 and while reducing the structured-control-flow fixes that became
#1935.
QCO conditionals previously represented only linear quantum results.
Preserving
classical SCF results therefore required either rejecting otherwise
valid
programs or lowering classical state through temporary memory.

The new representation keeps classical values in ordinary SSA form while
retaining QCO's explicit single-use quantum flow:

1. classical result prefix;
2. tied linear quantum result suffix.

Conditional region arguments remain linear-only. Classical inputs
continue to
use normal SSA capture, while `qco.yield` returns the complete
classical-plus-linear result signature.

## Implementation notes

- Both conditional operations use `AttrSizedResultSegments` and expose
explicit
  classical and linear result accessors.
- Custom parsers infer the linear suffix from the `args(...)`
assignments and
  retain quantum-only textual compatibility.
- Parent-aware `qco.yield` verification preserves the stricter modifier
  contracts.
- QC↔QCO conversions retain classical def-use chains directly and
replace only
  linear results with QC references on the QC side.
- Mapping handles every index-switch case and the default region,
preserving
  classical yield operands while realigning only quantum values.
- Module equivalence compares classical yield prefixes positionally
while
  keeping the linear suffix permutation-aware.

## Validation

All affected targets build successfully. The focused suites pass 933
tests in
total:

- 450 QCO IR tests
- 134 QC-to-QCO tests
- 132 QCO-to-QC tests
- 82 QCO utility tests
- 3 QTensor utility tests
- 15 mapping tests
- 117 Jeff round-trip tests

Repository lint, changed-source `clang-tidy`, and `git diff --check`
pass. Two
independent read-only reviews were performed; the final review found no
remaining actionable issues.
@denialhaag

Copy link
Copy Markdown
Member
  • Lower affected structured terminators in a second conversion phase so their operands use the final region state instead of depending on dialect-conversion traversal order.

Opus 4.8 brought up a similar point while I was working on #1927. I still have to understand whether there is really no form of a guaranteed conversion order. If that were the case, the QC-to-QCO conversion at large could fall apart at any moment. We heavily rely on the fact that each program is converted from top to bottom. 🤔

Yeah, me too. I was skeptical at first. But the regression tests in this PR did not pass without the changes to the pass, and the changes themselves feel sound.
Feel free to keep the investigation for that on some todo list 👍🏻

No no, the changes also look good to me, and the MLIR docs also don't suggest that there is a conversion order. At this point, I'm wondering more why the rest of the QC-to-QCO conversion is working as intended. But yeah, I'll investigate a bit more and then report back! 👍

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

Labels

fix Fix for something that isn't working MLIR Anything related to MLIR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants