Commit 4788b9bd authored by Nguyen, Thien Minh's avatar Nguyen, Thien Minh
Browse files

Got the ConditionalOp MLIR Op working



Followed the pattern of SCF::IfOp but conditioned by a Result* rather than an i1 var.

Signed-off-by: default avatarThien Nguyen <nguyentm@ornl.gov>
parent 6d9ab125
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -13,5 +13,10 @@
#include "mlir/IR/OpDefinition.h"
#include "mlir/Interfaces/SideEffectInterfaces.h"

#include "mlir/IR/Attributes.h"
#include "mlir/IR/Builders.h"
#include "mlir/Interfaces/ControlFlowInterfaces.h"
#include "mlir/Interfaces/LoopLikeInterface.h"

#define GET_OP_CLASSES
#include "Quantum/QuantumOps.h.inc"
 No newline at end of file
+26 −2
Original line number Diff line number Diff line
@@ -3,7 +3,8 @@

include "QuantumDialect.td"
include "mlir/Interfaces/SideEffectInterfaces.td"

include "mlir/Interfaces/ControlFlowInterfaces.td"
include "mlir/Interfaces/LoopLikeInterface.td"

def QubitType : OpaqueType<"quantum", "Qubit", "opaque qubit type">;
def ResultType : OpaqueType<"quantum", "Result", "opaque result type">;
@@ -234,12 +235,35 @@ def CreateCallableOp : QuantumOp<"createCallable", []> {
  p << "q.createCallable" << "(" << op.functors() << ") : " << op.callable().getType(); }];
}

def ConditionalOp : QuantumOp<"ifElseOp", []> {
def YieldOp : QuantumOp<"yield", [NoSideEffect, Terminator]> {
  let summary = "conditional termination operation";
  let arguments = (ins Variadic<AnyType>:$results);
  let builders = [OpBuilderDAG<(ins), [{ /* nothing to do */ }]>];
}

def ConditionalOp : QuantumOp<"ifOp", [SingleBlockImplicitTerminator<"YieldOp">, RecursiveSideEffects, NoRegionArguments]> {
  let summary = "if-then-else operation conditioned on a quantum Measure";
  // Must be conditioned on a Result type
  let arguments = (ins ResultType:$result_bit);
  let results = (outs);
  let regions = (region SizedRegion<1>:$thenRegion, AnyRegion:$elseRegion);
  let skipDefaultBuilders = 1;
  
  let skipDefaultBuilders = 1;
  let builders = [
    OpBuilderDAG<(ins "Value":$cond, "bool":$withElseRegion)>
  ];

  let extraClassDeclaration = [{
    OpBuilder getThenBodyBuilder(OpBuilder::Listener *listener = nullptr) {
      Block* body = getBody(0);
      return OpBuilder::atBlockTerminator(body, listener);
    }
    OpBuilder getElseBodyBuilder(OpBuilder::Listener *listener = nullptr) {
      Block* body = getBody(1);
      return OpBuilder::atBlockTerminator(body, listener);
    }
  }];
}

#endif // Quantum_OPS
 No newline at end of file
+27 −1
Original line number Diff line number Diff line
@@ -60,3 +60,29 @@ void QuantumDialect::initialize() {
//   printer << ")";

// }

//===----------------------------------------------------------------------===//
// ConditionalOp
//===----------------------------------------------------------------------===//

void ConditionalOp::build(OpBuilder &builder, OperationState &result, Value cond,
                 bool withElseRegion) {
  result.addOperands(cond);
  OpBuilder::InsertionGuard guard(builder);
  Region *thenRegion = result.addRegion();
  builder.createBlock(thenRegion);
  auto defaultBuilder = [&](OpBuilder &nested, Location loc) {
    ConditionalOp::ensureTerminator(*nested.getInsertionBlock()->getParent(),
                                    nested, loc);
  };

  defaultBuilder(builder, result.location);

  Region *elseRegion = result.addRegion();
  if (!withElseRegion) {
    return;
  }

  builder.createBlock(elseRegion);
  defaultBuilder(builder, result.location);
}
 No newline at end of file
+20 −5
Original line number Diff line number Diff line
@@ -10,6 +10,8 @@ namespace {
// i.e., this serve mainly as a stop-gap before fully-FTQC runtimes become
// available.

// FIXME: Define a Target Capability setting and make the compiler aware of that.

// Capture binary comparison conditional.
// Note: currently, only bit-level is modeled.
// (Some backends, e.g., Honeywell, support a richer set of comparison ops).
@@ -68,15 +70,28 @@ antlrcpp::Any qasm3_visitor::visitBranchingStatement(
  auto bit_check_conditional =
      tryParseSimpleBooleanExpression(*conditional_expr);
  // Currently, we're only support If (not else yet)
  auto meas_var =
      symbol_table.try_lookup_meas_result(bit_check_conditional->var_name);

  if (bit_check_conditional.has_value() &&
      context->programBlock().size() == 1 && meas_var.has_value()) {
      context->programBlock().size() == 1 &&
      symbol_table.try_lookup_meas_result(bit_check_conditional->var_name)
          .has_value()) {
    std::cout << "This is a simple Measure check\n";
    auto nisqIfStmt = builder.create<mlir::quantum::ConditionalOp>(
        location, meas_var.value());
    auto meas_var =
        symbol_table.try_lookup_meas_result(bit_check_conditional->var_name);
    auto ifOp =
        builder.create<mlir::quantum::ConditionalOp>(location, meas_var.value(),
                                                     /*withElseRegion=*/false);
    auto body_builder = ifOp.getThenBodyBuilder();
    auto cached_builder = builder;
    builder = body_builder;
    visitChildren(context->programBlock(0));
    builder = cached_builder;
   
    // Done
    return 0;
  }

  // TODO: The below code could be rewritten to an AffineIfOp/SCF::IfOp:
  // Map it to a Value
  qasm3_expression_generator exp_generator(builder, symbol_table, file_name);
  exp_generator.visit(conditional_expr);