Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 7 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,12 @@ endif()

cmake_dependent_option(BUILD_MQT_CORE_QIR_RUNNER "Build the QIR runner of the MQT Core project" ON
"BUILD_MQT_CORE_MLIR" OFF)
cmake_dependent_option(
BUILD_MQT_CORE_MLIR_PYTHON
"Build Python bindings for the MQT MLIR compiler collection (requires MLIR_ENABLE_BINDINGS_PYTHON=ON)"
OFF
"BUILD_MQT_CORE_MLIR"
OFF)
Comment on lines +123 to +128
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BUILD_MQT_CORE_MLIR_PYTHON should be enabled automatically if BUILD_MQT_CORE_MLIR and BUILD_MQT_CORE_BINDINGS are both enabled.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would even argue there may be no need for a separate option. Whenever MLIR is enabled and the bindings are as well, this should be built.


# add main library code
add_subdirectory(src)
Expand All @@ -143,6 +149,7 @@ endif()

if(BUILD_MQT_CORE_MLIR)
add_subdirectory(mlir)
add_subdirectory(poc)

# copy generated MLIR documentation
add_custom_command(
Expand Down
11 changes: 11 additions & 0 deletions mlir/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,17 @@ add_subdirectory(include)
add_subdirectory(lib)
add_subdirectory(tools)

if(BUILD_MQT_CORE_MLIR_PYTHON)
if(NOT MLIR_ENABLE_BINDINGS_PYTHON)
message(FATAL_ERROR "BUILD_MQT_CORE_MLIR_PYTHON requires MLIR to be built with "
"MLIR_ENABLE_BINDINGS_PYTHON=ON. Re-build MLIR with that flag set.")
endif()
include(AddMLIRPython)
include(MLIRDetectPythonEnv)
mlir_configure_python_dev_packages()
add_subdirectory(python)
endif()

# add test code
if(BUILD_MQT_CORE_TESTS)
add_subdirectory(unittests)
Expand Down
31 changes: 31 additions & 0 deletions mlir/include/mlir/CAPI/Dialects.h
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to structure this more like https://github.com/llvm/llvm-project/tree/main/mlir/include/mlir/CAPI.

Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright (c) 2023 - 2026 Chair for Design Automation, TUM
* Copyright (c) 2025 - 2026 Munich Quantum Software Company GmbH
* All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* Licensed under the MIT License
*/

#pragma once

#include "mlir-c/IR.h"
#include "mlir-c/Support.h"

#ifdef __cplusplus
extern "C" {
#endif

MLIR_DECLARE_CAPI_DIALECT_REGISTRATION(QC, qc);
MLIR_DECLARE_CAPI_DIALECT_REGISTRATION(QCO, qco);

/** Registers and loads all MQT MLIR dialects into a context. */
MLIR_CAPI_EXPORTED void mqtMlirRegisterAllDialects(MlirContext context);

/** Registers all MQT MLIR passes into the global registry. */
MLIR_CAPI_EXPORTED void mqtMlirRegisterAllPasses(void);

#ifdef __cplusplus
}
#endif
30 changes: 30 additions & 0 deletions mlir/lib/CAPI/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Copyright (c) 2023 - 2026 Chair for Design Automation, TUM
# Copyright (c) 2025 - 2026 Munich Quantum Software Company GmbH
# All rights reserved.
#
# SPDX-License-Identifier: MIT
#
# Licensed under the MIT License

add_mlir_public_c_api_library(
MQTMLIRCoreDialectsCAPI
Dialects.cpp
ADDITIONAL_HEADER_DIRS
${MQT_MLIR_SOURCE_INCLUDE_DIR}/mlir/CAPI
ENABLE_AGGREGATION
LINK_LIBS
PUBLIC
MLIRIR
MLIRSupport
MLIRQCDialect
MLIRQCODialect
MLIRQTensorDialect
MLIRArithDialect
MLIRFuncDialect
MLIRMemRefDialect
MLIRSCFDialect
MLIRQCTransforms
MLIRQCOTransforms
MLIRQCToQCO)

mqt_mlir_target_use_project_options(MQTMLIRCoreDialectsCAPI)
46 changes: 46 additions & 0 deletions mlir/lib/CAPI/Dialects.cpp
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to structure this more like https://github.com/llvm/llvm-project/tree/main/mlir/lib/CAPI.

Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright (c) 2023 - 2026 Chair for Design Automation, TUM
* Copyright (c) 2025 - 2026 Munich Quantum Software Company GmbH
* All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* Licensed under the MIT License
*/

#include "mlir/CAPI/Dialects.h"

#include "mlir-c/IR.h"
#include "mlir/CAPI/IR.h"
#include "mlir/CAPI/Registration.h"
#include "mlir/Conversion/QCToQCO/QCToQCO.h"
#include "mlir/Dialect/QC/IR/QCDialect.h"
#include "mlir/Dialect/QC/Transforms/Passes.h"
#include "mlir/Dialect/QCO/IR/QCODialect.h"
#include "mlir/Dialect/QCO/Transforms/Passes.h" // NOLINT(misc-include-cleaner)
#include "mlir/Dialect/QTensor/IR/QTensorDialect.h"

#include <mlir/Dialect/Arith/IR/Arith.h>
#include <mlir/Dialect/Func/IR/FuncOps.h>
#include <mlir/Dialect/MemRef/IR/MemRef.h>
#include <mlir/Dialect/SCF/IR/SCF.h>
#include <mlir/IR/DialectRegistry.h>

MLIR_DEFINE_CAPI_DIALECT_REGISTRATION(QC, qc, ::mlir::qc::QCDialect)
MLIR_DEFINE_CAPI_DIALECT_REGISTRATION(QCO, qco, ::mlir::qco::QCODialect)

void mqtMlirRegisterAllDialects(MlirContext context) {
mlir::DialectRegistry registry;
registry.insert<mlir::qc::QCDialect, mlir::qco::QCODialect,
mlir::qtensor::QTensorDialect, mlir::arith::ArithDialect,
mlir::func::FuncDialect, mlir::memref::MemRefDialect,
mlir::scf::SCFDialect>();
unwrap(context)->appendDialectRegistry(registry);
unwrap(context)->loadAllAvailableDialects();
}

void mqtMlirRegisterAllPasses() {
mlir::qc::registerQCPasses();
mlir::qco::registerQCOPasses();
mlir::registerQCToQCOPasses();
}
4 changes: 4 additions & 0 deletions mlir/lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,7 @@ add_subdirectory(Conversion)
add_subdirectory(Compiler)
add_subdirectory(Dialect)
add_subdirectory(Support)

if(BUILD_MQT_CORE_MLIR_PYTHON)
add_subdirectory(CAPI)
endif()
72 changes: 72 additions & 0 deletions mlir/python/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Copyright (c) 2023 - 2026 Chair for Design Automation, TUM
# Copyright (c) 2025 - 2026 Munich Quantum Software Company GmbH
# All rights reserved.
#
# SPDX-License-Identifier: MIT
#
# Licensed under the MIT License

# Disable versioned soname — causes duplication in Python wheels.
set(CMAKE_PLATFORM_NO_VERSIONED_SONAME ON)

set(MQT_MLIR_PYTHON_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/mqt/core/mlir")
set(MQT_MLIR_PYTHON_PACKAGES_DIR "${CMAKE_CURRENT_BINARY_DIR}/python_packages")

# ##################################################################################################
# Sources
# ##################################################################################################

declare_mlir_python_sources(MQTCoreMLIRPythonSources ROOT_DIR "${MQT_MLIR_PYTHON_ROOT_DIR}" SOURCES
__init__.py _pipeline.py)

declare_mlir_python_sources(MQTCoreMLIRPythonExtensions)

# ##################################################################################################
# Extension module
# ##################################################################################################

declare_mlir_python_extension(
MQTCoreMLIRPythonExtensions.Main
MODULE_NAME
_mqtCoreMlir
ADD_TO_PARENT
MQTCoreMLIRPythonExtensions
SOURCES
MQTCoreMLIRModule.cpp
EMBED_CAPI_LINK_LIBS
MQTMLIRCoreDialectsCAPI
MLIRQCTranslation
MLIRSupportMQT
PRIVATE_LINK_LIBS
LLVMSupport
MQT::CoreIR)

# ##################################################################################################
# Aggregate and install
# ##################################################################################################

set(_source_components MQTCoreMLIRPythonSources MQTCoreMLIRPythonExtensions)

add_mlir_python_common_capi_library(
MQTCoreMLIRAggregateCAPI
INSTALL_COMPONENT
MQTCoreMLIRPythonModules
INSTALL_DESTINATION
python_packages/mqt/core/mlir/_mlir_libs
OUTPUT_DIRECTORY
"${MQT_MLIR_PYTHON_PACKAGES_DIR}/mqt/core/mlir/_mlir_libs"
RELATIVE_INSTALL_ROOT
"../../../.."
DECLARED_SOURCES
${_source_components})

add_mlir_python_modules(
MQTCoreMLIRPythonModules
ROOT_PREFIX
"${MQT_MLIR_PYTHON_PACKAGES_DIR}/mqt/core/mlir"
INSTALL_PREFIX
"python_packages/mqt/core/mlir"
DECLARED_SOURCES
${_source_components}
COMMON_CAPI_LINK_LIBS
MQTCoreMLIRAggregateCAPI)
70 changes: 70 additions & 0 deletions mlir/python/MQTCoreMLIRModule.cpp
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright (c) 2023 - 2026 Chair for Design Automation, TUM
* Copyright (c) 2025 - 2026 Munich Quantum Software Company GmbH
* All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* Licensed under the MIT License
*/

#include "mlir-c/IR.h"
#include "mlir/Bindings/Python/NanobindAdaptors.h" // NOLINT(misc-include-cleaner)
#include "mlir/CAPI/Dialects.h"
#include "mlir/Conversion/QCToQCO/QCToQCO.h" // NOLINT(misc-include-cleaner)
#include "mlir/Dialect/QC/Translation/TranslateQuantumComputationToQC.h" // NOLINT(misc-include-cleaner)
#include "mlir/Support/Passes.h" // NOLINT(misc-include-cleaner)
#include "qasm3/Importer.hpp"

#include <llvm/Support/raw_ostream.h> // NOLINT(misc-include-cleaner)
#include <mlir/IR/BuiltinOps.h> // NOLINT(misc-include-cleaner)
#include <mlir/IR/MLIRContext.h> // NOLINT(misc-include-cleaner)
#include <mlir/Pass/PassManager.h> // NOLINT(misc-include-cleaner)
#include <mlir/Support/LogicalResult.h> // NOLINT(misc-include-cleaner)

#include <stdexcept> // NOLINT(misc-include-cleaner)
#include <string> // NOLINT(misc-include-cleaner)

namespace nb = nanobind; // NOLINT(misc-unused-alias-decls)

// NOLINTNEXTLINE(misc-use-internal-linkage,readability-identifier-naming,readability-named-parameter)
NB_MODULE(_mqtCoreMlir, m) {
mqtMlirRegisterAllPasses();

m.doc() = "MQT Core MLIR Python bindings";

auto registerDialects = [](MlirContext context) {
mqtMlirRegisterAllDialects(context);
};
m.def("register_dialects", registerDialects, nb::arg("context"),
"Register and load QC, QCO, QTensor, and dependent MLIR dialects.");

m.def(
"qasm_to_qco",
[](const std::string& qasm) -> std::string {
auto qc = qasm3::Importer::imports(qasm);

mlir::MLIRContext ctx;
MlirContext cCtx{&ctx};
mqtMlirRegisterAllDialects(cCtx);

auto module = mlir::translateQuantumComputationToQC(&ctx, qc);
if (!module) {
throw std::runtime_error("failed to translate circuit to QC MLIR");
}

mlir::PassManager pm(&ctx);
populateQCCleanupPipeline(pm);
pm.addPass(mlir::createQCToQCO());
if (mlir::failed(pm.run(*module))) {
throw std::runtime_error("qc-to-qco conversion failed");
}

std::string out;
llvm::raw_string_ostream os(out);
module->print(os);
return out;
},
nb::arg("qasm"),
"Run the full (py:qasm) -> (mlir:qc) -> (mlir:qco) pipeline.");
}
16 changes: 16 additions & 0 deletions mlir/python/mqt/core/mlir/__init__.py
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to extend this. All dialects, passes, and conversions should be accessible. It would also be nice to provide a compile_program() function that accepts an OpenQASM program and pushes it through the entire pipeline (see the steps in CompilerPipeline.cpp).

Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Copyright (c) 2023 - 2026 Chair for Design Automation, TUM
# Copyright (c) 2025 - 2026 Munich Quantum Software Company GmbH
# All rights reserved.
#
# SPDX-License-Identifier: MIT
#
# Licensed under the MIT License

"""Python bindings for the MQT MLIR compiler collection."""

from __future__ import annotations

from ._mlir_libs._mqtCoreMlir import qasm_to_qco, register_dialects
from ._pipeline import compile_qc_to_qco, make_context

__all__ = ["compile_qc_to_qco", "make_context", "qasm_to_qco", "register_dialects"]
39 changes: 39 additions & 0 deletions mlir/python/mqt/core/mlir/_pipeline.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Copyright (c) 2023 - 2026 Chair for Design Automation, TUM
# Copyright (c) 2025 - 2026 Munich Quantum Software Company GmbH
# All rights reserved.
#
# SPDX-License-Identifier: MIT
#
# Licensed under the MIT License

"""High-level pipeline helpers built on top of the MLIR Python bindings."""

from __future__ import annotations

from mlir.ir import Context, Module
from mlir.passmanager import PassManager

from ._mlir_libs._mqtCoreMlir import register_dialects


def make_context() -> Context:
"""Return an MLIRContext with all MQT dialects registered and loaded."""
ctx = Context()
register_dialects(ctx)
return ctx


def compile_qc_to_qco(mlir_text: str) -> str:
"""Run the qc-to-qco conversion pass on an MLIR module given as text.

Args:
mlir_text: MLIR module in the QC dialect, as a string.

Returns:
The resulting QCO dialect MLIR module as a string.
"""
with make_context() as ctx:
module = Module.parse(mlir_text, ctx)
pm = PassManager.parse("builtin.module(qc-to-qco)", ctx)
pm.run(module.operation)
return str(module)
27 changes: 27 additions & 0 deletions poc/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Copyright (c) 2023 - 2026 Chair for Design Automation, TUM
# Copyright (c) 2025 - 2026 Munich Quantum Software Company GmbH
# All rights reserved.
#
# SPDX-License-Identifier: MIT
#
# Licensed under the MIT License

add_executable(poc-test-pipeline test_pipeline.cpp)

target_link_libraries(
poc-test-pipeline
PRIVATE MLIRQCDialect
MLIRQCODialect
MLIRQTensorDialect
MLIRArithDialect
MLIRFuncDialect
MLIRMemRefDialect
MLIRSCFDialect
MLIRQCTranslation
MLIRQCToQCO
MLIRSupportMQT
MLIRPass
MQT::CoreIR
MQT::CoreQASM)

mqt_mlir_target_use_project_options(poc-test-pipeline)
Loading
Loading