diff --git a/include/cudaq/Optimizer/CodeGen/Peephole.h b/include/cudaq/Optimizer/CodeGen/Peephole.h index e0b66a06c2..aec6b54235 100644 --- a/include/cudaq/Optimizer/CodeGen/Peephole.h +++ b/include/cudaq/Optimizer/CodeGen/Peephole.h @@ -55,6 +55,17 @@ inline mlir::Value createMeasureCall(mlir::PatternRewriter &builder, return {}; } +inline mlir::Value createReadResultCall(mlir::PatternRewriter &builder, + mlir::Location loc, + mlir::OpResult result) { + auto i1Ty = mlir::IntegerType::get(builder.getContext(), 1); + return builder + .create(loc, mlir::TypeRange{i1Ty}, + cudaq::opt::QIRReadResultBody, + mlir::ArrayRef{result}) + .getResult(); +} + namespace { #include "cudaq/Optimizer/CodeGen/Peephole.inc" } diff --git a/include/cudaq/Optimizer/CodeGen/Peephole.td b/include/cudaq/Optimizer/CodeGen/Peephole.td index 6df9ec51ce..ccece5ab5b 100644 --- a/include/cudaq/Optimizer/CodeGen/Peephole.td +++ b/include/cudaq/Optimizer/CodeGen/Peephole.td @@ -148,4 +148,30 @@ def MeasureToRegisterCallConv : Pat< (CreateMeasureCall $call, $args), [(IsaMeasureToRegisterCall:$callee), (IsaIntToPtrOperand $args)]>; +//===----------------------------------------------------------------------===// + +def HasI1PtrType : Constraint>; + +def HasResultType : Constraint>; + +def IsaIntAttr : Constraint()">>; + +def CreateReadResultCall : NativeCodeCall< + "createReadResultCall($_builder, $_loc, $0)">; + +// %1 = llvm.constant 1 +// %2 = llvm.inttoptr %1 : i64 -> Result* +// %3 = llvm.bitcast %2 : Result* -> i1* +// %4 = llvm.load %3 +// ───────────────────────────────────── +// %4 = call @read_result %2 +def LoadMeasureResult : Pat< + (LLVM_LoadOp:$load (LLVM_BitcastOp:$bitcast (LLVM_IntToPtrOp:$cast + (LLVM_ConstantOp $attr))), $_, $_, $_, $_, $_, $_), + (CreateReadResultCall $cast), + [(HasI1PtrType:$bitcast), (HasResultType:$cast), (IsaIntAttr:$attr)]>; + #endif diff --git a/include/cudaq/Optimizer/CodeGen/QIRFunctionNames.h b/include/cudaq/Optimizer/CodeGen/QIRFunctionNames.h index 60da66cc49..96ef8875b9 100644 --- a/include/cudaq/Optimizer/CodeGen/QIRFunctionNames.h +++ b/include/cudaq/Optimizer/CodeGen/QIRFunctionNames.h @@ -22,6 +22,8 @@ constexpr static const char QIRMeasureToRegister[] = constexpr static const char QIRCnot[] = "__quantum__qis__cnot"; constexpr static const char QIRCphase[] = "__quantum__qis__cphase"; +constexpr static const char QIRReadResultBody[] = + "__quantum__qis__read_result__body"; constexpr static const char NVQIRInvokeWithControlBits[] = "invokeWithControlQubits"; diff --git a/lib/Optimizer/CodeGen/LowerToQIRProfile.cpp b/lib/Optimizer/CodeGen/LowerToQIRProfile.cpp index 0cef4bf153..885dc8c2a6 100644 --- a/lib/Optimizer/CodeGen/LowerToQIRProfile.cpp +++ b/lib/Optimizer/CodeGen/LowerToQIRProfile.cpp @@ -65,12 +65,11 @@ namespace { struct FunctionAnalysisData { std::size_t nQubits = 0; std::size_t nResults = 0; - // Use std::map to keep these sorted in ascending order. - // map[qb] --> [result,regName] - std::map> resultPtrValues; - // Additionally store by result to prevent collisions on a single qubit having + // Store by result to prevent collisions on a single qubit having // multiple measurements (Adaptive Profile) // map[result] --> [qb,regName] + // Use std::map to keep these sorted in ascending order. While this isn't + // required, it makes viewing the QIR easier. std::map> resultQubitVals; DenseMap allocationOffsets; }; @@ -164,26 +163,18 @@ struct FunctionProfileAnalysis { } if (optQb) { auto qb = *optQb; - auto iter = data.resultPtrValues.find(qb); auto *ctx = callOp.getContext(); auto intTy = IntegerType::get(ctx, 64); - if (iter == data.resultPtrValues.end()) { - auto resIdx = IntegerAttr::get(intTy, data.nResults); - callOp->setAttr(resultIndexName, resIdx); - auto regName = [&]() -> StringAttr { - if (auto nameAttr = callOp->getAttr("registerName") - .dyn_cast_or_null()) - return nameAttr; - return {}; - }(); - data.resultQubitVals.insert(std::make_pair( - data.nResults, std::make_pair(qb, regName.data()))); - data.resultPtrValues.insert( - std::make_pair(qb, std::make_pair(data.nResults++, regName))); - } else { - auto resIdx = IntegerAttr::get(intTy, iter->second.first); - callOp->setAttr(resultIndexName, resIdx); - } + auto resIdx = IntegerAttr::get(intTy, data.nResults); + callOp->setAttr(resultIndexName, resIdx); + auto regName = [&]() -> StringAttr { + if (auto nameAttr = callOp->getAttr("registerName") + .dyn_cast_or_null()) + return nameAttr; + return {}; + }(); + data.resultQubitVals.insert(std::make_pair( + data.nResults++, std::make_pair(qb, regName.data()))); } else { callOp.emitError("could not trace offset value"); } @@ -237,13 +228,13 @@ struct AddFuncAttribute : public OpRewritePattern { auto resultTy = cudaq::opt::getResultType(rewriter.getContext()); auto i64Ty = rewriter.getI64Type(); auto module = op->getParentOfType(); - for (auto &iv : info.resultPtrValues) { + for (auto &iv : info.resultQubitVals) { auto &rec = iv.second; - Value idx = builder.create(loc, i64Ty, rec.first); + Value idx = builder.create(loc, i64Ty, iv.first); Value ptr = builder.create(loc, resultTy, idx); auto regName = [&]() -> Value { auto charPtrTy = cudaq::opt::getCharPointerType(builder.getContext()); - if (rec.second) { + if (!rec.second.empty()) { // Note: it should be the case that this string literal has already // been added to the IR, so this step does not actually update the // module. @@ -422,6 +413,8 @@ struct QIRToQIRProfileQIRPass CalleeConv, EraseArrayAlloc, EraseArrayRelease, EraseDeadArrayGEP, MeasureCallConv, MeasureToRegisterCallConv, XCtrlOneTargetToCNot>(context); + if (convertTo.getValue() == "qir-adaptive") + patterns.insert(context); if (failed(applyPatternsAndFoldGreedily(op, std::move(patterns)))) signalPassFailure(); LLVM_DEBUG(llvm::dbgs() << "After QIR profile:\n" << *op << '\n'); @@ -472,6 +465,10 @@ struct QIRProfilePreparationPass {cudaq::opt::getQubitType(ctx), cudaq::opt::getResultType(ctx)}, module); + cudaq::opt::factory::createLLVMFunctionSymbol( + cudaq::opt::QIRReadResultBody, IntegerType::get(ctx, 1), + {cudaq::opt::getResultType(ctx)}, module); + // Add record functions for any // measurements. cudaq::opt::factory::createLLVMFunctionSymbol( @@ -585,6 +582,7 @@ cudaq::opt::verifyQIRProfilePass(llvm::StringRef convertTo) { void cudaq::opt::addQIRProfilePipeline(OpPassManager &pm, llvm::StringRef convertTo) { + assert(convertTo == "qir-adaptive" || convertTo == "qir-base"); pm.addPass(createQIRProfilePreparationPass()); pm.addNestedPass(createConvertToQIRFuncPass(convertTo)); pm.addPass(createQIRToQIRProfilePass(convertTo)); diff --git a/lib/Optimizer/Transforms/QuakeAddMetadata.cpp b/lib/Optimizer/Transforms/QuakeAddMetadata.cpp index b97653e71f..0356498784 100644 --- a/lib/Optimizer/Transforms/QuakeAddMetadata.cpp +++ b/lib/Optimizer/Transforms/QuakeAddMetadata.cpp @@ -98,6 +98,8 @@ struct QuakeFunctionAnalysis { auto allocValue = storeOp.getOperand(1); if (auto cp = allocValue.getDefiningOp()) allocValue = cp.getBase(); + if (auto castOp = allocValue.getDefiningOp()) + allocValue = castOp.getOperand(); if (auto allocaOp = allocValue.getDefiningOp()) { // Get the alloca users @@ -122,6 +124,35 @@ struct QuakeFunctionAnalysis { return WalkResult::interrupt(); } } + + // Look for any future cast/compute_ptr/load, and if that load is + // used by a conditional statement + if (auto cast = dyn_cast(allocUser)) { + for (auto castUser : cast->getUsers()) { + if (auto cp = dyn_cast(castUser)) { + for (auto cpUser : cp->getUsers()) { + if (auto load = dyn_cast(cpUser)) { + auto loadUser = *load->getUsers().begin(); + + // Loaded Val could be used directly or by an Arith + // boolean operation + while (loadUser->getDialect()->getNamespace() == + "arith") { + auto res = loadUser->getResult(0); + loadUser = *res.getUsers().begin(); + } + + // At this point we should be able to check if we are + // being used by a conditional + if (isa(loadUser)) { + data.hasConditionalsOnMeasure = true; + return WalkResult::interrupt(); + } + } + } + } + } + } } } } diff --git a/runtime/common/RuntimeMLIR.cpp b/runtime/common/RuntimeMLIR.cpp index 19555da28e..7960280edd 100644 --- a/runtime/common/RuntimeMLIR.cpp +++ b/runtime/common/RuntimeMLIR.cpp @@ -142,7 +142,8 @@ void applyWriteOnlyAttributes(llvm::Module *llvmModule) { // overlap. // Reference: // https://github.com/qir-alliance/qir-spec/blob/main/specification/under_development/profiles/Base_Profile.md?plain=1#L237 -mlir::LogicalResult verifyMeasurementOrdering(llvm::Module *llvmModule) { +mlir::LogicalResult +verifyBaseProfileMeasurementOrdering(llvm::Module *llvmModule) { bool irreversibleSeenYet = false; for (llvm::Function &func : *llvmModule) for (llvm::BasicBlock &block : func) @@ -321,14 +322,32 @@ mlir::LogicalResult verifyQubitAndResultRanges(llvm::Module *llvmModule) { } // Verify that only the allowed LLVM instructions are present -mlir::LogicalResult verifyLLVMInstructions(llvm::Module *llvmModule) { +mlir::LogicalResult verifyLLVMInstructions(llvm::Module *llvmModule, + bool isBaseProfile) { + bool isAdaptiveProfile = !isBaseProfile; for (llvm::Function &func : *llvmModule) for (llvm::BasicBlock &block : func) for (llvm::Instruction &inst : block) { - // Only call, br, and ret instructions are allowed at the top level. - if (!llvm::isa(inst) && - !llvm::isa(inst) && - !llvm::isa(inst)) { + // Only specific instructions are allowed at the top level, depending on + // the specific profile + bool isValidBaseProfileInstruction = + llvm::isa(inst) || + llvm::isa(inst) || + llvm::isa(inst); + // Note: there is an outstanding question about the adaptive profile + // with respect to `switch` and `select` instructions. They are + // currently described as "optional" in the spec, but there is no way to + // specify their presence via module flags. So to be cautious, for now + // we will assume they are not allowed in cuda-quantum programs. + bool isValidAdaptiveProfileInstruction = isValidBaseProfileInstruction; + // bool isValidAdaptiveProfileInstruction = + // isValidBaseProfileInstruction || + // llvm::isa(inst) || + // llvm::isa(inst); + if (isBaseProfile && !isValidBaseProfileInstruction) { + llvm::errs() << "error - invalid instruction found: " << inst << '\n'; + return failure(); + } else if (isAdaptiveProfile && !isValidAdaptiveProfileInstruction) { llvm::errs() << "error - invalid instruction found: " << inst << '\n'; return failure(); } @@ -366,6 +385,9 @@ qirProfileTranslationFunction(const char *qirProfile, Operation *op, const uint32_t qir_major_version = 1; const uint32_t qir_minor_version = 0; + const bool isAdaptiveProfile = std::string{qirProfile} == "qir-adaptive"; + const bool isBaseProfile = !isAdaptiveProfile; + auto context = op->getContext(); PassManager pm(context); if (printIntermediateMLIR) @@ -398,6 +420,26 @@ qirProfileTranslationFunction(const char *qirProfile, Operation *op, "dynamic_qubit_management", falseValue); llvmModule->addModuleFlag(llvm::Module::ModFlagBehavior::Error, "dynamic_result_management", falseValue); + if (isAdaptiveProfile) { + auto trueValue = + llvm::ConstantInt::getTrue(llvm::Type::getInt1Ty(*llvmContext)); + llvmModule->addModuleFlag(llvm::Module::ModFlagBehavior::Error, + "qubit_resetting", trueValue); + llvmModule->addModuleFlag(llvm::Module::ModFlagBehavior::Error, + "classical_ints", falseValue); + llvmModule->addModuleFlag(llvm::Module::ModFlagBehavior::Error, + "classical_floats", falseValue); + llvmModule->addModuleFlag(llvm::Module::ModFlagBehavior::Error, + "classical_fixed_points", falseValue); + llvmModule->addModuleFlag(llvm::Module::ModFlagBehavior::Error, + "user_functions", falseValue); + llvmModule->addModuleFlag(llvm::Module::ModFlagBehavior::Error, + "dynamic_float_args", falseValue); + llvmModule->addModuleFlag(llvm::Module::ModFlagBehavior::Error, + "extern_functions", falseValue); + llvmModule->addModuleFlag(llvm::Module::ModFlagBehavior::Error, + "backwards_branching", falseValue); + } // Note: optimizeLLVM is the one that is setting nonnull attributes on // the @__quantum__rt__result_record_output calls. @@ -405,19 +447,29 @@ qirProfileTranslationFunction(const char *qirProfile, Operation *op, if (!cudaq::setupTargetTriple(llvmModule.get())) throw std::runtime_error("Failed to setup the llvm module target triple."); + // PyQIR currently requires named blocks. It's not clear if blocks can share + // names across functions, so we are being conservative by giving every block + // in the module a unique name for now. + int blockCounter = 0; + for (llvm::Function &func : *llvmModule) + for (llvm::BasicBlock &block : func) + if (!block.hasName()) + block.setName(std::to_string(blockCounter++)); + if (printIR) llvm::errs() << *llvmModule; if (failed(verifyOutputRecordingFunctions(llvmModule.get()))) return failure(); - if (failed(verifyMeasurementOrdering(llvmModule.get()))) + if (isBaseProfile && + failed(verifyBaseProfileMeasurementOrdering(llvmModule.get()))) return failure(); if (failed(verifyQubitAndResultRanges(llvmModule.get()))) return failure(); - if (failed(verifyLLVMInstructions(llvmModule.get()))) + if (failed(verifyLLVMInstructions(llvmModule.get(), isBaseProfile))) return failure(); // Map the LLVM Module to Bitcode that can be submitted diff --git a/runtime/cudaq/platform/default/rest/RemoteRESTQPU.cpp b/runtime/cudaq/platform/default/rest/RemoteRESTQPU.cpp index e60b27f5df..46dacca9b2 100644 --- a/runtime/cudaq/platform/default/rest/RemoteRESTQPU.cpp +++ b/runtime/cudaq/platform/default/rest/RemoteRESTQPU.cpp @@ -119,16 +119,20 @@ class RemoteRESTQPU : public cudaq::QPU { /// of JIT engines for invoking the kernels. std::vector jitEngines; - /// @brief Invoke the kernel in the JIT engine and then delete the JIT engine. - void invokeJITKernelAndRelease(ExecutionEngine *jit, - const std::string &kernelName) { + /// @brief Invoke the kernel in the JIT engine + void invokeJITKernel(ExecutionEngine *jit, const std::string &kernelName) { auto funcPtr = jit->lookup(std::string("__nvqpp__mlirgen__") + kernelName); if (!funcPtr) { throw std::runtime_error( "cudaq::builder failed to get kernelReg function."); } reinterpret_cast(*funcPtr)(); - // We're done, delete the pointer. + } + + /// @brief Invoke the kernel in the JIT engine and then delete the JIT engine. + void invokeJITKernelAndRelease(ExecutionEngine *jit, + const std::string &kernelName) { + invokeJITKernel(jit, kernelName); delete jit; } @@ -165,7 +169,9 @@ class RemoteRESTQPU : public cudaq::QPU { bool isSimulator() override { return emulate; } /// @brief Return true if the current backend supports conditional feedback - bool supportsConditionalFeedback() override { return false; } + bool supportsConditionalFeedback() override { + return codegenTranslation == "qir-adaptive"; + } /// Provide the number of shots void setShots(int _nShots) override { @@ -491,6 +497,38 @@ class RemoteRESTQPU : public cudaq::QPU { if (seed > 0) cudaq::set_random_seed(seed); + bool hasConditionals = + cudaq::kernelHasConditionalFeedback(kernelName); + if (hasConditionals && codes.size() > 1) + throw std::runtime_error("error: spin_ops not yet supported with " + "kernels containing conditionals"); + if (hasConditionals) { + executor->setShots(1); // run one shot at a time + + // If this is adaptive profile and the kernel has conditionals, + // then you have to run the code localShots times instead of + // running the kernel once and sampling the state localShots + // times. + if (hasConditionals) { + // Populate `counts` one shot at a time + cudaq::sample_result counts; + for (std::size_t shot = 0; shot < localShots; shot++) { + cudaq::ExecutionContext context("sample", 1); + context.hasConditionalsOnMeasureResults = true; + cudaq::getExecutionManager()->setExecutionContext(&context); + invokeJITKernel(localJIT[0], kernelName); + cudaq::getExecutionManager()->resetExecutionContext(); + counts += context.result; + } + // Process `counts` and store into `results` + for (auto ®Name : counts.register_names()) { + results.emplace_back(counts.to_map(regName), regName); + results.back().sequentialData = + counts.sequential_data(regName); + } + } + } + for (std::size_t i = 0; i < codes.size(); i++) { cudaq::ExecutionContext context("sample", localShots); cudaq::getExecutionManager()->setExecutionContext(&context); diff --git a/runtime/cudaq/platform/default/rest/helpers/oqc/OQCServerHelp.cpp b/runtime/cudaq/platform/default/rest/helpers/oqc/OQCServerHelp.cpp index 875c884bb9..3f476ba5ec 100644 --- a/runtime/cudaq/platform/default/rest/helpers/oqc/OQCServerHelp.cpp +++ b/runtime/cudaq/platform/default/rest/helpers/oqc/OQCServerHelp.cpp @@ -118,16 +118,17 @@ OQCServerHelper::get_from_config(BackendConfig config, const std::string &key, return iter != backendConfig.end() ? iter->second : default_return; } -// Retrieve an environment variable +/// @brief Retrieve an environment variable. Return empty string if variable +/// does not exist. std::string OQCServerHelper::getEnvVar(const std::string &key) const { // Get the environment variable const char *env_var = std::getenv(key.c_str()); - // If the variable is not set, throw an exception - if (env_var == nullptr) { - throw std::runtime_error(key + " environment variable is not set."); - } - // Return the variable as a string - return std::string(env_var); + // Return the variable as a string. Initializing with a null pointer is + // undefined, so use empty constructor if necessary. + if (env_var) + return std::string(env_var); + else + return std::string(); } // Check if a key exists in the backend configuration @@ -326,6 +327,10 @@ RestHeaders OQCServerHelper::getHeaders() { // Check if the necessary keys exist in the configuration if (!keyExists("email") || !keyExists("password")) throw std::runtime_error("Key doesn't exist in backendConfig."); + if (backendConfig.at("email").empty()) + throw std::runtime_error("OQC_EMAIL environment variable is not set."); + if (backendConfig.at("password").empty()) + throw std::runtime_error("OQC_PASSWORD environment variable is not set."); // Construct the headers RestHeaders headers; diff --git a/runtime/cudaq/platform/default/rest/helpers/quantinuum/quantinuum.config b/runtime/cudaq/platform/default/rest/helpers/quantinuum/quantinuum.config index aa6e69ac4b..cab00a7b9d 100644 --- a/runtime/cudaq/platform/default/rest/helpers/quantinuum/quantinuum.config +++ b/runtime/cudaq/platform/default/rest/helpers/quantinuum/quantinuum.config @@ -15,11 +15,11 @@ GEN_TARGET_BACKEND=true # Add the rest-qpu library to the link list LINKLIBS="${LINKLIBS} -lcudaq-rest-qpu" -# Define the lowering pipeline, here we lower to Base QIR +# Define the lowering pipeline, here we lower to Adaptive QIR PLATFORM_LOWERING_CONFIG="expand-measurements,unrolling-pipeline,func.func(lower-to-cfg),canonicalize,func.func(quake-multicontrol-decomposition),quantinuum-gate-set-mapping" # Tell the rest-qpu that we are generating QIR. -CODEGEN_EMISSION=qir-base +CODEGEN_EMISSION=qir-adaptive # Physical backends must set library mode to false. LIBRARY_MODE=false diff --git a/runtime/nvqir/NVQIR.cpp b/runtime/nvqir/NVQIR.cpp index 5b9a83617c..661d595c30 100644 --- a/runtime/nvqir/NVQIR.cpp +++ b/runtime/nvqir/NVQIR.cpp @@ -359,6 +359,15 @@ Result *__quantum__qis__mz__body(Qubit *q) { return b ? ResultOne : ResultZero; } +bool __quantum__qis__read_result__body(Result *result) { + // TODO: implement post-measurement result retrieval. This is not needed for + // typical simulator operation (other than to have it defined), but it may be + // useful in the future. + // https://github.com/NVIDIA/cuda-quantum/issues/758 + cudaq::ScopedTrace trace("NVQIR::read_result (stubbed out)"); + return ResultZeroVal; +} + Result *__quantum__qis__mz__to__register(Qubit *q, const char *name) { std::string regName(name); auto qI = qubitToSizeT(q); diff --git a/test/NVQPP/qir_test_cond_for_break.cpp b/test/NVQPP/qir_test_cond_for_break.cpp new file mode 100644 index 0000000000..8583b94629 --- /dev/null +++ b/test/NVQPP/qir_test_cond_for_break.cpp @@ -0,0 +1,65 @@ +/******************************************************************************* + * 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. * + ******************************************************************************/ + +// clang-format off +// RUN: nvq++ --target quantinuum --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s +// XFAIL: * +// ^^^^^ Produces error: 'cc.loop' op not a simple counted loop +// clang-format on + +#include +#include + +struct kernel { + void operator()(const int n_iter) __qpu__ { + cudaq::qubit q0; + for (int i = 0; i < n_iter; i++) { + h(q0); + auto q0result = mz(q0); + if (q0result) + break; // loop until it lands heads + } + } +}; + +int main() { + + int nShots = 100; + int nIter = 20; + cudaq::set_random_seed(13); + + // Sample + auto counts = cudaq::sample(/*shots=*/nShots, kernel{}, nIter); + + // Count the maximum number of iterations it took + int nIterRan = nIter; + for (int i = 0; i < nIter; i++) { + char regName1[32]; + snprintf(regName1, sizeof(regName1), "q0result%%%02d", i); + char regName2[32]; + snprintf(regName2, sizeof(regName2), "auto_register_%d", i); + if (counts.size(regName1) == 0 && counts.size(regName2) == 0) { + nIterRan = i; + break; + } + } + + int ret = 0; // return status + + if (nIterRan < nIter) { + std::cout << "SUCCESS: nIterRan (" << nIterRan << ") < nIter (" << nIter << ")\n"; + ret = 0; + } else { + std::cout << "FAILURE: nIterRan (" << nIterRan << ") >= nIter (" << nIter << ")\n"; + ret = 1; + } + + return ret; +} + +// CHECK: SUCCESS diff --git a/test/NVQPP/qir_test_cond_for_loop-1.cpp b/test/NVQPP/qir_test_cond_for_loop-1.cpp new file mode 100644 index 0000000000..c4ce859cb7 --- /dev/null +++ b/test/NVQPP/qir_test_cond_for_loop-1.cpp @@ -0,0 +1,113 @@ +/******************************************************************************* + * 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. * + ******************************************************************************/ + +// clang-format off +// RUN: nvq++ --target quantinuum --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s +// clang-format on + +#include +#include + +struct kernel { + void operator()(const int n_iter) __qpu__ { + cudaq::qubit q0; + cudaq::qubit q1; + for (int i = 0; i < n_iter; i++) { + h(q0); + if (mz(q0)) + x(q1); // toggle q1 on every q0 coin toss that lands heads + } + auto q1result = mz(q1); // the measured q1 should contain the parity bit for + // the q0 measurements + } +}; + +int main() { + + int nShots = 100; + int nIter = 5; + cudaq::set_random_seed(13); + + // Sample + auto counts = cudaq::sample(/*shots=*/nShots, kernel{}, nIter); + counts.dump(); + + auto q1result_0 = counts.count("0", "q1result"); + auto q1result_1 = counts.count("1", "q1result"); + if (q1result_0 + q1result_1 != nShots) { + std::cout << "q1result_0 (" << q1result_0 << ") + q1result_1 (" + << q1result_1 << ") != nShots (" << nShots << ")\n"; + return 1; + } + if (q1result_0 < static_cast(0.3 * nShots) || + q1result_0 > static_cast(0.7 * nShots)) { + std::cout << "q1result_0 (" << q1result_0 + << ") is not within expected range [" + << static_cast(0.3 * nShots) << "," + << static_cast(0.7 * nShots) << "]\n"; + return 2; + } + + auto &platform = cudaq::get_platform(); + + // If you run this on quantinuum hardware (i.e. H1-1E), the following parity + // check will check that the results look reasonable. Skip the parity check on + // `--emulate` runs because the unnamed measurement is not saved and therefore + // cannot be compared in a parity check. + if (!platform.is_emulated()) { + + // Populate binaryQ0results[iteration][shot] + std::vector> binaryQ0results; + for (int i = 0; i < nIter; i++) { + auto vecOfStrings = counts.sequential_data("r0000" + std::to_string(i)); + binaryQ0results.push_back({}); + for (int shot = 0; shot < nShots; shot++) + binaryQ0results[i].push_back(vecOfStrings[shot][0] == '0' ? 0 : 1); + } + + // Populate binaryQ1results[shot] + auto q1result = counts.sequential_data("q1result"); + std::vector binaryQ1results(nShots); + for (int shot = 0; shot < nShots; shot++) + binaryQ1results[shot] = q1result[shot][0] == '0' ? 0 : 1; + + // For each shot, do the parity check + int parityCheckSuccessCount = 0; + for (int shot = 0; shot < nShots; shot++) { + int parity = 0; + for (int i = 0; i < nIter; i++) + parity ^= binaryQ0results[i][shot]; + if (parity == binaryQ1results[shot]) + parityCheckSuccessCount++; + } + + if (parityCheckSuccessCount != nShots) { + // Output q0result and q1results for easy viewing + std::cout << "q1result : "; + for (auto ch : q1result) + std::cout << ch; + std::cout << '\n'; + for (int i = 0; i < nIter; i++) { + std::cout << "q0result%" << i << ": "; + for (auto b : binaryQ0results[i]) + std::cout << b; + std::cout << '\n'; + } + + std::cout << "parityCheckSuccessCount: " << parityCheckSuccessCount + << '\n'; + std::cout << "nShots: " << nShots << '\n'; + return 3; + } + } + + std::cout << "SUCCESS\n"; + return 0; +} + +// CHECK: SUCCESS diff --git a/test/NVQPP/qir_test_cond_for_loop-2.cpp b/test/NVQPP/qir_test_cond_for_loop-2.cpp new file mode 100644 index 0000000000..a28ae47ac9 --- /dev/null +++ b/test/NVQPP/qir_test_cond_for_loop-2.cpp @@ -0,0 +1,90 @@ +/******************************************************************************* + * 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. * + ******************************************************************************/ + +// clang-format off +// RUN: nvq++ --target quantinuum --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s +// clang-format on + +#include +#include + +struct kernel { + void operator()(const int n_iter) __qpu__ { + cudaq::qubit q0; + cudaq::qubit q1; + for (int i = 0; i < n_iter; i++) { + h(q0); + auto q0result = mz(q0); + if (q0result) + x(q1); // toggle q1 on every q0 coin toss that lands heads + } + auto q1result = mz(q1); // the measured q1 should contain the parity bit for + // the q0 measurements + } +}; + +int main() { + + int nShots = 100; + int nIter = 5; + cudaq::set_random_seed(13); + + // Sample + auto counts = cudaq::sample(/*shots=*/nShots, kernel{}, nIter); + + // Perform parity check on results + + // Populate binaryQ0results[iteration][shot] + std::vector> binaryQ0results; + for (int i = 0; i < nIter; i++) { + auto vecOfStrings = counts.sequential_data("q0result%" + std::to_string(i)); + binaryQ0results.push_back({}); + for (int shot = 0; shot < nShots; shot++) + binaryQ0results[i].push_back(vecOfStrings[shot][0] == '0' ? 0 : 1); + } + + // Populate binaryQ1results[shot] + auto q1result = counts.sequential_data("q1result"); + std::vector binaryQ1results(nShots); + for (int shot = 0; shot < nShots; shot++) + binaryQ1results[shot] = q1result[shot][0] == '0' ? 0 : 1; + + // For each shot, do the parity check + int parityCheckSuccessCount = 0; + for (int shot = 0; shot < nShots; shot++) { + int parity = 0; + for (int i = 0; i < nIter; i++) + parity ^= binaryQ0results[i][shot]; + if (parity == binaryQ1results[shot]) + parityCheckSuccessCount++; + } + + if (parityCheckSuccessCount != nShots) { + // Output q0result and q1results for easy viewing + std::cout << "q1result : "; + for (auto ch : q1result) + std::cout << ch; + std::cout << '\n'; + for (int i = 0; i < nIter; i++) { + std::cout << "q0result%" << i << ": "; + for (auto b : binaryQ0results[i]) + std::cout << b; + std::cout << '\n'; + } + + std::cout << "parityCheckSuccessCount: " << parityCheckSuccessCount << '\n'; + std::cout << "nShots: " << nShots << '\n'; + return 3; // same error code for similar condition in + // qir_test_cond_for_loop-1.cpp + } + + std::cout << "SUCCESS\n"; + return 0; +} + +// CHECK: SUCCESS diff --git a/test/NVQPP/qir_test_cond_for_loop-3.cpp b/test/NVQPP/qir_test_cond_for_loop-3.cpp new file mode 100644 index 0000000000..93df11eaa8 --- /dev/null +++ b/test/NVQPP/qir_test_cond_for_loop-3.cpp @@ -0,0 +1,62 @@ +/******************************************************************************* + * 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. * + ******************************************************************************/ + +// clang-format off +// RUN: nvq++ --target quantinuum --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s +// clang-format on + +#include +#include + +struct kernel { + void operator()(const int n_iter) __qpu__ { + cudaq::qubit q0; + cudaq::qubit q1; + std::vector resultVector(n_iter); + for (int i = 0; i < n_iter; i++) { + h(q0); + resultVector[i] = mz(q0); + if (resultVector[i]) + x(q1); // toggle q1 on every q0 coin toss that lands heads + } + auto q1result = mz(q1); // the measured q1 should contain the parity bit for + // the q0 measurements + } +}; + +int main() { + + int nShots = 100; + int nIter = 5; + cudaq::set_random_seed(13); + + // Sample + auto counts = cudaq::sample(/*shots=*/nShots, kernel{}, nIter); + counts.dump(); + + auto q1result_0 = counts.count("0", "q1result"); + auto q1result_1 = counts.count("1", "q1result"); + if (q1result_0 + q1result_1 != nShots) { + std::cout << "q1result_0 (" << q1result_0 << ") + q1result_1 (" + << q1result_1 << ") != nShots (" << nShots << ")\n"; + return 1; + } + if (q1result_0 < static_cast(0.3 * nShots) || + q1result_0 > static_cast(0.7 * nShots)) { + std::cout << "q1result_0 (" << q1result_0 + << ") is not within expected range [" + << static_cast(0.3 * nShots) << "," + << static_cast(0.7 * nShots) << "]\n"; + return 2; + } + + std::cout << "SUCCESS\n"; + return 0; +} + +// CHECK: SUCCESS diff --git a/test/NVQPP/qir_test_cond_for_loop-4.cpp b/test/NVQPP/qir_test_cond_for_loop-4.cpp new file mode 100644 index 0000000000..87fba77c0d --- /dev/null +++ b/test/NVQPP/qir_test_cond_for_loop-4.cpp @@ -0,0 +1,65 @@ +/******************************************************************************* + * 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. * + ******************************************************************************/ + +// clang-format off +// RUN: nvq++ --target quantinuum --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s +// XFAIL: * +// ^^^^^ This probably needs an issue posted. It's not setting qubitMeasurementFeedback. +// It passes on H1-1E but not --emulate +// clang-format on + +#include +#include + +struct kernel { + void operator()(const int n_iter) __qpu__ { + cudaq::qubit q0; + cudaq::qubit q1; + std::vector resultVector(n_iter); + for (int i = 0; i < n_iter; i++) { + h(q0); + resultVector[i] = mz(q0); + if (resultVector[i]) + x(q1); // toggle q1 on every q0 coin toss that lands heads + } + auto q1result = mz(q1); // the measured q1 should contain the parity bit for + // the q0 measurements + } +}; + +int main() { + + int nShots = 100; + int nIter = 5; + cudaq::set_random_seed(13); + + // Sample + auto counts = cudaq::sample(/*shots=*/nShots, kernel{}, nIter); + counts.dump(); + + auto q1result_0 = counts.count("0", "q1result"); + auto q1result_1 = counts.count("1", "q1result"); + if (q1result_0 + q1result_1 != nShots) { + std::cout << "q1result_0 (" << q1result_0 << ") + q1result_1 (" + << q1result_1 << ") != nShots (" << nShots << ")\n"; + return 1; + } + if (q1result_0 < static_cast(0.3 * nShots) || + q1result_0 > static_cast(0.7 * nShots)) { + std::cout << "q1result_0 (" << q1result_0 + << ") is not within expected range [" + << static_cast(0.3 * nShots) << "," + << static_cast(0.7 * nShots) << "]\n"; + return 2; + } + + std::cout << "SUCCESS\n"; + return 0; +} + +// CHECK: SUCCESS diff --git a/test/NVQPP/qir_test_cond_for_loop-5.cpp b/test/NVQPP/qir_test_cond_for_loop-5.cpp new file mode 100644 index 0000000000..ab8160f4c6 --- /dev/null +++ b/test/NVQPP/qir_test_cond_for_loop-5.cpp @@ -0,0 +1,65 @@ +/******************************************************************************* + * 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. * + ******************************************************************************/ + +// clang-format off +// RUN: nvq++ --target quantinuum --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s +// XFAIL: * +// ^^^^^ This probably needs an issue posted. It's not setting qubitMeasurementFeedback. +// It passes on H1-1E but not --emulate +// clang-format on + +#include + +#define NUM_ITERATIONS 5 + +struct kernel { + void operator()() __qpu__ { + cudaq::qubit q0; + cudaq::qubit q1; + int resultArray[NUM_ITERATIONS]; + for (int i = 0; i < NUM_ITERATIONS; i++) { + h(q0); + resultArray[i] = mz(q0); + if (resultArray[i]) + x(q1); // toggle q1 on every q0 coin toss that lands heads + } + auto q1result = mz(q1); // the measured q1 should contain the parity bit for + // the q0 measurements + } +}; + +int main() { + + int nShots = 100; + cudaq::set_random_seed(13); + + // Sample + auto counts = cudaq::sample(/*shots=*/nShots, kernel{}); + counts.dump(); + + auto q1result_0 = counts.count("0", "q1result"); + auto q1result_1 = counts.count("1", "q1result"); + if (q1result_0 + q1result_1 != nShots) { + std::cout << "q1result_0 (" << q1result_0 << ") + q1result_1 (" + << q1result_1 << ") != nShots (" << nShots << ")\n"; + return 1; + } + if (q1result_0 < static_cast(0.3 * nShots) || + q1result_0 > static_cast(0.7 * nShots)) { + std::cout << "q1result_0 (" << q1result_0 + << ") is not within expected range [" + << static_cast(0.3 * nShots) << "," + << static_cast(0.7 * nShots) << "]\n"; + return 2; + } + + std::cout << "SUCCESS\n"; + return 0; +} + +// CHECK: SUCCESS diff --git a/test/NVQPP/qir_test_cond_for_loop-6.cpp b/test/NVQPP/qir_test_cond_for_loop-6.cpp new file mode 100644 index 0000000000..d4ede9f4b2 --- /dev/null +++ b/test/NVQPP/qir_test_cond_for_loop-6.cpp @@ -0,0 +1,67 @@ +/******************************************************************************* + * 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. * + ******************************************************************************/ + +// clang-format off +// RUN: nvq++ --target quantinuum --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s +// clang-format on + +#include +#include + +struct kernel { + void operator()(const int n_iter) __qpu__ { + cudaq::qubit q0; + bool keepGoing = true; + for (int i = 0; i < n_iter; i++) { + if (keepGoing) { + h(q0); + auto q0result = mz(q0); + if (q0result) + keepGoing = false; + } + } + } +}; + +int main() { + + int nShots = 100; + int nIter = 20; + cudaq::set_random_seed(13); + + // Sample + auto counts = cudaq::sample(/*shots=*/nShots, kernel{}, nIter); + counts.dump(); + + // Count the maximum number of iterations it took + int nIterRan = nIter; + for (int i = 0; i < nIter; i++) { + char regName1[32]; + snprintf(regName1, sizeof(regName1), "q0result%%%02d", i); + char regName2[32]; + snprintf(regName2, sizeof(regName2), "auto_register_%d", i); + if (counts.size(regName1) == 0 && counts.size(regName2) == 0) { + nIterRan = i; + break; + } + } + + int ret = 0; // return status + + if (nIterRan < nIter) { + std::cout << "SUCCESS: nIterRan (" << nIterRan << ") < nIter (" << nIter << ")\n"; + ret = 0; + } else { + std::cout << "FAILURE: nIterRan (" << nIterRan << ") >= nIter (" << nIter << ")\n"; + ret = 1; + } + + return ret; +} + +// CHECK: SUCCESS diff --git a/test/NVQPP/qir_test_if_base.cpp b/test/NVQPP/qir_test_if_base.cpp index ee714234b9..8184dd42ef 100644 --- a/test/NVQPP/qir_test_if_base.cpp +++ b/test/NVQPP/qir_test_if_base.cpp @@ -7,7 +7,6 @@ ******************************************************************************/ // Note: change |& to 2>&1 if running in bash -// RUN: nvq++ -v %s -o %basename_t.x --target quantinuum --emulate && ./%basename_t.x |& FileCheck %s // RUN: nvq++ -v %s -o %basename_t.x --target ionq --emulate && IONQ_API_KEY=0 ./%basename_t.x |& FileCheck %s #include diff --git a/test/NVQPP/qir_test_op1_after_measure.cpp b/test/NVQPP/qir_test_op1_after_measure.cpp index e19f4a262a..adffd5088a 100644 --- a/test/NVQPP/qir_test_op1_after_measure.cpp +++ b/test/NVQPP/qir_test_op1_after_measure.cpp @@ -7,7 +7,7 @@ ******************************************************************************/ // Note: change |& to 2>&1 if running in bash -// RUN: nvq++ -v %s -o %basename_t.x --target quantinuum --emulate && ./%basename_t.x |& FileCheck %s +// RUN: nvq++ -v %s -o %basename_t.x --target oqc --emulate && ./%basename_t.x |& FileCheck %s #include #include diff --git a/test/NVQPP/qir_test_op2_after_measure.cpp b/test/NVQPP/qir_test_op2_after_measure.cpp index aacafac83b..126b0aca23 100644 --- a/test/NVQPP/qir_test_op2_after_measure.cpp +++ b/test/NVQPP/qir_test_op2_after_measure.cpp @@ -7,7 +7,7 @@ ******************************************************************************/ // Note: change |& to 2>&1 if running in bash -// RUN: nvq++ -v %s -o %basename_t.x --target quantinuum --emulate && ./%basename_t.x |& FileCheck %s +// RUN: nvq++ -v %s -o %basename_t.x --target oqc --emulate && ./%basename_t.x |& FileCheck %s #include #include diff --git a/test/NVQPP/qir_test_op3_after_measure.cpp b/test/NVQPP/qir_test_op3_after_measure.cpp index 3ef790fd14..fe26a1999c 100644 --- a/test/NVQPP/qir_test_op3_after_measure.cpp +++ b/test/NVQPP/qir_test_op3_after_measure.cpp @@ -7,7 +7,7 @@ ******************************************************************************/ // Note: change |& to 2>&1 if running in bash -// RUN: nvq++ -v %s -o %basename_t.x --target quantinuum --emulate && ./%basename_t.x |& FileCheck %s +// RUN: nvq++ -v %s -o %basename_t.x --target oqc --emulate && ./%basename_t.x |& FileCheck %s // XFAIL: * #include diff --git a/test/NVQPP/qir_test_range_err_runtime.cpp b/test/NVQPP/qir_test_range_err_runtime.cpp index 2cdffa4d72..5a99d20e20 100644 --- a/test/NVQPP/qir_test_range_err_runtime.cpp +++ b/test/NVQPP/qir_test_range_err_runtime.cpp @@ -8,6 +8,7 @@ // Note: change |& to 2>&1| if running in bash // RUN: nvq++ %s -o %basename_t.x --target quantinuum --emulate && ./%basename_t.x |& FileCheck %s +// RUN: nvq++ %s -o %basename_t.x --target oqc --emulate && ./%basename_t.x |& FileCheck %s #include #include diff --git a/test/NVQPP/qir_test_simple_cond-1.cpp b/test/NVQPP/qir_test_simple_cond-1.cpp new file mode 100644 index 0000000000..3c44434eca --- /dev/null +++ b/test/NVQPP/qir_test_simple_cond-1.cpp @@ -0,0 +1,44 @@ +/******************************************************************************* + * 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. * + ******************************************************************************/ + +// clang-format off +// RUN: nvq++ --target quantinuum --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s +// clang-format on + +#include +#include + +struct kernel { + void operator()() __qpu__ { + cudaq::qubit q0; + cudaq::qubit q1; + h(q0); + auto q0result = mz(q0); + if (q0result) + x(q1); + auto q1result = mz(q1); // Every q1 measurement will be the same as q0 + } +}; + +int main() { + + int nShots = 100; + // Sample + auto counts = cudaq::sample(/*shots=*/nShots, kernel{}); + counts.dump(); + // Assert that all shots contained "00" or "11", exclusively + if (counts.count("00") + counts.count("11") != nShots) { + std::cout << "counts00 (" << counts.count("00") << ") + counts11 (" + << counts.count("11") << ") != nShots (" << nShots << ")\n"; + return 1; + } + std::cout << "SUCCESS\n"; + return 0; +} + +// CHECK: SUCCESS diff --git a/test/NVQPP/qir_test_simple_cond-2.cpp b/test/NVQPP/qir_test_simple_cond-2.cpp new file mode 100644 index 0000000000..ec748047b5 --- /dev/null +++ b/test/NVQPP/qir_test_simple_cond-2.cpp @@ -0,0 +1,64 @@ +/******************************************************************************* + * 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. * + ******************************************************************************/ + +// clang-format off +// RUN: nvq++ --target quantinuum --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s +// XFAIL: * +// ^^^^^ This is caused by this error: invalid instruction found: %2 = xor i1 %0, true +// This error is reasonable given the current version of the Adaptive +// Profile that is supported, but future versions of the Adaptive +// Profile (that contain optional capabilities) may legalize this. +// clang-format on + +#include +#include + +struct kernel { + void operator()() __qpu__ { + cudaq::qubit q0; + cudaq::qubit q1; + cudaq::qubit q2; + h(q0); + h(q1); + auto result0 = mz(q0); + auto result1 = mz(q1); + if (result0 && result1) + x(q2); // toggle q2 when both q0 and q1 are heads + auto result2 = mz(q2); + } +}; + +int main() { + + int nShots = 100; + cudaq::set_random_seed(13); + + // Sample + auto counts = cudaq::sample(/*shots=*/nShots, kernel{}); + counts.dump(); + + auto q2result_0 = counts.count("0", "q2result"); + auto q2result_1 = counts.count("1", "q2result"); + if (q2result_0 + q2result_1 != nShots) { + std::cout << "q2result_0 (" << q2result_0 << ") + q2result_1 (" + << q2result_1 << ") != nShots (" << nShots << ")\n"; + return 1; + } + if (q2result_0 < static_cast(0.3 * nShots) || + q2result_0 > static_cast(0.7 * nShots)) { + std::cout << "q2result_0 (" << q2result_0 + << ") is not within expected range [" + << static_cast(0.3 * nShots) << "," + << static_cast(0.7 * nShots) << "]\n"; + return 2; + } + std::cout << "SUCCESS\n"; + return 0; +} + +// CHECK: SUCCESS diff --git a/test/NVQPP/qir_test_string_labels.cpp b/test/NVQPP/qir_test_string_labels.cpp index a3d1c8066b..b22068d53a 100644 --- a/test/NVQPP/qir_test_string_labels.cpp +++ b/test/NVQPP/qir_test_string_labels.cpp @@ -33,8 +33,8 @@ int main() { // CHECK-DAG: define void @__nvqpp__mlirgen__function_qir_test.{{.*}}() local_unnamed_addr #[[ATTR_1:[0-9]+]] // CHECK: call void @__quantum__rt__result_record_output(%Result* null, i8* nonnull getelementptr inbounds ([14 x i8], [14 x i8]* @cstr.[[ADDRESS]], i64 0, i64 0)) // CHECK-DAG: attributes #[[ATTR_0]] = { "irreversible" } -// CHECK-DAG: attributes #[[ATTR_1]] = { "entry_point" {{.*}} "qir_profiles"="base_profile" "requiredQubits"="1" "requiredResults"="1" } -// CHECK-DAG: !llvm.module.flags = !{!0, !1, !2, !3, !4} +// CHECK-DAG: attributes #[[ATTR_1]] = { "entry_point" {{.*}} "qir_profiles"="adaptive_profile" "requiredQubits"="1" "requiredResults"="1" } +// CHECK-DAG: !llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10, !11, !12} // CHECK-DAG: !0 = !{i32 2, !"Debug Info Version", i32 3} // CHECK-DAG: !1 = !{i32 1, !"qir_major_version", i32 1} // CHECK-DAG: !2 = !{i32 7, !"qir_minor_version", i32 0} diff --git a/test/NVQPP/test-6.cpp b/test/NVQPP/test-6.cpp index a051f30329..18e4861de7 100644 --- a/test/NVQPP/test-6.cpp +++ b/test/NVQPP/test-6.cpp @@ -7,7 +7,6 @@ ******************************************************************************/ // RUN: nvq++ -v %s -o %basename_t.x --target quantinuum --emulate && ./%basename_t.x | FileCheck %s -// XFAIL: * #include #include diff --git a/test/NVQPP/testConditionalSample.cpp b/test/NVQPP/testConditionalSample.cpp index c13dac78d1..f6d83b28af 100644 --- a/test/NVQPP/testConditionalSample.cpp +++ b/test/NVQPP/testConditionalSample.cpp @@ -6,7 +6,8 @@ * the terms of the Apache License 2.0 which accompanies this distribution. * ******************************************************************************/ -// RUN: nvq++ --enable-mlir %s -o out_testifstmts.x && ./out_testifstmts.x +// RUN: nvq++ --enable-mlir %s -o %basename_t.x && ./%basename_t.x +// RUN: nvq++ --target quantinuum --emulate %s -o %basename_t.x && ./%basename_t.x // The test here is the assert statement. diff --git a/test/NVQPP/testIQPE_Conditionals.cpp b/test/NVQPP/testIQPE_Conditionals.cpp index c5a950dff2..f8feeb7261 100644 --- a/test/NVQPP/testIQPE_Conditionals.cpp +++ b/test/NVQPP/testIQPE_Conditionals.cpp @@ -6,7 +6,8 @@ * the terms of the Apache License 2.0 which accompanies this distribution. * ******************************************************************************/ -// RUN: nvq++ --enable-mlir %s -o out_testifstmts_iqpe.x && ./out_testifstmts_iqpe.x | FileCheck %s && rm out_testifstmts_iqpe.x +// RUN: nvq++ --enable-mlir %s -o %basename_t.x && ./%basename_t.x | FileCheck %s && rm %basename_t.x +// RUN: nvq++ --target quantinuum --emulate %s -o %basename_t.x && ./%basename_t.x | FileCheck %s && rm %basename_t.x #include