diff --git a/CHANGELOG.md b/CHANGELOG.md index 46f0972a52..a0c3ef4d7b 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], [#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], [#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], [#1602]) ([**@burgholzer**], [**@denialhaag**], [**@taminob**], [**@DRovara**], [**@li-mingbao**], [**@Ectras**], [**@MatthiasReumann**], [**@simon1hofmann**]) ### Changed @@ -347,6 +347,7 @@ _📚 Refer to the [GitHub Release Notes](https://github.com/munich-quantum-tool [#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 +[#1567]: https://github.com/munich-quantum-toolkit/core/pull/1567 [#1565]: https://github.com/munich-quantum-toolkit/core/pull/1565 [#1564]: https://github.com/munich-quantum-toolkit/core/pull/1564 [#1554]: https://github.com/munich-quantum-toolkit/core/pull/1554 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/Dialect/QC/IR/test_qc_ir.cpp b/mlir/unittests/Dialect/QC/IR/test_qc_ir.cpp index 2a58f028e2..d5266d35bf 100644 --- a/mlir/unittests/Dialect/QC/IR/test_qc_ir.cpp +++ b/mlir/unittests/Dialect/QC/IR/test_qc_ir.cpp @@ -914,6 +914,9 @@ INSTANTIATE_TEST_SUITE_P( QCTestCase{"StaticQubitsWithInv", MQT_NAMED_BUILDER(staticQubitsWithInv), MQT_NAMED_BUILDER(staticQubitsWithInv)}, + QCTestCase{"StaticQubitsWithDuplicates", + MQT_NAMED_BUILDER(staticQubitsWithDuplicates), + MQT_NAMED_BUILDER(staticQubitsCanonical)}, QCTestCase{"AllocDeallocPair", MQT_NAMED_BUILDER(allocDeallocPair), MQT_NAMED_BUILDER(emptyQC)})); /// @} diff --git a/mlir/unittests/Dialect/QIR/IR/test_qir_ir.cpp b/mlir/unittests/Dialect/QIR/IR/test_qir_ir.cpp index 66f063b069..9d4b38f9c8 100644 --- a/mlir/unittests/Dialect/QIR/IR/test_qir_ir.cpp +++ b/mlir/unittests/Dialect/QIR/IR/test_qir_ir.cpp @@ -548,5 +548,8 @@ INSTANTIATE_TEST_SUITE_P( MQT_NAMED_BUILDER(staticQubitsWithCtrl)}, QIRTestCase{"StaticQubitsWithInv", MQT_NAMED_BUILDER(staticQubitsWithInv), - MQT_NAMED_BUILDER(staticQubitsWithInv)})); + MQT_NAMED_BUILDER(staticQubitsWithInv)}, + QIRTestCase{"StaticQubitsWithDuplicates", + MQT_NAMED_BUILDER(staticQubitsWithDuplicates), + MQT_NAMED_BUILDER(staticQubitsCanonical)})); /// @} diff --git a/mlir/unittests/programs/qc_programs.cpp b/mlir/unittests/programs/qc_programs.cpp index 7e6acc8b90..6b55fbe957 100644 --- a/mlir/unittests/programs/qc_programs.cpp +++ b/mlir/unittests/programs/qc_programs.cpp @@ -65,6 +65,30 @@ void staticQubitsWithInv(QCProgramBuilder& b) { b.inv([&]() { b.t(q0); }); } +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.rx(std::numbers::pi / 4., q0a); + b.p(std::numbers::pi / 2., q1a); + b.rzz(0.123, q0b, q1b); + b.cx(q0b, q1b); + b.inv([&]() { b.t(q0a); }); +} + +void staticQubitsCanonical(QCProgramBuilder& b) { + const auto q0 = b.staticQubit(0); + const auto q1 = b.staticQubit(1); + + b.rx(std::numbers::pi / 4., q0); + b.p(std::numbers::pi / 2., q1); + b.rzz(0.123, q0, q1); + b.cx(q0, q1); + b.inv([&]() { b.t(q0); }); +} + void allocDeallocPair(QCProgramBuilder& b) { auto q = b.allocQubit(); b.dealloc(q); diff --git a/mlir/unittests/programs/qc_programs.h b/mlir/unittests/programs/qc_programs.h index e48c1c4404..fac185a866 100644 --- a/mlir/unittests/programs/qc_programs.h +++ b/mlir/unittests/programs/qc_programs.h @@ -48,6 +48,13 @@ void staticQubitsWithCtrl(QCProgramBuilder& b); /// Allocates a static qubit and applies an inverse modifier. void staticQubitsWithInv(QCProgramBuilder& b); +/// Allocates duplicate static qubits and applies operations on both. +void staticQubitsWithDuplicates(QCProgramBuilder& b); + +/// Same as `staticQubitsWithDuplicates`, but with canonical static qubit +/// retrievals. +void staticQubitsCanonical(QCProgramBuilder& b); + /// Allocates and explicitly deallocates a single qubit. void allocDeallocPair(QCProgramBuilder& b); diff --git a/mlir/unittests/programs/qir_programs.cpp b/mlir/unittests/programs/qir_programs.cpp index 8674715ca7..82bc0e6d2c 100644 --- a/mlir/unittests/programs/qir_programs.cpp +++ b/mlir/unittests/programs/qir_programs.cpp @@ -65,6 +65,28 @@ void staticQubitsWithInv(QIRProgramBuilder& b) { b.tdg(q0); } +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.rx(std::numbers::pi / 4., q0a); + b.p(std::numbers::pi / 2., q1a); + b.rzz(0.123, q0b, q1b); + b.cx(q0b, q1b); + b.tdg(q0a); +} + +void staticQubitsCanonical(QIRProgramBuilder& b) { + auto q0 = b.staticQubit(0); + auto q1 = b.staticQubit(1); + b.rx(std::numbers::pi / 4., q0); + b.p(std::numbers::pi / 2., q1); + b.rzz(0.123, q0, q1); + b.cx(q0, q1); + b.tdg(q0); +} + void singleMeasurementToSingleBit(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(1); const auto c = b.allocClassicalBitRegister(1); diff --git a/mlir/unittests/programs/qir_programs.h b/mlir/unittests/programs/qir_programs.h index 927a935286..2b9e591432 100644 --- a/mlir/unittests/programs/qir_programs.h +++ b/mlir/unittests/programs/qir_programs.h @@ -48,6 +48,13 @@ void staticQubitsWithCtrl(QIRProgramBuilder& b); /// Allocates a static qubit and applies the inverse of a T gate (Tdg). void staticQubitsWithInv(QIRProgramBuilder& b); +/// Allocates duplicate static qubits and applies operations on both. +void staticQubitsWithDuplicates(QIRProgramBuilder& b); + +/// Same as `staticQubitsWithDuplicates`, but with canonical static qubit +/// retrievals. +void staticQubitsCanonical(QIRProgramBuilder& b); + // --- MeasureOp ------------------------------------------------------------ // /// Measures a single qubit into a single classical bit.