@@ -14,6 +14,7 @@ include "mlir/IR/BuiltinTypeInterfaces.td"
1414include "mlir/IR/DialectBase.td"
1515include "mlir/IR/EnumAttr.td"
1616include "mlir/IR/OpBase.td"
17+ include "mlir/Interfaces/ControlFlowInterfaces.td"
1718include "mlir/Interfaces/InferTypeOpInterface.td"
1819include "mlir/Interfaces/SideEffectInterfaces.td"
1920
@@ -1048,7 +1049,7 @@ def BarrierOp : QCOOp<"barrier", traits = [UnitaryOpInterface]> {
10481049// Modifiers
10491050//===----------------------------------------------------------------------===//
10501051
1051- def YieldOp : QCOOp<"yield", traits = [Terminator]> {
1052+ def YieldOp : QCOOp<"yield", traits = [Terminator, ReturnLike ]> {
10521053 let summary = "Yield from a modifier region";
10531054 let description = [{
10541055 Terminates a modifier region, yielding the transformed target qubits back to the enclosing modifier operation.
@@ -1205,4 +1206,83 @@ def InvOp : QCOOp<"inv",
12051206 let hasVerifier = 1;
12061207}
12071208
1209+ //===----------------------------------------------------------------------===//
1210+ // SCF operations
1211+ //===----------------------------------------------------------------------===//
1212+
1213+ def IfOp : QCOOp<"if", traits =
1214+ [
1215+ DeclareOpInterfaceMethods<RegionBranchOpInterface, [
1216+ "getNumRegionInvocations", "getRegionInvocationBounds",
1217+ "getEntrySuccessorRegions"]>,
1218+ SingleBlock,
1219+ SingleBlockImplicitTerminator<"::mlir::qco::YieldOp">,
1220+ RecursiveMemoryEffects
1221+ ]> {
1222+
1223+ let summary = "If-then-else operation for linear (qubit) types";
1224+ let description = [{
1225+ The `qco.if` operation is an if-then-else construct similar to the standard scf.if operation.
1226+ In addition to the condition, the operation takes a variadic number of qubits as inputs that are
1227+ required in the bodies of both branches. These qubits are passed down to the individual regions
1228+ as block arguments. The number of results and the type of the results must be equivalent to the
1229+ number and types of the input qubits.
1230+
1231+ Example:
1232+ ```mlir
1233+ %result = qco.if %condition qubits(%arg0 = %q0) {
1234+ %q1 = qco.h %arg0 : !qco.qubit -> !qco.qubit
1235+ qco.yield %q1
1236+ } else qubits(%arg0 = %q0) {
1237+ qco.yield %arg0
1238+ } : {i1, !qco.qubit} -> {!qco.qubit}
1239+ ```
1240+ }];
1241+
1242+ let arguments = (ins I1:$condition, Variadic<QubitType>:$qubits);
1243+ let results = (outs Variadic<QubitType>:$results);
1244+ let regions = (region SizedRegion<1>:$thenRegion,
1245+ SizedRegion<1>:$elseRegion);
1246+
1247+ let assemblyFormat = [{
1248+ $condition
1249+ custom<IfOpAliasing>($thenRegion, $elseRegion, $qubits)
1250+ attr-dict `:`
1251+ `{` type($condition) `,` type($qubits) `}`
1252+ `->`
1253+ `{` type($results) `}`
1254+ }];
1255+
1256+ let builders = [
1257+ OpBuilder<(ins "Value":$condition, "ValueRange":$qubits), [{
1258+ build($_builder, $_state, qubits.getTypes(), condition, qubits);
1259+ }]>,
1260+ OpBuilder<(ins "Value":$condition, "ValueRange":$qubits, "llvm::function_ref<llvm::SmallVector<Value>(ValueRange)>":$thenBuilder,
1261+ CArg<"llvm::function_ref<llvm::SmallVector<Value>(ValueRange)>","nullptr">:$elseBuilder)>
1262+ ];
1263+
1264+ let extraClassDeclaration = [{
1265+ Block *thenBlock() {
1266+ return &getThenRegion().back();
1267+ }
1268+ YieldOp thenYield();
1269+ Block* elseBlock() {
1270+ return &getElseRegion().back();
1271+ }
1272+ YieldOp elseYield();
1273+ }];
1274+
1275+ let extraClassDefinition = [{
1276+ YieldOp $cppClass::thenYield() {
1277+ return cast<YieldOp>(&thenBlock()->back());
1278+ }
1279+ YieldOp $cppClass::elseYield() {
1280+ return cast<YieldOp>(&elseBlock()->back());
1281+ }
1282+ }];
1283+
1284+ let hasCanonicalizer = 1;
1285+ let hasVerifier = 1;
1286+ }
1287+
12081288#endif // QCOOPS
0 commit comments