Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
3e9099e
✨ Update QCO operations to reflect memory effects and enhance dealloc…
simon1hofmann Mar 17, 2026
6c77dbb
✨ Add `staticQubitWithOp` function to allocate a static qubit and app…
simon1hofmann Mar 17, 2026
646cf3e
✅ Add test cases for `staticQubitWithOp` across various dialects (QC,…
simon1hofmann Mar 17, 2026
ea7b675
🔧 Add missing include for LLVM casting support in QCOToQC.cpp
simon1hofmann Mar 17, 2026
b824284
✨ Rename `staticQubitWithOp` to `staticQubitsWithOps` and update rela…
simon1hofmann Mar 17, 2026
c2d414f
🔧 Enhance `ConvertFuncReturnOp` to exclude escaped qubits from the li…
simon1hofmann Mar 17, 2026
0b81e9c
✨ Enhance QubitType to support static and dynamic qubits, updating re…
simon1hofmann Mar 19, 2026
0221058
✨ Update QubitType handling in QCO and QC dialects to support static …
simon1hofmann Mar 19, 2026
a5ffdef
🔧 Refactor QCO and QC dialects: remove unnecessary includes, simplify…
simon1hofmann Mar 19, 2026
6af63db
✨ Introduce StaticQubit type in QC and QCO dialects, enhance StaticOp…
simon1hofmann Mar 19, 2026
08410f6
🔧 Update QCO and QC dialects: add missing LLVM casting includes, enha…
simon1hofmann Mar 19, 2026
893a746
Merge branch 'main' into static_qubit_handling
simon1hofmann Mar 19, 2026
ec4f2fa
🔧 Update StaticOp to output StaticQubit type and remove unnecessary v…
simon1hofmann Mar 19, 2026
6ff64e4
🔧 Refactor QubitType definitions in QC dialect: reintroduce DynamicQu…
simon1hofmann Mar 19, 2026
e0689dc
🔧 Add DynamicQubit and StaticQubit type definitions in QCO dialect, u…
simon1hofmann Mar 19, 2026
c624c3d
🔧 Update AllocOp to return DynamicQubit type, refactor ConvertFuncRet…
simon1hofmann Mar 19, 2026
8499977
🔧 Enhance QCO operations with type verification: add input-output typ…
simon1hofmann Mar 19, 2026
a16da14
Apply suggestions from code review
simon1hofmann Mar 20, 2026
adb5192
🔧 Refactor QCO operations to improve static qubit handling: update St…
simon1hofmann Mar 20, 2026
34a6ffe
Merge branch 'main' into static_qubit_handling
simon1hofmann Mar 20, 2026
ea8b155
🎨 pre-commit fixes
pre-commit-ci[bot] Mar 20, 2026
95970d6
🔧 Implement synchronizeMappedQubitTypes function to align qubit resul…
simon1hofmann Mar 20, 2026
0ed81fa
🔧 Update conversion patterns in QCO, QC, and QIR dialects to ensure c…
simon1hofmann Mar 20, 2026
c9d1b8f
🔧 Add missing includes in QCOToQC and Mapping.
simon1hofmann Mar 20, 2026
acdc0cb
🔧 Refactor qubit mapping in QCToQCO conversion patterns to use per-re…
simon1hofmann Mar 20, 2026
c3e1b2a
🐧 Fix compile error on Linux due to missing link library
burgholzer Mar 20, 2026
3dcb30a
✏️ Rename SSABeforeForDeallocOrder to SSAOrder and tweak docstring
burgholzer Mar 20, 2026
417857a
🎨 Replace two-qubit gate programs with gate that is less likely to be…
burgholzer Mar 20, 2026
4c8c0f9
🚨 Fix use of outdated rewrite method
burgholzer Mar 20, 2026
d6ad7c4
🎨 Refine static qubit handling to require less casting
burgholzer Mar 20, 2026
9c807b7
🩹 Mark result of `qc.alloc` as dynamic qubit
burgholzer Mar 20, 2026
ef2bdaa
🎨 one cast less
burgholzer Mar 20, 2026
bf3b82e
🎨 Incremental code quality improvements to the QCToQCO conversion
burgholzer Mar 20, 2026
57e150a
♻️ Streamline QCToQCO conversion by introducing helper functions
burgholzer Mar 20, 2026
2b6f808
🚨 Fix clang-tidy warnings
burgholzer Mar 20, 2026
20a7e6a
🐛 Fix the logic in `synchronizeMappedQubitTypes` and add dedicated tests
burgholzer Mar 21, 2026
3166aa0
✨ Update mapping pass to use `IRRewriter`.
simon1hofmann Mar 23, 2026
01e9861
✨ clang-tidy and coderabbit comments.
simon1hofmann Mar 23, 2026
bc04365
Merge branch 'main' into static_qubit_handling
simon1hofmann Mar 31, 2026
a202cd7
🎨 pre-commit fixes
pre-commit-ci[bot] Mar 31, 2026
4fdd34f
🔀 Resolve changes after merge
simon1hofmann Mar 31, 2026
5b52511
🔄 Rename `dealloc` to `sink` in QCO dialect for qubit management
simon1hofmann Mar 31, 2026
6fe5d43
🔧 Refactor QubitType handling in QC and QCO dialects
simon1hofmann Mar 31, 2026
22791f4
🔧 Refactor QCO operations to simplify type handling and remove redund…
simon1hofmann Mar 31, 2026
ead5c13
🔧 Move `QubitMode` enum and `inferQubitMode` function to a more appro…
simon1hofmann Mar 31, 2026
45800cc
🐇 Address rabbit's comments
simon1hofmann Mar 31, 2026
0ceb41d
🔧 Mark `inferQubitMode` as static to limit its linkage scope
simon1hofmann Mar 31, 2026
8c100e7
📝 Enhance documentation for `ConvertQCOSinkOp` to clarify transformat…
simon1hofmann Mar 31, 2026
888c53e
⏪ Revert adding cast
burgholzer Apr 1, 2026
d8dfec5
🎨 Simplify QCO to QC conversion by avoiding walking the entire program
burgholzer Apr 1, 2026
50c79fa
🚸 Add convenience functions for getting control and target ranges thr…
burgholzer Apr 1, 2026
7988993
♻️ Simplify QC to QCO conversion and drop sorting
burgholzer Apr 1, 2026
cd18772
🔥 Drop the programs for mixing dynamic and static qubits
burgholzer Apr 1, 2026
810322b
🎨 streamline QCO program builder
burgholzer Apr 1, 2026
da8c30e
⏪ Revert changes based on different type assumption
burgholzer Apr 1, 2026
4e92611
✏️ Adjust docstring
burgholzer Apr 1, 2026
b7be1cb
⏪ Cleanup PR diff
burgholzer Apr 1, 2026
fa20138
🚨 cleanup
burgholzer Apr 1, 2026
701e5e8
🚸 Add convenience functions for getting parameter ranges through the …
burgholzer Apr 1, 2026
ac68ee4
♻️ Adjust semantics of QC `InvOp`
burgholzer Apr 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ This project adheres to [Semantic Versioning], with the exception that minor rel
- ✨ Add conversions between Jeff and QCO ([#1479], [#1548], [#1565]) ([**@denialhaag**])
- ✨ Add a `place-and-route` pass for mapping circuits to architectures with restricted topologies ([#1537], [#1547], [#1568], [#1581], [#1583], [#1588]) ([**@MatthiasReumann**])
- ✨ Add initial infrastructure for new QC and QCO MLIR dialects
([#1264], [#1330], [#1402], [#1428], [#1430], [#1436], [#1443], [#1446], [#1464], [#1465], [#1470], [#1471], [#1472], [#1474], [#1475], [#1506], [#1510], [#1513], [#1521], [#1542], [#1548], [#1550], [#1554], [#1570], [#1572], [#1573])
([#1264], [#1330], [#1402], [#1428], [#1430], [#1436], [#1443], [#1446], [#1464], [#1465], [#1470], [#1471], [#1472], [#1474], [#1475], [#1506], [#1510], [#1513], [#1521], [#1542], [#1548], [#1550], [#1554], [#1569], [#1570], [#1572], [#1573])
Comment thread
simon1hofmann marked this conversation as resolved.
([**@burgholzer**], [**@denialhaag**], [**@taminob**], [**@DRovara**], [**@li-mingbao**], [**@Ectras**], [**@MatthiasReumann**], [**@simon1hofmann**])

### Changed
Expand Down Expand Up @@ -344,6 +344,7 @@ _📚 Refer to the [GitHub Release Notes](https://github.com/munich-quantum-tool
[#1572]: https://github.com/munich-quantum-toolkit/core/pull/1572
[#1571]: https://github.com/munich-quantum-toolkit/core/pull/1571
[#1570]: https://github.com/munich-quantum-toolkit/core/pull/1570
[#1569]: https://github.com/munich-quantum-toolkit/core/pull/1569
[#1568]: https://github.com/munich-quantum-toolkit/core/pull/1568
[#1565]: https://github.com/munich-quantum-toolkit/core/pull/1565
[#1564]: https://github.com/munich-quantum-toolkit/core/pull/1564
Expand Down
4 changes: 2 additions & 2 deletions mlir/include/mlir/Dialect/QC/Builder/QCProgramBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ class QCProgramBuilder final : public ImplicitLocOpBuilder {

/**
* @brief Get a static qubit by index
* @param index The qubit index (must be non-negative)
* @param index The qubit index
* @return A qubit reference
*
* @par Example:
Expand All @@ -121,7 +121,7 @@ class QCProgramBuilder final : public ImplicitLocOpBuilder {
* %q0 = qc.static 0 : !qc.qubit
* ```
*/
Value staticQubit(int64_t index);
Value staticQubit(uint64_t index);

/**
* @brief Allocate a qubit register
Expand Down
8 changes: 8 additions & 0 deletions mlir/include/mlir/Dialect/QC/IR/QCDialect.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ template <size_t T, size_t P> class TargetAndParameterArityTrait {
static size_t getNumQubits() { return T; }
static size_t getNumTargets() { return T; }
static size_t getNumControls() { return 0; }
static ValueRange getControls() { return {}; }

Value getQubit(size_t i) {
if constexpr (T == 0) {
Expand All @@ -71,6 +72,9 @@ template <size_t T, size_t P> class TargetAndParameterArityTrait {
}
return this->getOperation()->getOperand(i);
}
ValueRange getTargets() {
return this->getOperation()->getOperands().slice(0, T);
}

static Value getControl([[maybe_unused]] size_t i) {
llvm::reportFatalUsageError("Operation does not have controls");
Expand All @@ -84,6 +88,10 @@ template <size_t T, size_t P> class TargetAndParameterArityTrait {
}
return this->getOperation()->getOperand(T + i);
}

ValueRange getParameters() {
return this->getOperation()->getOperands().slice(T, P);
}
};
};

Expand Down
6 changes: 6 additions & 0 deletions mlir/include/mlir/Dialect/QC/IR/QCInterfaces.td
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,18 @@ def UnitaryOpInterface : OpInterface<"UnitaryOpInterface"> {
(ins "size_t":$i)>,
InterfaceMethod<"Returns the i-th control qubit.", "Value", "getControl",
(ins "size_t":$i)>,
InterfaceMethod<"Returns a range of all target qubits.", "ValueRange",
"getTargets", (ins)>,
InterfaceMethod<"Returns a range of all control qubits.", "ValueRange",
"getControls", (ins)>,

// Parameter handling
InterfaceMethod<"Returns the number of parameters.", "size_t",
"getNumParams", (ins)>,
InterfaceMethod<"Returns the i-th parameter.", "Value", "getParameter",
(ins "size_t":$i)>,
InterfaceMethod<"Returns a range of all parameters.", "ValueRange",
"getParameters", (ins)>,

// Convenience methods
InterfaceMethod<"Returns true if the operation has any control qubits, "
Expand Down
20 changes: 16 additions & 4 deletions mlir/include/mlir/Dialect/QC/IR/QCOps.td
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,10 @@ def StaticOp : QCOp<"static", [Pure]> {
let arguments = (ins ConfinedAttr<I64Attr, [IntNonNegative]>:$index);
let results = (outs QubitType:$qubit);
let assemblyFormat = "$index attr-dict `:` type($qubit)";

let builders = [OpBuilder<(ins "uint64_t":$index), [{
build($_builder, $_state, QubitType::get($_builder.getContext()), index);
}]>];
}

//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -910,11 +914,14 @@ def BarrierOp : QCOp<"barrier", traits = [UnitaryOpInterface]> {
size_t getNumQubits() { return getNumTargets(); }
size_t getNumTargets() { return getQubits().size(); }
static size_t getNumControls() { return 0; }
static ValueRange getControls() { return {}; }
Value getQubit(size_t i) { return getTarget(i); }
Value getTarget(size_t i);
ValueRange getTargets() { return getQubits(); }
static Value getControl(size_t i) { llvm::reportFatalUsageError("BarrierOp cannot be controlled"); }
static size_t getNumParams() { return 0; }
static Value getParameter(size_t i) { llvm::reportFatalUsageError("BarrierOp does not have parameters"); }
static ValueRange getParameters() { return {}; }
static StringRef getBaseSymbol() { return "barrier"; }
}];
}
Expand Down Expand Up @@ -969,9 +976,11 @@ def CtrlOp
size_t getNumControls() { return getControls().size(); }
Value getQubit(size_t i);
Value getTarget(size_t i) { return getBodyUnitary().getTarget(i); }
ValueRange getTargets() { return getBodyUnitary().getTargets(); }
Value getControl(size_t i);
size_t getNumParams() { return getBodyUnitary().getNumParams(); }
Value getParameter(size_t i) { return getBodyUnitary().getParameter(i); }
ValueRange getParameters() { return getBodyUnitary().getParameters(); }
static StringRef getBaseSymbol() { return "ctrl"; }
}];

Expand Down Expand Up @@ -1005,13 +1014,16 @@ def InvOp : QCOp<"inv",
let extraClassDeclaration = [{
[[nodiscard]] UnitaryOpInterface getBodyUnitary();
size_t getNumQubits() { return getBodyUnitary().getNumQubits(); }
size_t getNumTargets() { return getNumQubits(); }
static size_t getNumControls() { return 0; }
size_t getNumTargets() { return getBodyUnitary().getNumTargets(); }
size_t getNumControls() { return getBodyUnitary().getNumControls(); }
Value getQubit(size_t i) { return getBodyUnitary().getQubit(i); }
Value getTarget(size_t i) { return getQubit(i); }
static Value getControl(size_t i) { llvm::reportFatalUsageError("Operation does not have controls"); }
Value getTarget(size_t i) { return getBodyUnitary().getTarget(i); }
ValueRange getTargets() { return getBodyUnitary().getTargets(); }
Value getControl(size_t i) { return getBodyUnitary().getControl(i); }
ValueRange getControls() { return getBodyUnitary().getControls(); }
size_t getNumParams() { return getBodyUnitary().getNumParams(); }
Value getParameter(size_t i) { return getBodyUnitary().getParameter(i); }
ValueRange getParameters() { return getBodyUnitary().getParameters(); }
static StringRef getBaseSymbol() { return "inv"; }
}];

Expand Down
16 changes: 8 additions & 8 deletions mlir/include/mlir/Dialect/QCO/Builder/QCOProgramBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ class QCOProgramBuilder final : public ImplicitLocOpBuilder {

/**
* @brief Get a static qubit by index
* @param index The qubit index (must be non-negative)
* @param index The qubit index
* @return A tracked, valid qubit SSA value
*
* @par Example:
Expand All @@ -129,7 +129,7 @@ class QCOProgramBuilder final : public ImplicitLocOpBuilder {
* %q0 = qco.static 0 : !qco.qubit
* ```
*/
Value staticQubit(int64_t index);
Value staticQubit(uint64_t index);

/**
* @brief Allocate a qubit register
Expand Down Expand Up @@ -1228,24 +1228,24 @@ class QCOProgramBuilder final : public ImplicitLocOpBuilder {
//===--------------------------------------------------------------------===//

/**
* @brief Explicitly deallocate a qubit
* @brief Consume a qubit value (end of lifetime)
*
* @details
* Validates and removes the qubit from tracking. Optional; `finalize()`
* automatically deallocates all remaining qubits.
* automatically sinks all remaining qubits.
*
* @param qubit Qubit to deallocate (must be valid/unconsumed)
* @param qubit Qubit to sink (must be valid/unconsumed)
* @return Reference to this builder for method chaining
*
* @par Example:
* ```c++
* builder.dealloc(q);
* builder.sink(q);
* ```
* ```mlir
* qco.dealloc %q : !qco.qubit
* qco.sink %q : !qco.qubit
* ```
*/
QCOProgramBuilder& dealloc(Value qubit);
QCOProgramBuilder& sink(Value qubit);

//===--------------------------------------------------------------------===//
// SCF operations
Expand Down
14 changes: 10 additions & 4 deletions mlir/include/mlir/Dialect/QCO/IR/QCOOps.td
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,20 @@ def AllocOp : QCOOp<"alloc", [MemoryEffects<[MemAlloc]>]> {
let hasVerifier = 1;
}

def DeallocOp : QCOOp<"dealloc", [MemoryEffects<[MemFree]>]> {
let summary = "Deallocate a qubit";
def SinkOp : QCOOp<"sink", [MemoryEffects<[MemFree]>]> {
let summary = "Consume a qubit value (end of lifetime)";
let description = [{
Deallocates a qubit, releasing its resources.
Consumes a qubit SSA value and marks the end of its lifetime.

This operation is the canonical "sink" for QCO's linear/value semantics:
every qubit value must be consumed exactly once on all paths.

When converting back to QC (reference semantics), sinks corresponding to
static qubits may be erased.

Example:
```mlir
qco.dealloc %q : !qco.qubit
qco.sink %q : !qco.qubit
```
}];

Expand Down
4 changes: 2 additions & 2 deletions mlir/include/mlir/Dialect/QCO/Utils/Drivers.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,8 @@ template <typename Fn> void walkUnit(Region& region, Fn&& fn) {
.template Case<MeasureOp>([&](MeasureOp op) {
qubits.remap(op.getQubitIn(), op.getQubitOut());
})
.template Case<DeallocOp>(
[&](DeallocOp op) { qubits.remove(op.getQubit()); });
.template Case<SinkOp>(
[&](SinkOp op) { qubits.remove(op.getQubit()); });
}
}
} // namespace mlir::qco
18 changes: 9 additions & 9 deletions mlir/lib/Conversion/JeffToQCO/JeffToQCO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,7 @@ struct ConvertJeffQubitAllocOpToQCO final
};

/**
* @brief Converts jeff.qubit_free to qco.reset + qco.dealloc
* @brief Converts jeff.qubit_free to qco.reset + qco.sink
*
* @par Example:
* ```mlir
Expand All @@ -415,7 +415,7 @@ struct ConvertJeffQubitAllocOpToQCO final
* is converted to
* ```mlir
* %q_out = qco.reset %q_in : !qco.qubit
* qco.dealloc %q_out : !qco.qubit
* qco.sink %q_out : !qco.qubit
* ```
*/
struct ConvertJeffQubitFreeOpToQCO final
Expand All @@ -427,21 +427,21 @@ struct ConvertJeffQubitFreeOpToQCO final
ConversionPatternRewriter& rewriter) const override {
auto resetOp =
qco::ResetOp::create(rewriter, op.getLoc(), adaptor.getInQubit());
rewriter.replaceOpWithNewOp<qco::DeallocOp>(op, resetOp.getQubitOut());
rewriter.replaceOpWithNewOp<qco::SinkOp>(op, resetOp.getQubitOut());
return success();
}
};

/**
* @brief Converts jeff.qubit_free_zero to qco.dealloc
* @brief Converts jeff.qubit_free_zero to qco.sink
*
* @par Example:
* ```mlir
* jeff.qubit_free_zero %q : !jeff.qubit
* ```
* is converted to
* ```mlir
* qco.dealloc %q : !qco.qubit
* qco.sink %q : !qco.qubit
* ```
*/
struct ConvertJeffQubitFreeZeroOpToQCO final
Expand All @@ -451,13 +451,13 @@ struct ConvertJeffQubitFreeZeroOpToQCO final
LogicalResult
matchAndRewrite(jeff::QubitFreeZeroOp op, OpAdaptor adaptor,
ConversionPatternRewriter& rewriter) const override {
rewriter.replaceOpWithNewOp<qco::DeallocOp>(op, adaptor.getInQubit());
rewriter.replaceOpWithNewOp<qco::SinkOp>(op, adaptor.getInQubit());
return success();
}
};

/**
* @brief Converts jeff.qubit_measure to qco.measure + qco.dealloc
* @brief Converts jeff.qubit_measure to qco.measure + qco.sink
*
* @par Example:
* ```mlir
Expand All @@ -466,7 +466,7 @@ struct ConvertJeffQubitFreeZeroOpToQCO final
* is converted to
* ```mlir
* %q_out, %result = qco.measure %q_in : !qco.qubit
* qco.dealloc %q_out : !qco.qubit
* qco.sink %q_out : !qco.qubit
* ```
*/
struct ConvertJeffQubitMeasureOpToQCO final
Expand All @@ -479,7 +479,7 @@ struct ConvertJeffQubitMeasureOpToQCO final
auto loc = op.getLoc();
auto measureOp =
qco::MeasureOp::create(rewriter, loc, adaptor.getInQubit());
qco::DeallocOp::create(rewriter, loc, measureOp.getQubitOut());
qco::SinkOp::create(rewriter, loc, measureOp.getQubitOut());
rewriter.replaceOp(op, measureOp.getResult());
return success();
}
Expand Down
11 changes: 5 additions & 6 deletions mlir/lib/Conversion/QCOToJeff/QCOToJeff.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -269,23 +269,22 @@ struct ConvertQCOAllocOpToJeff final
};

/**
* @brief Converts qco.dealloc to jeff.qubit_free_zero
* @brief Converts qco.sink to jeff.qubit_free_zero
*
* @par Example:
* ```mlir
* qco.dealloc %q : !qco.qubit
* qco.sink %q : !qco.qubit
* ```
* is converted to
* ```mlir
* jeff.qubit_free_zero %q : !jeff.qubit
* ```
*/
struct ConvertQCODeallocOpToJeff final
: StatefulOpConversionPattern<qco::DeallocOp> {
struct ConvertQCOSinkOpToJeff final : StatefulOpConversionPattern<qco::SinkOp> {
using StatefulOpConversionPattern::StatefulOpConversionPattern;

LogicalResult
matchAndRewrite(qco::DeallocOp op, OpAdaptor adaptor,
matchAndRewrite(qco::SinkOp op, OpAdaptor adaptor,
ConversionPatternRewriter& rewriter) const override {
rewriter.replaceOpWithNewOp<jeff::QubitFreeZeroOp>(op, adaptor.getQubit());
return success();
Expand Down Expand Up @@ -1364,7 +1363,7 @@ struct QCOToJeff final : impl::QCOToJeffBase<QCOToJeff> {
// Register operation conversion patterns
jeff::populateNativeToJeffConversionPatterns(patterns);
patterns.add<
ConvertQCOAllocOpToJeff, ConvertQCODeallocOpToJeff,
ConvertQCOAllocOpToJeff, ConvertQCOSinkOpToJeff,
ConvertQCOMeasureOpToJeff, ConvertQCOResetOpToJeff,
ConvertQCOGPhaseOpToJeff,
ConvertQCOOneTargetZeroParameterToJeff<qco::IdOp, jeff::IOp, false>,
Expand Down
Loading
Loading