Skip to content
Merged
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
6 changes: 6 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,12 @@ repos:
(?:(?:::)?mlir::)?TypedValue\s*<[^;\n]+>\s+const\b )
files: ^(mlir|bindings/mlir)/.*\.(c|cc|cpp|cxx|h|hh|hpp|hxx)$
priority: 0
- id: disallow-stl-streams
name: Use LLVM streams in C++
language: pygrep
entry: '^\s*#\s*include\s*[<"](?:ios|iosfwd|iostream|istream|ostream|fstream|sstream|streambuf|iomanip|syncstream|strstream|spanstream)[>"]'
files: ^(include|src|bindings|mlir|test|examples)/.*\.(c|cc|cpp|cxx|h|hh|hpp|hxx|inc|cu|cuh)$
priority: 0
- id: cpp-documentation-style
name: Use LLVM-style C++ documentation comments
language: pygrep
Expand Down
4 changes: 4 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ comment, data-structure, diagnostic, and debugging guidance.
- Use `#pragma once`, direct includes, and standard-library facilities before
adding abstractions. Use C typedefs such as `size_t` and `uint64_t` without
`std::`. Do not use C-style casts, including casts to `void`.
- Use LLVM streams and buffers for I/O and `StringRef` for borrowed text. Use
existing synchronized diagnostics for concurrent logging. Do not include STL
stream headers, including in tests. Keep owned strings when ownership is
required.
- Use `//` for ordinary code comments. Never use `///` for them.
- Use `///` for Doxygen documentation, including structural commands. Start
descriptions with a short summary paragraph, separated from further content by
Expand Down
5 changes: 5 additions & 0 deletions cmake/AddMQTQDMIDevice.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,11 @@ function(mqt_copy_qdmi_runtime target)
if(NOT (APPLE AND SKBUILD))
set_property(TARGET ${target} PROPERTY BUILD_WITH_INSTALL_RPATH FALSE)
endif()
if(APPLE)
set_property(TARGET ${target} APPEND PROPERTY BUILD_RPATH "@loader_path")
elseif(UNIX)
set_property(TARGET ${target} APPEND PROPERTY BUILD_RPATH "$ORIGIN")
endif()
set(devices ${ARGN})
if(NOT devices)
mqt_get_qdmi_device_targets(devices)
Expand Down
3 changes: 3 additions & 0 deletions cmake/SetupMLIR.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,9 @@ message(STATUS "Using MLIRConfig.cmake in: ${MLIR_DIR}")
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
message(STATUS "LLVM/MLIR ${MLIR_VERSION}, assertions ${LLVM_ENABLE_ASSERTIONS}")

# LLVM component targets do not propagate headers to native consumers.
target_include_directories(LLVMSupport SYSTEM INTERFACE "$<BUILD_INTERFACE:${LLVM_INCLUDE_DIRS}>")

list(APPEND CMAKE_MODULE_PATH "${MLIR_CMAKE_DIR}")
list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}")

Expand Down
19 changes: 4 additions & 15 deletions cmake/mqt-core-config.cmake.in
Original file line number Diff line number Diff line change
Expand Up @@ -26,26 +26,15 @@ endif()

include(CMakeFindDependencyMacro)
find_dependency(qdmi)
find_dependency(LLVM @LLVM_VERSION_MAJOR@.@LLVM_VERSION_MINOR@ CONFIG)
# LLVM component exports omit their header usage requirements.
target_include_directories(LLVMSupport SYSTEM INTERFACE ${LLVM_INCLUDE_DIRS})

include("${CMAKE_CURRENT_LIST_DIR}/AddMQTQDMIDevice.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/mqt-core-runtime-targets.cmake")
if(mqt-core_Development_FOUND
AND (NOT mqt-core_FIND_COMPONENTS OR "Development" IN_LIST mqt-core_FIND_COMPONENTS))
find_package(LLVM @LLVM_VERSION_MAJOR@.@LLVM_VERSION_MINOR@ CONFIG QUIET)
if(LLVM_FOUND)
include("${CMAKE_CURRENT_LIST_DIR}/mqt-core-development-targets.cmake")
target_include_directories(MQT::CoreDD SYSTEM INTERFACE ${LLVM_INCLUDE_DIRS})
target_include_directories(MQT::CoreQDMICommon SYSTEM INTERFACE ${LLVM_INCLUDE_DIRS})
target_include_directories(MQT::CoreBench SYSTEM INTERFACE ${LLVM_INCLUDE_DIRS})
target_include_directories(MQT::CoreQDMIScDeviceConfig SYSTEM INTERFACE ${LLVM_INCLUDE_DIRS})
else()
set(mqt-core_Development_FOUND FALSE)
set(mqt-core_NOT_FOUND_MESSAGE
"The Development component requires an LLVM @LLVM_VERSION_MAJOR@.@LLVM_VERSION_MINOR@ SDK.")
if(NOT mqt-core_FIND_COMPONENTS)
set(mqt-core_FOUND FALSE)
endif()
endif()
include("${CMAKE_CURRENT_LIST_DIR}/mqt-core-development-targets.cmake")
endif()
check_required_components(mqt-core)

Expand Down
32 changes: 14 additions & 18 deletions docs/cpp_api.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@ builtin driver's C interface. Its bundle contains only the DDSIM device. Save it
as `main.cpp`:

```cpp
#include <qdmi/client.h>
#include "qdmi/client.h"

#include "llvm/Support/raw_ostream.h"

#include <cstddef>
#include <iostream>
#include <stdexcept>
#include <string>

Expand All @@ -39,8 +40,9 @@ int main() {
check(QDMI_session_alloc(&session));
check(QDMI_session_init(session));
QDMI_Device device = nullptr;
check(QDMI_session_query_session_property(
session, QDMI_SESSION_PROPERTY_DEVICES, sizeof(device), &device, nullptr));
check(QDMI_session_query_session_property(session,
QDMI_SESSION_PROPERTY_DEVICES,
sizeof(device), &device, nullptr));

QDMI_Job job = nullptr;
check(QDMI_device_create_job(device, &job));
Expand All @@ -49,7 +51,8 @@ int main() {
const void* program = circuit;
const size_t length = sizeof(circuit);
const size_t shots = 1;
check(QDMI_job_set_programs(job, QDMI_PROGRAM_FORMAT_QASM3, 1, &length, &program));
check(QDMI_job_set_programs(job, QDMI_PROGRAM_FORMAT_QASM3, 1, &length,
&program));
check(QDMI_job_set_parameter(job, QDMI_JOB_PARAMETER_SHOTSNUM, sizeof(shots),
&shots));
check(QDMI_job_submit(job));
Expand All @@ -63,7 +66,7 @@ int main() {
if (std::string(result) != "1") {
return 1;
}
std::cout << "DDSIM result: " << result << '\n';
llvm::outs() << "DDSIM result: " << result << '\n';
}
```

Expand All @@ -72,33 +75,26 @@ Save the following as `CMakeLists.txt`:
```cmake
cmake_minimum_required(VERSION 3.28)
project(qdmi-example LANGUAGES CXX)
if(APPLE)
set(CMAKE_BUILD_RPATH "@loader_path")
elseif(UNIX)
set(CMAKE_BUILD_RPATH "$ORIGIN")
endif()
find_package(mqt-core CONFIG REQUIRED COMPONENTS Runtime)
add_executable(qdmi-example main.cpp)
target_link_libraries(qdmi-example PRIVATE MQT::CoreQDMIDriver)
target_compile_features(qdmi-example PRIVATE cxx_std_20)
target_link_libraries(qdmi-example PRIVATE MQT::CoreQDMIDriver LLVMSupport)
mqt_copy_qdmi_runtime(qdmi-example MQT::CoreQDMI_DDSIM_Device)

enable_testing()
add_test(NAME qdmi-runtime COMMAND qdmi-example)
add_test(NAME compiler COMMAND MQT::mqt-cc --version)
add_test(NAME benchmark COMMAND MQT::mqt-core-bench list)
set_tests_properties(qdmi-runtime compiler benchmark PROPERTIES TIMEOUT 60)
```

With the wheel installed in the active environment, run:
With the wheel installed in the active environment and an LLVM SDK matching the
major and minor version used to build MQT Core, run:

```console
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="$(mqt-core-cli --cmake_dir)"
cmake --build build --config Release
ctest --test-dir build -C Release --output-on-failure
```

The application prints `DDSIM result: 1`. CTest also runs both imported tools.
No LLVM/MLIR installation is required.
The application prints `DDSIM result: 1`.

CMake also provides `MQT::mqt-cc` and `MQT::mqt-core-bench` imported executable
targets. Use them in custom commands, or run `mqt-cc` and `mqt-core-bench` from
Expand Down
5 changes: 5 additions & 0 deletions docs/development.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ differences between these guides; neither upstream document is imported in full.

- Use C++20 standard-library facilities before adding a project abstraction or
dependency.
- Use LLVM `raw_ostream` for output, `MemoryBuffer` for file input, and
`StringRef` for borrowed text. Reuse synchronized diagnostics for concurrent
logging. STL stream headers are forbidden, including in tests. Use GoogleTest
scoped traces for test context. Keep owned strings where needed; use
`SmallString` for suitable temporary buffers.
- Keep variables local, initialize them when declared, and give each name one
clear meaning.
- Use `auto` when the initializer makes the type clear or when spelling the type
Expand Down
2 changes: 1 addition & 1 deletion docs/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ macOS wheels use Apple Clang and ThinLTO with a macOS 13.3 deployment target.
Windows wheels use MSVC with IPO, except for DLLs that require automatic symbol
exports. Wheels include the QDMI driver and device bundles, `mqt-cc`, and
`mqt-core-bench`. Their CMake package exposes the QDMI C interfaces and tool
targets without requiring LLVM/MLIR. See {doc}`cpp_api` for native consumers.
targets. Native CMake consumers require a matching LLVM SDK; see {doc}`cpp_api`.
C++ development libraries and headers are available from source installations;
the DD library is static.

Expand Down
2 changes: 0 additions & 2 deletions include/mqt-core/dd/Package.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,6 @@
#include <cstddef>
#include <cstdint>
#include <functional>
#include <iosfwd>
#include <iostream>
#include <limits>
#include <map>
#include <random>
Expand Down
30 changes: 14 additions & 16 deletions mlir/lib/Dialect/QIR/Execution/JIT/Session.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
#include "llvm/Support/Debug.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/TargetSelect.h"
Expand All @@ -68,7 +69,6 @@
#include <memory>
#include <mutex>
#include <optional>
#include <sstream>
#include <stdexcept>
#include <string>
#include <string_view>
Expand Down Expand Up @@ -138,11 +138,11 @@ static auto selectEntryPoint(llvm::Module& module) -> llvm::Function& {
const auto* type = entryPoint.getFunctionType();
if (type->isVarArg() || type->getNumParams() != 0 ||
!type->getReturnType()->isIntegerTy(64)) {
std::string actual;
llvm::raw_string_ostream stream(actual);
type->print(stream);
throw std::runtime_error("QIR entry point '" + entryPoint.getName().str() +
"' must have type i64 (), but has type " + actual);
throw std::runtime_error(
llvm::formatv(
"QIR entry point '{0}' must have type i64 (), but has type {1}",
entryPoint.getName(), *type)
.str());
}
return entryPoint;
}
Expand Down Expand Up @@ -240,7 +240,8 @@ static auto matches(const llvm::FunctionType& actual,
}

static auto describe(const RuntimeSymbol& symbol) -> std::string {
std::ostringstream description;
std::string descriptionStorage;
llvm::raw_string_ostream description(descriptionStorage);
description << abiTypeName(symbol.result) << " (";
for (std::size_t i = 0; i < symbol.parameters.size(); ++i) {
if (i != 0) {
Expand All @@ -249,7 +250,7 @@ static auto describe(const RuntimeSymbol& symbol) -> std::string {
description << abiTypeName(symbol.parameters[i]);
}
description << ")";
return description.str();
return descriptionStorage;
}

template <typename Function>
Expand Down Expand Up @@ -390,14 +391,11 @@ static auto selectRuntimeSymbols(const llvm::Module& module)
"QIR runtime declaration '" + function.getName() + "'");
const auto& symbol = it->second;
if (!matches(*function.getFunctionType(), symbol)) {
std::string actual;
llvm::raw_string_ostream stream(actual);
function.getFunctionType()->print(stream);
std::ostringstream message;
message << "QIR declaration '" << function.getName().str()
<< "' has unsupported type " << actual << "; expected "
<< describe(symbol);
throw std::runtime_error(message.str());
throw std::runtime_error(
llvm::formatv(
"QIR declaration '{0}' has unsupported type {1}; expected {2}",
function.getName(), *function.getFunctionType(), describe(symbol))
.str());
}
selected.emplace_back(function.getName().str(), symbol.address);
}
Expand Down
18 changes: 9 additions & 9 deletions mlir/lib/Dialect/QIR/Execution/Runtime/Runtime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/raw_ostream.h"

#include <algorithm>
Expand All @@ -35,7 +36,6 @@
#include <optional>
#include <random>
#include <span>
#include <sstream>
#include <stdexcept>
#include <string>
#include <string_view>
Expand Down Expand Up @@ -171,10 +171,10 @@ auto Runtime::resolveAddress(const Qubit* qubit) -> dd::Qubit {

const auto it = qRegister.find(qubit);
if (it == qRegister.end()) {
std::ostringstream ss;
ss << __FILE__ << ":" << __LINE__
<< ": Qubit not allocated (not found): " << qubit;
throw std::out_of_range(ss.str());
throw std::out_of_range(
llvm::formatv("{0}:{1}: Qubit not allocated (not found): {2}", __FILE__,
__LINE__, qubit)
.str());
}
return it->second;
}
Expand Down Expand Up @@ -448,10 +448,10 @@ auto Runtime::deref(Result* result) -> ResultStruct& {
auto it = rRegister.find(result);
if (it == rRegister.end()) {
if (resultMode == ResourceMode::DYNAMIC) {
std::stringstream ss;
ss << __FILE__ << ":" << __LINE__
<< ": Result not allocated (not found): " << result;
throw std::out_of_range(ss.str());
throw std::out_of_range(
llvm::formatv("{0}:{1}: Result not allocated (not found): {2}",
__FILE__, __LINE__, result)
.str());
}
resultMode = ResourceMode::STATIC;
it = rRegister.emplace(result, ResultStruct{.r = false}).first;
Expand Down
1 change: 1 addition & 0 deletions mlir/unittests/Compiler/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ mqt_mlir_configure_unittest_target(mqt-core-mlir-unittests-compiler REQUIRES_EH)

gtest_discover_tests(
mqt-core-mlir-unittests-compiler
NO_PRETTY_VALUES
PROPERTIES LABELS mqt-mlir-unittests
DISCOVERY_TIMEOUT 60)

Expand Down
Loading
Loading