Skip to content

Update generated QIR to match the QIR adaptive spec #2990

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

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
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
21 changes: 19 additions & 2 deletions include/cudaq/Optimizer/CodeGen/QIRAttributeNames.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,26 @@ static constexpr const char QIRProfilesAttrName[] = "qir_profiles";
static constexpr const char QIROutputLabelingSchemaAttrName[] =
"output_labeling_schema";
static constexpr const char QIROutputNamesAttrName[] = "output_names";
static constexpr const char QIRRequiredQubitsAttrName[] = "requiredQubits";
static constexpr const char QIRRequiredResultsAttrName[] = "requiredResults";
static constexpr const char QIRRequiredQubitsAttrName[] = "required_num_qubits";
static constexpr const char QIRRequiredResultsAttrName[] =
"required_num_results";
static constexpr const char QIRIrreversibleFlagName[] = "irreversible";
static constexpr const char QIRMajorVersionFlagName[] = "qir_major_version";
static constexpr const char QIRMinorVersionFlagName[] = "qir_minor_version";
static constexpr const char QIRDynamicQubitsManagementFlagName[] =
"dynamic_qubit_management";
static constexpr const char QIRDynamicResultManagementFlagName[] =
"dynamic_result_management";
static constexpr const char QIRIrFunctionsFlagName[] = "ir_functions";
static constexpr const char QIRIntComputationsFlagName[] = "int_computations";
static constexpr const char QIRFloatComputationsFlagName[] =
"float_computations";
static constexpr const char QIRBackwardsBranchingFlagName[] =
"backwards_branching";
static constexpr const char QIRMultipleTargetBranchingFlagName[] =
"multiple_target_branching";
static constexpr const char QIRMultipleReturnPointsFlagName[] =
"multiple_return_points";

static constexpr const char StartingOffsetAttrName[] = "StartingOffset";
static constexpr const char ResultIndexAttrName[] = "ResultIndex";
Expand Down
3 changes: 1 addition & 2 deletions include/cudaq/Optimizer/CodeGen/QIRFunctionNames.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@ static constexpr const char QIRReset[] = "__quantum__qis__reset";
static constexpr const char QIRCnot[] = "__quantum__qis__cnot__body";
static constexpr const char QIRCphase[] = "__quantum__qis__cphase";
static constexpr const char QIRCZ[] = "__quantum__qis__cz__body";
static constexpr const char QIRReadResultBody[] =
"__quantum__qis__read_result__body";
static constexpr const char QIRReadResultBody[] = "__quantum__rt__read_result";

static constexpr const char QIRCustomOp[] = "__quantum__qis__custom_unitary";
static constexpr const char QIRCustomAdjOp[] =
Expand Down
2 changes: 1 addition & 1 deletion lib/Optimizer/Builder/Intrinsics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -484,7 +484,7 @@ static constexpr IntrinsicCode intrinsicTable[] = {
func.func private @__quantum__rt__result_record_output(!qir_result, !qir_charptr)
func.func private @__quantum__qis__cnot__body(!qir_qubit, !qir_qubit)
func.func private @__quantum__qis__cz__body(!qir_qubit, !qir_qubit)
func.func private @__quantum__qis__read_result__body(!qir_result) -> i1
func.func private @__quantum__rt__read_result(!qir_result) -> i1
)#"},

// Declarations of all full QIR functions used by codegen.
Expand Down
2 changes: 1 addition & 1 deletion lib/Optimizer/CodeGen/WireSetsToProfileQIR.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,7 @@ struct WireSetToProfileQIRPrepPass
addBodyDecl("mz", measTy);
auto readResTy = FunctionType::get(ctx, TypeRange{resTy},
TypeRange{builder.getI1Type()});
createNewDecl("__quantum__qis__read_result__body", readResTy);
createNewDecl(cudaq::opt::QIRReadResultBody, readResTy);

auto i8PtrTy = cudaq::cc::PointerType::get(builder.getI8Type());
auto recordTy =
Expand Down
193 changes: 193 additions & 0 deletions python/tests/mlir/target/qir_adapvive_module_flags.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
# ============================================================================ #
# 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: CUDAQ_DUMP_JIT_IR=1 PYTHONPATH=../../.. python3 %s --target quantinuum --emulate |& FileCheck %s

import cudaq
import numpy as np

# Test hasMultipleTargetBranching flag
# TODO: add test after the support for switch statements is added.


# Test multiple_return_points flag
# NOTE: we create a common return with a phi node, not currently possible to
# produce a `True` value for the multiple_return_points flag
def test_return():

@cudaq.kernel
def kernel(n: int) -> int:
q = cudaq.qvector(n)
if mz(q[0]):
x(q[0])
return 1
return 2

print(cudaq.sample(kernel, 2))


test_return()

# CHECK: ; ModuleID = 'LLVMDialectModule'
# CHECK: {{.*}}
# CHECK: !llvm.module.flags = !{!0, !1, !2, !3, !4, !5}

# CHECK: !0 = !{i32 2, !"Debug Info Version", i32 3}
# CHECK: !1 = !{i32 1, !"qir_major_version", i32 1}
# CHECK: !2 = !{i32 7, !"qir_minor_version", i32 0}
# CHECK: !3 = !{i32 1, !"dynamic_qubit_management", i1 false}
# CHECK: !4 = !{i32 1, !"dynamic_result_management", i1 false}
# CHECK: !5 = !{i32 1, !"backwards_branching", i2 0}


# Test int_computations and float_computations flags
# TODO: add cudaq.run tests using runtime output functions
def test_computations():

@cudaq.kernel
def kernel(n: int, m: np.int32):
q = cudaq.qvector(n)
j = 0
jf = 1.2
for i in range(10):
k = 0
if i > 5:
k = 1
x(q[k])
if mz(q[k]):
j = j + 1
m = m + m
jf = jf + jf

if jf > 3 and j > 5:
x(q[0])

cudaq.sample(kernel, 2, 134)


test_computations()

# CHECK: {{.*}}
# CHECK: ; ModuleID = 'LLVMDialectModule'
# CHECK: {{.*}}
# CHECK: !llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7}

# CHECK: !0 = !{i32 2, !"Debug Info Version", i32 3}
# CHECK: !1 = !{i32 1, !"qir_major_version", i32 1}
# CHECK: !2 = !{i32 7, !"qir_minor_version", i32 0}
# CHECK: !3 = !{i32 1, !"dynamic_qubit_management", i1 false}
# CHECK: !4 = !{i32 1, !"dynamic_result_management", i1 false}
# CHECK: !5 = !{i32 1, !"int_computations", [6 x i8] c"i1,i64"}
# CHECK: !6 = !{i32 1, !"float_computations", [3 x i8] c"f64"}
# CHECK: !7 = !{i32 1, !"backwards_branching", i2 0}

# Test backwards_branching flag


def test_iteration_loop():

@cudaq.kernel
def kernel(n: int):
q = cudaq.qvector(n)
i = 0
j = 0
while i < 10000 - 1:
cx(q[j], q[j + 1])
i = i + 1
j = j + 1
if j >= n - 1:
j = 0

print(cudaq.sample(kernel, 2))


test_iteration_loop()

# CHECK: {{.*}}
# CHECK: ; ModuleID = 'LLVMDialectModule'
# CHECK: {{.*}}
# CHECK: !llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6}

# CHECK: !0 = !{i32 2, !"Debug Info Version", i32 3}
# CHECK: !1 = !{i32 1, !"qir_major_version", i32 1}
# CHECK: !2 = !{i32 7, !"qir_minor_version", i32 0}
# CHECK: !3 = !{i32 1, !"dynamic_qubit_management", i1 false}
# CHECK: !4 = !{i32 1, !"dynamic_result_management", i1 false}
# CHECK: !5 = !{i32 1, !"int_computations", [3 x i8] c"i64"}
# NOTE: 1 is "01" bitstring base 2
# CHECK: !6 = !{i32 1, !"backwards_branching", i2 1}


def test_conditionally_terminating_loops():

@cudaq.kernel
def kernel():
q = cudaq.qubit()
t = False
while not t:
x(q)
t = mz(q)

cudaq.sample(kernel)


test_conditionally_terminating_loops()

# CHECK: {{.*}}
# CHECK: ; ModuleID = 'LLVMDialectModule'
# CHECK: {{.*}}
# CHECK: !llvm.module.flags = !{!0, !1, !2, !3, !4, !5}

# CHECK: !0 = !{i32 2, !"Debug Info Version", i32 3}
# CHECK: !1 = !{i32 1, !"qir_major_version", i32 1}
# CHECK: !2 = !{i32 7, !"qir_minor_version", i32 0}
# CHECK: !3 = !{i32 1, !"dynamic_qubit_management", i1 false}
# CHECK: !4 = !{i32 1, !"dynamic_result_management", i1 false}
# NOTE: -2 is "10" bitstring base 2
# CHECK: !5 = !{i32 1, !"backwards_branching", i2 -2}


def test_iteration_and_conditionally_terminating_loop():

@cudaq.kernel
def kernel(n: int):
q = cudaq.qvector(n)
i = 0
j = 0
# Use large number of iterations to prevent unrolling.
while i < 1025:
cx(q[j], q[j + 1])
i = i + 1
j = j + 1
if j >= n - 1:
j = 0

qbit = cudaq.qubit()
t = False
while not t:
h(qbit)
t = mz(qbit)

print(cudaq.sample(kernel, 2))


test_iteration_and_conditionally_terminating_loop()

# CHECK: {{.*}}
# CHECK: ; ModuleID = 'LLVMDialectModule'
# CHECK: {{.*}}
# CHECK: !llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6}

# CHECK: !0 = !{i32 2, !"Debug Info Version", i32 3}
# CHECK: !1 = !{i32 1, !"qir_major_version", i32 1}
# CHECK: !2 = !{i32 7, !"qir_minor_version", i32 0}
# CHECK: !3 = !{i32 1, !"dynamic_qubit_management", i1 false}
# CHECK: !4 = !{i32 1, !"dynamic_result_management", i1 false}
# CHECK: !5 = !{i32 1, !"int_computations", [3 x i8] c"i64"}
# NOTE: -1 is "11" bitstring base 2
# CHECK: !6 = !{i32 1, !"backwards_branching", i2 -1}
Loading
Loading