Skip to content
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
1b60374
Add pass foundation
MatthiasReumann Jun 15, 2026
80636f7
Finalize pass implementation
MatthiasReumann Jun 16, 2026
4b69f8c
Add populate function
MatthiasReumann Jun 16, 2026
b42ba92
🎨 pre-commit fixes
pre-commit-ci[bot] Jun 16, 2026
9bbdf24
Fix off by one error
MatthiasReumann Jun 16, 2026
6af1739
Fix initialization order
MatthiasReumann Jun 16, 2026
d0ef4e7
Add MLIRQCToQIR library
MatthiasReumann Jun 16, 2026
34e54be
🎨 pre-commit fixes
pre-commit-ci[bot] Jun 16, 2026
d6272b2
Apply linting suggestions
MatthiasReumann Jun 16, 2026
b5104ea
Fix symbol names
MatthiasReumann Jun 16, 2026
a49a1b6
Fix invalid use of call attrs
MatthiasReumann Jun 16, 2026
205c793
Remove unused include
MatthiasReumann Jun 16, 2026
18d47b2
Rename pass
MatthiasReumann Jun 16, 2026
ac46f40
🎨 pre-commit fixes
pre-commit-ci[bot] Jun 16, 2026
2feade8
Integrate into QIRProgramBuilder
MatthiasReumann Jun 17, 2026
a5607e9
🎨 pre-commit fixes
pre-commit-ci[bot] Jun 17, 2026
12634d3
Fix totalState count
MatthiasReumann Jun 17, 2026
f7b04c3
Fix build
MatthiasReumann Jun 17, 2026
913f563
Remove unused and include missing headers
MatthiasReumann Jun 17, 2026
f0b53de
Merge branch 'main' into feat/set-qir-metadata-pass
MatthiasReumann Jun 17, 2026
bb160f5
Update CHANGELOG.md [no ci]
MatthiasReumann Jun 17, 2026
b22ea11
Simplify conversion
MatthiasReumann Jun 17, 2026
8d3b27f
Improve pass naming and description
MatthiasReumann Jun 17, 2026
c64c0e3
🎨 pre-commit fixes
pre-commit-ci[bot] Jun 17, 2026
2b3b827
Fix lint
MatthiasReumann Jun 17, 2026
026ba2c
Merge branch 'feat/set-qir-metadata-pass' of https://github.com/munic…
MatthiasReumann Jun 17, 2026
5c68d9e
Fix backward branching logic
MatthiasReumann Jun 17, 2026
3443bd8
🎨 pre-commit fixes
pre-commit-ci[bot] Jun 17, 2026
b0834cc
Apply bunny changes
MatthiasReumann Jun 17, 2026
4f54917
Merge branch 'feat/set-qir-metadata-pass' of https://github.com/munic…
MatthiasReumann Jun 17, 2026
0d2676f
Merge branch 'main' into feat/set-qir-metadata-pass
MatthiasReumann Jun 17, 2026
0bc1bbf
🎨 pre-commit fixes
pre-commit-ci[bot] Jun 17, 2026
3630496
Remove missing include
MatthiasReumann Jun 17, 2026
1d61aee
Merge branch 'feat/set-qir-metadata-pass' of https://github.com/munic…
MatthiasReumann Jun 17, 2026
cd87972
🎨 pre-commit fixes
pre-commit-ci[bot] Jun 17, 2026
2d8a560
Update 'removeExistingModuleFlags'
MatthiasReumann Jun 18, 2026
9aa255c
Update spelling
MatthiasReumann Jun 18, 2026
11c011a
Merge branch 'main' into feat/set-qir-metadata-pass
MatthiasReumann Jun 18, 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 @@ -19,7 +19,7 @@ This project adheres to [Semantic Versioning], with the exception that minor rel
- ✨ Add conversions between `jeff` and QCO ([#1479], [#1548], [#1565], [#1637], [#1676], [#1706], [#1776]) ([**@denialhaag**], [**@burgholzer**])
- ✨ Add a `place-and-route` pass for mapping circuits to architectures with restricted topologies ([#1537], [#1547], [#1568], [#1581], [#1583], [#1588], [#1600], [#1664], [#1709], [#1716], [#1748]) ([**@MatthiasReumann**], [**@burgholzer**])
- ✨ 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], [#1580], [#1602], [#1620], [#1623], [#1624], [#1626], [#1627], [#1635], [#1638], [#1673], [#1675], [#1700], [#1710], [#1717], [#1728], [#1730], [#1749], [#1751], [#1762], [#1765], [#1774], [#1781])
([#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], [#1620], [#1623], [#1624], [#1626], [#1627], [#1635], [#1638], [#1673], [#1675], [#1700], [#1710], [#1717], [#1728], [#1730], [#1749], [#1751], [#1762], [#1765], [#1774], [#1781], [#1787])
([**@burgholzer**], [**@denialhaag**], [**@taminob**], [**@DRovara**], [**@li-mingbao**], [**@Ectras**], [**@MatthiasReumann**], [**@simon1hofmann**])

### Changed
Expand Down Expand Up @@ -403,6 +403,7 @@ _📚 Refer to the [GitHub Release Notes](https://github.com/munich-quantum-tool

<!-- PR links -->

[#1787]: https://github.com/munich-quantum-toolkit/core/pull/1787
[#1781]: https://github.com/munich-quantum-toolkit/core/pull/1781
[#1776]: https://github.com/munich-quantum-toolkit/core/pull/1776
[#1774]: https://github.com/munich-quantum-toolkit/core/pull/1774
Expand Down
5 changes: 1 addition & 4 deletions mlir/include/mlir/Conversion/QCToQIR/QIRCommon/QIRCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@

#pragma once

#include "mlir/Dialect/QIR/Utils/QIRMetadata.h"

#include <llvm/ADT/StringMap.h>
#include <llvm/Support/Allocator.h>
#include <llvm/Support/StringSaver.h>
Expand All @@ -26,7 +24,6 @@
#include <utility>

namespace mlir {
using namespace qir;

/** @brief Qubit allocation mode */
enum class AllocationMode : std::uint8_t {
Expand All @@ -38,7 +35,7 @@ enum class AllocationMode : std::uint8_t {
/**
* @brief State object for tracking lowering information during QIR conversion
*/
struct LoweringState : QIRMetadata {
struct LoweringState {
/// Cache static qubit pointers for reuse
DenseMap<int64_t, Value> staticQubits;

Expand Down
11 changes: 6 additions & 5 deletions mlir/include/mlir/Dialect/QIR/Builder/QIRProgramBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@

#pragma once

#include "mlir/Dialect/QIR/Utils/QIRMetadata.h"

#include <llvm/ADT/StringMap.h>
#include <llvm/Support/Allocator.h>
#include <llvm/Support/StringSaver.h>
Expand Down Expand Up @@ -1086,15 +1084,18 @@ class QIRProgramBuilder final : public ImplicitLocOpBuilder {
/// Map from register to their loaded indices
DenseMap<Value, DenseSet<Value>> loadedQubits;

/// Track qubit and result counts for QIR metadata
QIRMetadata metadata_;

/// Helper variable for storing the LLVM pointer type
Type ptrType;

/// Helper variable for storing the LLVM void type
Type voidType;

/// The number of used qubits.
size_t numQubits{0};

/// The number of result values.
size_t numResults{0};

/**
* @brief Helper to create a LLVM CallOp
*
Expand Down
9 changes: 9 additions & 0 deletions mlir/include/mlir/Dialect/QIR/Transforms/Passes.td
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@

include "mlir/Pass/PassBase.td"

def QIRSetAttributesAndMetadata
: Pass<"set-qir-attributes-and-metadata", "mlir::ModuleOp"> {
let dependentDialects = ["mlir::LLVM::LLVMDialect"];
let summary = "Sets the required attributes to the entry point function and "
"adds the required module flags, compliant with QIR 2.1";
let options = [Option<"useAdaptive", "use-adaptive", "bool",
/*default= */ "true", "Specifies the profile.">];
}

def QIRCleanupPass : Pass<"qir-cleanup", "mlir::ModuleOp"> {
let dependentDialects = ["mlir::LLVM::LLVMDialect"];
let summary = "Remove redundant QIR runtime bookkeeping.";
Expand Down
43 changes: 0 additions & 43 deletions mlir/include/mlir/Dialect/QIR/Utils/QIRMetadata.h

This file was deleted.

25 changes: 0 additions & 25 deletions mlir/include/mlir/Dialect/QIR/Utils/QIRUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@

#pragma once

#include "mlir/Dialect/QIR/Utils/QIRMetadata.h"

#include <llvm/Support/ErrorHandling.h>
#include <mlir/IR/Location.h>
#include <mlir/IR/Types.h>
Expand Down Expand Up @@ -169,29 +167,6 @@ DEFINE_GETTER(XXMINUSYY)
*/
LLVM::LLVMFuncOp getMainFunction(Operation* op);

/**
* @brief Set QIR base profile metadata attributes on the main function
*
* @details
* Adds the required metadata attributes for QIR base profile compliance:
* - `entry_point`: Marks the main entry point function
* - `output_labeling_schema`: labeled
* - `qir_profiles`: base_profile
* - `required_num_qubits`: Number of qubits used
* - `required_num_results`: Number of measurement results
* - `qir_major_version`: 2
* - `qir_minor_version`: 1
* - `dynamic_qubit_management`: true/false
* - `dynamic_result_management`: true/false
*
* These attributes are required by the QIR specification and inform QIR
* consumers about the module's resource requirements and capabilities.
*
* @param main The main LLVM function to annotate
* @param metadata The QIR metadata containing qubit/result counts
*/
void setQIRAttributes(LLVM::LLVMFuncOp& main, const QIRMetadata& metadata);

/**
* @brief Get or create a QIR function declaration
*
Expand Down
16 changes: 13 additions & 3 deletions mlir/include/mlir/Support/Passes.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ class ModuleOp;
class PassManager;
} // namespace mlir

/**
* @brief Populate the pass manager and run it on the module.
*/
mlir::LogicalResult
runWithPassManager(mlir::ModuleOp module,
mlir::function_ref<void(mlir::PassManager&)> populatePasses,
mlir::StringRef errorMessage);

/**
* @brief Populate a QC-oriented cleanup pipeline on the given pass manager.
* @details Adds generic cleanup and QC qubit-register shrinking.
Expand All @@ -31,9 +39,10 @@ void populateQCOCleanupPipeline(mlir::PassManager& pm);

/**
* @brief Populate a QIR-oriented cleanup pipeline on the given pass manager.
* @details Adds generic cleanup and QIR-specific simplifications.
* @details Adds generic cleanup and QIR-specific simplifications. Updates the
* meta data accordingly.
*/
void populateQIRCleanupPipeline(mlir::PassManager& pm);
void populateQIRCleanupPipeline(mlir::PassManager& pm, bool useAdaptive);

/**
* @brief Run the QC-oriented cleanup pipeline on a module.
Expand All @@ -48,4 +57,5 @@ void populateQIRCleanupPipeline(mlir::PassManager& pm);
/**
* @brief Run the QIR-oriented cleanup pipeline on a module.
*/
[[nodiscard]] mlir::LogicalResult runQIRCleanupPipeline(mlir::ModuleOp module);
[[nodiscard]] mlir::LogicalResult runQIRCleanupPipeline(mlir::ModuleOp module,
bool useAdaptive);
2 changes: 1 addition & 1 deletion mlir/lib/Compiler/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ add_mlir_library(
MLIRTransformUtils
MLIRQCToQCO
MLIRQCOToQC
MLIRQCToQIRAdaptive
MLIRQCToQIRBase
MLIRQCToQIRAdaptive
MLIRQCOTransforms
MQT::MLIRSupport)

Expand Down
22 changes: 10 additions & 12 deletions mlir/lib/Compiler/CompilerPipeline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -199,18 +199,15 @@ QuantumCompilerPipeline::runPipeline(ModuleOp module,
}
// Stage 9: QC-to-QIR conversion (optional)
if (convertToQIR) {
auto addConversionPass = [&](PassManager& pm) {
if (config_.convertToQIRBase) {
pm.addPass(createQCToQIRBase());
} else {
pm.addPass(createQCToQIRAdaptive());
}
};

if (failed(runStage(addConversionPass))) {
if (failed(runStage([&](PassManager& pm) {
if (config_.convertToQIRAdaptive) {
pm.addPass(createQCToQIRAdaptive());
} else {
pm.addPass(createQCToQIRBase());
}
}))) {
return failure();
}

if (record != nullptr && config_.recordIntermediates) {
record->afterQIRConversion = captureIR(module);
if (config_.printIRAfterAllStages) {
Expand All @@ -219,8 +216,9 @@ QuantumCompilerPipeline::runPipeline(ModuleOp module,
}
}
// Stage 10: QIR cleanup (optional)
if (failed(runStage(
[&](PassManager& pm) { populateQIRCleanupPipeline(pm); }))) {
if (failed(runStage([&](PassManager& pm) {
populateQIRCleanupPipeline(pm, config_.convertToQIRAdaptive);
}))) {
return failure();
}
if (record != nullptr && config_.recordIntermediates) {
Expand Down
44 changes: 4 additions & 40 deletions mlir/lib/Conversion/QCToQIR/QIRAdaptive/QCToQIRAdaptive.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
#include <mlir/IR/Region.h>
#include <mlir/Pass/PassManager.h>
#include <mlir/Support/LogicalResult.h>
#include <mlir/Support/WalkResult.h>
#include <mlir/Transforms/DialectConversion.h>

#include <cassert>
Expand Down Expand Up @@ -84,9 +83,6 @@ struct ConvertMemRefAllocOp final
}

auto& state = getState();
state.useDynamicQubit = true;
state.useArrays = true;

auto* ctx = getContext();
auto ptrType = LLVM::LLVMPointerType::get(ctx);

Expand Down Expand Up @@ -235,7 +231,6 @@ struct ConvertQCAllocOp final : StatefulOpConversionPattern<AllocOp> {
op.getOperation()))) {
return failure();
}
state.useDynamicQubit = true;

auto* ctx = getContext();
auto ptrType = LLVM::LLVMPointerType::get(ctx);
Expand Down Expand Up @@ -363,8 +358,6 @@ struct ConvertQCMeasureOp final : StatefulOpConversionPattern<MeasureOp> {
matchAndRewrite(MeasureOp op, OpAdaptor adaptor,
ConversionPatternRewriter& rewriter) const override {
auto& state = getState();
state.useDynamicResult = true;

auto& resultArrays = state.resultArrays;
auto& loadedResults = state.loadedResults;
auto& resultPtrs = state.resultPtrs;
Expand All @@ -381,7 +374,6 @@ struct ConvertQCMeasureOp final : StatefulOpConversionPattern<MeasureOp> {
// Get result pointer
Value result;
if (op.getRegisterName() && op.getRegisterSize() && op.getRegisterIndex()) {
state.useArrays = true;
const auto registerName = op.getRegisterName().value();
const auto registerSize =
static_cast<int64_t>(op.getRegisterSize().value());
Expand Down Expand Up @@ -425,7 +417,6 @@ struct ConvertQCMeasureOp final : StatefulOpConversionPattern<MeasureOp> {
rewriter.setInsertionPoint(state.entryBlock->getTerminator());
result = createPointerFromIndex(rewriter, op.getLoc(), resultPtrs.size());
resultPtrs.try_emplace(resultPtrs.size(), result);
state.numResults++;
}

rewriter.restoreInsertionPoint(savedInsertionPoint);
Expand Down Expand Up @@ -573,22 +564,6 @@ struct QCToQIRAdaptive final : impl::QCToQIRAdaptiveBase<QCToQIRAdaptive> {
}
}

/**
* @brief Iterates through the module to find any scf.while or scf.for
* operation to set the backward branching flag before they are converted to
* cf operations.
*/
static void setSCFFlags(Operation* op, LoweringState* state) {
op->walk([&](scf::ForOp) {
state->backwardsBranching += 1;
return WalkResult::interrupt();
});
op->walk([&](scf::WhileOp) {
state->backwardsBranching += 2;
return WalkResult::interrupt();
});
}

protected:
/**
* @brief Executes the QC to QIR conversion pass
Expand All @@ -614,15 +589,11 @@ struct QCToQIRAdaptive final : impl::QCToQIRAdaptiveBase<QCToQIRAdaptive> {
* Convert QC dialect operations and memref operations to QIR calls and add
* output recording to the output block.
*
* **Stage 6: QIR Attributes**
* Add QIR Profile metadata to the main function, including qubit/result
* counts and version information.
*
* **Stage 7: Standard dialects to LLVM**
* **Stage 6: Standard dialects to LLVM**
* Convert arith and control flow dialects to LLVM (for index arithmetic and
* function control flow).
*
* **Stage 8: Reconcile casts**
* **Stage 7: Reconcile casts**
* Clean up any unrealized cast operations introduced during type
* conversion.
*/
Expand All @@ -632,15 +603,11 @@ struct QCToQIRAdaptive final : impl::QCToQIRAdaptiveBase<QCToQIRAdaptive> {
ConversionTarget target(*ctx);
QCToQIRTypeConverter typeConverter(ctx);
LoweringState state;
state.useAdaptive = true;

target.addLegalDialect<LLVM::LLVMDialect>();

// Stage 1: Convert scf dialect to cf
{
// Find the required flags before the scf operations are converted
setSCFFlags(moduleOp, &state);

RewritePatternSet scfPatterns(ctx);
target.addIllegalDialect<scf::SCFDialect>();
target.addLegalDialect<cf::ControlFlowDialect>();
Expand Down Expand Up @@ -696,10 +663,7 @@ struct QCToQIRAdaptive final : impl::QCToQIRAdaptiveBase<QCToQIRAdaptive> {
releaseResults(main, ctx, &state);
}

// Stage 6: Set QIR metadata attributes
setQIRAttributes(main, state);

// Stage 7: Convert standard dialects to LLVM
// Stage 6: Convert standard dialects to LLVM
{
RewritePatternSet stdPatterns(ctx);
target.addIllegalDialect<arith::ArithDialect>();
Expand All @@ -716,7 +680,7 @@ struct QCToQIRAdaptive final : impl::QCToQIRAdaptiveBase<QCToQIRAdaptive> {
}
}

// Stage 8: Reconcile unrealized casts
// Stage 7: Reconcile unrealized casts
PassManager passManager(ctx);
passManager.addPass(createReconcileUnrealizedCastsPass());
if (passManager.run(moduleOp).failed()) {
Expand Down
Loading
Loading