diff --git a/mlir/include/Ion/IR/IonOps.td b/mlir/include/Ion/IR/IonOps.td index 00ed564b7d..382f7270c9 100644 --- a/mlir/include/Ion/IR/IonOps.td +++ b/mlir/include/Ion/IR/IonOps.td @@ -157,13 +157,13 @@ def PulseOp : Ion_Op<"pulse"> { let arguments = (ins AnyFloat: $time, - QubitType: $in_qubit, + AnyTypeOf<[IonType, QubitType]>: $in_qubit, BeamAttr: $beam, Builtin_FloatAttr: $phase ); let assemblyFormat = [{ - `(` $time `:` type($time) `)` $in_qubit attr-dict + `(` $time `:` type($time) `)` $in_qubit `:` type($in_qubit) attr-dict }]; } @@ -172,10 +172,10 @@ def ParallelProtocolOp : Ion_Op<"parallelprotocol", [SingleBlockImplicitTerminat let summary = "Represent a parallel protocol of pulses."; let arguments = (ins - Variadic: $in_qubits + Variadic>: $in_qubits ); - let results = (outs Variadic:$out_qubits); + let results = (outs Variadic>:$out_qubits); let regions = (region SizedRegion<1>:$region); let builders = [ @@ -192,7 +192,7 @@ def ParallelProtocolOp : Ion_Op<"parallelprotocol", [SingleBlockImplicitTerminat }]; let assemblyFormat = [{ - `(` $in_qubits `)` attr-dict `:` type($out_qubits) $region + `(` ($in_qubits^ `:` type($in_qubits))? `)` attr-dict `:` type($out_qubits) $region }]; } @@ -200,7 +200,7 @@ def YieldOp : Ion_Op<"yield", [Pure, ReturnLike, Terminator, ParentOneOf<["Paral let summary = "Return results from parallel protocol regions"; let arguments = (ins - Variadic:$results + Variadic:$results ); let assemblyFormat = [{ diff --git a/mlir/include/Ion/Transforms/Passes.td b/mlir/include/Ion/Transforms/Passes.td index 5af78d6558..f831860e21 100644 --- a/mlir/include/Ion/Transforms/Passes.td +++ b/mlir/include/Ion/Transforms/Passes.td @@ -30,9 +30,6 @@ def QuantumToIonPass : Pass<"quantum-to-ion"> { Option<"Gate2PulseDecompTomlLoc", "gate-to-pulse-toml-loc", "std::string", /*default=*/"\"\"", "Toml file location for the ion hardware gate-to-pulse decomposition parameters.">, - Option<"LoadIon", "load-ion", - "bool", /*default=*/"true", - "Whether to load the physical parameters for the ion (e.g. mass, charge, spin) into the IR.">, ]; let dependentDialects = [ diff --git a/mlir/lib/Ion/IR/IonOps.cpp b/mlir/lib/Ion/IR/IonOps.cpp index 8438e4b40c..4226694c71 100644 --- a/mlir/lib/Ion/IR/IonOps.cpp +++ b/mlir/lib/Ion/IR/IonOps.cpp @@ -43,15 +43,26 @@ void ParallelProtocolOp::build(OpBuilder &builder, OperationState &result, Value { OpBuilder::InsertionGuard guard(builder); Location loc = result.location; - + Type ionType = IonType::get(result.getContext()); + + // The parallel protocol op can interact with the outside world by accepting + // either ion types or qubit types. + // We allow qubit types because during `quantum-to-ion`, during gate-to-pulse + // decomposition, we still need the core quantum dialect to track SSA def use + // chains of qubit values. + // After gate-to-pulse decomposition is finished, we change all parallel protocol + // ops to return ion types. + // Note that the body region is shielded from the outside, so its block can + // have an ion type argument directly result.addOperands(inQubits); - for (Value v : inQubits) + for (Value v : inQubits) { result.addTypes(v.getType()); + } Region *bodyRegion = result.addRegion(); Block *bodyBlock = builder.createBlock(bodyRegion); for (Value v : inQubits) { - bodyBlock->addArgument(v.getType(), v.getLoc()); + bodyBlock->addArgument(ionType, v.getLoc()); } builder.setInsertionPointToStart(bodyBlock); diff --git a/mlir/lib/Ion/Transforms/quantum_to_ion.cpp b/mlir/lib/Ion/Transforms/quantum_to_ion.cpp index 65887ba2dc..665a1410f1 100644 --- a/mlir/lib/Ion/Transforms/quantum_to_ion.cpp +++ b/mlir/lib/Ion/Transforms/quantum_to_ion.cpp @@ -68,7 +68,6 @@ struct QuantumToIonPass : impl::QuantumToIonPassBase { void runOnOperation() final { func::FuncOp op = cast(getOperation()); - // auto module = getOperation(); auto &context = getContext(); ConversionTarget target(context); @@ -78,12 +77,16 @@ struct QuantumToIonPass : impl::QuantumToIonPassBase { OQDDatabaseManager dataManager(DeviceTomlLoc, QubitTomlLoc, Gate2PulseDecompTomlLoc); - if (LoadIon) { - // FIXME(?): we only load Yb171 ion since the hardware ion species is unlikely to change - MLIRContext *ctx = op->getContext(); - IRRewriter builder(ctx); - Ion ion = dataManager.getIonParams().at("Yb171"); + // FIXME(?): we only load Yb171 ion since the hardware ion species is unlikely to change + MLIRContext *ctx = op->getContext(); + IRRewriter builder(ctx); + Ion ion = dataManager.getIonParams().at("Yb171"); + // First, we need to convert each qubit to an ion + // A qubit is initialized as an extract op from an alloc op in quantum dialect + llvm::DenseMap qubitMap; + + op->walk([&](quantum::ExtractOp qExtract) { SmallVector levels, transitions; for (const Level &level : ion.levels) { levels.push_back(cast(getLevelAttr(ctx, builder, level))); @@ -92,20 +95,45 @@ struct QuantumToIonPass : impl::QuantumToIonPassBase { transitions.push_back(cast(getTransitionAttr(ctx, builder, transition))); } - builder.setInsertionPointToStart(&(op->getRegion(0).front())); - builder.create( + builder.setInsertionPointAfter(qExtract); + ion::IonOp ionOp = builder.create( op->getLoc(), IonType::get(ctx), builder.getStringAttr(ion.name), builder.getF64FloatAttr(ion.mass), builder.getF64FloatAttr(ion.charge), builder.getI64VectorAttr(ion.position), builder.getArrayAttr(levels), builder.getArrayAttr(transitions)); - } + qubitMap.insert({qExtract.getQubit(), ionOp.getOutIon()}); + }); + + // Then, we decompose the quantum gates on qubits to pulses on qubits + // We keep the quantum dialect at this stage since we still want the SSA def use + // chains from the quantum dialect. RewritePatternSet ionPatterns(&getContext()); populateQuantumToIonPatterns(ionPatterns, dataManager); if (failed(applyPartialConversion(op, target, std::move(ionPatterns)))) { return signalPassFailure(); } + + // Finally, to aid ion api stub generation, we eliminate all quantum dialect + // We replace uses and change all quantum.bit types to ion.ion types + for (auto [qubit, ion] : qubitMap) { + qubit.replaceAllUsesWith(ion); + qubit.getDefiningOp()->erase(); + } + + Type ionType = IonType::get(ctx); + op->walk([&](ion::ParallelProtocolOp ppOp) { + for (auto v : ppOp->getResults()) { + v.setType(ionType); + } + }); + + SmallVector qAllocOps; + op->walk([&](quantum::AllocOp alloc) { qAllocOps.push_back(alloc); }); + for (auto alloc : qAllocOps) { + alloc->erase(); + } } }; diff --git a/mlir/test/Ion/Dialect.mlir b/mlir/test/Ion/Dialect.mlir index e96ac871e3..5a4dd85057 100644 --- a/mlir/test/Ion/Dialect.mlir +++ b/mlir/test/Ion/Dialect.mlir @@ -20,14 +20,14 @@ func.func @example_pulse(%arg0: f64) -> !quantum.bit { // CHECK: [[q0:%.+]] = quantum.extract %0[ 0] : !quantum.reg -> !quantum.bit %1 = quantum.extract %0[0] : !quantum.reg -> !quantum.bit - // CHECK: ion.pulse(%arg0 : f64) [[q0]] {beam = #ion.beam< + // CHECK: ion.pulse(%arg0 : f64) [[q0]] : !quantum.bit {beam = #ion.beam< // CHECK-SAME: transition_index = 0 : i64, // CHECK-SAME: rabi = 1.010000e+01 : f64, // CHECK-SAME: detuning = 1.111000e+01 : f64, // CHECK-SAME: polarization = dense<[0, 1]> : tensor<2xi64>, // CHECK-SAME: wavevector = dense<[0, 1]> : tensor<2xi64>>, // CHECK-SAME: phase = 0.000000e+00 : f64} - ion.pulse(%arg0: f64) %1 { + ion.pulse(%arg0: f64) %1 : !quantum.bit { beam=#ion.beam< transition_index=0, rabi=10.10, @@ -49,17 +49,17 @@ func.func @example_parallel_protocol(%arg0: f64) -> !quantum.bit { // CHECK: [[q0:%.+]] = quantum.extract %0[ 0] : !quantum.reg -> !quantum.bit %1 = quantum.extract %0[0] : !quantum.reg -> !quantum.bit - // CHECK: [[paraproto:%.+]] = ion.parallelprotocol([[q0]]) : !quantum.bit { - %2 = ion.parallelprotocol(%1): !quantum.bit { - ^bb0(%arg1: !quantum.bit): - // CHECK: ion.pulse(%arg0 : f64) %arg1 {beam = #ion.beam< + // CHECK: [[paraproto:%.+]] = ion.parallelprotocol([[q0]] : !quantum.bit) : !quantum.bit { + %2 = ion.parallelprotocol(%1 : !quantum.bit): !quantum.bit { + ^bb0(%arg1: !ion.ion): + // CHECK: ion.pulse(%arg0 : f64) %arg1 : !ion.ion {beam = #ion.beam< // CHECK-SAME: transition_index = 1 : i64, // CHECK-SAME: rabi = 1.010000e+01 : f64, // CHECK-SAME: detuning = 1.111000e+01 : f64, // CHECK-SAME: polarization = dense<[0, 1]> : tensor<2xi64>, // CHECK-SAME: wavevector = dense<[0, 1]> : tensor<2xi64>>, // CHECK-SAME: phase = 0.000000e+00 : f64} - ion.pulse(%arg0: f64) %arg1 { + ion.pulse(%arg0: f64) %arg1 : !ion.ion { beam=#ion.beam< transition_index=1, rabi=10.10, @@ -69,14 +69,14 @@ func.func @example_parallel_protocol(%arg0: f64) -> !quantum.bit { >, phase=0.0 } - // CHECK: ion.pulse(%arg0 : f64) %arg1 {beam = #ion.beam< + // CHECK: ion.pulse(%arg0 : f64) %arg1 : !ion.ion {beam = #ion.beam< // CHECK-SAME: transition_index = 0 : i64, // CHECK-SAME: rabi = 1.010000e+01 : f64, // CHECK-SAME: detuning = 1.111000e+01 : f64, // CHECK-SAME: polarization = dense<[0, 1]> : tensor<2xi64>, // CHECK-SAME: wavevector = dense<[0, 1]> : tensor<2xi64>>, // CHECK-SAME: phase = 0.000000e+00 : f64} - ion.pulse(%arg0: f64) %arg1 { + ion.pulse(%arg0: f64) %arg1 : !ion.ion { beam=#ion.beam< transition_index=0, rabi=10.10, @@ -86,8 +86,8 @@ func.func @example_parallel_protocol(%arg0: f64) -> !quantum.bit { >, phase=0.0 } - // CHECK: ion.yield %arg1 : !quantum.bit - ion.yield %arg1: !quantum.bit + // CHECK: ion.yield %arg1 : !ion.ion + ion.yield %arg1: !ion.ion } // CHECK: return [[paraproto]] : !quantum.bit @@ -103,17 +103,17 @@ func.func @example_parallel_protocol_two_qubits(%arg0: f64) -> (!quantum.bit, !q // CHECK: [[q1:%.+]] = quantum.extract %0[ 1] : !quantum.reg -> !quantum.bit %2 = quantum.extract %0[1] : !quantum.reg -> !quantum.bit - // CHECK: [[paraproto:%.+]]{{:2}} = ion.parallelprotocol([[q0]], [[q1]]) : !quantum.bit, !quantum.bit { - %3:2 = ion.parallelprotocol(%1, %2): !quantum.bit, !quantum.bit { - ^bb0(%arg1: !quantum.bit, %arg2: !quantum.bit): - // CHECK: ion.pulse(%arg0 : f64) %arg1 {beam = #ion.beam< + // CHECK: [[paraproto:%.+]]{{:2}} = ion.parallelprotocol([[q0]], [[q1]] : !quantum.bit, !quantum.bit) : !quantum.bit, !quantum.bit { + %3:2 = ion.parallelprotocol(%1, %2 : !quantum.bit, !quantum.bit): !quantum.bit, !quantum.bit { + ^bb0(%arg1: !ion.ion, %arg2: !ion.ion): + // CHECK: ion.pulse(%arg0 : f64) %arg1 : !ion.ion {beam = #ion.beam< // CHECK-SAME: transition_index = 2 : i64, // CHECK-SAME: rabi = 1.010000e+01 : f64, // CHECK-SAME: detuning = 1.111000e+01 : f64, // CHECK-SAME: polarization = dense<[0, 1]> : tensor<2xi64>, // CHECK-SAME: wavevector = dense<[0, 1]> : tensor<2xi64>>, // CHECK-SAME: phase = 0.000000e+00 : f64} - ion.pulse(%arg0: f64) %arg1 { + ion.pulse(%arg0: f64) %arg1 : !ion.ion { beam=#ion.beam< transition_index=2, rabi=10.10, @@ -123,14 +123,14 @@ func.func @example_parallel_protocol_two_qubits(%arg0: f64) -> (!quantum.bit, !q >, phase=0.0 } - // CHECK: ion.pulse(%arg0 : f64) %arg2 {beam = #ion.beam< + // CHECK: ion.pulse(%arg0 : f64) %arg2 : !ion.ion {beam = #ion.beam< // CHECK-SAME: transition_index = 1 : i64, // CHECK-SAME: rabi = 1.010000e+01 : f64, // CHECK-SAME: detuning = 1.111000e+01 : f64, // CHECK-SAME: polarization = dense<[0, 1]> : tensor<2xi64>, // CHECK-SAME: wavevector = dense<[0, 1]> : tensor<2xi64>>, // CHECK-SAME: phase = 0.000000e+00 : f64} - ion.pulse(%arg0: f64) %arg2 { + ion.pulse(%arg0: f64) %arg2 : !ion.ion { beam=#ion.beam< transition_index=1, rabi=10.10, @@ -140,8 +140,8 @@ func.func @example_parallel_protocol_two_qubits(%arg0: f64) -> (!quantum.bit, !q >, phase=0.0 } - // CHECK: ion.yield %arg1, %arg2 : !quantum.bit, !quantum.bit - ion.yield %arg1, %arg2: !quantum.bit, !quantum.bit + // CHECK: ion.yield %arg1, %arg2 : !ion.ion, !ion.ion + ion.yield %arg1, %arg2: !ion.ion, !ion.ion } // CHECK: return [[paraproto]]#0, [[paraproto]]#1 : !quantum.bit, !quantum.bit diff --git a/mlir/test/Ion/QuantumToIon.mlir b/mlir/test/Ion/QuantumToIon.mlir index e72126a056..9c7eb8797b 100644 --- a/mlir/test/Ion/QuantumToIon.mlir +++ b/mlir/test/Ion/QuantumToIon.mlir @@ -19,14 +19,14 @@ // RUN: --split-input-file -verify-diagnostics | FileCheck %s // CHECK-LABEL: example_ion_two_qubit -func.func @example_ion_two_qubit(%arg0: f64) -> !quantum.bit { +func.func @example_ion_two_qubit(%arg0: f64) -> () { // COM: attr-dict in op's assembly format sorts fields alphabetically // COM: so we have to CHECK-SAME in alphabetical order as well // COM: The order is charge, levels, mass, name, position, transitions - // CHECK: {{%.+}} = ion.ion { + // CHECK: [[qubit0:%.+]] = ion.ion { // CHECK-SAME: charge = 1.000000e+00 // CHECK-SAME: levels = [ // CHECK-SAME: #ion.level< @@ -85,18 +85,16 @@ func.func @example_ion_two_qubit(%arg0: f64) -> !quantum.bit { // CHECK-SAME: ] // CHECK-SAME: } : !ion.ion + // CHECK-NEXT: [[qubit1:%.+]] = ion.ion %1 = quantum.alloc( 2) : !quantum.reg - - // CHECK: [[qubit0:%.+]] = quantum.extract %1[ 0] : !quantum.reg -> !quantum.bit - // CHECK: [[qubit1:%.+]] = quantum.extract %1[ 1] : !quantum.reg -> !quantum.bit %2 = quantum.extract %1[ 0] : !quantum.reg -> !quantum.bit %3 = quantum.extract %1[ 1] : !quantum.reg -> !quantum.bit - // CHECK: [[rx1out:%.+]] = ion.parallelprotocol([[qubit0]]) : !quantum.bit { - // CHECK-NEXT: ^{{.*}}(%arg1: !quantum.bit): + // CHECK: [[rx1out:%.+]] = ion.parallelprotocol([[qubit0]] : !ion.ion) : !ion.ion { + // CHECK-NEXT: ^{{.*}}(%arg1: !ion.ion): // CHECK-NEXT: [[rabi1:%.+]] = arith.constant 1.100000e+00 : f64 // CHECK-NEXT: [[timerx1:%.+]] = arith.divf %arg0, [[rabi1]] : f64 - // CHECK-NEXT: ion.pulse([[timerx1]] : f64) %arg1 { + // CHECK-NEXT: ion.pulse([[timerx1]] : f64) %arg1 : !ion.ion { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 0 : i64, // CHECK-SAME: rabi = 1.100000e+00 : f64, @@ -104,7 +102,7 @@ func.func @example_ion_two_qubit(%arg0: f64) -> !quantum.bit { // CHECK-SAME: polarization = dense<[0, 1]> : vector<2xi64>, // CHECK-SAME: wavevector = dense<[-2, 3]> : vector<2xi64>>, // CHECK-SAME: phase = 0.000000e+00 : f64} - // CHECK-NEXT: ion.pulse([[timerx1]] : f64) %arg1 { + // CHECK-NEXT: ion.pulse([[timerx1]] : f64) %arg1 : !ion.ion { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 1 : i64, // CHECK-SAME: rabi = 1.100000e+00 : f64, @@ -112,15 +110,15 @@ func.func @example_ion_two_qubit(%arg0: f64) -> !quantum.bit { // CHECK-SAME: polarization = dense<[0, 1]> : vector<2xi64>, // CHECK-SAME: wavevector = dense<[-2, 3]> : vector<2xi64>>, // CHECK-SAME: phase = 0.000000e+00 : f64} - // CHECK-NEXT: ion.yield %arg1 : !quantum.bit + // CHECK-NEXT: ion.yield %arg1 : !ion.ion // CHECK-NEXT: } %4 = quantum.custom "RX"(%arg0) %2 : !quantum.bit - // CHECK: [[ry1out:%.+]] = ion.parallelprotocol([[rx1out]]) : !quantum.bit { - // CHECK-NEXT: ^{{.*}}(%arg1: !quantum.bit): + // CHECK: [[ry1out:%.+]] = ion.parallelprotocol([[rx1out]] : !ion.ion) : !ion.ion { + // CHECK-NEXT: ^{{.*}}(%arg1: !ion.ion): // CHECK-NEXT: [[rabi1:%.+]] = arith.constant 1.100000e+00 : f64 // CHECK-NEXT: [[timery1:%.+]] = arith.divf %arg0, [[rabi1]] : f64 - // CHECK-NEXT: ion.pulse([[timery1]] : f64) %arg1 { + // CHECK-NEXT: ion.pulse([[timery1]] : f64) %arg1 : !ion.ion { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 0 : i64, // CHECK-SAME: rabi = 1.100000e+00 : f64, @@ -128,7 +126,7 @@ func.func @example_ion_two_qubit(%arg0: f64) -> !quantum.bit { // CHECK-SAME: polarization = dense<[0, 1]> : vector<2xi64>, // CHECK-SAME: wavevector = dense<[-2, 3]> : vector<2xi64>>, // CHECK-SAME: phase = 0.000000e+00 : f64} - // CHECK-NEXT: ion.pulse([[timery1]] : f64) %arg1 { + // CHECK-NEXT: ion.pulse([[timery1]] : f64) %arg1 : !ion.ion { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 1 : i64, // CHECK-SAME: rabi = 1.100000e+00 : f64, @@ -136,15 +134,15 @@ func.func @example_ion_two_qubit(%arg0: f64) -> !quantum.bit { // CHECK-SAME: polarization = dense<[0, 1]> : vector<2xi64>, // CHECK-SAME: wavevector = dense<[-2, 3]> : vector<2xi64>>, // CHECK-SAME: phase = 3.1415926535{{[0-9]*}} : f64} - // CHECK-NEXT: ion.yield %arg1 : !quantum.bit + // CHECK-NEXT: ion.yield %arg1 : !ion.ion // CHECK-NEXT: } %5 = quantum.custom "RY"(%arg0) %4 : !quantum.bit - // CHECK: [[rx2out:%.+]] = ion.parallelprotocol([[ry1out]]) : !quantum.bit { - // CHECK-NEXT: ^{{.*}}(%arg1: !quantum.bit): + // CHECK: [[rx2out:%.+]] = ion.parallelprotocol([[ry1out]] : !ion.ion) : !ion.ion { + // CHECK-NEXT: ^{{.*}}(%arg1: !ion.ion): // CHECK-NEXT: [[rabi1:%.+]] = arith.constant 1.100000e+00 : f64 // CHECK-NEXT: [[timerx2:%.+]] = arith.divf %arg0, [[rabi1]] : f64 - // CHECK-NEXT: ion.pulse([[timerx2]] : f64) %arg1 { + // CHECK-NEXT: ion.pulse([[timerx2]] : f64) %arg1 : !ion.ion { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 0 : i64, // CHECK-SAME: rabi = 1.100000e+00 : f64, @@ -152,7 +150,7 @@ func.func @example_ion_two_qubit(%arg0: f64) -> !quantum.bit { // CHECK-SAME: polarization = dense<[0, 1]> : vector<2xi64>, // CHECK-SAME: wavevector = dense<[-2, 3]> : vector<2xi64>>, // CHECK-SAME: phase = 0.000000e+00 : f64} - // CHECK-NEXT: ion.pulse([[timerx2]] : f64) %arg1 { + // CHECK-NEXT: ion.pulse([[timerx2]] : f64) %arg1 : !ion.ion { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 1 : i64, // CHECK-SAME: rabi = 1.100000e+00 : f64, @@ -160,15 +158,15 @@ func.func @example_ion_two_qubit(%arg0: f64) -> !quantum.bit { // CHECK-SAME: polarization = dense<[0, 1]> : vector<2xi64>, // CHECK-SAME: wavevector = dense<[-2, 3]> : vector<2xi64>>, // CHECK-SAME: phase = 0.000000e+00 : f64} - // CHECK-NEXT: ion.yield %arg1 : !quantum.bit + // CHECK-NEXT: ion.yield %arg1 : !ion.ion // CHECK-NEXT: } %6 = quantum.custom "RX"(%arg0) %5 : !quantum.bit - // CHECK: [[msout:%.+]] = ion.parallelprotocol([[rx2out]], [[qubit1]]) : !quantum.bit, !quantum.bit { - // CHECK-NEXT: ^{{.*}}(%arg1: !quantum.bit, %arg2: !quantum.bit): + // CHECK: [[msout:%.+]] = ion.parallelprotocol([[rx2out]], [[qubit1]] : !ion.ion, !ion.ion) : !ion.ion, !ion.ion { + // CHECK-NEXT: ^{{.*}}(%arg1: !ion.ion, %arg2: !ion.ion): // CHECK-NEXT: [[rabi2:%.+]] = arith.constant 1.230000e+00 : f64 // CHECK-NEXT: [[timems:%.+]] = arith.divf %arg0, [[rabi2]] : f64 - // CHECK-NEXT: ion.pulse([[timems]] : f64) %arg1 { + // CHECK-NEXT: ion.pulse([[timems]] : f64) %arg1 : !ion.ion { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 0 : i64, // CHECK-SAME: rabi = 1.230000e+00 : f64, @@ -176,7 +174,7 @@ func.func @example_ion_two_qubit(%arg0: f64) -> !quantum.bit { // CHECK-SAME: polarization = dense<[7, 8]> : vector<2xi64>, // CHECK-SAME: wavevector = dense<[9, 10]> : vector<2xi64>>, // CHECK-SAME: phase = 0.000000e+00 : f64} - // CHECK-NEXT: ion.pulse([[timems]] : f64) %arg1 { + // CHECK-NEXT: ion.pulse([[timems]] : f64) %arg1 : !ion.ion { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 1 : i64, // CHECK-SAME: rabi = 1.230000e+00 : f64, @@ -184,7 +182,7 @@ func.func @example_ion_two_qubit(%arg0: f64) -> !quantum.bit { // CHECK-SAME: polarization = dense<[7, 8]> : vector<2xi64>, // CHECK-SAME: wavevector = dense<[-9, -10]> : vector<2xi64>>, // CHECK-SAME: phase = 0.000000e+00 : f64} - // CHECK-NEXT: ion.pulse([[timems]] : f64) %arg1 { + // CHECK-NEXT: ion.pulse([[timems]] : f64) %arg1 : !ion.ion { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 1 : i64, // CHECK-SAME: rabi = 1.230000e+00 : f64, @@ -192,7 +190,7 @@ func.func @example_ion_two_qubit(%arg0: f64) -> !quantum.bit { // CHECK-SAME: polarization = dense<[7, 8]> : vector<2xi64>, // CHECK-SAME: wavevector = dense<[-9, -10]> : vector<2xi64>>, // CHECK-SAME: phase = 0.000000e+00 : f64} - // CHECK-NEXT: ion.pulse([[timems]] : f64) %arg2 { + // CHECK-NEXT: ion.pulse([[timems]] : f64) %arg2 : !ion.ion { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 0 : i64, // CHECK-SAME: rabi = 1.230000e+00 : f64, @@ -200,7 +198,7 @@ func.func @example_ion_two_qubit(%arg0: f64) -> !quantum.bit { // CHECK-SAME: polarization = dense<[7, 8]> : vector<2xi64>, // CHECK-SAME: wavevector = dense<[9, 10]> : vector<2xi64>>, // CHECK-SAME: phase = 0.000000e+00 : f64} - // CHECK-NEXT: ion.pulse([[timems]] : f64) %arg2 { + // CHECK-NEXT: ion.pulse([[timems]] : f64) %arg2 : !ion.ion { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 1 : i64, // CHECK-SAME: rabi = 1.230000e+00 : f64, @@ -208,7 +206,7 @@ func.func @example_ion_two_qubit(%arg0: f64) -> !quantum.bit { // CHECK-SAME: polarization = dense<[7, 8]> : vector<2xi64>, // CHECK-SAME: wavevector = dense<[-9, -10]> : vector<2xi64>>, // CHECK-SAME: phase = 0.000000e+00 : f64} - // CHECK-NEXT: ion.pulse([[timems]] : f64) %arg2 { + // CHECK-NEXT: ion.pulse([[timems]] : f64) %arg2 : !ion.ion { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 1 : i64, // CHECK-SAME: rabi = 1.230000e+00 : f64, @@ -216,10 +214,10 @@ func.func @example_ion_two_qubit(%arg0: f64) -> !quantum.bit { // CHECK-SAME: polarization = dense<[7, 8]> : vector<2xi64>, // CHECK-SAME: wavevector = dense<[-9, -10]> : vector<2xi64>>, // CHECK-SAME: phase = 0.000000e+00 : f64} - // CHECK-NEXT: ion.yield %arg1, %arg2 : !quantum.bit, !quantum.bit + // CHECK-NEXT: ion.yield %arg1, %arg2 : !ion.ion, !ion.ion // CHECK-NEXT: } %7:2 = quantum.custom "MS"(%arg0) %6, %3 : !quantum.bit, !quantum.bit - return %7#0: !quantum.bit + return } @@ -227,25 +225,23 @@ func.func @example_ion_two_qubit(%arg0: f64) -> !quantum.bit { // CHECK-LABEL: example_ion_three_qubit -func.func @example_ion_three_qubit(%arg0: f64) -> (!quantum.bit, !quantum.bit, !quantum.bit) { +func.func @example_ion_three_qubit(%arg0: f64) -> () { - // CHECK: {{%.+}} = ion.ion + // CHECK: [[qubit0:%.+]] = ion.ion + // CHECK-NEXT: [[qubit1:%.+]] = ion.ion + // CHECK-NEXT: [[qubit2:%.+]] = ion.ion %1 = quantum.alloc( 3) : !quantum.reg - - // CHECK: [[qubit0:%.+]] = quantum.extract %1[ 0] : !quantum.reg -> !quantum.bit - // CHECK: [[qubit1:%.+]] = quantum.extract %1[ 1] : !quantum.reg -> !quantum.bit - // CHECK: [[qubit2:%.+]] = quantum.extract %1[ 2] : !quantum.reg -> !quantum.bit %2 = quantum.extract %1[ 0] : !quantum.reg -> !quantum.bit %3 = quantum.extract %1[ 1] : !quantum.reg -> !quantum.bit %4 = quantum.extract %1[ 2] : !quantum.reg -> !quantum.bit - // CHECK: [[ms1out:%.+]]:2 = ion.parallelprotocol([[qubit0]], [[qubit1]]) : !quantum.bit, !quantum.bit { + // CHECK: [[ms1out:%.+]]:2 = ion.parallelprotocol([[qubit0]], [[qubit1]] : !ion.ion, !ion.ion) : !ion.ion, !ion.ion { - // CHECK-NEXT: ^{{.*}}(%arg1: !quantum.bit, %arg2: !quantum.bit): + // CHECK-NEXT: ^{{.*}}(%arg1: !ion.ion, %arg2: !ion.ion): // CHECK-NEXT: [[rabi1:%.+]] = arith.constant 1.230000e+00 : f64 // CHECK-NEXT: [[timems1:%.+]] = arith.divf %arg0, [[rabi1]] : f64 - // CHECK-NEXT: ion.pulse([[timems1]] : f64) %arg1 { + // CHECK-NEXT: ion.pulse([[timems1]] : f64) %arg1 : !ion.ion { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 0 : i64, // CHECK-SAME: rabi = 1.230000e+00 : f64, @@ -253,7 +249,7 @@ func.func @example_ion_three_qubit(%arg0: f64) -> (!quantum.bit, !quantum.bit, ! // CHECK-SAME: polarization = dense<[7, 8]> : vector<2xi64>, // CHECK-SAME: wavevector = dense<[9, 10]> : vector<2xi64>>, // CHECK-SAME: phase = 0.000000e+00 : f64} - // CHECK-NEXT: ion.pulse([[timems1]] : f64) %arg1 { + // CHECK-NEXT: ion.pulse([[timems1]] : f64) %arg1 : !ion.ion { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 1 : i64, // CHECK-SAME: rabi = 1.230000e+00 : f64, @@ -261,7 +257,7 @@ func.func @example_ion_three_qubit(%arg0: f64) -> (!quantum.bit, !quantum.bit, ! // CHECK-SAME: polarization = dense<[7, 8]> : vector<2xi64>, // CHECK-SAME: wavevector = dense<[-9, -10]> : vector<2xi64>>, // CHECK-SAME: phase = 0.000000e+00 : f64} - // CHECK-NEXT: ion.pulse([[timems1]] : f64) %arg1 { + // CHECK-NEXT: ion.pulse([[timems1]] : f64) %arg1 : !ion.ion { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 1 : i64, // CHECK-SAME: rabi = 1.230000e+00 : f64, @@ -269,7 +265,7 @@ func.func @example_ion_three_qubit(%arg0: f64) -> (!quantum.bit, !quantum.bit, ! // CHECK-SAME: polarization = dense<[7, 8]> : vector<2xi64>, // CHECK-SAME: wavevector = dense<[-9, -10]> : vector<2xi64>>, // CHECK-SAME: phase = 0.000000e+00 : f64} - // CHECK-NEXT: ion.pulse([[timems1]] : f64) %arg2 { + // CHECK-NEXT: ion.pulse([[timems1]] : f64) %arg2 : !ion.ion { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 0 : i64, // CHECK-SAME: rabi = 1.230000e+00 : f64, @@ -277,7 +273,7 @@ func.func @example_ion_three_qubit(%arg0: f64) -> (!quantum.bit, !quantum.bit, ! // CHECK-SAME: polarization = dense<[7, 8]> : vector<2xi64>, // CHECK-SAME: wavevector = dense<[9, 10]> : vector<2xi64>>, // CHECK-SAME: phase = 0.000000e+00 : f64} - // CHECK-NEXT: ion.pulse([[timems1]] : f64) %arg2 { + // CHECK-NEXT: ion.pulse([[timems1]] : f64) %arg2 : !ion.ion { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 1 : i64, // CHECK-SAME: rabi = 1.230000e+00 : f64, @@ -285,7 +281,7 @@ func.func @example_ion_three_qubit(%arg0: f64) -> (!quantum.bit, !quantum.bit, ! // CHECK-SAME: polarization = dense<[7, 8]> : vector<2xi64>, // CHECK-SAME: wavevector = dense<[-9, -10]> : vector<2xi64>>, // CHECK-SAME: phase = 0.000000e+00 : f64} - // CHECK-NEXT: ion.pulse([[timems1]] : f64) %arg2 { + // CHECK-NEXT: ion.pulse([[timems1]] : f64) %arg2 : !ion.ion { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 1 : i64, // CHECK-SAME: rabi = 1.230000e+00 : f64, @@ -293,15 +289,15 @@ func.func @example_ion_three_qubit(%arg0: f64) -> (!quantum.bit, !quantum.bit, ! // CHECK-SAME: polarization = dense<[7, 8]> : vector<2xi64>, // CHECK-SAME: wavevector = dense<[-9, -10]> : vector<2xi64>>, // CHECK-SAME: phase = 0.000000e+00 : f64} - // CHECK-NEXT: ion.yield %arg1, %arg2 : !quantum.bit, !quantum.bit + // CHECK-NEXT: ion.yield %arg1, %arg2 : !ion.ion, !ion.ion // CHECK-NEXT: } %5:2 = quantum.custom "MS"(%arg0) %2, %3 : !quantum.bit, !quantum.bit - // CHECK: [[ms2out:%.+]]:2 = ion.parallelprotocol([[ms1out]]#0, [[qubit2]]) : !quantum.bit, !quantum.bit { - // CHECK-NEXT: ^{{.*}}(%arg1: !quantum.bit, %arg2: !quantum.bit): + // CHECK: [[ms2out:%.+]]:2 = ion.parallelprotocol([[ms1out]]#0, [[qubit2]] : !ion.ion, !ion.ion) : !ion.ion, !ion.ion { + // CHECK-NEXT: ^{{.*}}(%arg1: !ion.ion, %arg2: !ion.ion): // CHECK-NEXT: [[rabi2:%.+]] = arith.constant 4.560000e+00 : f64 // CHECK-NEXT: [[timems2:%.+]] = arith.divf %arg0, [[rabi2]] : f64 - // CHECK-NEXT: ion.pulse([[timems2]] : f64) %arg1 { + // CHECK-NEXT: ion.pulse([[timems2]] : f64) %arg1 : !ion.ion { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 0 : i64, // CHECK-SAME: rabi = 4.560000e+00 : f64, @@ -309,7 +305,7 @@ func.func @example_ion_three_qubit(%arg0: f64) -> (!quantum.bit, !quantum.bit, ! // CHECK-SAME: polarization = dense<[1, 2]> : vector<2xi64>, // CHECK-SAME: wavevector = dense<[-3, 4]> : vector<2xi64>>, // CHECK-SAME: phase = 0.000000e+00 : f64} - // CHECK-NEXT: ion.pulse([[timems2]] : f64) %arg1 { + // CHECK-NEXT: ion.pulse([[timems2]] : f64) %arg1 : !ion.ion { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 1 : i64, // CHECK-SAME: rabi = 4.560000e+00 : f64, @@ -317,7 +313,7 @@ func.func @example_ion_three_qubit(%arg0: f64) -> (!quantum.bit, !quantum.bit, ! // CHECK-SAME: polarization = dense<[1, 2]> : vector<2xi64>, // CHECK-SAME: wavevector = dense<[3, -4]> : vector<2xi64>>, // CHECK-SAME: phase = 0.000000e+00 : f64} - // CHECK-NEXT: ion.pulse([[timems2]] : f64) %arg1 { + // CHECK-NEXT: ion.pulse([[timems2]] : f64) %arg1 : !ion.ion { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 1 : i64, // CHECK-SAME: rabi = 4.560000e+00 : f64, @@ -325,7 +321,7 @@ func.func @example_ion_three_qubit(%arg0: f64) -> (!quantum.bit, !quantum.bit, ! // CHECK-SAME: polarization = dense<[1, 2]> : vector<2xi64>, // CHECK-SAME: wavevector = dense<[3, -4]> : vector<2xi64>>, // CHECK-SAME: phase = 0.000000e+00 : f64} - // CHECK-NEXT: ion.pulse([[timems2]] : f64) %arg2 { + // CHECK-NEXT: ion.pulse([[timems2]] : f64) %arg2 : !ion.ion { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 0 : i64, // CHECK-SAME: rabi = 4.560000e+00 : f64, @@ -333,7 +329,7 @@ func.func @example_ion_three_qubit(%arg0: f64) -> (!quantum.bit, !quantum.bit, ! // CHECK-SAME: polarization = dense<[1, 2]> : vector<2xi64>, // CHECK-SAME: wavevector = dense<[-3, 4]> : vector<2xi64>>, // CHECK-SAME: phase = 0.000000e+00 : f64} - // CHECK-NEXT: ion.pulse([[timems2]] : f64) %arg2 { + // CHECK-NEXT: ion.pulse([[timems2]] : f64) %arg2 : !ion.ion { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 1 : i64, // CHECK-SAME: rabi = 4.560000e+00 : f64, @@ -341,7 +337,7 @@ func.func @example_ion_three_qubit(%arg0: f64) -> (!quantum.bit, !quantum.bit, ! // CHECK-SAME: polarization = dense<[1, 2]> : vector<2xi64>, // CHECK-SAME: wavevector = dense<[3, -4]> : vector<2xi64>>, // CHECK-SAME: phase = 0.000000e+00 : f64} - // CHECK-NEXT: ion.pulse([[timems2]] : f64) %arg2 { + // CHECK-NEXT: ion.pulse([[timems2]] : f64) %arg2 : !ion.ion { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 1 : i64, // CHECK-SAME: rabi = 4.560000e+00 : f64, @@ -349,15 +345,15 @@ func.func @example_ion_three_qubit(%arg0: f64) -> (!quantum.bit, !quantum.bit, ! // CHECK-SAME: polarization = dense<[1, 2]> : vector<2xi64>, // CHECK-SAME: wavevector = dense<[3, -4]> : vector<2xi64>>, // CHECK-SAME: phase = 0.000000e+00 : f64} - // CHECK-NEXT: ion.yield %arg1, %arg2 : !quantum.bit, !quantum.bit + // CHECK-NEXT: ion.yield %arg1, %arg2 : !ion.ion, !ion.ion // CHECK-NEXT: } %6:2 = quantum.custom "MS"(%arg0) %5#0, %4 : !quantum.bit, !quantum.bit - // CHECK: [[ms3out:%.+]]:2 = ion.parallelprotocol([[ms1out]]#1, [[ms2out]]#1) : !quantum.bit, !quantum.bit { - // CHECK-NEXT: ^{{.*}}(%arg1: !quantum.bit, %arg2: !quantum.bit): + // CHECK: [[ms3out:%.+]]:2 = ion.parallelprotocol([[ms1out]]#1, [[ms2out]]#1 : !ion.ion, !ion.ion) : !ion.ion, !ion.ion { + // CHECK-NEXT: ^{{.*}}(%arg1: !ion.ion, %arg2: !ion.ion): // CHECK-NEXT: [[rabi3:%.+]] = arith.constant 99.989999999999994 : f64 // CHECK-NEXT: [[timems3:%.+]] = arith.divf %arg0, [[rabi3]] : f64 - // CHECK-NEXT: ion.pulse([[timems3]] : f64) %arg1 { + // CHECK-NEXT: ion.pulse([[timems3]] : f64) %arg1 : !ion.ion { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 0 : i64, // CHECK-SAME: rabi = 99.989999999999994 : f64, @@ -365,7 +361,7 @@ func.func @example_ion_three_qubit(%arg0: f64) -> (!quantum.bit, !quantum.bit, ! // CHECK-SAME: polarization = dense<[37, 42]> : vector<2xi64>, // CHECK-SAME: wavevector = dense<[-42, -37]> : vector<2xi64>>, // CHECK-SAME: phase = 0.000000e+00 : f64} - // CHECK-NEXT: ion.pulse([[timems3]] : f64) %arg1 { + // CHECK-NEXT: ion.pulse([[timems3]] : f64) %arg1 : !ion.ion { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 1 : i64, // CHECK-SAME: rabi = 99.989999999999994 : f64, @@ -373,7 +369,7 @@ func.func @example_ion_three_qubit(%arg0: f64) -> (!quantum.bit, !quantum.bit, ! // CHECK-SAME: polarization = dense<[37, 42]> : vector<2xi64>, // CHECK-SAME: wavevector = dense<[42, 37]> : vector<2xi64>>, // CHECK-SAME: phase = 0.000000e+00 : f64} - // CHECK-NEXT: ion.pulse([[timems3]] : f64) %arg1 { + // CHECK-NEXT: ion.pulse([[timems3]] : f64) %arg1 : !ion.ion { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 1 : i64, // CHECK-SAME: rabi = 99.989999999999994 : f64, @@ -381,7 +377,7 @@ func.func @example_ion_three_qubit(%arg0: f64) -> (!quantum.bit, !quantum.bit, ! // CHECK-SAME: polarization = dense<[37, 42]> : vector<2xi64>, // CHECK-SAME: wavevector = dense<[42, 37]> : vector<2xi64>>, // CHECK-SAME: phase = 0.000000e+00 : f64} - // CHECK-NEXT: ion.pulse([[timems3]] : f64) %arg2 { + // CHECK-NEXT: ion.pulse([[timems3]] : f64) %arg2 : !ion.ion { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 0 : i64, // CHECK-SAME: rabi = 99.989999999999994 : f64, @@ -389,7 +385,7 @@ func.func @example_ion_three_qubit(%arg0: f64) -> (!quantum.bit, !quantum.bit, ! // CHECK-SAME: polarization = dense<[37, 42]> : vector<2xi64>, // CHECK-SAME: wavevector = dense<[-42, -37]> : vector<2xi64>>, // CHECK-SAME: phase = 0.000000e+00 : f64} - // CHECK-NEXT: ion.pulse([[timems3]] : f64) %arg2 { + // CHECK-NEXT: ion.pulse([[timems3]] : f64) %arg2 : !ion.ion { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 1 : i64, // CHECK-SAME: rabi = 99.989999999999994 : f64, @@ -397,7 +393,7 @@ func.func @example_ion_three_qubit(%arg0: f64) -> (!quantum.bit, !quantum.bit, ! // CHECK-SAME: polarization = dense<[37, 42]> : vector<2xi64>, // CHECK-SAME: wavevector = dense<[42, 37]> : vector<2xi64>>, // CHECK-SAME: phase = 0.000000e+00 : f64} - // CHECK-NEXT: ion.pulse([[timems3]] : f64) %arg2 { + // CHECK-NEXT: ion.pulse([[timems3]] : f64) %arg2 : !ion.ion { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 1 : i64, // CHECK-SAME: rabi = 99.989999999999994 : f64, @@ -405,8 +401,8 @@ func.func @example_ion_three_qubit(%arg0: f64) -> (!quantum.bit, !quantum.bit, ! // CHECK-SAME: polarization = dense<[37, 42]> : vector<2xi64>, // CHECK-SAME: wavevector = dense<[42, 37]> : vector<2xi64>>, // CHECK-SAME: phase = 0.000000e+00 : f64} - // CHECK-NEXT: ion.yield %arg1, %arg2 : !quantum.bit, !quantum.bit + // CHECK-NEXT: ion.yield %arg1, %arg2 : !ion.ion, !ion.ion // CHECK-NEXT: } %7:2 = quantum.custom "MS"(%arg0) %5#1, %6#1 : !quantum.bit, !quantum.bit - return %6#0, %7#0, %7#1: !quantum.bit, !quantum.bit, !quantum.bit + return }