munich-quantum-toolkit / munich-quantum-toolkit/core
✨ Support register-aware qubit reuse for static QTensor allocations
Nobody has claimed this yet.
- Dominant language
- C++
- Stars
- 133
- Forks
- 73
- Avg merge
- 17h 34m
- Merged PRs (30d)
- 261
Description
🤖 AI text below 🤖
Context
#1923 adds qubit reuse for individually allocated qco.alloc values. Qubits declared in statically sized registers instead lower through qtensor.alloc, qtensor.extract, qtensor.insert, and qtensor.dealloc, so the reuse pass currently leaves them untouched.
The closed #1125 proposed eliminating registers in the value-semantics dialect. This follow-up deliberately keeps the opposite boundary: retain the logical register in QCO IR and avoid globally scalarizing it merely to make reuse analysis easier.
Goal
Support qubit reuse for the common statically sized register case by:
- reasoning about individual constant-index lanes of a QTensor;
- reusing lanes whose quantum dataflow lifetimes do not overlap;
- resetting reused lanes before their next logical lifetime;
- reducing the amount of newly allocated register storage accordingly; and
- preserving the logical
tensor<Nx!qco.qubit>representation through the QCO optimization stage.
For a target register of width N with K reusable lanes, the intended resource effect is to allocate only the N - K fresh lanes while retaining an N-lane logical register for subsequent computation.
Required analysis
Generic forward-slice analysis is too coarse because every lane participates in the same tensor SSA chain. A register-aware analysis should build on qtensor::TensorIterator and track, for every statically known lane:
- the matching constant-index extract/insert operations;
- whether the lane is currently resident in or extracted from the tensor;
- the scalar QCO wire between extraction and reinsertion;
- interactions with other scalar wires that prevent reuse; and
- the lane's allocation and final-use boundaries.
Different constant indices may commute through the tensor chain. A same-index insert, a dynamic index, ambiguous occupancy, or an unsupported region/CFG transition must invalidate the relevant proof rather than guessing.
Candidate implementation strategies
1. Equal-width whole-register reuse
Use this as the smallest first milestone. When every lane of a fully populated static register is dead before another equal-width register starts:
- consume the old tensor instead of deallocating it;
- extract, reset, and reinsert each lane;
- replace the later
qtensor.allocresult with the reset tensor; and - erase the redundant allocation/deallocation pair.
This can be expressed with the existing QTensor and QCO operations. It preserves the register abstraction and reduces two width-N allocation roots to one.
2. Static lane compaction
For partial reuse, compute a mapping from each logical target lane to either a reusable source lane or fresh storage. Allocate only the fresh portion, reset the reusable lanes, and reconstruct the full logical target register.
The existing qtensor.from_elements operation may be useful for reconstruction, but it is not currently supported by QCO-to-QC, QCO-to-Jeff, or the Mapping pass. An implementation choosing this route must add the required downstream handling and demonstrate that ownership and resource accounting remain correct.
This is the preferred general direction if it can be implemented without prematurely scalarizing the register's computation.
3. Mapping-time lifetime coloring
Alternatively, keep the QTensor structure unchanged and let Mapping assign the same physical qubit to non-overlapping logical lane lifetimes, inserting resets at lifetime boundaries.
This preserves the high-level IR longest and may avoid tensor reconstruction, but it couples reuse to placement and does not by itself reduce allocation roots in standalone optimized QCO. It should therefore be chosen only if structural compaction is substantially more invasive.
Suggested staging
- Introduce and test reusable static lane/occupancy analysis.
- Implement equal-static-width whole-register reuse.
- Extend Mapping to understand successive logical lifetimes on reused register lanes.
- Add partial static lane compaction and any required
qtensor.from_elementsconsumer support. - Consider dynamic indices and tensor-carried structured control flow separately.
Acceptance criteria
- A QCO program with two noninteracting static register lifetimes requires fewer allocated qubits after reuse.
- The whole-register case reduces two width-
Nallocation roots to one and preserves anN-lane QTensor for both logical lifetimes. - Partial static reuse reduces the total newly allocated width by exactly the number of safely reusable lanes.
- Reused lanes are reset before their next lifetime; provably untouched allocation-zero lanes may canonicalize redundant resets away.
- Interacting lanes, ambiguous aliases, partially populated tensors, dynamic indices, unsupported CFG shapes, and tensor-carried control flow are conservatively left unchanged in the initial implementation.
- The resulting IR verifies and remains supported by QCO-to-QC, QCO-to-Jeff, Mapping, canonicalization, and register shrinking.
- Tests cover whole-register reuse, partial reuse, non-reusable interactions, dynamic-index no-op behavior, incomplete occupancy, control-flow rejection, conversion, mapping, and OpenQASM input with
qubit[N]declarations. - Pass documentation states the supported register shapes and conservative fallbacks.
Non-goals for the initial implementation
- introducing a dedicated
qtensor.reuseoperation; - dynamic register extents or arbitrary dynamic lane aliases;
- optimal/global lifetime coloring;
- CFG-aware motion across basic blocks; or
- tensor-carried structured control flow.
Relevant implementation areas
mlir/lib/Dialect/QCO/Transforms/Optimizations/ReuseQubits.cppmlir/lib/Dialect/QTensor/Utils/TensorIterator.cppmlir/lib/Dialect/QTensor/Transforms/ShrinkRegisters.cppmlir/lib/Dialect/QCO/IR/Operations/ResetOp.cppmlir/lib/Dialect/QCO/Transforms/Mapping/Mapping.cpp- QCO-to-QC and QCO-to-Jeff conversions
- QCO optimization, QTensor, conversion, Mapping, and compiler-pipeline tests
This issue should be picked up after #1923 is merged so the scalar-allocation reuse behavior and its tests form the baseline.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with mlir/lib/Dialect/QCO/Transforms/Optimizations/ReuseQubits.cpp and mlir/lib/Dialect/QTensor/Utils/TensorIterator.cpp, using #1923 and its tests as the baseline. Review the related ShrinkRegisters, ResetOp, Mapping, conversion, and compiler-pipeline areas before running the existing QCO optimization tests. Done means conservative static-lane analysis and reuse preserve the logical QTensor, reset reusable lanes, reduce allocation roots or fresh width, and pass the listed conversion and mapping coverage.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- compilers
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100