Skip to content
4 changes: 2 additions & 2 deletions lib/Optimizer/CodeGen/ConvertToQIRAPI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1007,8 +1007,8 @@ struct ExpPauliOpPattern
operands.push_back(pauliWord);

// First need to check the type of the Pauli word. We expect a pauli_word
// directly `{i8*,i64}` or a string literal `ptr<i8>`. If it is a string
// literal, we need to map it to a pauli word.
// directly (a.k.a. a span)`{i8*,i64}` or a string literal `ptr<array<i8 x
// n>>`. If it is a string literal, we need to map it to a pauli word.
auto i8PtrTy = cudaq::cc::PointerType::get(rewriter.getI8Type());
if (auto ptrTy = dyn_cast<cudaq::cc::PointerType>(pauliWord.getType())) {
// Make sure we have the right types to extract the length of the string
Expand Down
49 changes: 41 additions & 8 deletions lib/Optimizer/Transforms/DecompositionPatterns.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -339,25 +339,56 @@ struct ExpPauliDecomposition : public OpRewritePattern<quake::ExpPauliOp> {
auto qubits = expPauliOp.getTarget();
auto theta = expPauliOp.getParameter();
auto pauliWord = expPauliOp.getPauli();
auto stringTy = pauliWord.getType();

if (expPauliOp.isAdj())
theta = rewriter.create<arith::NegFOp>(loc, theta);

std::optional<StringRef> optPauliWordStr;
if (auto defOp =
pauliWord.getDefiningOp<cudaq::cc::CreateStringLiteralOp>()) {
optPauliWordStr = defOp.getStringLiteral();

if (isa<cudaq::cc::PointerType>(stringTy)) {
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>()) {
if (auto load = pauliWord.getDefiningOp<cudaq::cc::LoadOp>()) {
// Look for a matching StoreOp for the LoadOp. This search isn't
// necessarily efficient or exhaustive. Instead of using dominance
// information, we scan the current basic block looking for the
// nearest StoreOp before the LoadOp. If one is found, we forward the
// stored value.
auto ptrVal = load.getPtrvalue();
auto storeVal = [&]() -> Value {
SmallVector<Operation *> stores;
for (auto *use : ptrVal.getUsers()) {
if (auto store = dyn_cast<cudaq::cc::StoreOp>(use)) {
if (store.getPtrvalue() == ptrVal &&
store->getBlock() == load->getBlock())
stores.push_back(store.getOperation());
}
}
if (stores.empty())
return {};
for (Operation *op = load.getOperation()->getPrevNode(); op;
op = op->getPrevNode()) {
auto iter = std::find(stores.begin(), stores.end(), op);
if (iter == stores.end())
continue;
return cast<cudaq::cc::StoreOp>(*iter).getValue();
}
return {};
}();
if (storeVal)
pauliWord = storeVal;
}
if (auto vecInit = pauliWord.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>()) {
// Get the pauli word string from a constant global string generated
// during argument synthesis.
auto globalName = addr.getGlobalName();
auto symbol = module.lookupSymbol(globalName);
if (auto global = dyn_cast<LLVM::GlobalOp>(symbol)) {
Expand All @@ -367,6 +398,8 @@ struct ExpPauliDecomposition : public OpRewritePattern<quake::ExpPauliOp> {
}
} else if (auto lit = addrOp.getDefiningOp<
cudaq::cc::CreateStringLiteralOp>()) {
// Get the pauli word string if it was a literal wrapped in a stdvec
// structure.
optPauliWordStr = lit.getStringLiteral();
}
}
Expand Down
33 changes: 33 additions & 0 deletions test/NVQPP/exp_pauli.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*******************************************************************************
* Copyright (c) 2022 - 2025 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: nvq++ --target quantinuum %s -o %t && %t || echo "passed" |& FileCheck %s

#include <cudaq.h>
#include <cstdio>

struct Qernel_A {
void operator()(std::vector<double> angles,
std::vector<cudaq::pauli_word> paulis) __qpu__ {
cudaq::qvector q(3);
for (int i = 0; i < angles.size(); i++) {
exp_pauli(angles[i], q, paulis[i]);
}
}
};

int main() {
Qernel_A a;
std::vector<double> v = {1.0, 2.0};
std::vector<cudaq::pauli_word> p = {"XYZ", "IXX"};
printf("calling sample\n");
cudaq::sample(a, v, p);
return 0;
}

// CHECK-NOT: cannot determine pauli word string
Loading