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 exp_pauli issues on remote simulators and quantum devices #2226

Merged
merged 12 commits into from
Sep 30, 2024
15 changes: 8 additions & 7 deletions lib/Optimizer/CodeGen/QuakeToLLVM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -462,11 +462,12 @@ class ExpPauliRewrite : public ConvertOpToLLVMPattern<quake::ExpPauliOp> {
cudaq::opt::factory::genLlvmI64Constant(loc, rewriter, numElements);

// Set the string literal data
auto strPtr = rewriter.create<LLVM::GEPOp>(
loc, LLVM::LLVMPointerType::get(rewriter.getI8Type()), alloca,
ValueRange{zero, zero});
auto castedPauli = rewriter.create<LLVM::BitcastOp>(
loc, cudaq::opt::factory::getPointerType(context), pauliWord);
auto charPtrTy = cudaq::opt::factory::getPointerType(context);
auto strPtrTy = LLVM::LLVMPointerType::get(charPtrTy);
auto strPtr = rewriter.create<LLVM::GEPOp>(loc, strPtrTy, alloca,
ValueRange{zero, zero});
auto castedPauli =
rewriter.create<LLVM::BitcastOp>(loc, charPtrTy, pauliWord);
rewriter.create<LLVM::StoreOp>(loc, castedPauli, strPtr);

// Set the integer length
Expand All @@ -476,8 +477,8 @@ class ExpPauliRewrite : public ConvertOpToLLVMPattern<quake::ExpPauliOp> {
rewriter.create<LLVM::StoreOp>(loc, size, intPtr);

// Cast to raw opaque pointer
auto castedStore = rewriter.create<LLVM::BitcastOp>(
loc, cudaq::opt::factory::getPointerType(context), alloca);
auto castedStore =
rewriter.create<LLVM::BitcastOp>(loc, charPtrTy, alloca);
operands.push_back(castedStore);
rewriter.replaceOpWithNewOp<LLVM::CallOp>(instOp, TypeRange{}, symbolRef,
operands);
Expand Down
42 changes: 38 additions & 4 deletions lib/Optimizer/Transforms/DecompositionPatterns.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -335,18 +335,52 @@ struct ExpPauliDecomposition : public OpRewritePattern<quake::ExpPauliOp> {
LogicalResult matchAndRewrite(quake::ExpPauliOp expPauliOp,
PatternRewriter &rewriter) const override {
auto loc = expPauliOp.getLoc();
auto module = expPauliOp->getParentOfType<ModuleOp>();
auto qubits = expPauliOp.getQubits();
auto theta = expPauliOp.getParameter();
auto pauliWord = expPauliOp.getPauli();

std::optional<StringRef> optPauliWordStr;
if (auto defOp =
pauliWord.getDefiningOp<cudaq::cc::CreateStringLiteralOp>()) {
optPauliWordStr = defOp.getStringLiteral();
} else {
// Get the pauli word string from a constant global string generated
// during argument synthesis.
auto stringOp = expPauliOp.getOperand(2);
auto stringTy = stringOp.getType();
if (auto charSpanTy = dyn_cast<cudaq::cc::CharspanType>(stringTy)) {
if (auto vecInit = stringOp.getDefiningOp<cudaq::cc::StdvecInitOp>()) {
auto addrOp = vecInit.getOperand(0);
if (auto cast = addrOp.getDefiningOp<cudaq::cc::CastOp>())
addrOp = cast.getOperand();
if (auto addr = addrOp.getDefiningOp<cudaq::cc::AddressOfOp>()) {
auto globalName = addr.getGlobalName();
auto symbol = module.lookupSymbol(globalName);
if (auto global = dyn_cast<LLVM::GlobalOp>(symbol)) {
auto attr = global.getValue();
auto strAttr = cast<mlir::StringAttr>(attr.value());
optPauliWordStr = strAttr.getValue();
}
}
}
}
}

// Assert that we have a constant known pauli word
auto defOp = pauliWord.getDefiningOp<cudaq::cc::CreateStringLiteralOp>();
if (!defOp)
if (!optPauliWordStr.has_value()) {
annagrin marked this conversation as resolved.
Show resolved Hide resolved
return failure();
}

auto pauliWordStr = optPauliWordStr.value();

// Remove optional last zero character
auto size = pauliWordStr.size();
if (pauliWordStr[size - 1] == '\0')
annagrin marked this conversation as resolved.
Show resolved Hide resolved
size--;

SmallVector<Value> qubitSupport;
StringRef pauliWordStr = defOp.getStringLiteral();
for (std::size_t i = 0; i < pauliWordStr.size(); i++) {
for (std::size_t i = 0; i < size; i++) {
Value index = rewriter.create<arith::ConstantIntOp>(loc, i, 64);
Value qubitI = rewriter.create<quake::ExtractRefOp>(loc, qubits, index);
if (pauliWordStr[i] != 'I')
Expand Down
61 changes: 61 additions & 0 deletions targettests/execution/exp_pauli.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*******************************************************************************
* Copyright (c) 2022 - 2024 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. *
******************************************************************************/

// clang-format off
// Simulators
// RUN: nvq++ %cpp_std --enable-mlir %s -o %t && %t | FileCheck %s
// RUN: nvq++ %cpp_std --enable-mlir --target remote-mqpu -fkernel-exec-kind=2 %s -o %t && %t | FileCheck %s
//
// Quantum emulators
// RUN: nvq++ %cpp_std --target quantinuum --emulate -fkernel-exec-kind=2 %s -o %t && %t | FileCheck %s
// RUN: nvq++ %cpp_std --target ionq --emulate -fkernel-exec-kind=2 %s -o %t && %t | FileCheck %s
// 2 different IQM machines for 2 different topologies
// RUN: nvq++ %cpp_std --target iqm --iqm-machine Adonis --emulate -fkernel-exec-kind=2 %s -o %t && %t | FileCheck %s
// RUN: nvq++ %cpp_std --target iqm --iqm-machine Apollo --emulate -fkernel-exec-kind=2 %s -o %t && %t | FileCheck %s
// RUN: nvq++ %cpp_std --target oqc --emulate -fkernel-exec-kind=2 %s -o %t && %t | FileCheck %s
// clang-format on
annagrin marked this conversation as resolved.
Show resolved Hide resolved

#include <cudaq.h>
#include <iostream>

__qpu__ void test() {
cudaq::qvector q(2);
cudaq::exp_pauli(1.0, q, "XX");
}

__qpu__ void test_param(cudaq::pauli_word w) {
cudaq::qvector q(2);
cudaq::exp_pauli(1.0, q, w);
}

void printCounts(cudaq::sample_result& result) {
std::vector<std::string> values{};
for (auto &&[bits, counts] : result) {
values.push_back(bits);
}

std::sort(values.begin(), values.end());
for (auto &&bits : values) {
std::cout << bits << '\n';
}
}

int main() {
auto counts = cudaq::sample(test);
printCounts(counts);

counts = cudaq::sample(test_param, cudaq::pauli_word{"XY"});
printCounts(counts);
return 0;
}

// CHECK: 00
// CHECK: 11

// CHECK: 00
// CHECK: 11
annagrin marked this conversation as resolved.
Show resolved Hide resolved
35 changes: 34 additions & 1 deletion test/Transforms/DecompositionPatterns/ExpPauliToHRyRzCX.qke
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ module attributes {quake.mangled_name_map = {__nvqpp__mlirgen__Z4mainE3$_0 = "_Z
quake.exp_pauli %4, %1, %5 : (f64, !quake.veq<4>, !cc.ptr<!cc.array<i8 x 5>>) -> ()
return
}
}

// CHECK-LABEL: func.func @__nvqpp__mlirgen__Z4mainE3$_0(
// CHECK-SAME: %[[VAL_0:.*]]: f64) attributes {"cudaq-entrypoint", "cudaq-kernel"} {
Expand Down Expand Up @@ -66,3 +65,37 @@ module attributes {quake.mangled_name_map = {__nvqpp__mlirgen__Z4mainE3$_0 = "_Z
// CHECK: quake.h %[[VAL_20]] : (!quake.ref) -> ()
// CHECK: return
// CHECK: }

func.func @__nvqpp__mlirgen__function_test_param._Z10test_paramN5cudaq10pauli_wordE() attributes {"cudaq-entrypoint", "cudaq-kernel", no_this} {
%cst = arith.constant 1.000000e+00 : f64
%c2_i64 = arith.constant 2 : i64
%0 = cc.address_of @cstr.585900 : !cc.ptr<!llvm.array<3 x i8>>
%1 = cc.cast %0 : (!cc.ptr<!llvm.array<3 x i8>>) -> !cc.ptr<i8>
%2 = cc.stdvec_init %1, %c2_i64 : (!cc.ptr<i8>, i64) -> !cc.charspan
%3 = quake.alloca !quake.veq<2>
quake.exp_pauli %cst, %3, %2 : (f64, !quake.veq<2>, !cc.charspan) -> ()
return
}
llvm.mlir.global private constant @cstr.585900("XY\00") {addr_space = 0 : i32}

// CHECK-LABEL: func.func @__nvqpp__mlirgen__function_test_param._Z10test_paramN5cudaq10pauli_wordE() attributes {"cudaq-entrypoint", "cudaq-kernel", no_this} {
// CHECK: %[[VAL_0:.*]] = arith.constant 0 : i64
// CHECK: %[[VAL_1:.*]] = arith.constant 1 : i64
// CHECK: %[[VAL_2:.*]] = arith.constant 1.5707963267948966 : f64
// CHECK: %[[VAL_3:.*]] = arith.constant -1.5707963267948966 : f64
// CHECK: %[[VAL_4:.*]] = arith.constant 1.000000e+00 : f64
// CHECK: %[[VAL_5:.*]] = quake.alloca !quake.veq<2>
// CHECK: %[[VAL_6:.*]] = quake.extract_ref %[[VAL_5]][%[[VAL_0]]] : (!quake.veq<2>, i64) -> !quake.ref
// CHECK: quake.h %[[VAL_6]] : (!quake.ref) -> ()
// CHECK: %[[VAL_7:.*]] = quake.extract_ref %[[VAL_5]][%[[VAL_1]]] : (!quake.veq<2>, i64) -> !quake.ref
// CHECK: quake.rx (%[[VAL_2]]) %[[VAL_7]] : (f64, !quake.ref) -> ()
// CHECK: quake.x [%[[VAL_6]]] %[[VAL_7]] : (!quake.ref, !quake.ref) -> ()
// CHECK: quake.rz (%[[VAL_4]]) %[[VAL_7]] : (f64, !quake.ref) -> ()
// CHECK: quake.x [%[[VAL_6]]] %[[VAL_7]] : (!quake.ref, !quake.ref) -> ()
// CHECK: %[[VAL_8:.*]] = quake.extract_ref %[[VAL_5]][%[[VAL_1]]] : (!quake.veq<2>, i64) -> !quake.ref
// CHECK: quake.rx (%[[VAL_3]]) %[[VAL_8]] : (f64, !quake.ref) -> ()
// CHECK: %[[VAL_9:.*]] = quake.extract_ref %[[VAL_5]][%[[VAL_0]]] : (!quake.veq<2>, i64) -> !quake.ref
// CHECK: quake.h %[[VAL_9]] : (!quake.ref) -> ()
// CHECK: return
// CHECK: }
}
Loading