Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
95 commits
Select commit Hold shift + click to select a range
46c39de
RTIO dialect is added to Catalyst
rniczh Nov 10, 2025
fd2dea4
Merge branch 'main' into rniczh/add-rtio-dialect
rniczh Nov 10, 2025
f127e6a
reformatting
rniczh Nov 10, 2025
eb19fa3
pulse should use f64 for duration
rniczh Nov 11, 2025
e5b170f
Update mlir/include/RTIO/IR/RTIODialect.td
rniczh Nov 17, 2025
6c9e90d
Update mlir/include/RTIO/IR/RTIODialect.td
rniczh Nov 17, 2025
a502944
Update mlir/include/RTIO/IR/RTIODialect.td
rniczh Nov 17, 2025
94927c3
Update mlir/include/RTIO/IR/RTIODialect.td
rniczh Nov 17, 2025
e9b1e84
Update mlir/include/RTIO/IR/RTIOOps.td
rniczh Nov 17, 2025
1452e7b
Update mlir/include/RTIO/IR/RTIODialect.td
rniczh Nov 17, 2025
38242f5
Update mlir/include/RTIO/IR/RTIOOps.td
rniczh Nov 17, 2025
6c00116
add empty op
rniczh Nov 18, 2025
48ecf52
Merge branch 'rniczh/add-rtio-dialect' of github.com:PennyLaneAI/cata…
rniczh Nov 18, 2025
ef5c3a6
fix formatting
rniczh Nov 18, 2025
c819333
update td
rniczh Nov 18, 2025
a26864c
Add pass to lower ion dialect to rtio dialect
rniczh Nov 18, 2025
c0e7234
update
rniczh Nov 18, 2025
f1ad990
add missing include
rniczh Nov 18, 2025
4cf83fe
update
rniczh Nov 18, 2025
27a4b98
add missing lib
rniczh Nov 18, 2025
4b3408f
Merge branch 'rniczh/add-rtio-dialect' of github.com:PennyLaneAI/cata…
rniczh Nov 18, 2025
29ffc70
remove redundant include
rniczh Nov 18, 2025
fcd540d
update
rniczh Nov 19, 2025
82bb3aa
remove other redundant functions
rniczh Nov 20, 2025
4a7430a
update pass
rniczh Nov 27, 2025
a349b1c
remove redundant code
rniczh Nov 27, 2025
cc814da
update linkage
rniczh Nov 28, 2025
5681bb3
add rtio.config
rniczh Dec 2, 2025
f326bf2
drop timeline IR
rniczh Dec 2, 2025
0e6b14f
remove unrelated thing
rniczh Dec 2, 2025
c0da830
Merge branch 'main' into rniczh/add-rtio-dialect
rniczh Dec 2, 2025
bd1c4c4
update channel ID underlying number
rniczh Dec 2, 2025
8e58bbe
Merge branch 'rniczh/add-rtio-dialect' of github.com:PennyLaneAI/cata…
rniczh Dec 2, 2025
6d57469
add bracket for if
rniczh Dec 2, 2025
cf5874e
fix
rniczh Dec 2, 2025
c4a3afa
add assert for oob
rniczh Dec 2, 2025
5e136eb
update comment
rniczh Dec 2, 2025
9fd57fc
merge from upstream
rniczh Dec 2, 2025
b623d0d
supports importing json to rtio.config
rniczh Dec 2, 2025
b127e9e
update changelog
rniczh Dec 2, 2025
1ce02ba
add deviceDB option
rniczh Dec 2, 2025
a379528
add missing comma
rniczh Dec 2, 2025
4f851ef
add missing include
rniczh Dec 2, 2025
2ff88f9
Update mlir/lib/RTIO/IR/RTIODialect.cpp
rniczh Dec 3, 2025
2486c74
Update mlir/include/RTIO/IR/RTIOOps.td
rniczh Dec 3, 2025
e6d0c7c
Add filecheck line
rniczh Dec 3, 2025
d8588ad
Merge branch 'main' into rniczh/add-rtio-dialect
rniczh Dec 3, 2025
49b2c0b
merge from upstream
rniczh Dec 3, 2025
3937ecf
revert
rniczh Dec 3, 2025
5559870
merge
rniczh Dec 3, 2025
e92d58e
Add changelog
rniczh Dec 3, 2025
7ed6c04
Merge branch 'rniczh/add-rtio-dialect' of github.com:PennyLaneAI/cata…
rniczh Dec 3, 2025
f77a12b
update changelog
rniczh Dec 3, 2025
ff777d3
merge from upstream
rniczh Dec 4, 2025
d0eba30
udpate
rniczh Dec 4, 2025
9837334
update
rniczh Dec 4, 2025
6314072
add test
rniczh Dec 5, 2025
528e0bb
remove comment
rniczh Dec 5, 2025
99a85c5
remove comment
rniczh Dec 5, 2025
7e7ee45
update changelog
rniczh Dec 5, 2025
2040912
Add scf.if and scf.for test
rniczh Dec 5, 2025
737425c
Merge branch 'main' into rniczh/lower-ion-to-rtio
mehrdad2m Dec 8, 2025
a9a33c6
convert rtio to llvmir
rniczh Dec 8, 2025
e19c29c
change variable name
rniczh Dec 8, 2025
c368eff
only support walkresult as return type
rniczh Dec 8, 2025
aa46203
fix
rniczh Dec 8, 2025
81db109
exit gracefully
rniczh Dec 8, 2025
436beaa
move ionInfo to separate file
rniczh Dec 8, 2025
820ec19
move json utils to separate files
rniczh Dec 8, 2025
8c210ca
refactor
rniczh Dec 8, 2025
4385130
reformat
rniczh Dec 8, 2025
ef7b2fa
Merge branch 'rniczh/lower-ion-to-rtio' of github.com:PennyLaneAI/cat…
rniczh Dec 8, 2025
18921e5
refactor
rniczh Dec 8, 2025
89027a4
fix
rniczh Dec 8, 2025
2fa61f6
clean unused ops
rniczh Dec 8, 2025
54c3ad3
Merge branch 'rniczh/lower-ion-to-rtio' of github.com:PennyLaneAI/cat…
rniczh Dec 8, 2025
b8caf32
format
rniczh Dec 8, 2025
3a220a2
fix freq
rniczh Dec 9, 2025
65f3388
remove redundancy
rniczh Dec 9, 2025
5876b02
Merge branch 'main' into rniczh/lower-ion-to-rtio
rniczh Dec 9, 2025
3c50cdd
Merge branch 'rniczh/lower-ion-to-rtio' into rniczh/convert-rtio-to-l…
rniczh Dec 9, 2025
4eed6d5
add missing file change
rniczh Dec 9, 2025
6c3efb9
Merge branch 'rniczh/lower-ion-to-rtio' of github.com:PennyLaneAI/cat…
rniczh Dec 9, 2025
7ebe7f4
Merge branch 'rniczh/convert-rtio-to-llvmir' of github.com:PennyLaneA…
rniczh Dec 9, 2025
c96ce69
need 8mu delay after config spi
rniczh Dec 9, 2025
6b1c4ea
add lit test
rniczh Dec 9, 2025
26d2279
bfs canreach()
rniczh Dec 9, 2025
dcc2ae5
remove assert
rniczh Dec 9, 2025
8a2162d
Merge branch 'rniczh/lower-ion-to-rtio' into rniczh/convert-rtio-to-l…
rniczh Dec 10, 2025
4735556
reuse catalyst ensureFunctionDeclartion
rniczh Dec 10, 2025
e3f5197
fix sequence error
rniczh Dec 10, 2025
f5a7ea6
move utils
rniczh Dec 10, 2025
cbd628d
module -> mod
paul0403 Dec 11, 2025
52221ab
remove dynamic channel ID branch
paul0403 Dec 11, 2025
42bd906
format
paul0403 Dec 11, 2025
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
11 changes: 8 additions & 3 deletions doc/releases/changelog-dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,6 @@
detecting when the Python compiler is being used and routing through it appropriately.
[(#2190)](https://github.com/PennyLaneAI/catalyst/pull/2190)

* RTIO dialect is added to bypass the compilation flow from OpenAPL to ARTIQ’s LLVM IR. It is introduced to bridge the gap between ION dialect and ARTIQ’s LLVM IR. The design philosophy of RTIO dialect is primarily event-based. Every operation is asynchronous; sync behaviour occurs only via `rtio.sync` or `wait operand` in event operation.
[(#2185)](https://github.com/PennyLaneAI/catalyst/pull/2185)

* Added ``catalyst.switch``, a qjit compatible, index-switch style control flow decorator.
[(#2171)](https://github.com/PennyLaneAI/catalyst/pull/2171)

Expand Down Expand Up @@ -366,6 +363,14 @@

<h3>Internal changes ⚙️</h3>

* RTIO dialect is added to bypass the compilation flow from OpenAPL to ARTIQ’s LLVM IR. It is
introduced to bridge the gap between ION dialect and ARTIQ’s LLVM IR. The design philosophy
of RTIO dialect is primarily event-based. Every operation is asynchronous; sync behaviour occurs
only via `rtio.sync` or `wait operand` in event operation. And we now support the compiling from
ION dialect to RTIO dilalect.
[(#2185)](https://github.com/PennyLaneAI/catalyst/pull/2185)
[(#2204)](https://github.com/PennyLaneAI/catalyst/pull/2204)

* Integration tests for `qml.specs` have been updated to match the new output format introduced
in PennyLane.
[(#2255)](https://github.com/PennyLaneAI/catalyst/pull/2255)
Expand Down
35 changes: 35 additions & 0 deletions mlir/include/Catalyst/Utils/JSONUtils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright 2025 Xanadu Quantum Technologies Inc.

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

// http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once

#include "llvm/Support/JSON.h"

#include "mlir/IR/Attributes.h"
#include "mlir/IR/BuiltinAttributes.h"
#include "mlir/IR/MLIRContext.h"
#include "mlir/Support/LogicalResult.h"

namespace catalyst {

/// Convert a JSON value to an MLIR Attribute.
/// Handles strings, integers, floats, booleans, arrays, objects, and null.
mlir::Attribute jsonToAttribute(mlir::MLIRContext *ctx, const llvm::json::Value &json);

/// Load a JSON file and convert it to a DictionaryAttr.
/// Returns failure if the file cannot be read or parsed, or if the root is not an object.
mlir::FailureOr<mlir::DictionaryAttr> loadJsonFileAsDict(mlir::MLIRContext *ctx,
llvm::StringRef filePath);

} // namespace catalyst
129 changes: 129 additions & 0 deletions mlir/include/Ion/IR/IonInfo.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
// Copyright 2025 Xanadu Quantum Technologies Inc.

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

// http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once

#include <optional>
#include <string>

#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"

#include "Ion/IR/IonOps.h"

namespace catalyst {
namespace ion {

/// Helper class to store and query ion information from an IonOp.
class IonInfo {
public:
struct TransitionInfo {
std::string level0;
std::string level1;
double einstein_a;
std::string multipole;
};

private:
llvm::StringMap<double> levelEnergyMap;
llvm::SmallVector<TransitionInfo> transitions;

public:
explicit IonInfo(ion::IonOp op)
{
auto levelAttrs = op.getLevels();
auto transitionsAttr = op.getTransitions();

// Map from Level label to Energy value
for (auto levelAttr : levelAttrs) {
auto level = mlir::cast<LevelAttr>(levelAttr);
std::string label = level.getLabel().getValue().str();
double energy = level.getEnergy().getValueAsDouble();
levelEnergyMap[label] = energy;
}

// Store transition information
for (auto transitionAttr : transitionsAttr) {
auto transition = mlir::cast<TransitionAttr>(transitionAttr);
TransitionInfo info;
info.level0 = transition.getLevel_0().getValue().str();
info.level1 = transition.getLevel_1().getValue().str();
info.einstein_a = transition.getEinsteinA().getValueAsDouble();
info.multipole = transition.getMultipole().getValue().str();
transitions.push_back(info);
}
}

/// Get energy of a level by label
std::optional<double> getLevelEnergy(llvm::StringRef label) const
{
auto it = levelEnergyMap.find(label.str());
if (it != levelEnergyMap.end()) {
return it->second;
}
return std::nullopt;
}

/// Get level energy of a transition by index
template <int IndexT>
std::optional<double> getTransitionLevelEnergy(size_t transitionIndex) const
{
static_assert(IndexT == 0 || IndexT == 1, "IndexT must be 0 or 1");

if (transitionIndex >= transitions.size()) {
return std::nullopt;
}

const auto &transition = transitions[transitionIndex];
if constexpr (IndexT == 0) {
return getLevelEnergy(transition.level0);
}
else {
return getLevelEnergy(transition.level1);
}
}

/// Get energy difference of a transition (level1 energy - level0 energy)
std::optional<double> getTransitionEnergyDiff(size_t index) const
{
if (index >= transitions.size()) {
return std::nullopt;
}

auto energy0 = getTransitionLevelEnergy<0>(index);
auto energy1 = getTransitionLevelEnergy<1>(index);

if (energy0.has_value() && energy1.has_value()) {
return energy1.value() - energy0.value();
}

return std::nullopt;
}

/// Get number of transitions
size_t getNumTransitions() const { return transitions.size(); }

/// Get transition info by index
std::optional<TransitionInfo> getTransition(size_t index) const
{
if (index < transitions.size()) {
return transitions[index];
}
return std::nullopt;
}
};

} // namespace ion
} // namespace catalyst
24 changes: 24 additions & 0 deletions mlir/include/Ion/Transforms/Passes.td
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,28 @@ def IonConversionPass : Pass<"convert-ion-to-llvm"> {
];
}

def IonToRTIOPass : Pass<"convert-ion-to-rtio", "mlir::ModuleOp"> {
let summary = "Convert Ion dialect operations to RTIO dialect";

let dependentDialects = [
"rtio::RTIODialect",
"arith::ArithDialect",
"func::FuncDialect",
"memref::MemRefDialect",
"scf::SCFDialect",
"quantum::QuantumDialect",
"ion::IonDialect",
"linalg::LinalgDialect",
];

let options = [
Option<"kernelName", "kernel-name",
"std::string", /*default=*/"\"__kernel__\"",
"Name of the generated kernel function">,
Option<"deviceDb", "device_db",
"std::string", /*default=*/"\"\"",
"Path to the device database JSON file">,
];
}

#endif // ION_PASSES
11 changes: 10 additions & 1 deletion mlir/include/Ion/Transforms/Patterns.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,23 @@
#include "mlir/IR/PatternMatch.h"
#include "mlir/Transforms/DialectConversion.h"

#include "Ion/IR/IonInfo.h"
#include "Ion/Transforms/oqd_database_managers.hpp"

namespace catalyst {
namespace ion {

// Gates to pulses conversion patterns
void populateGatesToPulsesPatterns(mlir::RewritePatternSet &, const OQDDatabaseManager &);
void populateConversionPatterns(mlir::LLVMTypeConverter &typeConverter,
mlir::RewritePatternSet &patterns);

// Ion to RTIO conversion patterns
void populateIonPulseToRTIOPatterns(mlir::TypeConverter &typeConverter,
mlir::RewritePatternSet &patterns, const IonInfo &ionInfo,
mlir::DenseMap<mlir::Value, mlir::Value> &qextractToMemrefMap);
void populateParallelProtocolToRTIOPatterns(mlir::TypeConverter &typeConverter,
mlir::RewritePatternSet &patterns);
void populateIonToRTIOFinalizePatterns(mlir::RewritePatternSet &patterns);

} // namespace ion
} // namespace catalyst
142 changes: 142 additions & 0 deletions mlir/include/Ion/Transforms/ValueTracing.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
// Copyright 2025 Xanadu Quantum Technologies Inc.

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

// http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once

#include <queue>

#include "mlir/Dialect/SCF/IR/SCF.h"
#include "mlir/IR/Value.h"

#include "Ion/IR/IonOps.h"
#include "Quantum/IR/QuantumOps.h"
#include "RTIO/IR/RTIOOps.h"

namespace catalyst {
namespace ion {

enum class TraceMode {
Qreg = 0,
Event = 1,
};

/// Traces a Value backward through the IR by tracing its dataflow dependencies
/// across control flow and specific quantum operations.
///
/// Template Parameters:
/// - ModeT: TraceMode enum (Qreg or Event) that controls how quantum.insert
/// operations are handled
/// Qreg mode: Trace to find the source qreg of the given value
/// Event mode: Trace to find all events that contribute to the given value
/// - CallbackT: Callable type that will be invoked for each visited value.
/// May optionally return WalkResult for early termination.
///
/// Supported Operations:
/// - scf.for
/// - scf.if
/// - ion.parallelprotocol
/// - unrealized_conversion_cast
/// - quantum.extract
/// - quantum.insert
template <TraceMode ModeT, typename CallbackT>
auto traceValueWithCallback(mlir::Value value, CallbackT &&callback)
{
using namespace mlir;
static_assert(std::is_same_v<std::invoke_result_t<CallbackT, Value>, WalkResult>,
"Callback must return WalkResult");

WalkResult walkResult = WalkResult::advance();
std::queue<Value> worklist;
worklist.push(value);

while (!worklist.empty()) {
Value value = worklist.front();
worklist.pop();

if (callback(value).wasInterrupted()) {
walkResult = WalkResult::interrupt();
continue;
}

if (auto arg = mlir::dyn_cast<BlockArgument>(value)) {
Block *block = arg.getOwner();
Operation *parentOp = block->getParentOp();

if (auto forOp = dyn_cast<scf::ForOp>(parentOp)) {
unsigned argIndex = arg.getArgNumber();
Value iterArg = forOp.getInitArgs()[argIndex - 1];
worklist.push(iterArg);
continue;
}
else if (auto parallelProtocolOp = dyn_cast<ion::ParallelProtocolOp>(parentOp)) {
unsigned argIndex = arg.getArgNumber();
Value inQubit = parallelProtocolOp.getInQubits()[argIndex];
worklist.push(inQubit);
continue;
}
return WalkResult::interrupt();
}

Operation *defOp = value.getDefiningOp();
if (defOp == nullptr) {
continue;
}

if (auto forOp = dyn_cast<scf::ForOp>(defOp)) {
unsigned resultIdx = llvm::cast<OpResult>(value).getResultNumber();
BlockArgument iterArg = forOp.getRegionIterArg(resultIdx);
worklist.push(iterArg);
}
else if (auto ifOp = dyn_cast<scf::IfOp>(defOp)) {
unsigned resultIdx = llvm::cast<OpResult>(value).getResultNumber();
Value thenValue = ifOp.thenYield().getOperand(resultIdx);
Value elseValue = ifOp.elseYield().getOperand(resultIdx);
worklist.push(thenValue);
worklist.push(elseValue);
}
else if (auto parallelProtocolOp = dyn_cast<ion::ParallelProtocolOp>(defOp)) {
unsigned resultIdx = llvm::cast<OpResult>(value).getResultNumber();
Value inQubit = parallelProtocolOp.getInQubits()[resultIdx];
worklist.push(inQubit);
}
else if (auto op = dyn_cast<mlir::UnrealizedConversionCastOp>(defOp)) {
worklist.push(op.getInputs().front());
}
else if (auto op = dyn_cast<quantum::ExtractOp>(defOp)) {
worklist.push(op.getQreg());
}
else if (auto op = dyn_cast<rtio::RTIOQubitToChannelOp>(defOp)) {
worklist.push(op.getQubit());
}
else if (auto op = dyn_cast<quantum::InsertOp>(defOp)) {
Value inQreg = op.getInQreg();
Value qubit = op.getQubit();
if constexpr (ModeT == TraceMode::Qreg) {
worklist.push(inQreg);
}
else if constexpr (ModeT == TraceMode::Event) {
worklist.push(qubit);
// only trace qreg if it defined op is also come from insert op
if (llvm::isa_and_present<quantum::InsertOp>(inQreg.getDefiningOp())) {
worklist.push(inQreg);
}
}
}
}

return walkResult;
}

} // namespace ion
} // namespace catalyst
1 change: 1 addition & 0 deletions mlir/include/RTIO/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
add_subdirectory(IR)
add_subdirectory(Transforms)
1 change: 1 addition & 0 deletions mlir/include/RTIO/IR/RTIOOps.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "mlir/Bytecode/BytecodeOpInterface.h"
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/OpDefinition.h"
#include "mlir/IR/PatternMatch.h"
#include "mlir/Interfaces/SideEffectInterfaces.h"

#define GET_ATTRDEF_CLASSES
Expand Down
Loading