diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ed8c0f998..4e2da940e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,7 @@ This project adheres to [Semantic Versioning], with the exception that minor rel - ✨ Add conversions between Jeff and QCO ([#1479], [#1548]) ([**@denialhaag**]) - ✨ Add a `place-and-route` pass for mapping circuits to architectures with restricted topologies ([#1537], [#1547]) ([**@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], [#1548], [#1550], [#1554]) + ([#1264], [#1330], [#1402], [#1428], [#1430], [#1436], [#1443], [#1446], [#1464], [#1465], [#1470], [#1471], [#1472], [#1474], [#1475], [#1506], [#1510], [#1513], [#1521], [#1548], [#1550], [#1554], [#1567]) ([**@burgholzer**], [**@denialhaag**], [**@taminob**], [**@DRovara**], [**@li-mingbao**], [**@Ectras**], [**@MatthiasReumann**], [**@simon1hofmann**]) ### Changed @@ -331,6 +331,7 @@ _📚 Refer to the [GitHub Release Notes](https://github.com/munich-quantum-tool +[#1567]: https://github.com/munich-quantum-toolkit/core/pull/1567 [#1554]: https://github.com/munich-quantum-toolkit/core/pull/1554 [#1550]: https://github.com/munich-quantum-toolkit/core/pull/1550 [#1549]: https://github.com/munich-quantum-toolkit/core/pull/1549 diff --git a/mlir/include/mlir/Compiler/CompilerPipeline.h b/mlir/include/mlir/Compiler/CompilerPipeline.h index ee7fbc9adf..ec7473a8cf 100644 --- a/mlir/include/mlir/Compiler/CompilerPipeline.h +++ b/mlir/include/mlir/Compiler/CompilerPipeline.h @@ -115,8 +115,8 @@ class QuantumCompilerPipeline { * @brief Add canonicalization and cleanup passes * * @details - * Always adds the standard MLIR canonicalization pass followed by dead - * value removal. + * Always adds the standard MLIR canonicalization pass followed by common + * sub-expression elimination and dead value removal. */ static void addCleanupPasses(PassManager& pm); diff --git a/mlir/lib/Compiler/CompilerPipeline.cpp b/mlir/lib/Compiler/CompilerPipeline.cpp index 18040d7720..119e343755 100644 --- a/mlir/lib/Compiler/CompilerPipeline.cpp +++ b/mlir/lib/Compiler/CompilerPipeline.cpp @@ -46,8 +46,10 @@ static void prettyPrintStage(ModuleOp module, const llvm::StringRef stageName, } void QuantumCompilerPipeline::addCleanupPasses(PassManager& pm) { - // Always run canonicalization and dead value removal + // Always run canonicalization, common sub-expression elimination, and dead + // value removal pm.addPass(createCanonicalizerPass()); + pm.addPass(createCSEPass()); pm.addPass(createRemoveDeadValuesPass()); } diff --git a/mlir/lib/Support/Passes.cpp b/mlir/lib/Support/Passes.cpp index 242d48b8bf..5e998761bc 100644 --- a/mlir/lib/Support/Passes.cpp +++ b/mlir/lib/Support/Passes.cpp @@ -20,6 +20,7 @@ using namespace mlir; void runCanonicalizationPasses(ModuleOp module) { PassManager pm(module.getContext()); pm.addPass(createCanonicalizerPass()); + pm.addPass(createCSEPass()); pm.addPass(createRemoveDeadValuesPass()); if (pm.run(module).failed()) { llvm::errs() << "Failed to run canonicalization passes.\n"; diff --git a/mlir/unittests/Compiler/test_compiler_pipeline.cpp b/mlir/unittests/Compiler/test_compiler_pipeline.cpp index 1b72a08521..f6958ed3e4 100644 --- a/mlir/unittests/Compiler/test_compiler_pipeline.cpp +++ b/mlir/unittests/Compiler/test_compiler_pipeline.cpp @@ -185,6 +185,11 @@ INSTANTIATE_TEST_SUITE_P( "StaticQubits", nullptr, MQT_NAMED_BUILDER(mlir::qc::staticQubits), MQT_NAMED_BUILDER(mlir::qc::staticQubits), MQT_NAMED_BUILDER(mlir::qir::staticQubits), false}, + CompilerPipelineTestCase{ + "StaticQubitsWithDuplicates", nullptr, + MQT_NAMED_BUILDER(mlir::qc::staticQubitsWithDuplicates), + MQT_NAMED_BUILDER(mlir::qc::staticQubits), + MQT_NAMED_BUILDER(mlir::qir::staticQubits), false}, CompilerPipelineTestCase{"AllocQubit", MQT_NAMED_BUILDER(qc::allocQubit), nullptr, MQT_NAMED_BUILDER(mlir::qc::allocQubit), diff --git a/mlir/unittests/Conversion/QCToQIR/test_qc_to_qir.cpp b/mlir/unittests/Conversion/QCToQIR/test_qc_to_qir.cpp index f8825c0dc1..132265f228 100644 --- a/mlir/unittests/Conversion/QCToQIR/test_qc_to_qir.cpp +++ b/mlir/unittests/Conversion/QCToQIR/test_qc_to_qir.cpp @@ -618,7 +618,10 @@ INSTANTIATE_TEST_SUITE_P( MQT_NAMED_BUILDER(qc::allocLargeRegister), MQT_NAMED_BUILDER(qir::emptyQIR)}, QCToQIRTestCase{"StaticQubits", MQT_NAMED_BUILDER(qc::staticQubits), - MQT_NAMED_BUILDER(qir::emptyQIR)}, + MQT_NAMED_BUILDER(qir::staticQubits)}, + QCToQIRTestCase{"StaticQubitsWithDuplicates", + MQT_NAMED_BUILDER(qc::staticQubitsWithDuplicates), + MQT_NAMED_BUILDER(qir::staticQubits)}, QCToQIRTestCase{"AllocDeallocPair", MQT_NAMED_BUILDER(qc::allocDeallocPair), MQT_NAMED_BUILDER(qir::emptyQIR)})); diff --git a/mlir/unittests/Dialect/QC/IR/test_qc_ir.cpp b/mlir/unittests/Dialect/QC/IR/test_qc_ir.cpp index fe8c0abd7a..e1f90f7c30 100644 --- a/mlir/unittests/Dialect/QC/IR/test_qc_ir.cpp +++ b/mlir/unittests/Dialect/QC/IR/test_qc_ir.cpp @@ -893,7 +893,10 @@ INSTANTIATE_TEST_SUITE_P( QCTestCase{"AllocLargeRegister", MQT_NAMED_BUILDER(allocLargeRegister), MQT_NAMED_BUILDER(emptyQC)}, QCTestCase{"StaticQubits", MQT_NAMED_BUILDER(staticQubits), - MQT_NAMED_BUILDER(emptyQC)}, + MQT_NAMED_BUILDER(staticQubits)}, + QCTestCase{"StaticQubitsWithDuplicates", + MQT_NAMED_BUILDER(staticQubitsWithDuplicates), + MQT_NAMED_BUILDER(staticQubits)}, QCTestCase{"AllocDeallocPair", MQT_NAMED_BUILDER(allocDeallocPair), MQT_NAMED_BUILDER(emptyQC)})); /// @} diff --git a/mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp b/mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp index 3220aa753c..0df3151229 100644 --- a/mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp +++ b/mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp @@ -1051,7 +1051,7 @@ INSTANTIATE_TEST_SUITE_P( QCOTestCase{"AllocLargeRegister", MQT_NAMED_BUILDER(allocLargeRegister), MQT_NAMED_BUILDER(emptyQCO)}, QCOTestCase{"StaticQubits", MQT_NAMED_BUILDER(staticQubits), - MQT_NAMED_BUILDER(emptyQCO)}, + MQT_NAMED_BUILDER(staticQubits)}, QCOTestCase{"AllocDeallocPair", MQT_NAMED_BUILDER(allocDeallocPair), MQT_NAMED_BUILDER(emptyQCO)})); /// @} diff --git a/mlir/unittests/Dialect/QIR/IR/test_qir_ir.cpp b/mlir/unittests/Dialect/QIR/IR/test_qir_ir.cpp index f9fdf94ddb..9c26a29fa0 100644 --- a/mlir/unittests/Dialect/QIR/IR/test_qir_ir.cpp +++ b/mlir/unittests/Dialect/QIR/IR/test_qir_ir.cpp @@ -529,5 +529,8 @@ INSTANTIATE_TEST_SUITE_P( MQT_NAMED_BUILDER(allocLargeRegister), MQT_NAMED_BUILDER(allocLargeRegister)}, QIRTestCase{"StaticQubits", MQT_NAMED_BUILDER(staticQubits), + MQT_NAMED_BUILDER(staticQubits)}, + QIRTestCase{"StaticQubitsWithDuplicates", + MQT_NAMED_BUILDER(staticQubitsWithDuplicates), MQT_NAMED_BUILDER(staticQubits)})); /// @} diff --git a/mlir/unittests/programs/qc_programs.cpp b/mlir/unittests/programs/qc_programs.cpp index 2134b1f368..2734918aeb 100644 --- a/mlir/unittests/programs/qc_programs.cpp +++ b/mlir/unittests/programs/qc_programs.cpp @@ -30,8 +30,23 @@ void allocMultipleQubitRegisters(QCProgramBuilder& b) { void allocLargeRegister(QCProgramBuilder& b) { b.allocQubitRegister(100); } void staticQubits(QCProgramBuilder& b) { - b.staticQubit(0); - b.staticQubit(1); + const auto q0 = b.staticQubit(0); + const auto q1 = b.staticQubit(1); + + b.h(q0); + b.h(q1); + b.ctrl(q0, [&] { b.x(q1); }); +} + +void staticQubitsWithDuplicates(QCProgramBuilder& b) { + const auto q0a = b.staticQubit(0); + const auto q1a = b.staticQubit(1); + const auto q0b = b.staticQubit(0); + const auto q1b = b.staticQubit(1); + + b.h(q0a); + b.h(q1a); + b.ctrl(q0b, [&] { b.x(q1b); }); } void allocDeallocPair(QCProgramBuilder& b) { diff --git a/mlir/unittests/programs/qc_programs.h b/mlir/unittests/programs/qc_programs.h index 21225c5b44..da074cb208 100644 --- a/mlir/unittests/programs/qc_programs.h +++ b/mlir/unittests/programs/qc_programs.h @@ -30,9 +30,14 @@ void allocMultipleQubitRegisters(QCProgramBuilder& b); /// Allocates a large qubit register. void allocLargeRegister(QCProgramBuilder& b); -/// Allocates two inline qubits. +/// Allocates two inline qubits and applies H on both and a controlled-X between +/// them. void staticQubits(QCProgramBuilder& b); +/// Allocates duplicate static qubits and applies H on both and a controlled-X +/// between them. +void staticQubitsWithDuplicates(QCProgramBuilder& b); + /// Allocates and explicitly deallocates a single qubit. void allocDeallocPair(QCProgramBuilder& b); diff --git a/mlir/unittests/programs/qco_programs.cpp b/mlir/unittests/programs/qco_programs.cpp index 5c6a42bf1e..4175f30c1a 100644 --- a/mlir/unittests/programs/qco_programs.cpp +++ b/mlir/unittests/programs/qco_programs.cpp @@ -34,8 +34,14 @@ void allocMultipleQubitRegisters(QCOProgramBuilder& b) { void allocLargeRegister(QCOProgramBuilder& b) { b.allocQubitRegister(100); } void staticQubits(QCOProgramBuilder& b) { - b.staticQubit(0); - b.staticQubit(1); + auto q0 = b.staticQubit(0); + auto q1 = b.staticQubit(1); + + q0 = b.h(q0); + q1 = b.h(q1); + b.ctrl({q0}, {q1}, [&](mlir::ValueRange targets) { + return llvm::SmallVector{b.x(targets[0])}; + }); } void allocDeallocPair(QCOProgramBuilder& b) { diff --git a/mlir/unittests/programs/qco_programs.h b/mlir/unittests/programs/qco_programs.h index c0374325b2..c227297fd7 100644 --- a/mlir/unittests/programs/qco_programs.h +++ b/mlir/unittests/programs/qco_programs.h @@ -30,7 +30,8 @@ void allocMultipleQubitRegisters(QCOProgramBuilder& b); /// Allocates a large qubit register. void allocLargeRegister(QCOProgramBuilder& b); -/// Allocates two inline qubits. +/// Allocates two inline qubits and applies H on both and a controlled-X between +/// them. void staticQubits(QCOProgramBuilder& b); /// Allocates and explicitly deallocates a single qubit. diff --git a/mlir/unittests/programs/qir_programs.cpp b/mlir/unittests/programs/qir_programs.cpp index 883cf59af8..dea9cf9864 100644 --- a/mlir/unittests/programs/qir_programs.cpp +++ b/mlir/unittests/programs/qir_programs.cpp @@ -28,8 +28,21 @@ void allocMultipleQubitRegisters(QIRProgramBuilder& b) { void allocLargeRegister(QIRProgramBuilder& b) { b.allocQubitRegister(100); } void staticQubits(QIRProgramBuilder& b) { - b.staticQubit(0); - b.staticQubit(1); + auto q0 = b.staticQubit(0); + auto q1 = b.staticQubit(1); + b.h(q0); + b.h(q1); + b.cx(q0, q1); +} + +void staticQubitsWithDuplicates(QIRProgramBuilder& b) { + auto q0a = b.staticQubit(0); + auto q1a = b.staticQubit(1); + auto q0b = b.staticQubit(0); + auto q1b = b.staticQubit(1); + b.h(q0a); + b.h(q1a); + b.cx(q0b, q1b); } void singleMeasurementToSingleBit(QIRProgramBuilder& b) { diff --git a/mlir/unittests/programs/qir_programs.h b/mlir/unittests/programs/qir_programs.h index f379f19785..767e962464 100644 --- a/mlir/unittests/programs/qir_programs.h +++ b/mlir/unittests/programs/qir_programs.h @@ -30,9 +30,14 @@ void allocMultipleQubitRegisters(QIRProgramBuilder& b); /// Allocates a large qubit register. void allocLargeRegister(QIRProgramBuilder& b); -/// Allocates two inline qubits. +/// Allocates two inline qubits and applies H on both and a controlled-X between +/// them. void staticQubits(QIRProgramBuilder& b); +/// Allocates duplicate static qubits and applies H on both and a controlled-X +/// between them. +void staticQubitsWithDuplicates(QIRProgramBuilder& b); + // --- MeasureOp ------------------------------------------------------------ // /// Measures a single qubit into a single classical bit.