Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix for issue #641: QASM export #649

Merged
merged 3 commits into from
Sep 12, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
38 changes: 28 additions & 10 deletions lib/Optimizer/CodeGen/TranslateToOpenQASM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@
#include "cudaq/Optimizer/CodeGen/OpenQASMEmitter.h"
#include "cudaq/Optimizer/Dialect/CC/CCTypes.h"
#include "cudaq/Optimizer/Dialect/Quake/QuakeOps.h"
#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/TypeSwitch.h"
#include "mlir/Analysis/SliceAnalysis.h"
#include "mlir/Analysis/CallGraph.h"

using namespace mlir;
using namespace cudaq;
Expand Down Expand Up @@ -94,7 +95,8 @@ static LogicalResult emitOperation(Emitter &emitter, ModuleOp moduleOp) {
emitter.os << "// Code generated by NVIDIA's nvq++ compiler\n";
emitter.os << "OPENQASM 2.0;\n\n";
emitter.os << "include \"qelib1.inc\";\n\n";
mlir::SetVector<mlir::Operation *> sortedOp;
// Build the call graph of the module
const mlir::CallGraph callGraph(moduleOp);

for (Operation &op : moduleOp) {
if (op.hasAttr(cudaq::entryPointAttrName)) {
Expand All @@ -103,20 +105,36 @@ static LogicalResult emitOperation(Emitter &emitter, ModuleOp moduleOp) {
entryPoint = dyn_cast_or_null<func::FuncOp>(op);
continue;
}
if (auto funcOp = dyn_cast_or_null<func::FuncOp>(op)) {
// Cache FuncOp to do topological sorting before emit
sortedOp.insert(funcOp);
} else {
// Just emit
if (!isa<func::FuncOp>(op)) {
// If not a FuncOp, just emit
if (failed(emitOperation(emitter, op)))
return failure();
emitter.os << '\n';
}
}

// Sort FuncOp topologically then emit
sortedOp = mlir::topologicalSort(sortedOp);
for (Operation *op : sortedOp) {
// Use PostOrderTraversal to get the ordered list of FuncOps.
// Note: this list will be in the reversed order, i.e., entry point function
// first.
llvm::ReversePostOrderTraversal<const mlir::CallGraph *> rpot(&callGraph);
std::vector<func::FuncOp> funcOps;
for (auto &node : rpot) {
if (node->isExternal())
continue;

auto *callableRegion = node->getCallableRegion();
auto *parentOp = callableRegion->getParentOp();
if (auto fnOp = dyn_cast_or_null<func::FuncOp>(parentOp)) {
// Don't add the entry point function.
if (fnOp != entryPoint) {
// Insert at the front, i.e., reverse the order.
funcOps.insert(funcOps.begin(), fnOp);
}
}
}

// Emit these functions as custom gate defs.
for (auto &op : funcOps) {
if (failed(emitOperation(emitter, *op)))
return failure();
emitter.os << '\n';
Expand Down
10 changes: 5 additions & 5 deletions test/Target/OpenQASM/basic.qke
Original file line number Diff line number Diff line change
Expand Up @@ -82,18 +82,18 @@ module {

// CHECK: include "qelib1.inc";

// CHECK: gate umaj q0, q1, q2 {
// CHECK: ccx q0, q1, q2;
// CHECK: cx q2, q1;
// CHECK: cx q2, q0;
// CHECK: }

// CHECK: gate maj q0, q1, q2 {
// CHECK: cx q2, q0;
// CHECK: cx q2, q1;
// CHECK: ccx q0, q1, q2;
// CHECK: }

// CHECK: gate umaj q0, q1, q2 {
// CHECK: ccx q0, q1, q2;
// CHECK: cx q2, q1;
// CHECK: cx q2, q0;
// CHECK: }

// CHECK: qreg var0[1];
// CHECK: qreg var1[4];
Expand Down
57 changes: 57 additions & 0 deletions test/Target/OpenQASM/bugReport_641.qke
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// ========================================================================== //
// Copyright (c) 2022 - 2023 NVIDIA Corporation & Affiliates. //
// All rights reserved. //
// //
// This source code and the accompanying materials are made available under //
// the terms of the Apache License 2.0 which accompanies this distribution. //
// ========================================================================== //

// RUN: cudaq-translate --convert-to=openqasm %s | FileCheck %s

module {
func.func @__nvqpp__mlirgen____nvqppBuilderKernel_361293194784() attributes {"cudaq-entrypoint"} {
%0 = quake.alloca !quake.ref
call @__nvqpp__mlirgen____nvqppBuilderKernel_367535629127(%0) : (!quake.ref) -> ()
call @__nvqpp__mlirgen____nvqppBuilderKernel_202375922897(%0) : (!quake.ref) -> ()
return
}
func.func @__nvqpp__mlirgen____nvqppBuilderKernel_367535629127(%arg0: !quake.ref) {
return
}
func.func @__nvqpp__mlirgen____nvqppBuilderKernel_202375922897(%arg0: !quake.ref) {
quake.h %arg0 : (!quake.ref) -> ()
call @__nvqpp__mlirgen____nvqppBuilderKernel_093606261879(%arg0) : (!quake.ref) -> ()
quake.h %arg0 : (!quake.ref) -> ()
%bits = quake.mz %arg0 name "" : (!quake.ref) -> i1
return
}
func.func @__nvqpp__mlirgen____nvqppBuilderKernel_093606261879(%arg0: !quake.ref) {
quake.x %arg0 : (!quake.ref) -> ()
call @__nvqpp__mlirgen____nvqppBuilderKernel_367535629127(%arg0) : (!quake.ref) -> ()
return
}
}

// CHECK: OPENQASM 2.0;

// CHECK: include "qelib1.inc";

// CHECK: gate nvqpp__mlirgen____nvqppBuilderKernel_367535629127 q0 {
// CHECK: }

// CHECK: gate nvqpp__mlirgen____nvqppBuilderKernel_093606261879 q0 {
// CHECK: x q0;
// CHECK: nvqpp__mlirgen____nvqppBuilderKernel_367535629127 q0;
// CHECK: }

// CHECK: gate nvqpp__mlirgen____nvqppBuilderKernel_202375922897 q0 {
// CHECK: h q0;
// CHECK: nvqpp__mlirgen____nvqppBuilderKernel_093606261879 q0;
// CHECK: h q0;
// CHECK: creg var1[1];
// CHECK: measure q0 -> var1[0];
// CHECK: }

// CHECK: qreg var0[1];
// CHECK: nvqpp__mlirgen____nvqppBuilderKernel_367535629127 var0[0];
// CHECK: nvqpp__mlirgen____nvqppBuilderKernel_202375922897 var0[0];
55 changes: 55 additions & 0 deletions test/Target/OpenQASM/callGraph_641.qke
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// ========================================================================== //
// Copyright (c) 2022 - 2023 NVIDIA Corporation & Affiliates. //
// All rights reserved. //
// //
// This source code and the accompanying materials are made available under //
// the terms of the Apache License 2.0 which accompanies this distribution. //
// ========================================================================== //

// Test complex call graph
// RUN: cudaq-translate --convert-to=openqasm %s | FileCheck %s

module {
func.func @__nvqpp__mlirgen____nvqppBuilderKernel_554765693745() attributes {"cudaq-entrypoint"} {
%0 = quake.alloca !quake.ref
call @__nvqpp__mlirgen____nvqppBuilderKernel_503610632061(%0) : (!quake.ref) -> ()
call @__nvqpp__mlirgen____nvqppBuilderKernel_093606261879(%0) : (!quake.ref) -> ()
return
}
func.func @__nvqpp__mlirgen____nvqppBuilderKernel_503610632061(%arg0: !quake.ref) {
call @__nvqpp__mlirgen____nvqppBuilderKernel_202375922897(%arg0) : (!quake.ref) -> ()
return
}
func.func @__nvqpp__mlirgen____nvqppBuilderKernel_202375922897(%arg0: !quake.ref) {
call @__nvqpp__mlirgen____nvqppBuilderKernel_367535629127(%arg0) : (!quake.ref) -> ()
return
}
func.func @__nvqpp__mlirgen____nvqppBuilderKernel_367535629127(%arg0: !quake.ref) {
return
}
func.func @__nvqpp__mlirgen____nvqppBuilderKernel_093606261879(%arg0: !quake.ref) {
return
}
}

// CHECK: OPENQASM 2.0;

// CHECK: include "qelib1.inc";

// CHECK: gate nvqpp__mlirgen____nvqppBuilderKernel_367535629127 q0 {
// CHECK: }

// CHECK: gate nvqpp__mlirgen____nvqppBuilderKernel_202375922897 q0 {
// CHECK: nvqpp__mlirgen____nvqppBuilderKernel_367535629127 q0;
// CHECK: }

// CHECK: gate nvqpp__mlirgen____nvqppBuilderKernel_503610632061 q0 {
// CHECK: nvqpp__mlirgen____nvqppBuilderKernel_202375922897 q0;
// CHECK: }

// CHECK: gate nvqpp__mlirgen____nvqppBuilderKernel_093606261879 q0 {
// CHECK: }

// CHECK: qreg var0[1];
// CHECK: nvqpp__mlirgen____nvqppBuilderKernel_503610632061 var0[0];
// CHECK: nvqpp__mlirgen____nvqppBuilderKernel_093606261879 var0[0];
Loading