diff --git a/mlir/include/mlir/CMakeLists.txt b/mlir/include/mlir/CMakeLists.txt index 385d04e35..9add328fe 100644 --- a/mlir/include/mlir/CMakeLists.txt +++ b/mlir/include/mlir/CMakeLists.txt @@ -7,3 +7,4 @@ # Licensed under the MIT License add_subdirectory(Dialect) +add_subdirectory(Conversion) diff --git a/mlir/include/mlir/Conversion/CMakeLists.txt b/mlir/include/mlir/Conversion/CMakeLists.txt new file mode 100644 index 000000000..f9a1f2c4b --- /dev/null +++ b/mlir/include/mlir/Conversion/CMakeLists.txt @@ -0,0 +1,10 @@ +# Copyright (c) 2023 - 2025 Chair for Design Automation, TUM +# Copyright (c) 2025 Munich Quantum Software Company GmbH +# All rights reserved. +# +# SPDX-License-Identifier: MIT +# +# Licensed under the MIT License + +add_subdirectory(MQTDynToMQTOpt) +add_subdirectory(MQTOptToMQTDyn) diff --git a/mlir/include/mlir/Conversion/MQTDynToMQTOpt/CMakeLists.txt b/mlir/include/mlir/Conversion/MQTDynToMQTOpt/CMakeLists.txt new file mode 100644 index 000000000..0307bd820 --- /dev/null +++ b/mlir/include/mlir/Conversion/MQTDynToMQTOpt/CMakeLists.txt @@ -0,0 +1,13 @@ +# Copyright (c) 2023 - 2025 Chair for Design Automation, TUM +# Copyright (c) 2025 Munich Quantum Software Company GmbH +# All rights reserved. +# +# SPDX-License-Identifier: MIT +# +# Licensed under the MIT License + +set(LLVM_TARGET_DEFINITIONS MQTDynToMQTOpt.td) +mlir_tablegen(MQTDynToMQTOpt.h.inc -gen-pass-decls -name MQTDynToMQTOpt) +add_public_tablegen_target(MQTDynToMQTOptIncGen) + +add_mlir_doc(MQTDynToMQTOpt MLIRMQTDynToMQTOpt Conversions/ -gen-pass-doc) diff --git a/mlir/include/mlir/Conversion/MQTDynToMQTOpt/MQTDynToMQTOpt.h b/mlir/include/mlir/Conversion/MQTDynToMQTOpt/MQTDynToMQTOpt.h new file mode 100644 index 000000000..83c798371 --- /dev/null +++ b/mlir/include/mlir/Conversion/MQTDynToMQTOpt/MQTDynToMQTOpt.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023 - 2025 Chair for Design Automation, TUM + * Copyright (c) 2025 Munich Quantum Software Company GmbH + * All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * Licensed under the MIT License + */ + +#pragma once + +#include // from @llvm-project + +namespace mqt::ir { + +#define GEN_PASS_DECL +#include "mlir/Conversion/MQTDynToMQTOpt/MQTDynToMQTOpt.h.inc" + +#define GEN_PASS_REGISTRATION +#include "mlir/Conversion/MQTDynToMQTOpt/MQTDynToMQTOpt.h.inc" + +} // namespace mqt::ir diff --git a/mlir/include/mlir/Conversion/MQTDynToMQTOpt/MQTDynToMQTOpt.td b/mlir/include/mlir/Conversion/MQTDynToMQTOpt/MQTDynToMQTOpt.td new file mode 100644 index 000000000..31a93f1b3 --- /dev/null +++ b/mlir/include/mlir/Conversion/MQTDynToMQTOpt/MQTDynToMQTOpt.td @@ -0,0 +1,28 @@ +// Copyright (c) 2023 - 2025 Chair for Design Automation, TUM +// Copyright (c) 2025 Munich Quantum Software Company GmbH +// All rights reserved. +// +// SPDX-License-Identifier: MIT +// +// Licensed under the MIT License + +include "mlir/Pass/PassBase.td" + +def MQTDynToMQTOpt : Pass<"mqtdyn-to-mqtopt"> { + let summary = "Convert MQT's `MQTDyn` to MQT's `MQTOpt` dialect."; + + let description = [{ + This pass converts all current mqtdyn operations to an equivalent mqtopt operation. + To convert them to the opt dialect, the conversion pass keeps an updated map that tracks each dyn qubit + and dyn qubit register to its latest state value when replacing them with an opt operation. These state values + are obtained by updating the map with the return values of the newly created opt operations. The mqtopt insert + operation is added when matching the dealloc operation of any qubit register. A mqtopt insert operation is then + created for each qubit that was extracted from the qubit register and placed before the dealloc operation. + }]; + + // Define dependent dialects + let dependentDialects = [ + "::mqt::ir::dyn::MQTDynDialect", + "::mqt::ir::opt::MQTOptDialect" + ]; +} diff --git a/mlir/include/mlir/Conversion/MQTOptToMQTDyn/CMakeLists.txt b/mlir/include/mlir/Conversion/MQTOptToMQTDyn/CMakeLists.txt new file mode 100644 index 000000000..7acac489b --- /dev/null +++ b/mlir/include/mlir/Conversion/MQTOptToMQTDyn/CMakeLists.txt @@ -0,0 +1,13 @@ +# Copyright (c) 2023 - 2025 Chair for Design Automation, TUM +# Copyright (c) 2025 Munich Quantum Software Company GmbH +# All rights reserved. +# +# SPDX-License-Identifier: MIT +# +# Licensed under the MIT License + +set(LLVM_TARGET_DEFINITIONS MQTOptToMQTDyn.td) +mlir_tablegen(MQTOptToMQTDyn.h.inc -gen-pass-decls -name MQTOptToMQTDyn) +add_public_tablegen_target(MQTOptToMQTDynIncGen) + +add_mlir_doc(MQTOptToMQTDyn MQTOptToMQTDyn Conversions/ -gen-pass-doc) diff --git a/mlir/include/mlir/Conversion/MQTOptToMQTDyn/MQTOptToMQTDyn.h b/mlir/include/mlir/Conversion/MQTOptToMQTDyn/MQTOptToMQTDyn.h new file mode 100644 index 000000000..50ff1cf3e --- /dev/null +++ b/mlir/include/mlir/Conversion/MQTOptToMQTDyn/MQTOptToMQTDyn.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023 - 2025 Chair for Design Automation, TUM + * Copyright (c) 2025 Munich Quantum Software Company GmbH + * All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * Licensed under the MIT License + */ + +#pragma once + +#include // from @llvm-project + +namespace mqt::ir { + +#define GEN_PASS_DECL +#include "mlir/Conversion/MQTOptToMQTDyn/MQTOptToMQTDyn.h.inc" + +#define GEN_PASS_REGISTRATION +#include "mlir/Conversion/MQTOptToMQTDyn/MQTOptToMQTDyn.h.inc" + +} // namespace mqt::ir diff --git a/mlir/include/mlir/Conversion/MQTOptToMQTDyn/MQTOptToMQTDyn.td b/mlir/include/mlir/Conversion/MQTOptToMQTDyn/MQTOptToMQTDyn.td new file mode 100644 index 000000000..7fc32969d --- /dev/null +++ b/mlir/include/mlir/Conversion/MQTOptToMQTDyn/MQTOptToMQTDyn.td @@ -0,0 +1,28 @@ +// Copyright (c) 2023 - 2025 Chair for Design Automation, TUM +// Copyright (c) 2025 Munich Quantum Software Company GmbH +// All rights reserved. +// +// SPDX-License-Identifier: MIT +// +// Licensed under the MIT License + +include "mlir/Pass/PassBase.td" + +def MQTOptToMQTDyn : Pass<"mqtopt-to-mqtdyn"> { + let summary = "Convert MQT's `MQTOpt` to MQT's `MQTDyn` dialect."; + + let description = [{ + This pass converts all current mqtopt operations to an equivalent mqtdyn operation. + The result of the converted mqtdyn alloc operation acts as a qubit register reference and replaces the operand of the operation + that uses the initial mqtopt qubit register. This reference is then propagated to all subsequent operations that use the state + of the initial mqtopt register and replaces their operand. The same applies to the result of the extract operation that acts as a qubit + reference and is propagated to all later uses of this qubit. The mqtopt insert operation is deleted as there is no equivalent + operation in the mqtdyn dialect and any subsequent operation that uses the result of this operation acts on the qubit register reference. + }]; + + // Define dependent dialects + let dependentDialects = [ + "::mqt::ir::dyn::MQTDynDialect", + "::mqt::ir::opt::MQTOptDialect" + ]; +} diff --git a/mlir/lib/CMakeLists.txt b/mlir/lib/CMakeLists.txt index 385d04e35..9add328fe 100644 --- a/mlir/lib/CMakeLists.txt +++ b/mlir/lib/CMakeLists.txt @@ -7,3 +7,4 @@ # Licensed under the MIT License add_subdirectory(Dialect) +add_subdirectory(Conversion) diff --git a/mlir/lib/Conversion/CMakeLists.txt b/mlir/lib/Conversion/CMakeLists.txt new file mode 100644 index 000000000..0de4ace2e --- /dev/null +++ b/mlir/lib/Conversion/CMakeLists.txt @@ -0,0 +1,10 @@ +# Copyright (c) 2023 - 2025 Chair for Design Automation, TUM +# Copyright (c) 2025 Munich Quantum Software Company GmbH +# All rights reserved. +# +# SPDX-License-Identifier: MIT +# +# Licensed under the MIT License + +add_subdirectory(MQTOptToMQTDyn) +add_subdirectory(MQTDynToMQTOpt) diff --git a/mlir/lib/Conversion/MQTDynToMQTOpt/CMakeLists.txt b/mlir/lib/Conversion/MQTDynToMQTOpt/CMakeLists.txt new file mode 100644 index 000000000..2b294a690 --- /dev/null +++ b/mlir/lib/Conversion/MQTDynToMQTOpt/CMakeLists.txt @@ -0,0 +1,16 @@ +# Copyright (c) 2023 - 2025 Chair for Design Automation, TUM +# Copyright (c) 2025 Munich Quantum Software Company GmbH +# All rights reserved. +# +# SPDX-License-Identifier: MIT +# +# Licensed under the MIT License + +get_property(CONVERSION_LIBS GLOBAL PROPERTY MLIR_CONVERSION_LIBS) +list(APPEND CONVERSION_LIBS MQT::CoreIR) +add_compile_options(-fexceptions) + +file(GLOB CONVERSION_SOURCES *.cpp) + +add_mlir_library(MQTDynToMQTOpt ${CONVERSION_SOURCES} LINK_LIBS ${LIBRARIES} DEPENDS + MQTDynToMQTOptIncGen) diff --git a/mlir/lib/Conversion/MQTDynToMQTOpt/MQTDynToMQTOpt.cpp b/mlir/lib/Conversion/MQTDynToMQTOpt/MQTDynToMQTOpt.cpp new file mode 100644 index 000000000..d5655c0e1 --- /dev/null +++ b/mlir/lib/Conversion/MQTDynToMQTOpt/MQTDynToMQTOpt.cpp @@ -0,0 +1,469 @@ +/* + * Copyright (c) 2023 - 2025 Chair for Design Automation, TUM + * Copyright (c) 2025 Munich Quantum Software Company GmbH + * All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * Licensed under the MIT License + */ + +// macro to add the conversion pattern from any dyn gate operation to the same +// gate operation in the opt dialect +#define ADD_CONVERT_PATTERN(gate) \ + patterns \ + .add>( \ + typeConverter, context, qubitMap); + +#include "mlir/Conversion/MQTDynToMQTOpt/MQTDynToMQTOpt.h" + +#include "mlir/Dialect/Func/IR/FuncOps.h" +#include "mlir/Dialect/Func/Transforms/FuncConversions.h" +#include "mlir/Dialect/MQTDyn/IR/MQTDynDialect.h" +#include "mlir/Dialect/MQTOpt/IR/MQTOptDialect.h" +#include "mlir/IR/ValueRange.h" + +#include "llvm/ADT/DenseMap.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace mqt::ir { + +using namespace mlir; + +#define GEN_PASS_DEF_MQTDYNTOMQTOPT +#include + +namespace { +// struct to store the metadata for qubits +struct QubitData { + // dyn register from where the qubit was extracted + Value qReg; + // index given as a value + Value index; + // index given as an attribute + IntegerAttr indexAttr; + QubitData(Value qReg, Value index, IntegerAttr indexAttr) + : qReg(qReg), index(index), indexAttr(indexAttr) {} + QubitData() = default; +}; +} // namespace + +class MQTDynToMQTOptTypeConverter : public TypeConverter { +public: + explicit MQTDynToMQTOptTypeConverter(MLIRContext* ctx) { + // Identity conversion + addConversion([](Type type) { return type; }); + + // QubitType conversion + addConversion([ctx](dyn::QubitType /*type*/) -> Type { + return opt::QubitType::get(ctx); + }); + + // QregType conversion + addConversion([ctx](dyn::QubitRegisterType /*type*/) -> Type { + return opt::QubitRegisterType::get(ctx); + }); + } +}; + +struct ConvertMQTDynAlloc : public OpConversionPattern { + llvm::DenseMap& + qregMap; // NOLINT(*-avoid-const-or-ref-data-members) + + explicit ConvertMQTDynAlloc(TypeConverter& typeConverter, + MLIRContext* context, + llvm::DenseMap& qregMap) + : OpConversionPattern(typeConverter, context), + qregMap(qregMap) {} + + LogicalResult + matchAndRewrite(dyn::AllocOp op, OpAdaptor /*adaptor*/, + ConversionPatternRewriter& rewriter) const override { + // create result type + const auto qregType = opt::QubitRegisterType::get(rewriter.getContext()); + + // create new operation + auto mqtoptOp = rewriter.create( + op.getLoc(), qregType, op.getSize(), op.getSizeAttrAttr()); + + const auto dynQreg = op.getQreg(); + const auto optQreg = mqtoptOp.getQreg(); + + // put the pair of the dyn register and the latest opt register in the map + qregMap.try_emplace(dynQreg, optQreg); + + // replace the old register use with the new register otherwise + // there will be an unrealized conversion + rewriter.replaceOp(op, optQreg); + + return success(); + } +}; + +struct ConvertMQTDynDealloc : public OpConversionPattern { + + llvm::DenseMap& + qubitMap; // NOLINT(*-avoid-const-or-ref-data-members) + llvm::DenseMap& + qubitDataMap; // NOLINT(*-avoid-const-or-ref-data-members) + llvm::DenseMap& + qregMap; // NOLINT(*-avoid-const-or-ref-data-members) + llvm::DenseMap>& + qregQubitsMap; // NOLINT(*-avoid-const-or-ref-data-members) + + explicit ConvertMQTDynDealloc( + TypeConverter& typeConverter, MLIRContext* context, + llvm::DenseMap& qubitMap, + llvm::DenseMap& qubitDataMap, + llvm::DenseMap& qregMap, + llvm::DenseMap>& qregQubitsMap) + : OpConversionPattern(typeConverter, context), + qubitMap(qubitMap), qubitDataMap(qubitDataMap), qregMap(qregMap), + qregQubitsMap(qregQubitsMap) {} + + LogicalResult + matchAndRewrite(dyn::DeallocOp op, OpAdaptor /*adaptor*/, + ConversionPatternRewriter& rewriter) const override { + + // prepare return type + const auto qregType = opt::QubitRegisterType::get(rewriter.getContext()); + + const auto dynQreg = op.getQreg(); + auto optQreg = qregMap[dynQreg]; + + // iterate over all the qubits that were extracted from the register + for (const auto& dynQubit : qregQubitsMap[dynQreg]) { + const auto& qubitData = qubitDataMap[dynQubit]; + const auto& optQubit = qubitMap[dynQubit]; + + auto optInsertOp = rewriter.create( + op.getLoc(), qregType, optQreg, optQubit, qubitData.index, + qubitData.indexAttr); + + // move it before the current dealloc operation + optInsertOp->moveBefore(op); + + // update the optQreg + optQreg = optInsertOp.getOutQreg(); + + // erase the dynQubit entry from the maps + qubitMap.erase(dynQubit); + qubitDataMap.erase(dynQubit); + } + + // create the new dealloc operation + rewriter.create(op.getLoc(), optQreg); + + // erase the register from the maps + qregMap.erase(dynQreg); + qregQubitsMap.erase(dynQreg); + + // erase old operation + rewriter.eraseOp(op); + + return success(); + } +}; + +struct ConvertMQTDynExtract : public OpConversionPattern { + llvm::DenseMap& + qubitMap; // NOLINT(*-avoid-const-or-ref-data-members) + llvm::DenseMap& + qubitDataMap; // NOLINT(*-avoid-const-or-ref-data-members) + llvm::DenseMap& + qregMap; // NOLINT(*-avoid-const-or-ref-data-members) + llvm::DenseMap>& + qregQubitsMap; // NOLINT(*-avoid-const-or-ref-data-members) + + explicit ConvertMQTDynExtract( + TypeConverter& typeConverter, MLIRContext* context, + llvm::DenseMap& qubitMap, + llvm::DenseMap& qubitDataMap, + llvm::DenseMap& qregMap, + llvm::DenseMap>& qregQubitsMap) + : OpConversionPattern(typeConverter, context), + qubitMap(qubitMap), qubitDataMap(qubitDataMap), qregMap(qregMap), + qregQubitsMap(qregQubitsMap) {} + + LogicalResult + matchAndRewrite(dyn::ExtractOp op, OpAdaptor /*adaptor*/, + ConversionPatternRewriter& rewriter) const override { + + // create result types + const auto qregType = opt::QubitRegisterType::get(rewriter.getContext()); + const auto qubitType = opt::QubitType::get(rewriter.getContext()); + + const auto dynQreg = op.getInQreg(); + const auto& optQreg = qregMap[dynQreg]; + + // create new operation + auto mqtoptOp = rewriter.create( + op.getLoc(), qregType, qubitType, optQreg, op.getIndex(), + op.getIndexAttrAttr()); + + const auto dynQubit = op.getOutQubit(); + const auto optQubit = mqtoptOp.getOutQubit(); + const auto newOptQreg = mqtoptOp.getOutQreg(); + + // put the pair of the dyn qubit and the latest opt qubit in the map + qubitMap.try_emplace(dynQubit, optQubit); + + // update the latest opt register of the initial dyn register + qregMap[dynQreg] = newOptQreg; + + // add an entry to the qubitDataMap to store the indices and the register + // for the insertOperation + qubitDataMap.try_emplace( + dynQubit, QubitData(dynQreg, op.getIndex(), op.getIndexAttrAttr())); + + // append the entry to the qregQubitsMap to store which qubits that were + // extracted from the register + qregQubitsMap[dynQreg].emplace_back(dynQubit); + + // replace the old operation result with the new qubit otherwise there will + // be an unrealized conversion + rewriter.replaceOp(op, optQubit); + + return success(); + } +}; + +struct ConvertMQTDynMeasure : public OpConversionPattern { + llvm::DenseMap& + qubitMap; // NOLINT(*-avoid-const-or-ref-data-members) + + explicit ConvertMQTDynMeasure(TypeConverter& typeConverter, + MLIRContext* context, + llvm::DenseMap& qubitMap) + : OpConversionPattern(typeConverter, context), + qubitMap(qubitMap) {} + + LogicalResult + matchAndRewrite(dyn::MeasureOp op, OpAdaptor /*adaptor*/, + ConversionPatternRewriter& rewriter) const override { + + // prepare result type + const auto qubitType = opt::QubitType::get(rewriter.getContext()); + + const auto dynQubits = op.getInQubits(); + + std::vector optQubits; + std::vector qubitTypes; + // get the latest opt qubit from the map and add them and their type to the + // vectors + for (auto dynQubit : dynQubits) { + optQubits.emplace_back(qubitMap[dynQubit]); + qubitTypes.emplace_back(qubitType); + } + + // create new operation + auto mqtoptOp = rewriter.create( + op.getLoc(), qubitTypes, op.getOutBits().getTypes(), optQubits); + + const auto outOptQubits = mqtoptOp.getOutQubits(); + const auto oldBits = op.getOutBits(); + const auto newBits = mqtoptOp.getOutBits(); + + // iterate over all qubits and bits + for (size_t i = 0; i < dynQubits.size(); i++) { + + // update the latest opt qubit of the initial dyn qubit + qubitMap[dynQubits[i]] = outOptQubits[i]; + + const auto& oldBit = oldBits[i]; + const auto& newBit = newBits[i]; + + // update the operand of the previous bit users + for (auto* user : oldBit.getUsers()) { + // Only consider operations after the current operation + if (!user->isBeforeInBlock(mqtoptOp) && user != mqtoptOp && + user != op) { + user->replaceUsesOfWith(oldBit, newBit); + } + } + } + + // erase old operation + rewriter.eraseOp(op); + + return success(); + } +}; + +template +struct ConvertMQTDynGateOp : public OpConversionPattern { + llvm::DenseMap& + qubitMap; // NOLINT(*-avoid-const-or-ref-data-members) + + explicit ConvertMQTDynGateOp(TypeConverter& typeConverter, + MLIRContext* context, + llvm::DenseMap& qubitMap) + : OpConversionPattern(typeConverter, context), + qubitMap(qubitMap) {} + + LogicalResult + matchAndRewrite(MQTGateDynOp op, typename MQTGateDynOp::Adaptor /*adaptor*/, + ConversionPatternRewriter& rewriter) const override { + + // get all the input qubits including the ctrl qubits + const auto dynInQubitsValues = op.getInQubits(); + const auto dynPosCtrlQubitsValues = op.getPosCtrlInQubits(); + const auto dynNegCtrlQubitsValues = op.getNegCtrlInQubits(); + const auto dynAllQubits = op.getAllInQubits(); + + // get the latest opt qubit of all dyn input qubits + std::vector optInQubits; + std::vector optPosCtrlQubitsValues; + std::vector optNegCtrlQubitsValues; + + for (auto dynQubit : dynInQubitsValues) { + optInQubits.emplace_back(qubitMap[dynQubit]); + } + for (auto dynQubit : dynPosCtrlQubitsValues) { + optPosCtrlQubitsValues.emplace_back(qubitMap[dynQubit]); + } + for (auto dynQubit : dynNegCtrlQubitsValues) { + optNegCtrlQubitsValues.emplace_back(qubitMap[dynQubit]); + } + + // get the static params and paramMask if they exist + DenseF64ArrayAttr staticParams = nullptr; + if (auto optionalParams = op.getStaticParams()) { + staticParams = + DenseF64ArrayAttr::get(rewriter.getContext(), optionalParams.value()); + } else { + staticParams = DenseF64ArrayAttr{}; + } + DenseBoolArrayAttr paramMask = nullptr; + if (auto optionalMask = op.getParamsMask()) { + paramMask = + DenseBoolArrayAttr::get(rewriter.getContext(), optionalMask.value()); + } else { + paramMask = DenseBoolArrayAttr{}; + } + + // create new operation + auto mqtoptOp = rewriter.create( + op.getLoc(), ValueRange(optInQubits).getTypes(), + ValueRange(optPosCtrlQubitsValues).getTypes(), + ValueRange(optNegCtrlQubitsValues).getTypes(), staticParams, paramMask, + op.getParams(), optInQubits, optPosCtrlQubitsValues, + optNegCtrlQubitsValues); + + const auto optResults = mqtoptOp.getAllOutQubits(); + // iterate over all the dyn input qubits and update their latest opt qubit + for (size_t i = 0; i < dynAllQubits.size(); i++) { + const auto& dynQubit = dynAllQubits[i]; + qubitMap[dynQubit] = optResults[i]; + } + + // erase the old operation + rewriter.eraseOp(op); + + return success(); + } +}; + +struct MQTDynToMQTOpt : impl::MQTDynToMQTOptBase { + using MQTDynToMQTOptBase::MQTDynToMQTOptBase; + + // map each initial dyn qubit to its latest opt qubit + llvm::DenseMap qubitMap; + // map each initial dyn qubit to its metadata + llvm::DenseMap qubitDataMap; + // map each initial dyn register to its latest opt register + llvm::DenseMap qregMap; + // map each initial dyn register to its dynQubits + llvm::DenseMap> qregQubitsMap; + + void runOnOperation() override { + MLIRContext* context = &getContext(); + auto* module = getOperation(); + + ConversionTarget target(*context); + RewritePatternSet patterns(context); + MQTDynToMQTOptTypeConverter typeConverter(context); + + target.addIllegalDialect(); + target.addLegalDialect(); + patterns.add(typeConverter, context, qregMap); + patterns.add(typeConverter, context, qubitMap, + qubitDataMap, qregMap, qregQubitsMap); + patterns.add(typeConverter, context, qubitMap, + qubitDataMap, qregMap, qregQubitsMap); + patterns.add(typeConverter, context, qubitMap); + + ADD_CONVERT_PATTERN(GPhaseOp) + ADD_CONVERT_PATTERN(IOp) + ADD_CONVERT_PATTERN(BarrierOp) + ADD_CONVERT_PATTERN(HOp) + ADD_CONVERT_PATTERN(XOp) + ADD_CONVERT_PATTERN(YOp) + ADD_CONVERT_PATTERN(ZOp) + ADD_CONVERT_PATTERN(SOp) + ADD_CONVERT_PATTERN(SdgOp) + ADD_CONVERT_PATTERN(TOp) + ADD_CONVERT_PATTERN(TdgOp) + ADD_CONVERT_PATTERN(VOp) + ADD_CONVERT_PATTERN(VdgOp) + ADD_CONVERT_PATTERN(UOp) + ADD_CONVERT_PATTERN(U2Op) + ADD_CONVERT_PATTERN(POp) + ADD_CONVERT_PATTERN(SXOp) + ADD_CONVERT_PATTERN(SXdgOp) + ADD_CONVERT_PATTERN(RXOp) + ADD_CONVERT_PATTERN(RYOp) + ADD_CONVERT_PATTERN(RZOp) + ADD_CONVERT_PATTERN(SWAPOp) + ADD_CONVERT_PATTERN(iSWAPOp) + ADD_CONVERT_PATTERN(iSWAPdgOp) + ADD_CONVERT_PATTERN(PeresOp) + ADD_CONVERT_PATTERN(PeresdgOp) + ADD_CONVERT_PATTERN(DCXOp) + ADD_CONVERT_PATTERN(ECROp) + ADD_CONVERT_PATTERN(RXXOp) + ADD_CONVERT_PATTERN(RYYOp) + ADD_CONVERT_PATTERN(RZZOp) + ADD_CONVERT_PATTERN(RZXOp) + ADD_CONVERT_PATTERN(XXminusYY) + ADD_CONVERT_PATTERN(XXplusYY) + + // conversion of mqtopt types in func.func signatures + // does not work for now as signature needs to be changed + populateFunctionOpInterfaceTypeConversionPattern( + patterns, typeConverter); + target.addDynamicallyLegalOp([&](func::FuncOp op) { + return typeConverter.isSignatureLegal(op.getFunctionType()) && + typeConverter.isLegal(&op.getBody()); + }); + // conversion of mqtdyn types in func.return + populateReturnOpTypeConversionPattern(patterns, typeConverter); + target.addDynamicallyLegalOp( + [&](func::ReturnOp op) { return typeConverter.isLegal(op); }); + + // conversion of mqtdyn types in func.call + populateCallOpTypeConversionPattern(patterns, typeConverter); + target.addDynamicallyLegalOp( + [&](func::CallOp op) { return typeConverter.isLegal(op); }); + + // conversion of mqtdyn types in control-flow ops; e.g. cf.br + populateBranchOpInterfaceTypeConversionPattern(patterns, typeConverter); + if (failed(applyPartialConversion(module, target, std::move(patterns)))) { + signalPassFailure(); + } + }; +}; + +} // namespace mqt::ir diff --git a/mlir/lib/Conversion/MQTOptToMQTDyn/CMakeLists.txt b/mlir/lib/Conversion/MQTOptToMQTDyn/CMakeLists.txt new file mode 100644 index 000000000..c98472a47 --- /dev/null +++ b/mlir/lib/Conversion/MQTOptToMQTDyn/CMakeLists.txt @@ -0,0 +1,16 @@ +# Copyright (c) 2023 - 2025 Chair for Design Automation, TUM +# Copyright (c) 2025 Munich Quantum Software Company GmbH +# All rights reserved. +# +# SPDX-License-Identifier: MIT +# +# Licensed under the MIT License + +get_property(CONVERSION_LIBS GLOBAL PROPERTY MLIR_CONVERSION_LIBS) +list(APPEND CONVERSION_LIBS MQT::CoreIR) +add_compile_options(-fexceptions) + +file(GLOB CONVERSION_SOURCES *.cpp) + +add_mlir_library(MQTOptToMQTDyn ${CONVERSION_SOURCES} LINK_LIBS ${LIBRARIES} DEPENDS + MQTOptToMQTDynIncGen) diff --git a/mlir/lib/Conversion/MQTOptToMQTDyn/MQTOptToMQTDyn.cpp b/mlir/lib/Conversion/MQTOptToMQTDyn/MQTOptToMQTDyn.cpp new file mode 100644 index 000000000..455260877 --- /dev/null +++ b/mlir/lib/Conversion/MQTOptToMQTDyn/MQTOptToMQTDyn.cpp @@ -0,0 +1,340 @@ +/* + * Copyright (c) 2023 - 2025 Chair for Design Automation, TUM + * Copyright (c) 2025 Munich Quantum Software Company GmbH + * All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * Licensed under the MIT License + */ + +// macro to add the conversion pattern from any opt gate operation to the same +// gate operation in the dyn dialect +#define ADD_CONVERT_PATTERN(gate) \ + patterns \ + .add>( \ + typeConverter, context); + +#include "mlir/Conversion/MQTOptToMQTDyn/MQTOptToMQTDyn.h" + +#include "mlir/Dialect/Func/IR/FuncOps.h" +#include "mlir/Dialect/Func/Transforms/FuncConversions.h" +#include "mlir/Dialect/MQTDyn/IR/MQTDynDialect.h" +#include "mlir/Dialect/MQTOpt/IR/MQTOptDialect.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace mqt::ir { + +using namespace mlir; + +#define GEN_PASS_DEF_MQTOPTTOMQTDYN +#include + +class MQTOptToMQTDynTypeConverter : public TypeConverter { +public: + explicit MQTOptToMQTDynTypeConverter(MLIRContext* ctx) { + // Identity conversion + addConversion([](Type type) { return type; }); + + // QubitType conversion + addConversion([ctx](opt::QubitType /*type*/) -> Type { + return dyn::QubitType::get(ctx); + }); + + // QregType conversion + addConversion([ctx](opt::QubitRegisterType /*type*/) -> Type { + return dyn::QubitRegisterType::get(ctx); + }); + } +}; + +struct ConvertMQTOptAlloc : public OpConversionPattern { + using OpConversionPattern::OpConversionPattern; + + LogicalResult + matchAndRewrite(opt::AllocOp op, OpAdaptor adaptor, + ConversionPatternRewriter& rewriter) const override { + // create result type + const auto qregType = dyn::QubitRegisterType::get(rewriter.getContext()); + + // create new operation + auto mqtdynOp = rewriter.create( + op.getLoc(), qregType, adaptor.getSize(), adaptor.getSizeAttrAttr()); + + const auto optQreg = op.getQreg(); + const auto dynQreg = mqtdynOp.getQreg(); + + // update the operands of the opt register user + (*optQreg.getUsers().begin())->replaceUsesOfWith(optQreg, dynQreg); + + // erase the old operation + rewriter.eraseOp(op); + + return success(); + } +}; + +struct ConvertMQTOptDealloc : public OpConversionPattern { + using OpConversionPattern::OpConversionPattern; + + LogicalResult + matchAndRewrite(opt::DeallocOp op, OpAdaptor adaptor, + ConversionPatternRewriter& rewriter) const override { + // create new operation + auto mqtdynOp = + rewriter.create(op.getLoc(), adaptor.getQreg()); + + // replace old operation with new operation + rewriter.replaceOp(op, mqtdynOp); + + return success(); + } +}; + +struct ConvertMQTOptExtract : public OpConversionPattern { + using OpConversionPattern::OpConversionPattern; + + LogicalResult + matchAndRewrite(opt::ExtractOp op, OpAdaptor adaptor, + ConversionPatternRewriter& rewriter) const override { + // create result type + const auto qubitType = dyn::QubitType::get(rewriter.getContext()); + + const auto dynQreg = adaptor.getInQreg(); + + // create new operation + auto mqtdynOp = rewriter.create(op.getLoc(), qubitType, + dynQreg, adaptor.getIndex(), + adaptor.getIndexAttrAttr()); + + const auto optQubit = op.getOutQubit(); + const auto dynQubit = mqtdynOp.getOutQubit(); + const auto optQreg = op.getOutQreg(); + + // update the operands of the opt users + (*optQubit.getUsers().begin())->replaceUsesOfWith(optQubit, dynQubit); + (*optQreg.getUsers().begin())->replaceUsesOfWith(optQreg, dynQreg); + + // erase old operation + rewriter.eraseOp(op); + + return success(); + } +}; + +struct ConvertMQTOptInsert : public OpConversionPattern { + using OpConversionPattern::OpConversionPattern; + + LogicalResult + matchAndRewrite(opt::InsertOp op, OpAdaptor adaptor, + ConversionPatternRewriter& rewriter) const override { + + const auto optQreg = op.getOutQreg(); + const auto dynQreg = adaptor.getInQreg(); + + // update the operands of the opt register users + (*optQreg.getUsers().begin())->replaceUsesOfWith(optQreg, dynQreg); + + // erase old operation + rewriter.eraseOp(op); + + return success(); + } +}; + +struct ConvertMQTOptMeasure : public OpConversionPattern { + using OpConversionPattern::OpConversionPattern; + + LogicalResult + matchAndRewrite(opt::MeasureOp op, OpAdaptor adaptor, + ConversionPatternRewriter& rewriter) const override { + + const auto oldBits = op.getOutBits(); + const auto dynQubits = adaptor.getInQubits(); + const auto optQubits = op.getOutQubits(); + + // create new operation + auto mqtdynOp = rewriter.create( + op.getLoc(), oldBits.getTypes(), dynQubits); + + const auto newBits = mqtdynOp.getOutBits(); + + // iterate over the qubits and bits + for (size_t i = 0; i < optQubits.size(); i++) { + const auto& dynQubit = dynQubits[i]; + const auto& optQubit = optQubits[i]; + const auto& oldBit = oldBits[i]; + const auto& newBit = newBits[i]; + + // update the operands of the opt qubit user + (*optQubit.getUsers().begin())->replaceUsesOfWith(optQubit, dynQubit); + + const std::vector bitUsers(oldBit.getUsers().begin(), + oldBit.getUsers().end()); + // iterate over the users of the old bit and replace the old bit with the + // new bit + for (auto* user : bitUsers) { + user->replaceUsesOfWith(oldBit, newBit); + } + } + + // erase the previous operation + rewriter.eraseOp(op); + + return success(); + } +}; + +template +struct ConvertMQTOptGateOp : public OpConversionPattern { + using OpConversionPattern::OpConversionPattern; + + LogicalResult + matchAndRewrite(MQTGateOptOp op, typename MQTGateOptOp::Adaptor adaptor, + ConversionPatternRewriter& rewriter) const override { + // get all the input qubits including the ctrl qubits + const auto dynInQubitsValues = adaptor.getInQubits(); + const auto dynPosCtrlQubitsValues = adaptor.getPosCtrlInQubits(); + const auto dynNegCtrlQubitsValues = adaptor.getNegCtrlInQubits(); + + // append them to a single vector + std::vector allDynInputQubits(dynInQubitsValues.begin(), + dynInQubitsValues.end()); + allDynInputQubits.insert(allDynInputQubits.end(), + dynPosCtrlQubitsValues.begin(), + dynPosCtrlQubitsValues.end()); + allDynInputQubits.insert(allDynInputQubits.end(), + dynNegCtrlQubitsValues.begin(), + dynNegCtrlQubitsValues.end()); + + // get the static params and paramMask if they exist + DenseF64ArrayAttr staticParams = nullptr; + if (auto optionalParams = op.getStaticParams()) { + staticParams = + DenseF64ArrayAttr::get(rewriter.getContext(), optionalParams.value()); + } else { + staticParams = DenseF64ArrayAttr{}; + } + DenseBoolArrayAttr paramMask = nullptr; + if (auto optionalMask = op.getParamsMask()) { + paramMask = + DenseBoolArrayAttr::get(rewriter.getContext(), optionalMask.value()); + } else { + paramMask = DenseBoolArrayAttr{}; + } + + // create new operation + rewriter.create( + op.getLoc(), staticParams, paramMask, op.getParams(), dynInQubitsValues, + dynPosCtrlQubitsValues, dynNegCtrlQubitsValues); + + const auto optResults = op.getAllOutQubits(); + + // iterate over all opt qubits + for (size_t i = 0; i < optResults.size(); i++) { + const auto& optQubit = optResults[i]; + const auto& dynQubit = allDynInputQubits[i]; + + // get a view of the opt qubit users that can be modified + (*optQubit.getUsers().begin())->replaceUsesOfWith(optQubit, dynQubit); + } + + // erase the previous operation + rewriter.eraseOp(op); + + return success(); + } +}; + +struct MQTOptToMQTDyn : impl::MQTOptToMQTDynBase { + using MQTOptToMQTDynBase::MQTOptToMQTDynBase; + void runOnOperation() override { + MLIRContext* context = &getContext(); + auto* module = getOperation(); + + ConversionTarget target(*context); + RewritePatternSet patterns(context); + MQTOptToMQTDynTypeConverter typeConverter(context); + + target.addIllegalDialect(); + target.addLegalDialect(); + + patterns.add(typeConverter, + context); + + ADD_CONVERT_PATTERN(GPhaseOp) + ADD_CONVERT_PATTERN(IOp) + ADD_CONVERT_PATTERN(BarrierOp) + ADD_CONVERT_PATTERN(HOp) + ADD_CONVERT_PATTERN(XOp) + ADD_CONVERT_PATTERN(YOp) + ADD_CONVERT_PATTERN(ZOp) + ADD_CONVERT_PATTERN(SOp) + ADD_CONVERT_PATTERN(SdgOp) + ADD_CONVERT_PATTERN(TOp) + ADD_CONVERT_PATTERN(TdgOp) + ADD_CONVERT_PATTERN(VOp) + ADD_CONVERT_PATTERN(VdgOp) + ADD_CONVERT_PATTERN(UOp) + ADD_CONVERT_PATTERN(U2Op) + ADD_CONVERT_PATTERN(POp) + ADD_CONVERT_PATTERN(SXOp) + ADD_CONVERT_PATTERN(SXdgOp) + ADD_CONVERT_PATTERN(RXOp) + ADD_CONVERT_PATTERN(RYOp) + ADD_CONVERT_PATTERN(RZOp) + ADD_CONVERT_PATTERN(SWAPOp) + ADD_CONVERT_PATTERN(iSWAPOp) + ADD_CONVERT_PATTERN(iSWAPdgOp) + ADD_CONVERT_PATTERN(PeresOp) + ADD_CONVERT_PATTERN(PeresdgOp) + ADD_CONVERT_PATTERN(DCXOp) + ADD_CONVERT_PATTERN(ECROp) + ADD_CONVERT_PATTERN(RXXOp) + ADD_CONVERT_PATTERN(RYYOp) + ADD_CONVERT_PATTERN(RZZOp) + ADD_CONVERT_PATTERN(RZXOp) + ADD_CONVERT_PATTERN(XXminusYY) + ADD_CONVERT_PATTERN(XXplusYY) + + // conversion of mqtopt types in func.func signatures + populateFunctionOpInterfaceTypeConversionPattern( + patterns, typeConverter); + target.addDynamicallyLegalOp([&](func::FuncOp op) { + return typeConverter.isSignatureLegal(op.getFunctionType()) && + typeConverter.isLegal(&op.getBody()); + }); + + // conversion of mqtopt types in func.return + populateReturnOpTypeConversionPattern(patterns, typeConverter); + target.addDynamicallyLegalOp( + [&](func::ReturnOp op) { return typeConverter.isLegal(op); }); + + // conversion of mqtopt types in func.call + populateCallOpTypeConversionPattern(patterns, typeConverter); + target.addDynamicallyLegalOp( + [&](func::CallOp op) { return typeConverter.isLegal(op); }); + + // conversion of mqtopt types in control-flow ops; e.g. cf.br + populateBranchOpInterfaceTypeConversionPattern(patterns, typeConverter); + + if (failed(applyPartialConversion(module, target, std::move(patterns)))) { + signalPassFailure(); + } + }; +}; + +} // namespace mqt::ir diff --git a/mlir/test/Conversion/mqtdyn-to-mqtopt.mlir b/mlir/test/Conversion/mqtdyn-to-mqtopt.mlir new file mode 100644 index 000000000..b6e2c9219 --- /dev/null +++ b/mlir/test/Conversion/mqtdyn-to-mqtopt.mlir @@ -0,0 +1,51 @@ +// Copyright (c) 2023 - 2025 Chair for Design Automation, TUM +// Copyright (c) 2025 Munich Quantum Software Company GmbH +// All rights reserved. +// +// SPDX-License-Identifier: MIT +// +// Licensed under the MIT License + +// RUN: quantum-opt %s --mqtdyn-to-mqtopt | FileCheck %s + +module { + // CHECK-LABEL: func @foo() + func.func @foo() -> (i1, i1) { + // CHECK: %[[reg_0:.*]] = "mqtopt.allocQubitRegister"() <{size_attr = 5 : i64}> + %r0 = "mqtdyn.allocQubitRegister" () {"size_attr" = 5 : i64} : () -> !mqtdyn.QubitRegister + // CHECK: %[[reg_1:.*]], %[[q_0:.*]] = "mqtopt.extractQubit"(%[[reg_0]]) <{index_attr = 0 : i64}> + %q0 = "mqtdyn.extractQubit" (%r0) {"index_attr" = 0 : i64} : (!mqtdyn.QubitRegister) -> !mqtdyn.Qubit + // CHECK: %[[index_0:.*]] = arith.constant 1 + %i = arith.constant 1 : i64 + // CHECK: %[[reg_2:.*]], %[[q_1:.*]] = "mqtopt.extractQubit"(%[[reg_1]], %[[index_0]]) + // CHECK: %[[reg_3:.*]], %[[q_2:.*]] = "mqtopt.extractQubit"(%[[reg_2]]) <{index_attr = 2 : i64}> + // CHECK: %[[reg_4:.*]], %[[q_3:.*]] = "mqtopt.extractQubit"(%[[reg_3]]) <{index_attr = 3 : i64}> + // CHECK: %[[reg_5:.*]], %[[q_4:.*]] = "mqtopt.extractQubit"(%[[reg_4]]) <{index_attr = 4 : i64}> + %q1 = "mqtdyn.extractQubit" (%r0, %i) : (!mqtdyn.QubitRegister, i64) -> !mqtdyn.Qubit + %q2 = "mqtdyn.extractQubit" (%r0) {"index_attr" = 2 : i64}: (!mqtdyn.QubitRegister) -> !mqtdyn.Qubit + %q3 = "mqtdyn.extractQubit" (%r0) {"index_attr" = 3 : i64}: (!mqtdyn.QubitRegister) -> !mqtdyn.Qubit + %q4 = "mqtdyn.extractQubit" (%r0) {"index_attr" = 4 : i64}: (!mqtdyn.QubitRegister) -> !mqtdyn.Qubit + // CHECK: %[[q_5:.*]] = mqtopt.x() %[[q_0]] : !mqtopt.Qubit + mqtdyn.x () %q0 + // CHECK: %[[q_6:.*]], %[[q_7:.*]] = mqtopt.x() %[[q_1]] ctrl %[[q_5]] : !mqtopt.Qubit ctrl !mqtopt.Qubit + mqtdyn.x () %q1 ctrl %q0 + + // CHECK: %[[c_0:.*]] = arith.constant 3.000000e-01 + %cst = arith.constant 3.000000e-01 : f64 + // CHECK: %[[q_8:.*]] = mqtopt.u(%[[c_0]], %[[c_0]] static [3.000000e-01] mask [false, true, false]) %[[q_6]] + mqtdyn.u(%cst, %cst static [3.000000e-01] mask [false, true, false]) %q1 + // CHECK: %[[q_9:.*]], [[b_0:.*]] = "mqtopt.measure"(%[[q_7]]) + // CHECK: %[[q_10:.*]], [[b_1:.*]] = "mqtopt.measure"(%[[q_8]]) + %c0 = "mqtdyn.measure" (%q0) : (!mqtdyn.Qubit) -> i1 + %c1 = "mqtdyn.measure" (%q1) : (!mqtdyn.Qubit) -> i1 + // CHECK: %[[reg_6:.*]] = "mqtopt.insertQubit"(%[[reg_5]], %[[q_9]]) <{index_attr = 0 : i64}> + // CHECK: %[[reg_7:.*]] = "mqtopt.insertQubit"(%[[reg_6]], %[[q_10]], %[[index_0]]) + // CHECK: %[[reg_8:.*]] = "mqtopt.insertQubit"(%[[reg_7]], %[[q_2]]) <{index_attr = 2 : i64}> + // CHECK: %[[reg_9:.*]] = "mqtopt.insertQubit"(%[[reg_8]], %[[q_3]]) <{index_attr = 3 : i64}> + // CHECK: %[[reg_10:.*]] = "mqtopt.insertQubit"(%[[reg_9]], %[[q_4]]) <{index_attr = 4 : i64}> + // CHECK: "mqtopt.deallocQubitRegister"(%[[reg_10]]) : (!mqtopt.QubitRegister) -> () + "mqtdyn.deallocQubitRegister" (%r0) : (!mqtdyn.QubitRegister) -> () + + return %c0, %c1 : i1, i1 + } +} diff --git a/mlir/test/Conversion/mqtopt-to-mqtdyn.mlir b/mlir/test/Conversion/mqtopt-to-mqtdyn.mlir new file mode 100644 index 000000000..825b764dc --- /dev/null +++ b/mlir/test/Conversion/mqtopt-to-mqtdyn.mlir @@ -0,0 +1,52 @@ +// Copyright (c) 2023 - 2025 Chair for Design Automation, TUM +// Copyright (c) 2025 Munich Quantum Software Company GmbH +// All rights reserved. +// +// SPDX-License-Identifier: MIT +// +// Licensed under the MIT License + +// RUN: quantum-opt %s --mqtopt-to-mqtdyn | FileCheck %s + +module { +// CHECK-LABEL: func @foo() + func.func @foo() -> (i1, i1) { + // CHECK: %[[reg_0:.*]] = "mqtdyn.allocQubitRegister"() <{size_attr = 5 : i64}> + %r0 = "mqtopt.allocQubitRegister"() <{size_attr = 5 : i64}> : () -> !mqtopt.QubitRegister + // CHECK: %[[q_0:.*]] = "mqtdyn.extractQubit"(%[[reg_0]]) <{index_attr = 0 : i64}> : (!mqtdyn.QubitRegister) -> !mqtdyn.Qubit + %r1, %q0 = "mqtopt.extractQubit"(%r0) <{index_attr = 0 : i64}> : (!mqtopt.QubitRegister) -> (!mqtopt.QubitRegister, !mqtopt.Qubit) + // CHECK: %[[index_0:.*]] = arith.constant 1 + %i = arith.constant 1 : i64 + // CHECK: %[[q_1:.*]] = "mqtdyn.extractQubit"(%[[reg_0]], %[[index_0]]) + // CHECK: %[[q_2:.*]] = "mqtdyn.extractQubit"(%[[reg_0]]) <{index_attr = 2 : i64}> : (!mqtdyn.QubitRegister) -> !mqtdyn.Qubit + // CHECK: %[[q_3:.*]] = "mqtdyn.extractQubit"(%[[reg_0]]) <{index_attr = 3 : i64}> : (!mqtdyn.QubitRegister) -> !mqtdyn.Qubit + // CHECK: %[[q_4:.*]] = "mqtdyn.extractQubit"(%[[reg_0]]) <{index_attr = 4 : i64}> : (!mqtdyn.QubitRegister) -> !mqtdyn.Qubit + %r2, %q1 = "mqtopt.extractQubit"(%r1, %i) : (!mqtopt.QubitRegister, i64) -> (!mqtopt.QubitRegister, !mqtopt.Qubit) + %r3, %q2 = "mqtopt.extractQubit"(%r2) <{index_attr = 2 : i64}> : (!mqtopt.QubitRegister) -> (!mqtopt.QubitRegister, !mqtopt.Qubit) + %r4, %q3 = "mqtopt.extractQubit"(%r3) <{index_attr = 3 : i64}> : (!mqtopt.QubitRegister) -> (!mqtopt.QubitRegister, !mqtopt.Qubit) + %r5, %q4 = "mqtopt.extractQubit"(%r4) <{index_attr = 4 : i64}> : (!mqtopt.QubitRegister) -> (!mqtopt.QubitRegister, !mqtopt.Qubit) + + // CHECK: mqtdyn.x() %[[q_0]] + %q5 = mqtopt.x() %q0 : !mqtopt.Qubit + // CHECK: mqtdyn.x() %[[q_1]] ctrl %[[q_0]] + %q6, %q7 = mqtopt.x() %q1 ctrl %q5 : !mqtopt.Qubit ctrl !mqtopt.Qubit + + // CHECK: %[[c_0:.*]] = arith.constant 3.000000e-01 + %cst = arith.constant 3.000000e-01 : f64 + // CHECK: mqtdyn.u(%[[c_0]], %[[c_0]] static [3.000000e-01] mask [false, true, false]) %[[q_1]] + %q8 = mqtopt.u(%cst, %cst static [3.000000e-01] mask [false, true, false]) %q6 : !mqtopt.Qubit + // CHECK: [[b_0:.*]] = "mqtdyn.measure"(%[[q_0]]) + // CHECK: [[b_1:.*]] = "mqtdyn.measure"(%[[q_1]]) + %q9, %c0 = "mqtopt.measure"(%q7) : (!mqtopt.Qubit) -> (!mqtopt.Qubit, i1) + %q10, %c1 = "mqtopt.measure"(%q8) : (!mqtopt.Qubit) -> (!mqtopt.Qubit, i1) + %r6 = "mqtopt.insertQubit"(%r5, %q9) <{index_attr = 0 : i64}> : (!mqtopt.QubitRegister, !mqtopt.Qubit) -> !mqtopt.QubitRegister + %r7 = "mqtopt.insertQubit"(%r6, %q4) <{index_attr = 4 : i64}> : (!mqtopt.QubitRegister, !mqtopt.Qubit) -> !mqtopt.QubitRegister + %r8 = "mqtopt.insertQubit"(%r7, %q3) <{index_attr = 3 : i64}> : (!mqtopt.QubitRegister, !mqtopt.Qubit) -> !mqtopt.QubitRegister + %r9 = "mqtopt.insertQubit"(%r8, %q2) <{index_attr = 2 : i64}> : (!mqtopt.QubitRegister, !mqtopt.Qubit) -> !mqtopt.QubitRegister + %r10 = "mqtopt.insertQubit"(%r9, %q10, %i) : (!mqtopt.QubitRegister, !mqtopt.Qubit, i64) -> !mqtopt.QubitRegister + // CHECK: "mqtdyn.deallocQubitRegister"(%[[reg_0]]) : (!mqtdyn.QubitRegister) -> () + "mqtopt.deallocQubitRegister"(%r10) : (!mqtopt.QubitRegister) -> () + + return %c0, %c1 : i1, i1 + } +} diff --git a/mlir/tools/quantum-opt/CMakeLists.txt b/mlir/tools/quantum-opt/CMakeLists.txt index 8eadfce13..594223663 100644 --- a/mlir/tools/quantum-opt/CMakeLists.txt +++ b/mlir/tools/quantum-opt/CMakeLists.txt @@ -17,7 +17,9 @@ set(LIBS ${passes_libs} MLIROptLib MLIRMQTOptTransforms - MLIRMQTDynTransforms) + MLIRMQTDynTransforms + MQTDynToMQTOpt + MQTOptToMQTDyn) add_mlir_tool(quantum-opt quantum-opt.cpp DEPENDS ${LIBS} SUPPORT_PLUGINS) target_compile_options(quantum-opt PRIVATE -fexceptions) diff --git a/mlir/tools/quantum-opt/quantum-opt.cpp b/mlir/tools/quantum-opt/quantum-opt.cpp index 46bd60cdb..07acce0bb 100644 --- a/mlir/tools/quantum-opt/quantum-opt.cpp +++ b/mlir/tools/quantum-opt/quantum-opt.cpp @@ -8,10 +8,12 @@ * Licensed under the MIT License */ -#include "mlir/Dialect/MQTDyn/IR/MQTDynDialect.h" // IWYU pragma: keep -#include "mlir/Dialect/MQTDyn/Transforms/Passes.h" // IWYU pragma: keep -#include "mlir/Dialect/MQTOpt/IR/MQTOptDialect.h" // IWYU pragma: keep -#include "mlir/Dialect/MQTOpt/Transforms/Passes.h" // IWYU pragma: keep +#include "mlir/Conversion/MQTDynToMQTOpt/MQTDynToMQTOpt.h" // IWYU pragma: keep +#include "mlir/Conversion/MQTOptToMQTDyn/MQTOptToMQTDyn.h" // IWYU pragma: keep +#include "mlir/Dialect/MQTDyn/IR/MQTDynDialect.h" // IWYU pragma: keep +#include "mlir/Dialect/MQTDyn/Transforms/Passes.h" // IWYU pragma: keep +#include "mlir/Dialect/MQTOpt/IR/MQTOptDialect.h" // IWYU pragma: keep +#include "mlir/Dialect/MQTOpt/Transforms/Passes.h" // IWYU pragma: keep #include #include @@ -23,6 +25,8 @@ int main(const int argc, char** argv) { mlir::registerAllPasses(); mqt::ir::opt::registerMQTOptPasses(); mqt::ir::dyn::registerMQTDynPasses(); + mqt::ir::registerMQTDynToMQTOptPasses(); + mqt::ir::registerMQTOptToMQTDynPasses(); mlir::DialectRegistry registry; mlir::registerAllDialects(registry);