Skip to content
Merged
Show file tree
Hide file tree
Changes from 12 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
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ This project adheres to [Semantic Versioning], with the exception that minor rel

### Added

- ✨ Add initial infrastructure for new QC and QCO MLIR dialects ([#1264], [#1402], [#1428], [#1430], [#1436], [#1443]) ([**@burgholzer**], [**@denialhaag**], [**@taminob**], [**@DRovara**])
- ✨ Add initial infrastructure for new QC and QCO MLIR dialects ([#1264], [#1402], [#1428], [#1430], [#1436], [#1443], [#1446]) ([**@burgholzer**], [**@denialhaag**], [**@taminob**], [**@DRovara**])

### Changed

Expand Down Expand Up @@ -307,6 +307,7 @@ _📚 Refer to the [GitHub Release Notes](https://github.com/munich-quantum-tool

<!-- PR links -->

[#1446]: https://github.com/munich-quantum-toolkit/core/pull/1446
[#1443]: https://github.com/munich-quantum-toolkit/core/pull/1443
[#1437]: https://github.com/munich-quantum-toolkit/core/pull/1437
[#1436]: https://github.com/munich-quantum-toolkit/core/pull/1436
Expand Down
3 changes: 1 addition & 2 deletions mlir/include/mlir/Dialect/QC/Builder/QCProgramBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ namespace mlir::qc {
* auto module = builder.finalize();
* ```
*/
class QCProgramBuilder final : public OpBuilder {
class QCProgramBuilder final : public ImplicitLocOpBuilder {
public:
/**
* @brief Construct a new QCProgramBuilder
Expand Down Expand Up @@ -887,7 +887,6 @@ class QCProgramBuilder final : public OpBuilder {

private:
MLIRContext* ctx{};
Location loc;
ModuleOp module;

/// Track allocated qubits for automatic deallocation
Expand Down
3 changes: 1 addition & 2 deletions mlir/include/mlir/Dialect/QCO/Builder/QCOProgramBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ namespace mlir::qco {
* auto module = builder.finalize();
* ```
*/
class QCOProgramBuilder final : public OpBuilder {
class QCOProgramBuilder final : public ImplicitLocOpBuilder {
public:
/**
* @brief Construct a new QCOProgramBuilder
Expand Down Expand Up @@ -1048,7 +1048,6 @@ class QCOProgramBuilder final : public OpBuilder {

private:
MLIRContext* ctx{};
Location loc;
ModuleOp module;

/// Check if the builder has been finalized
Expand Down
14 changes: 10 additions & 4 deletions mlir/include/mlir/Dialect/QIR/Builder/QIRProgramBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ namespace mlir::qir {
* auto module = builder.finalize();
* ```
*/
class QIRProgramBuilder {
class QIRProgramBuilder final : public ImplicitLocOpBuilder {
public:
/**
* @brief Construct a new QIRProgramBuilder
Expand Down Expand Up @@ -138,7 +138,7 @@ class QIRProgramBuilder {
*/
struct Bit {
/// Name of the register containing this bit
std::string registerName;
llvm::StringRef registerName;
/// Size of the register containing this bit
int64_t registerSize{};
/// Index of this bit within the register
Expand Down Expand Up @@ -811,10 +811,10 @@ class QIRProgramBuilder {
OwningOpRef<ModuleOp> finalize();

private:
OpBuilder builder;
/// The main module
ModuleOp module;
Location loc;

/// The main function
LLVM::LLVMFuncOp mainFunc;

/// Allocator and StringSaver for stable StringRefs
Expand Down Expand Up @@ -842,6 +842,12 @@ class QIRProgramBuilder {
/// Track qubit and result counts for QIR metadata
QIRMetadata metadata_;

/// Helper variable for storing the LLVM pointer type
LLVM::LLVMPointerType ptrType;

/// Helper variable for storing the LLVM void type
LLVM::LLVMVoidType voidType;

/**
* @brief Helper to create a LLVM CallOp
*
Expand Down
80 changes: 39 additions & 41 deletions mlir/lib/Dialect/QC/Builder/QCProgramBuilder.cpp

Large diffs are not rendered by default.

52 changes: 27 additions & 25 deletions mlir/lib/Dialect/QCO/Builder/QCOProgramBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <mlir/Dialect/Func/IR/FuncOps.h>
#include <mlir/IR/Builders.h>
#include <mlir/IR/BuiltinOps.h>
#include <mlir/IR/Location.h>
#include <mlir/IR/MLIRContext.h>
#include <mlir/IR/OwningOpRef.h>
#include <mlir/IR/Value.h>
Expand All @@ -34,8 +35,9 @@
namespace mlir::qco {

QCOProgramBuilder::QCOProgramBuilder(MLIRContext* context)
: OpBuilder(context), ctx(context), loc(getUnknownLoc()),
module(ModuleOp::create(loc)) {
: ImplicitLocOpBuilder(
FileLineColLoc::get(context, "<qco-program-builder>", 1, 1), context),
ctx(context), module(ModuleOp::create(*this)) {
ctx->loadDialect<QCODialect>();
}

Expand All @@ -45,7 +47,7 @@ void QCOProgramBuilder::initialize() {

// Create main function as entry point
auto funcType = getFunctionType({}, {getI64Type()});
auto mainFunc = func::FuncOp::create(*this, loc, "main", funcType);
auto mainFunc = func::FuncOp::create(*this, "main", funcType);

// Add entry_point attribute to identify the main function
auto entryPointAttr = getStringAttr("entry_point");
Expand All @@ -59,7 +61,7 @@ void QCOProgramBuilder::initialize() {
Value QCOProgramBuilder::allocQubit() {
checkFinalized();

auto allocOp = AllocOp::create(*this, loc);
auto allocOp = AllocOp::create(*this);
const auto qubit = allocOp.getResult();

// Track the allocated qubit as valid
Expand All @@ -76,7 +78,7 @@ Value QCOProgramBuilder::staticQubit(const int64_t index) {
}

auto indexAttr = getI64IntegerAttr(index);
auto staticOp = StaticOp::create(*this, loc, indexAttr);
auto staticOp = StaticOp::create(*this, indexAttr);
const auto qubit = staticOp.getQubit();

// Track the static qubit as valid
Expand All @@ -102,7 +104,7 @@ QCOProgramBuilder::allocQubitRegister(const int64_t size,

for (int64_t i = 0; i < size; ++i) {
const auto indexAttr = getI64IntegerAttr(i);
auto allocOp = AllocOp::create(*this, loc, nameAttr, sizeAttr, indexAttr);
auto allocOp = AllocOp::create(*this, nameAttr, sizeAttr, indexAttr);
const auto& qubit = qubits.emplace_back(allocOp.getResult());
// Track the allocated qubit as valid
validQubits.insert(qubit);
Expand Down Expand Up @@ -156,7 +158,7 @@ void QCOProgramBuilder::updateQubitTracking(Value inputQubit,
std::pair<Value, Value> QCOProgramBuilder::measure(Value qubit) {
checkFinalized();

auto measureOp = MeasureOp::create(*this, loc, qubit);
auto measureOp = MeasureOp::create(*this, qubit);
auto qubitOut = measureOp.getQubitOut();
auto result = measureOp.getResult();

Expand All @@ -173,7 +175,7 @@ Value QCOProgramBuilder::measure(Value qubit, const Bit& bit) {
auto sizeAttr = getI64IntegerAttr(bit.registerSize);
auto indexAttr = getI64IntegerAttr(bit.registerIndex);
auto measureOp =
MeasureOp::create(*this, loc, qubit, nameAttr, sizeAttr, indexAttr);
MeasureOp::create(*this, qubit, nameAttr, sizeAttr, indexAttr);
const auto qubitOut = measureOp.getQubitOut();

// Update tracking
Expand All @@ -185,7 +187,7 @@ Value QCOProgramBuilder::measure(Value qubit, const Bit& bit) {
Value QCOProgramBuilder::reset(Value qubit) {
checkFinalized();

auto resetOp = ResetOp::create(*this, loc, qubit);
auto resetOp = ResetOp::create(*this, qubit);
const auto qubitOut = resetOp.getQubitOut();

// Update tracking
Expand All @@ -203,7 +205,7 @@ Value QCOProgramBuilder::reset(Value qubit) {
#define DEFINE_ZERO_TARGET_ONE_PARAMETER(OP_CLASS, OP_NAME, PARAM) \
void QCOProgramBuilder::OP_NAME(const std::variant<double, Value>&(PARAM)) { \
checkFinalized(); \
OP_CLASS::create(*this, loc, PARAM); \
OP_CLASS::create(*this, PARAM); \
} \
Value QCOProgramBuilder::c##OP_NAME( \
const std::variant<double, Value>&(PARAM), Value control) { \
Expand Down Expand Up @@ -239,7 +241,7 @@ DEFINE_ZERO_TARGET_ONE_PARAMETER(GPhaseOp, gphase, theta)
#define DEFINE_ONE_TARGET_ZERO_PARAMETER(OP_CLASS, OP_NAME) \
Value QCOProgramBuilder::OP_NAME(Value qubit) { \
checkFinalized(); \
auto op = OP_CLASS::create(*this, loc, qubit); \
auto op = OP_CLASS::create(*this, qubit); \
const auto& qubitOut = op.getQubitOut(); \
updateQubitTracking(qubit, qubitOut); \
return qubitOut; \
Expand Down Expand Up @@ -284,7 +286,7 @@ DEFINE_ONE_TARGET_ZERO_PARAMETER(SXdgOp, sxdg)
Value QCOProgramBuilder::OP_NAME(const std::variant<double, Value>&(PARAM), \
Value qubit) { \
checkFinalized(); \
auto op = OP_CLASS::create(*this, loc, qubit, PARAM); \
auto op = OP_CLASS::create(*this, qubit, PARAM); \
const auto& qubitOut = op.getQubitOut(); \
updateQubitTracking(qubit, qubitOut); \
return qubitOut; \
Expand Down Expand Up @@ -325,7 +327,7 @@ DEFINE_ONE_TARGET_ONE_PARAMETER(POp, p, phi)
const std::variant<double, Value>&(PARAM2), \
Value qubit) { \
checkFinalized(); \
auto op = OP_CLASS::create(*this, loc, qubit, PARAM1, PARAM2); \
auto op = OP_CLASS::create(*this, qubit, PARAM1, PARAM2); \
const auto& qubitOut = op.getQubitOut(); \
updateQubitTracking(qubit, qubitOut); \
return qubitOut; \
Expand Down Expand Up @@ -368,7 +370,7 @@ DEFINE_ONE_TARGET_TWO_PARAMETER(U2Op, u2, phi, lambda)
const std::variant<double, Value>&(PARAM3), \
Value qubit) { \
checkFinalized(); \
auto op = OP_CLASS::create(*this, loc, qubit, PARAM1, PARAM2, PARAM3); \
auto op = OP_CLASS::create(*this, qubit, PARAM1, PARAM2, PARAM3); \
const auto& qubitOut = op.getQubitOut(); \
updateQubitTracking(qubit, qubitOut); \
return qubitOut; \
Expand Down Expand Up @@ -409,7 +411,7 @@ DEFINE_ONE_TARGET_THREE_PARAMETER(UOp, u, theta, phi, lambda)
std::pair<Value, Value> QCOProgramBuilder::OP_NAME(Value qubit0, \
Value qubit1) { \
checkFinalized(); \
auto op = OP_CLASS::create(*this, loc, qubit0, qubit1); \
auto op = OP_CLASS::create(*this, qubit0, qubit1); \
const auto& qubit0Out = op.getQubit0Out(); \
const auto& qubit1Out = op.getQubit1Out(); \
updateQubitTracking(qubit0, qubit0Out); \
Expand Down Expand Up @@ -453,7 +455,7 @@ DEFINE_TWO_TARGET_ZERO_PARAMETER(ECROp, ecr)
std::pair<Value, Value> QCOProgramBuilder::OP_NAME( \
const std::variant<double, Value>&(PARAM), Value qubit0, Value qubit1) { \
checkFinalized(); \
auto op = OP_CLASS::create(*this, loc, qubit0, qubit1, PARAM); \
auto op = OP_CLASS::create(*this, qubit0, qubit1, PARAM); \
const auto& qubit0Out = op.getQubit0Out(); \
const auto& qubit1Out = op.getQubit1Out(); \
updateQubitTracking(qubit0, qubit0Out); \
Expand Down Expand Up @@ -501,7 +503,7 @@ DEFINE_TWO_TARGET_ONE_PARAMETER(RZZOp, rzz, theta)
const std::variant<double, Value>&(PARAM2), Value qubit0, \
Value qubit1) { \
checkFinalized(); \
auto op = OP_CLASS::create(*this, loc, qubit0, qubit1, PARAM1, PARAM2); \
auto op = OP_CLASS::create(*this, qubit0, qubit1, PARAM1, PARAM2); \
const auto& qubit0Out = op.getQubit0Out(); \
const auto& qubit1Out = op.getQubit1Out(); \
updateQubitTracking(qubit0, qubit0Out); \
Expand Down Expand Up @@ -548,7 +550,7 @@ DEFINE_TWO_TARGET_TWO_PARAMETER(XXMinusYYOp, xx_minus_yy, theta, beta)
ValueRange QCOProgramBuilder::barrier(ValueRange qubits) {
checkFinalized();

auto op = BarrierOp::create(*this, loc, qubits);
auto op = BarrierOp::create(*this, qubits);
const auto& qubitsOut = op.getQubitsOut();
for (const auto& [inputQubit, outputQubit] : llvm::zip(qubits, qubitsOut)) {
updateQubitTracking(inputQubit, outputQubit);
Expand All @@ -565,17 +567,17 @@ std::pair<ValueRange, ValueRange> QCOProgramBuilder::ctrl(
llvm::function_ref<llvm::SmallVector<Value>(ValueRange)> body) {
checkFinalized();

auto ctrlOp = CtrlOp::create(*this, loc, controls, targets);
auto ctrlOp = CtrlOp::create(*this, controls, targets);
auto& block = ctrlOp.getBodyRegion().emplaceBlock();
const auto qubitType = QubitType::get(getContext());
for (const auto target : targets) {
const auto arg = block.addArgument(qubitType, loc);
const auto arg = block.addArgument(qubitType, getLoc());
updateQubitTracking(target, arg);
}
const InsertionGuard guard(*this);
setInsertionPointToStart(&block);
const auto innerTargetsOut = body(block.getArguments());
YieldOp::create(*this, loc, innerTargetsOut);
YieldOp::create(*this, innerTargetsOut);

if (innerTargetsOut.size() != targets.size()) {
llvm::reportFatalUsageError(
Expand Down Expand Up @@ -606,7 +608,7 @@ QCOProgramBuilder& QCOProgramBuilder::dealloc(Value qubit) {
validateQubitValue(qubit);
validQubits.erase(qubit);

DeallocOp::create(*this, loc, qubit);
DeallocOp::create(*this, qubit);

return *this;
}
Expand Down Expand Up @@ -655,16 +657,16 @@ OwningOpRef<ModuleOp> QCOProgramBuilder::finalize() {
return opA->isBeforeInBlock(opB);
});
for (auto qubit : sortedQubits) {
DeallocOp::create(*this, loc, qubit);
DeallocOp::create(*this, qubit);
}

validQubits.clear();

// Create constant 0 for successful exit code
auto exitCode = arith::ConstantOp::create(*this, loc, getI64IntegerAttr(0));
auto exitCode = arith::ConstantOp::create(*this, getI64IntegerAttr(0));

// Add return statement with exit code 0 to the main function
func::ReturnOp::create(*this, loc, ValueRange{exitCode});
func::ReturnOp::create(*this, ValueRange{exitCode});

// Invalidate context to prevent use-after-finalize
ctx = nullptr;
Expand Down
Loading
Loading