Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
10 changes: 7 additions & 3 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 @@ -811,9 +811,7 @@ class QIRProgramBuilder {
OwningOpRef<ModuleOp> finalize();

private:
OpBuilder builder;
ModuleOp module;
Location loc;

LLVM::LLVMFuncOp mainFunc;

Expand Down Expand Up @@ -842,6 +840,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>", 0, 0), 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