Skip to content

Commit 89448cf

Browse files
✨ Add QIRSetAttributesAndMetadata Pass (#1787)
1 parent 742e9bc commit 89448cf

21 files changed

Lines changed: 557 additions & 277 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ with the exception that minor releases may include breaking changes.
4242
[#1569], [#1570], [#1572], [#1573], [#1580], [#1602], [#1620], [#1623],
4343
[#1624], [#1626], [#1627], [#1635], [#1638], [#1673], [#1675], [#1700],
4444
[#1710], [#1717], [#1728], [#1730], [#1749], [#1751], [#1762], [#1765],
45-
[#1774], [#1781], [#1782])
45+
[#1774], [#1781], [#1782], [#1787])
4646
([**@burgholzer**], [**@denialhaag**], [**@taminob**], [**@DRovara**],
4747
[**@li-mingbao**], [**@Ectras**], [**@MatthiasReumann**],
4848
[**@simon1hofmann**])
@@ -598,6 +598,7 @@ changelogs._
598598

599599
<!-- PR links -->
600600

601+
[#1787]: https://github.com/munich-quantum-toolkit/core/pull/1787
601602
[#1782]: https://github.com/munich-quantum-toolkit/core/pull/1782
602603
[#1781]: https://github.com/munich-quantum-toolkit/core/pull/1781
603604
[#1776]: https://github.com/munich-quantum-toolkit/core/pull/1776

mlir/include/mlir/Conversion/QCToQIR/QIRCommon/QIRCommon.h

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@
1010

1111
#pragma once
1212

13-
#include "mlir/Dialect/QIR/Utils/QIRMetadata.h"
14-
1513
#include <llvm/ADT/StringMap.h>
1614
#include <llvm/Support/Allocator.h>
1715
#include <llvm/Support/StringSaver.h>
@@ -26,7 +24,6 @@
2624
#include <utility>
2725

2826
namespace mlir {
29-
using namespace qir;
3027

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

mlir/include/mlir/Dialect/QIR/Builder/QIRProgramBuilder.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@
1010

1111
#pragma once
1212

13-
#include "mlir/Dialect/QIR/Utils/QIRMetadata.h"
14-
1513
#include <llvm/ADT/StringMap.h>
1614
#include <llvm/Support/Allocator.h>
1715
#include <llvm/Support/StringSaver.h>
@@ -1086,15 +1084,18 @@ class QIRProgramBuilder final : public ImplicitLocOpBuilder {
10861084
/// Map from register to their loaded indices
10871085
DenseMap<Value, DenseSet<Value>> loadedQubits;
10881086

1089-
/// Track qubit and result counts for QIR metadata
1090-
QIRMetadata metadata_;
1091-
10921087
/// Helper variable for storing the LLVM pointer type
10931088
Type ptrType;
10941089

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

1093+
/// The number of used qubits.
1094+
size_t numQubits{0};
1095+
1096+
/// The number of result values.
1097+
size_t numResults{0};
1098+
10981099
/**
10991100
* @brief Helper to create a LLVM CallOp
11001101
*

mlir/include/mlir/Dialect/QIR/Transforms/Passes.td

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,15 @@
1111

1212
include "mlir/Pass/PassBase.td"
1313

14+
def QIRSetAttributesAndMetadata
15+
: Pass<"set-qir-attributes-and-metadata", "mlir::ModuleOp"> {
16+
let dependentDialects = ["mlir::LLVM::LLVMDialect"];
17+
let summary = "Sets the required attributes to the entry point function and "
18+
"adds the required module flags, compliant with QIR 2.1";
19+
let options = [Option<"useAdaptive", "use-adaptive", "bool",
20+
/*default= */ "true", "Specifies the profile.">];
21+
}
22+
1423
def QIRCleanupPass : Pass<"qir-cleanup", "mlir::ModuleOp"> {
1524
let dependentDialects = ["mlir::LLVM::LLVMDialect"];
1625
let summary = "Remove redundant QIR runtime bookkeeping.";

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

Lines changed: 0 additions & 43 deletions
This file was deleted.

mlir/include/mlir/Dialect/QIR/Utils/QIRUtils.h

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@
1010

1111
#pragma once
1212

13-
#include "mlir/Dialect/QIR/Utils/QIRMetadata.h"
14-
1513
#include <llvm/Support/ErrorHandling.h>
1614
#include <mlir/IR/Location.h>
1715
#include <mlir/IR/Types.h>
@@ -169,29 +167,6 @@ DEFINE_GETTER(XXMINUSYY)
169167
*/
170168
LLVM::LLVMFuncOp getMainFunction(Operation* op);
171169

172-
/**
173-
* @brief Set QIR base profile metadata attributes on the main function
174-
*
175-
* @details
176-
* Adds the required metadata attributes for QIR base profile compliance:
177-
* - `entry_point`: Marks the main entry point function
178-
* - `output_labeling_schema`: labeled
179-
* - `qir_profiles`: base_profile
180-
* - `required_num_qubits`: Number of qubits used
181-
* - `required_num_results`: Number of measurement results
182-
* - `qir_major_version`: 2
183-
* - `qir_minor_version`: 1
184-
* - `dynamic_qubit_management`: true/false
185-
* - `dynamic_result_management`: true/false
186-
*
187-
* These attributes are required by the QIR specification and inform QIR
188-
* consumers about the module's resource requirements and capabilities.
189-
*
190-
* @param main The main LLVM function to annotate
191-
* @param metadata The QIR metadata containing qubit/result counts
192-
*/
193-
void setQIRAttributes(LLVM::LLVMFuncOp& main, const QIRMetadata& metadata);
194-
195170
/**
196171
* @brief Get or create a QIR function declaration
197172
*

mlir/include/mlir/Support/Passes.h

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,14 @@ class ModuleOp;
1717
class PassManager;
1818
} // namespace mlir
1919

20+
/**
21+
* @brief Populate the pass manager and run it on the module.
22+
*/
23+
mlir::LogicalResult
24+
runWithPassManager(mlir::ModuleOp module,
25+
mlir::function_ref<void(mlir::PassManager&)> populatePasses,
26+
mlir::StringRef errorMessage);
27+
2028
/**
2129
* @brief Populate a QC-oriented cleanup pipeline on the given pass manager.
2230
* @details Adds generic cleanup and QC qubit-register shrinking.
@@ -31,9 +39,10 @@ void populateQCOCleanupPipeline(mlir::PassManager& pm);
3139

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

3847
/**
3948
* @brief Run the QC-oriented cleanup pipeline on a module.
@@ -48,4 +57,5 @@ void populateQIRCleanupPipeline(mlir::PassManager& pm);
4857
/**
4958
* @brief Run the QIR-oriented cleanup pipeline on a module.
5059
*/
51-
[[nodiscard]] mlir::LogicalResult runQIRCleanupPipeline(mlir::ModuleOp module);
60+
[[nodiscard]] mlir::LogicalResult runQIRCleanupPipeline(mlir::ModuleOp module,
61+
bool useAdaptive);

mlir/lib/Compiler/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ add_mlir_library(
1919
MLIRTransformUtils
2020
MLIRQCToQCO
2121
MLIRQCOToQC
22-
MLIRQCToQIRAdaptive
2322
MLIRQCToQIRBase
23+
MLIRQCToQIRAdaptive
2424
MLIRQCOTransforms
2525
MQT::MLIRSupport)
2626

mlir/lib/Compiler/CompilerPipeline.cpp

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -199,18 +199,15 @@ QuantumCompilerPipeline::runPipeline(ModuleOp module,
199199
}
200200
// Stage 9: QC-to-QIR conversion (optional)
201201
if (convertToQIR) {
202-
auto addConversionPass = [&](PassManager& pm) {
203-
if (config_.convertToQIRBase) {
204-
pm.addPass(createQCToQIRBase());
205-
} else {
206-
pm.addPass(createQCToQIRAdaptive());
207-
}
208-
};
209-
210-
if (failed(runStage(addConversionPass))) {
202+
if (failed(runStage([&](PassManager& pm) {
203+
if (config_.convertToQIRAdaptive) {
204+
pm.addPass(createQCToQIRAdaptive());
205+
} else {
206+
pm.addPass(createQCToQIRBase());
207+
}
208+
}))) {
211209
return failure();
212210
}
213-
214211
if (record != nullptr && config_.recordIntermediates) {
215212
record->afterQIRConversion = captureIR(module);
216213
if (config_.printIRAfterAllStages) {
@@ -219,8 +216,9 @@ QuantumCompilerPipeline::runPipeline(ModuleOp module,
219216
}
220217
}
221218
// Stage 10: QIR cleanup (optional)
222-
if (failed(runStage(
223-
[&](PassManager& pm) { populateQIRCleanupPipeline(pm); }))) {
219+
if (failed(runStage([&](PassManager& pm) {
220+
populateQIRCleanupPipeline(pm, config_.convertToQIRAdaptive);
221+
}))) {
224222
return failure();
225223
}
226224
if (record != nullptr && config_.recordIntermediates) {

mlir/lib/Conversion/QCToQIR/QIRAdaptive/QCToQIRAdaptive.cpp

Lines changed: 4 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
#include <mlir/IR/Region.h>
3636
#include <mlir/Pass/PassManager.h>
3737
#include <mlir/Support/LogicalResult.h>
38-
#include <mlir/Support/WalkResult.h>
3938
#include <mlir/Transforms/DialectConversion.h>
4039

4140
#include <cassert>
@@ -84,9 +83,6 @@ struct ConvertMemRefAllocOp final
8483
}
8584

8685
auto& state = getState();
87-
state.useDynamicQubit = true;
88-
state.useArrays = true;
89-
9086
auto* ctx = getContext();
9187
auto ptrType = LLVM::LLVMPointerType::get(ctx);
9288

@@ -235,7 +231,6 @@ struct ConvertQCAllocOp final : StatefulOpConversionPattern<AllocOp> {
235231
op.getOperation()))) {
236232
return failure();
237233
}
238-
state.useDynamicQubit = true;
239234

240235
auto* ctx = getContext();
241236
auto ptrType = LLVM::LLVMPointerType::get(ctx);
@@ -363,8 +358,6 @@ struct ConvertQCMeasureOp final : StatefulOpConversionPattern<MeasureOp> {
363358
matchAndRewrite(MeasureOp op, OpAdaptor adaptor,
364359
ConversionPatternRewriter& rewriter) const override {
365360
auto& state = getState();
366-
state.useDynamicResult = true;
367-
368361
auto& resultArrays = state.resultArrays;
369362
auto& loadedResults = state.loadedResults;
370363
auto& resultPtrs = state.resultPtrs;
@@ -381,7 +374,6 @@ struct ConvertQCMeasureOp final : StatefulOpConversionPattern<MeasureOp> {
381374
// Get result pointer
382375
Value result;
383376
if (op.getRegisterName() && op.getRegisterSize() && op.getRegisterIndex()) {
384-
state.useArrays = true;
385377
const auto registerName = op.getRegisterName().value();
386378
const auto registerSize =
387379
static_cast<int64_t>(op.getRegisterSize().value());
@@ -425,7 +417,6 @@ struct ConvertQCMeasureOp final : StatefulOpConversionPattern<MeasureOp> {
425417
rewriter.setInsertionPoint(state.entryBlock->getTerminator());
426418
result = createPointerFromIndex(rewriter, op.getLoc(), resultPtrs.size());
427419
resultPtrs.try_emplace(resultPtrs.size(), result);
428-
state.numResults++;
429420
}
430421

431422
rewriter.restoreInsertionPoint(savedInsertionPoint);
@@ -573,22 +564,6 @@ struct QCToQIRAdaptive final : impl::QCToQIRAdaptiveBase<QCToQIRAdaptive> {
573564
}
574565
}
575566

576-
/**
577-
* @brief Iterates through the module to find any scf.while or scf.for
578-
* operation to set the backward branching flag before they are converted to
579-
* cf operations.
580-
*/
581-
static void setSCFFlags(Operation* op, LoweringState* state) {
582-
op->walk([&](scf::ForOp) {
583-
state->backwardsBranching += 1;
584-
return WalkResult::interrupt();
585-
});
586-
op->walk([&](scf::WhileOp) {
587-
state->backwardsBranching += 2;
588-
return WalkResult::interrupt();
589-
});
590-
}
591-
592567
protected:
593568
/**
594569
* @brief Executes the QC to QIR conversion pass
@@ -614,15 +589,11 @@ struct QCToQIRAdaptive final : impl::QCToQIRAdaptiveBase<QCToQIRAdaptive> {
614589
* Convert QC dialect operations and memref operations to QIR calls and add
615590
* output recording to the output block.
616591
*
617-
* **Stage 6: QIR Attributes**
618-
* Add QIR Profile metadata to the main function, including qubit/result
619-
* counts and version information.
620-
*
621-
* **Stage 7: Standard dialects to LLVM**
592+
* **Stage 6: Standard dialects to LLVM**
622593
* Convert arith and control flow dialects to LLVM (for index arithmetic and
623594
* function control flow).
624595
*
625-
* **Stage 8: Reconcile casts**
596+
* **Stage 7: Reconcile casts**
626597
* Clean up any unrealized cast operations introduced during type
627598
* conversion.
628599
*/
@@ -632,15 +603,11 @@ struct QCToQIRAdaptive final : impl::QCToQIRAdaptiveBase<QCToQIRAdaptive> {
632603
ConversionTarget target(*ctx);
633604
QCToQIRTypeConverter typeConverter(ctx);
634605
LoweringState state;
635-
state.useAdaptive = true;
636606

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

639609
// Stage 1: Convert scf dialect to cf
640610
{
641-
// Find the required flags before the scf operations are converted
642-
setSCFFlags(moduleOp, &state);
643-
644611
RewritePatternSet scfPatterns(ctx);
645612
target.addIllegalDialect<scf::SCFDialect>();
646613
target.addLegalDialect<cf::ControlFlowDialect>();
@@ -696,10 +663,7 @@ struct QCToQIRAdaptive final : impl::QCToQIRAdaptiveBase<QCToQIRAdaptive> {
696663
releaseResults(main, ctx, &state);
697664
}
698665

699-
// Stage 6: Set QIR metadata attributes
700-
setQIRAttributes(main, state);
701-
702-
// Stage 7: Convert standard dialects to LLVM
666+
// Stage 6: Convert standard dialects to LLVM
703667
{
704668
RewritePatternSet stdPatterns(ctx);
705669
target.addIllegalDialect<arith::ArithDialect>();
@@ -716,7 +680,7 @@ struct QCToQIRAdaptive final : impl::QCToQIRAdaptiveBase<QCToQIRAdaptive> {
716680
}
717681
}
718682

719-
// Stage 8: Reconcile unrealized casts
683+
// Stage 7: Reconcile unrealized casts
720684
PassManager passManager(ctx);
721685
passManager.addPass(createReconcileUnrealizedCastsPass());
722686
if (passManager.run(moduleOp).failed()) {

0 commit comments

Comments
 (0)