Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
3df8777
Replace behavior of allocQubitRegister() methods
denialhaag Mar 19, 2026
d318cba
Update conversion from QC to QIR
denialhaag Mar 20, 2026
98f4055
Update conversion between QCO and Jeff
denialhaag Mar 23, 2026
6458e73
Fix QC IR tests
denialhaag Mar 23, 2026
685551b
Fix QCO IR tests
denialhaag Mar 23, 2026
3e8d254
Fix QC-to-QIR tests
denialhaag Mar 23, 2026
5253e14
Fix linter errors
denialhaag Mar 27, 2026
4b02d3f
Fix some more tests
denialhaag Mar 27, 2026
47f84a8
Exclude Jeff tests from discovery for now
denialhaag Mar 30, 2026
5eb6778
Support static qubits in QIR again
denialhaag Mar 30, 2026
8f80b98
Load results once
denialhaag Mar 30, 2026
9887b3f
Fix sorting of qtensor.insert statements
denialhaag Mar 30, 2026
12d9443
Fix linter errors
denialhaag Mar 30, 2026
4622c95
Resolve some TODOs
denialhaag Mar 30, 2026
56f5771
Improve documentation
denialhaag Mar 30, 2026
f8619ed
Address the Rabbit's comments
denialhaag Mar 30, 2026
f52206b
Fix linter errors
denialhaag Mar 30, 2026
068de19
Address the Rabbit's comments
denialhaag Mar 30, 2026
d1fd730
Fix linter error
denialhaag Mar 31, 2026
a86274e
Address the Rabbit's comments
denialhaag Mar 31, 2026
b1eb566
Merge remote-tracking branch 'origin/main' into registers
denialhaag Mar 31, 2026
58abb28
Address the Rabbit's comments
denialhaag Mar 31, 2026
ad7f265
Initialize at top of entry block
denialhaag Mar 31, 2026
3e7bbf0
Address the Rabbit's comments
denialhaag Apr 1, 2026
ffd6426
Fix linter errors
denialhaag Apr 1, 2026
af9fa1f
Merge remote-tracking branch 'origin/main' into registers
denialhaag Apr 1, 2026
f0b1b4d
Make everything work again
denialhaag Apr 1, 2026
9f2dc2a
Save one materialization
denialhaag Apr 1, 2026
6e047dd
Make tensor map region-based as well
denialhaag Apr 1, 2026
7038926
Address the Rabbit's comments
denialhaag Apr 1, 2026
5660b64
Fix linter errors
denialhaag Apr 1, 2026
f81c35a
Address the Rabbit's comments
denialhaag Apr 1, 2026
112c478
Merge branch 'main' into registers
burgholzer Apr 1, 2026
2623d9b
📝 Add changelog entry
burgholzer Apr 1, 2026
3574819
🎨 Small tweaks to the QC program builder
burgholzer Apr 2, 2026
1fc2430
♻️ Add back fold for `qtensor.insert` and enhance capabilities of the…
burgholzer Apr 2, 2026
a4aa18a
🚸 Generalize IRVerification to handle commuting chains of `qtensor.in…
burgholzer Apr 2, 2026
f10935e
🎨 Small tweaks to the QCO program builder
burgholzer Apr 2, 2026
00b1c83
♻️ Add canonicalization for interleaved extract-insert operations
burgholzer Apr 3, 2026
dbbf154
♻️ Turn `qco.reset` canonicalization into fold and handle tensor oper…
burgholzer Apr 3, 2026
badf76f
♻️ Turn zero-angle rotation gate canonicalizations into folds
burgholzer Apr 3, 2026
f2ac639
♻️ Expand QTensor commutation canonicalizations to also handle slices
burgholzer Apr 3, 2026
a2ab458
♻️ Extract common code from QTensor handling
burgholzer Apr 3, 2026
3d800b9
⏪ Revert changes to programs
burgholzer Apr 3, 2026
4a666b8
✨ Add QC pass for shrinking registers to fit accessed indices
burgholzer Apr 3, 2026
3a94b90
✨ Add QCO pass for shrinking qtensors to fit accessed indices
burgholzer Apr 3, 2026
1aeaf7a
✨ Add QIR pass for simplifying qubit-array allocation/release pairs
burgholzer Apr 3, 2026
45b74aa
🎨 Miscellaneous small fixes
burgholzer Apr 3, 2026
c709efb
♻️ Adjust compiler pipeline and tests to use new passes
burgholzer Apr 3, 2026
28d6c31
⚡ Reduce redundant lookups in QCToQCO.cpp
burgholzer Apr 5, 2026
87cebaa
♻️ Streamline the QC to QCO conversion
burgholzer Apr 5, 2026
9afcb0f
Merge branch 'refs/heads/main' into registers
burgholzer Apr 6, 2026
f0849fe
🔥 Remove `qtensor.insert_slice` and `qtensor.extract_slice` operations
burgholzer Apr 6, 2026
7be6f12
✅ Add dedicated test suite for the QTensor dialect
burgholzer Apr 6, 2026
b5cfbbc
♻️ Do not default to dynamic shape for QTensor conversion from QCO to QC
burgholzer Apr 6, 2026
dcea944
🎨 Newline cosmetic
burgholzer Apr 6, 2026
7409023
Fix linter errors
denialhaag Apr 6, 2026
c808bf1
Address some of the Rabbit's comments
denialhaag Apr 6, 2026
b5cebd3
Address the Rabbit's comments
denialhaag Apr 7, 2026
2e50202
Fix linter errors
denialhaag Apr 7, 2026
fdced7d
Raise error if qc.dealloc is called manually
denialhaag Apr 7, 2026
82510ba
Make areEquivalentIndices() more strict
denialhaag Apr 7, 2026
18c7747
Return result of cleanup pipelines
denialhaag Apr 7, 2026
5f719f9
Address the Rabbit's comments
denialhaag Apr 7, 2026
b149a67
Make index checks even more strict
denialhaag Apr 7, 2026
8f18b6d
Add test
denialhaag Apr 7, 2026
e982b15
Address the Rabbit's comments
denialhaag Apr 7, 2026
88def0f
Fix linter errors
denialhaag Apr 7, 2026
51f719f
Address the Rabbit's final comment
denialhaag Apr 7, 2026
bf520ed
Address the Rabbit's final comment
denialhaag Apr 7, 2026
543a27b
Streamline QTensor tests
denialhaag Apr 7, 2026
c16ce6e
Remove redundant folds
denialhaag Apr 7, 2026
90978a0
Remove redundant canonicalization pattern
denialhaag Apr 7, 2026
928a590
Fix linter errors
denialhaag Apr 7, 2026
f587454
Put back InsertOp::fold()
denialhaag Apr 7, 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], [#1567], [#1569], [#1570], [#1572], [#1573], [#1602])
([#1264], [#1330], [#1402], [#1428], [#1430], [#1436], [#1443], [#1446], [#1464], [#1465], [#1470], [#1471], [#1472], [#1474], [#1475], [#1506], [#1510], [#1513], [#1521], [#1542], [#1548], [#1550], [#1554], [#1567], [#1569], [#1570], [#1572], [#1573], [#1580], [#1602])
([**@burgholzer**], [**@denialhaag**], [**@taminob**], [**@DRovara**], [**@li-mingbao**], [**@Ectras**], [**@MatthiasReumann**], [**@simon1hofmann**])

### Changed
Expand Down Expand Up @@ -341,6 +341,7 @@ _📚 Refer to the [GitHub Release Notes](https://github.com/munich-quantum-tool
[#1588]: https://github.com/munich-quantum-toolkit/core/pull/1588
[#1583]: https://github.com/munich-quantum-toolkit/core/pull/1583
[#1581]: https://github.com/munich-quantum-toolkit/core/pull/1581
[#1580]: https://github.com/munich-quantum-toolkit/core/pull/1580
[#1573]: https://github.com/munich-quantum-toolkit/core/pull/1573
[#1572]: https://github.com/munich-quantum-toolkit/core/pull/1572
[#1571]: https://github.com/munich-quantum-toolkit/core/pull/1571
Expand Down
23 changes: 7 additions & 16 deletions mlir/include/mlir/Compiler/CompilerPipeline.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,18 +72,18 @@ struct CompilationRecord {
*
* 1. QC dialect (reference semantics) - imported from
* qc::QuantumComputation
* 2. Canonicalization + cleanup
* 2. QC cleanup pipeline
* 3. QCO dialect (value semantics) - enables SSA-based optimizations
* 4. Canonicalization + cleanup
* 4. QCO cleanup pipeline
* 5. Quantum optimization passes
* 6. Canonicalization + cleanup
* 6. QCO cleanup pipeline
* 7. QC dialect - converted back for backend lowering
* 8. Canonicalization + cleanup
* 8. QC cleanup pipeline
* 9. QIR (Quantum Intermediate Representation) - optional final lowering
* 10. Canonicalization + cleanup
* 10. QIR cleanup pipeline
*
* Following MLIR best practices, canonicalization and dead value removal
* are always run after each major transformation stage.
* Following MLIR best practices, simplification and dead-value cleanup are
* run after each major transformation stage.
*/
class QuantumCompilerPipeline {
public:
Expand Down Expand Up @@ -111,15 +111,6 @@ class QuantumCompilerPipeline {
CompilationRecord* record = nullptr) const;

private:
/**
* @brief Add canonicalization and cleanup passes
*
* @details
* Always adds the standard MLIR canonicalization pass followed by common
* sub-expression elimination and dead value removal.
*/
static void addCleanupPasses(PassManager& pm);

/**
* @brief Configure PassManager with diagnostic options
*
Expand Down
3 changes: 2 additions & 1 deletion mlir/include/mlir/Conversion/QCOToQC/QCOToQC.td
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@ def QCOToQC : Pass<"qco-to-qc"> {
It handles the transformation of qubit values in QCO to qubit references in QC, ensuring that the semantics of quantum operations are preserved during the conversion process.
}];

let dependentDialects = ["mlir::qc::QCDialect"];
let dependentDialects = ["mlir::memref::MemRefDialect",
"mlir::qc::QCDialect"];
}
3 changes: 2 additions & 1 deletion mlir/include/mlir/Conversion/QCToQCO/QCToQCO.td
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@ def QCToQCO : Pass<"qc-to-qco"> {
It handles the transformation of qubit references in QC to qubit values in QCO, ensuring that the semantics of quantum operations are preserved during the conversion process.
}];

let dependentDialects = ["mlir::qco::QCODialect"];
let dependentDialects = ["mlir::arith::ArithDialect", "mlir::qco::QCODialect",
"mlir::qtensor::QTensorDialect"];
}
1 change: 1 addition & 0 deletions mlir/include/mlir/Dialect/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@

add_subdirectory(QC)
add_subdirectory(QCO)
add_subdirectory(QIR)
add_subdirectory(QTensor)
16 changes: 9 additions & 7 deletions mlir/include/mlir/Dialect/QC/Builder/QCProgramBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,21 +126,20 @@ class QCProgramBuilder final : public ImplicitLocOpBuilder {
/**
* @brief Allocate a qubit register
* @param size Number of qubits (must be positive)
* @param name Register name (default: "q")
* @return Vector of qubit references
*
* @par Example:
* ```c++
* auto q = builder.allocQubitRegister(3, "q");
* auto q = builder.allocQubitRegister(3);
* ```
* ```mlir
* %q0 = qc.alloc("q", 3, 0) : !qc.qubit
* %q1 = qc.alloc("q", 3, 1) : !qc.qubit
* %q2 = qc.alloc("q", 3, 2) : !qc.qubit
* %memref = memref.alloc() : memref<3x!qc.qubit>
* %q0 = memref.load %memref[%c0] : memref<3x!qc.qubit>
* %q1 = memref.load %memref[%c1] : memref<3x!qc.qubit>
* %q2 = memref.load %memref[%c2] : memref<3x!qc.qubit>
* ```
*/
llvm::SmallVector<Value> allocQubitRegister(int64_t size,
const std::string& name = "q");
llvm::SmallVector<Value> allocQubitRegister(int64_t size);
Comment thread
burgholzer marked this conversation as resolved.

/**
* @brief A small structure representing a single classical bit within a
Expand Down Expand Up @@ -942,6 +941,9 @@ class QCProgramBuilder final : public ImplicitLocOpBuilder {
/// Track allocated qubits for automatic deallocation
llvm::DenseSet<Value> allocatedQubits;

/// Track allocated MemRefs for automatic deallocation
llvm::DenseSet<Value> allocatedMemrefs;

/// Check if the builder has been finalized
void checkFinalized() const;
};
Expand Down
1 change: 1 addition & 0 deletions mlir/include/mlir/Dialect/QC/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@
# Licensed under the MIT License

add_subdirectory(IR)
add_subdirectory(Transforms)
13 changes: 13 additions & 0 deletions mlir/include/mlir/Dialect/QC/Transforms/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Copyright (c) 2023 - 2026 Chair for Design Automation, TUM
# Copyright (c) 2025 - 2026 Munich Quantum Software Company GmbH
# All rights reserved.
#
# SPDX-License-Identifier: MIT
#
# Licensed under the MIT License

set(LLVM_TARGET_DEFINITIONS Passes.td)
mlir_tablegen(Passes.h.inc -gen-pass-decls -name QC)
add_public_tablegen_target(MLIRQCTransformsIncGen)

add_mlir_doc(Passes QCTransforms Passes/ -gen-pass-doc)
31 changes: 31 additions & 0 deletions mlir/include/mlir/Dialect/QC/Transforms/Passes.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright (c) 2023 - 2026 Chair for Design Automation, TUM
* Copyright (c) 2025 - 2026 Munich Quantum Software Company GmbH
* All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* Licensed under the MIT License
*/

#pragma once

#include "mlir/Dialect/QC/IR/QCDialect.h"

#include <mlir/Pass/Pass.h>
#include <mlir/Pass/PassRegistry.h>

namespace mlir::qc {

#define GEN_PASS_DECL
#include "mlir/Dialect/QC/Transforms/Passes.h.inc" // IWYU pragma: export

//===----------------------------------------------------------------------===//
// Registration
//===----------------------------------------------------------------------===//

/// Generate the code for registering passes.
#define GEN_PASS_REGISTRATION
#include "mlir/Dialect/QC/Transforms/Passes.h.inc" // IWYU pragma: export

} // namespace mlir::qc
27 changes: 27 additions & 0 deletions mlir/include/mlir/Dialect/QC/Transforms/Passes.td
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright (c) 2023 - 2026 Chair for Design Automation, TUM
// Copyright (c) 2025 - 2026 Munich Quantum Software Company GmbH
// All rights reserved.
//
// SPDX-License-Identifier: MIT
//
// Licensed under the MIT License

#ifndef MLIR_DIALECT_QC_TRANSFORMS_PASSES_TD
#define MLIR_DIALECT_QC_TRANSFORMS_PASSES_TD

include "mlir/Pass/PassBase.td"

def ShrinkQubitRegistersPass
: Pass<"qc-shrink-qubit-registers", "mlir::ModuleOp"> {
let dependentDialects = ["mlir::qc::QCDialect", "mlir::arith::ArithDialect",
"mlir::memref::MemRefDialect"];
let summary =
"Shrink static qc::QubitType memref registers to accessed indices.";
let description = [{
Shrinks one-dimensional static memref registers with element type
`!qc.qubit` by removing never-read indices and remapping `memref.load`
users accordingly.
}];
}

#endif // MLIR_DIALECT_QC_TRANSFORMS_PASSES_TD
103 changes: 33 additions & 70 deletions mlir/include/mlir/Dialect/QCO/Builder/QCOProgramBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

#pragma once

#include <llvm/ADT/DenseMap.h>
#include <llvm/ADT/DenseSet.h>
#include <llvm/ADT/STLFunctionalExtras.h>
#include <llvm/ADT/SmallVector.h>
Expand Down Expand Up @@ -134,21 +135,20 @@ class QCOProgramBuilder final : public ImplicitLocOpBuilder {
/**
* @brief Allocate a qubit register
* @param size Number of qubits (must be positive)
* @param name Register name (default: "q")
* @return Vector of tracked, valid qubit SSA values
*
* @par Example:
* ```c++
* auto q = builder.allocQubitRegister(3, "q");
* auto q = builder.allocQubitRegister(3);
* ```
* ```mlir
* %q0 = qco.alloc("q", 3, 0) : !qco.qubit
* %q1 = qco.alloc("q", 3, 1) : !qco.qubit
* %q2 = qco.alloc("q", 3, 2) : !qco.qubit
* %t0 = qtensor.alloc(%c3) : tensor<3x!qco.qubit>
* %t1, %q0 = qtensor.extract %t0[%c0]: tensor<3x!qco.qubit>
* %t2, %q1 = qtensor.extract %t1[%c1]: tensor<3x!qco.qubit>
* %t3, %q2 = qtensor.extract %t2[%c2]: tensor<3x!qco.qubit>
* ```
*/
llvm::SmallVector<Value> allocQubitRegister(int64_t size,
const std::string& name = "q");
llvm::SmallVector<Value> allocQubitRegister(int64_t size);
Comment thread
burgholzer marked this conversation as resolved.

/**
* @brief A small structure representing a single classical bit within a
Expand Down Expand Up @@ -272,36 +272,7 @@ class QCOProgramBuilder final : public ImplicitLocOpBuilder {
* %outTensor, %q0 = qtensor.extract %tensor[%c0]: tensor<3x!qco.qubit>
* ```
*/
std::pair<Value, Value>
qtensorExtract(Value tensor, const std::variant<int64_t, Value>& index);

/**
* @brief Extract a qubit slice from a tensor
*
* @details
* Extracts a slice from a one-dimensional tensor of qubits at the given
* offset and size and returns the updated input tensor and the extracted
* tensor. The extracted tensor is added to the qubit tensor tracking and the
* tracking for the input tensor is updated.
*
* @param tensor Source tensor (must be valid/unconsumed)
* @param offset The offset from where the slice is extracted
* @param size The size of the extracted slice
* @return Pair of (outTensor, extractedSlice)
*
* @par Example:
* ```c++
* auto [outTensor, extractedSlice] = builder.qtensorExtractSlice(tensor, 0,
* 2);
* ```
* ```mlir
* %outTensor, %extractedSlice = qtensor.extract_slice %tensor[%c0][%c2]
* : tensor<3x!qco.qubit> to tensor<2x!qco.qubit>
* ```
*/
std::pair<Value, Value>
qtensorExtractSlice(Value tensor, const std::variant<int64_t, Value>& offset,
const std::variant<int64_t, Value>& size);
std::pair<Value, Value> qtensorExtract(Value tensor, const int64_t index);

/**
* @brief Insert a qubit into a tensor
Expand All @@ -328,35 +299,6 @@ class QCOProgramBuilder final : public ImplicitLocOpBuilder {
Value qtensorInsert(Value scalar, Value tensor,
const std::variant<int64_t, Value>& index);

/**
* @brief Insert a qubit slice into a tensor
*
* @details
* Inserts a one-dimensional tensor of qubits into another one-dimensional
* tensor of qubits at the given offset and size. The inserted tensor slice is
* consumed and removed from the tracking, while the tracking for the
* destination tensor is updated.
*
* @param sourceTensor The slice that is inserted (must be valid/unconsumed)
* @param destTensor The tensor where the slice is inserted (must be
* valid/unconsumed)
* @param offset The offset into where the slice is inserted
* @param size The size of the inserted slice
* @return The output tensor
*
* @par Example:
* ```c++
* auto outTensor = builder.qtensorInsertSlice(slicedTensor, tensor, 0, 2);
* ```
* ```mlir
* %outTensor = qtensor.insert_slice %slicedTensor into %tensor[%c0][%c2]
* : tensor<2x!qco.qubit> into tensor<3x!qco.qubit>
* ```
*/
Value qtensorInsertSlice(Value sourceTensor, Value destTensor,
const std::variant<int64_t, Value>& offset,
const std::variant<int64_t, Value>& size);

/**
* @brief Explicitly deallocate a tensor
*
Expand Down Expand Up @@ -1347,11 +1289,24 @@ class QCOProgramBuilder final : public ImplicitLocOpBuilder {
*/
void updateQubitTracking(Value inputQubit, Value outputQubit);

/// Count unique tensors
int64_t tensorCounter = 0;

/**
* @brief Information about a qubit
*/
struct QubitInfo {
/// ID of the register the qubit belongs to
int64_t regId = -1;
/// Index of the qubit within its register
int64_t regIndex = -1;
};
Comment thread
burgholzer marked this conversation as resolved.

/// Track valid (unconsumed) qubit SSA values for linear type enforcement.
/// Only values present in this set are valid for use in operations.
/// Only values present in this map are valid for use in operations.
/// When an operation consumes a qubit and produces a new one, the old value
/// is removed and the new output is added.
llvm::DenseSet<Value> validQubits;
llvm::DenseMap<Value, QubitInfo> validQubits;

/**
* @brief Validate that a tensor value is valid and unconsumed. This also
Expand All @@ -1369,10 +1324,18 @@ class QCOProgramBuilder final : public ImplicitLocOpBuilder {
*/
void updateTensorTracking(Value inputTensor, Value outputTensor);

/**
* @brief Information about a tensor
*/
struct TensorInfo {
/// ID of the register the tensor corresponds to
int64_t regId = -1;
};

/// Track valid (unconsumed) tensor SSA values for linear type enforcement.
/// Only values present in this set are valid for use in operations.
/// Only values present in this map are valid for use in operations.
/// When an operation consumes a tensor and produces a new one, the old value
/// is removed and the new output is added.
llvm::DenseSet<Value> validTensors;
llvm::DenseMap<Value, TensorInfo> validTensors;
};
} // namespace mlir::qco
Loading
Loading