Skip to content

Commit 050825e

Browse files
* Drop the intrinsic funciton fro converting to Boolean vector
* Insert discriminate op wherever necessary * Adjust tests Signed-off-by: Pradnya Khalate <[email protected]>
1 parent 81796ff commit 050825e

24 files changed

+459
-351
lines changed

include/cudaq/Optimizer/Builder/Intrinsics.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,6 @@ static constexpr const char llvmStackRestore[] = "llvm.stackrestore";
7373
static constexpr const char cudaqConvertToInteger[] =
7474
"__nvqpp_cudaqConvertToInteger";
7575

76-
static constexpr const char cudaqConvertToBoolVector[] =
77-
"__nvqpp_cudaq_to_bool_vector";
78-
7976
/// Builder for lowering the clang AST to an IR for CUDA-Q. Lowering includes
8077
/// the transformation of both quantum and classical computation. Different
8178
/// features of the CUDA-Q programming model are lowered into different dialects

lib/Frontend/nvqpp/ConvertExpr.cpp

Lines changed: 65 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -636,21 +636,39 @@ bool QuakeBridgeVisitor::VisitCastExpr(clang::CastExpr *x) {
636636
builder.create<cudaq::cc::CastOp>(loc, castToTy, popValue(), mode));
637637
}
638638
case clang::CastKind::CK_IntegralToFloating: {
639+
auto value = popValue();
640+
// If source is `!quake.measure`, discriminate it first
641+
if (isa<quake::MeasureType>(value.getType())) {
642+
value = builder.create<quake::DiscriminateOp>(loc, builder.getI1Type(),
643+
value);
644+
}
639645
auto mode =
640646
(x->getSubExpr()->getType()->isUnsignedIntegerOrEnumerationType())
641647
? cudaq::cc::CastOpMode::Unsigned
642648
: cudaq::cc::CastOpMode::Signed;
643649
return pushValue(
644-
builder.create<cudaq::cc::CastOp>(loc, castToTy, popValue(), mode));
650+
builder.create<cudaq::cc::CastOp>(loc, castToTy, value, mode));
645651
}
646652
case clang::CastKind::CK_IntegralToBoolean: {
647653
auto last = popValue();
654+
// If the value is `!quake.measure`, discriminate it first
655+
if (isa<quake::MeasureType>(last.getType())) {
656+
last =
657+
builder.create<quake::DiscriminateOp>(loc, builder.getI1Type(), last);
658+
return pushValue(last);
659+
}
648660
Value zero = builder.create<arith::ConstantIntOp>(loc, 0, last.getType());
649661
return pushValue(builder.create<arith::CmpIOp>(
650662
loc, arith::CmpIPredicate::ne, last, zero));
651663
}
652664
case clang::CastKind::CK_FloatingToBoolean: {
653665
auto last = popValue();
666+
// If the value is `!quake.measure`, discriminate it first
667+
if (isa<quake::MeasureType>(last.getType())) {
668+
last =
669+
builder.create<quake::DiscriminateOp>(loc, builder.getI1Type(), last);
670+
return pushValue(last);
671+
}
654672
Value zero = opt::factory::createFloatConstant(
655673
loc, builder, 0.0, cast<FloatType>(last.getType()));
656674
return pushValue(builder.create<arith::CmpFOp>(
@@ -667,10 +685,20 @@ bool QuakeBridgeVisitor::VisitCastExpr(clang::CastExpr *x) {
667685
return result;
668686
}
669687
auto i1Type = builder.getI1Type();
670-
671-
// Handle conversion of `measure_result` to `bool`.
672-
if (isa<quake::MeasureType>(sub.getType()))
673-
return pushValue(builder.create<quake::DiscriminateOp>(loc, i1Type, sub));
688+
// Handle conversion of `measure_result`
689+
if (isa<quake::MeasureType>(sub.getType())) {
690+
auto i1Val = builder.create<quake::DiscriminateOp>(loc, i1Type, sub);
691+
// Convert to `int`
692+
if (isa<IntegerType>(castToTy))
693+
return pushValue(
694+
builder.create<cudaq::cc::CastOp>(loc, castToTy, i1Val));
695+
// Convert to `float`
696+
if (isa<FloatType>(castToTy))
697+
return pushValue(builder.create<cudaq::cc::CastOp>(
698+
loc, castToTy, i1Val, cudaq::cc::CastOpMode::Unsigned));
699+
// Otherwise, just return the `i1` value
700+
return pushValue(i1Val);
701+
}
674702

675703
// Handle conversion of `std::vector<measure_result>` to `std::vector<bool>`
676704
if (auto vecTy = dyn_cast<cc::StdvecType>(sub.getType()))
@@ -831,6 +859,13 @@ bool QuakeBridgeVisitor::VisitBinaryOperator(clang::BinaryOperator *x) {
831859
x->getOpcode() == clang::BinaryOperatorKind::BO_NE) {
832860
rhs = maybeLoadValue(rhs);
833861
lhs = maybeLoadValue(lhs);
862+
// Discriminate measure types before comparison
863+
if (isa<quake::MeasureType>(lhs.getType()))
864+
lhs =
865+
builder.create<quake::DiscriminateOp>(loc, builder.getI1Type(), lhs);
866+
if (isa<quake::MeasureType>(rhs.getType()))
867+
rhs =
868+
builder.create<quake::DiscriminateOp>(loc, builder.getI1Type(), rhs);
834869
// Floating point comparison?
835870
if (isa<FloatType>(lhs.getType())) {
836871
arith::CmpFPredicate pred;
@@ -909,6 +944,11 @@ bool QuakeBridgeVisitor::VisitBinaryOperator(clang::BinaryOperator *x) {
909944
}
910945
rhs = maybeLoadValue(rhs);
911946
lhs = maybeLoadValue(lhs);
947+
// Discriminate measure types before arithmetic
948+
if (isa<quake::MeasureType>(lhs.getType()))
949+
lhs = builder.create<quake::DiscriminateOp>(loc, builder.getI1Type(), lhs);
950+
if (isa<quake::MeasureType>(rhs.getType()))
951+
rhs = builder.create<quake::DiscriminateOp>(loc, builder.getI1Type(), rhs);
912952
castToSameType(builder, loc, x->getLHS()->getType().getTypePtrOrNull(), lhs,
913953
x->getRHS()->getType().getTypePtrOrNull(), rhs);
914954
switch (x->getOpcode()) {
@@ -996,6 +1036,10 @@ bool QuakeBridgeVisitor::TraverseConditionalOperator(
9961036
if (!TraverseStmt(x->getCond()))
9971037
return false;
9981038
auto condVal = popValue();
1039+
// Discriminate if condition is `!quake.measure`
1040+
if (isa<quake::MeasureType>(condVal.getType()))
1041+
condVal = builder.create<quake::DiscriminateOp>(loc, builder.getI1Type(),
1042+
condVal);
9991043
Type resultTy = builder.getI64Type();
10001044

10011045
// Create shared lambda for the x->getTrueExpr() and x->getFalseExpr()
@@ -2147,19 +2191,30 @@ bool QuakeBridgeVisitor::VisitCallExpr(clang::CallExpr *x) {
21472191
}
21482192

21492193
if (funcName == "toInteger" || funcName == "to_integer") {
2194+
auto arg = args[0];
2195+
// Insert discriminate if input is `!cc.stdvec<!quake.measure>`
2196+
if (auto vecTy = dyn_cast<cc::StdvecType>(arg.getType())) {
2197+
if (isa<quake::MeasureType>(vecTy.getElementType())) {
2198+
auto i1Ty = builder.getI1Type();
2199+
arg = builder.create<quake::DiscriminateOp>(
2200+
loc, cc::StdvecType::get(i1Ty), arg);
2201+
}
2202+
}
21502203
IRBuilder irBuilder(builder.getContext());
21512204
if (failed(irBuilder.loadIntrinsic(module, cudaqConvertToInteger))) {
21522205
reportClangError(x, mangler, "cannot load cudaqConvertToInteger");
21532206
return false;
21542207
}
21552208
auto i64Ty = builder.getI64Type();
2156-
return pushValue(
2157-
builder.create<func::CallOp>(loc, i64Ty, cudaqConvertToInteger, args)
2158-
.getResult(0));
2209+
return pushValue(builder
2210+
.create<func::CallOp>(loc, i64Ty,
2211+
cudaqConvertToInteger,
2212+
ValueRange{arg})
2213+
.getResult(0));
21592214
}
21602215

21612216
if (funcName == "to_bool_vector") {
2162-
// args[0] is !cc.stdvec<!quake.measure> from mz()
2217+
// `args[0]` is `!cc.stdvec<!quake.measure>`
21632218
auto arg = args[0];
21642219
// Insert discriminate if needed
21652220
if (auto vecTy = dyn_cast<cc::StdvecType>(arg.getType())) {
@@ -2169,15 +2224,7 @@ bool QuakeBridgeVisitor::VisitCallExpr(clang::CallExpr *x) {
21692224
loc, cc::StdvecType::get(i1Ty), arg);
21702225
}
21712226
}
2172-
IRBuilder irBuilder(builder.getContext());
2173-
if (failed(irBuilder.loadIntrinsic(module, cudaqConvertToBoolVector))) {
2174-
reportClangError(x, mangler, "cannot load cudaqConvertToBoolVector");
2175-
return false;
2176-
}
2177-
return pushValue(builder
2178-
.create<func::CallOp>(loc, arg.getType(),
2179-
cudaqConvertToBoolVector, arg)
2180-
.getResult(0));
2227+
return pushValue(arg);
21812228
}
21822229

21832230
if (funcName == "slice_vector") {

lib/Frontend/nvqpp/ConvertStmt.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -359,12 +359,10 @@ bool QuakeBridgeVisitor::VisitReturnStmt(clang::ReturnStmt *x) {
359359
};
360360
IRBuilder irb(builder);
361361
Value tySize;
362-
if (!cudaq::cc::isDynamicType(eleTy))
363-
tySize = irb.getByteSizeOfType(loc, eleTy);
364362
if (isa<quake::MeasureType>(eleTy)) {
365363
/// FIXME: Confirm that this is okay.
366364
tySize = irb.getByteSizeOfType(loc, builder.getI32Type());
367-
} else {
365+
} else if (!cudaq::cc::isDynamicType(eleTy)) {
368366
tySize = irb.getByteSizeOfType(loc, eleTy);
369367
}
370368
if (!tySize) {

lib/Frontend/nvqpp/ConvertType.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,8 @@ static bool isKernelResultType(Type t) {
150150
static bool isKernelArgumentType(Type t) {
151151
return isArithmeticType(t) || isComposedArithmeticType(t) ||
152152
quake::isQuantumReferenceType(t) || isKernelCallable(t) ||
153-
isFunctionCallable(t) ||
153+
isFunctionCallable(t) || isMeasureResultType(t) ||
154+
isMeasureResultSequenceType(t) ||
154155
// TODO: move from pointers to a builtin string type.
155156
cudaq::isCharPointerType(t);
156157
}

lib/Optimizer/Builder/Intrinsics.cpp

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -337,13 +337,6 @@ static constexpr IntrinsicCode intrinsicTable[] = {
337337
func.func private @__nvqpp_cudaq_state_numberOfQubits(%p : !cc.ptr<!quake.state>) -> i64
338338
)#"},
339339

340-
{cudaq::cudaqConvertToBoolVector, {}, R"#(
341-
func.func private @__nvqpp_cudaq_to_bool_vector(%arg : !cc.stdvec<i1>) -> !cc.stdvec<i1> {
342-
// TODO: Implement
343-
return %arg : !cc.stdvec<i1>
344-
}
345-
)#"},
346-
347340
{cudaq::runtime::bindingDeconstructString,
348341
{},
349342
"func.func private @__nvqpp_deconstructString(!cc.ptr<i8>)"},

runtime/cudaq/qis/measure_result.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,9 @@ class measure_result {
3333
measure_result(int res) : result(res) {}
3434
measure_result(int res, std::size_t id) : result(res), uniqueId(id) {}
3535

36-
operator int() const { return result; }
3736
operator bool() const { return __nvqpp__MeasureResultBoolConversion(result); }
37+
explicit operator int() const { return result; }
38+
explicit operator double() const { return static_cast<double>(result); }
3839
};
3940

4041
} // namespace cudaq

test/AST-Quake/auto_kernel-1.cpp

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* the terms of the Apache License 2.0 which accompanies this distribution. *
77
******************************************************************************/
88

9-
// RUN: cudaq-quake %s | FileCheck %s
9+
// RUN: cudaq-quake %s | cudaq-opt | FileCheck %s
1010

1111
// Simple test using a type inferenced return value type.
1212

@@ -21,15 +21,14 @@ struct ak1 {
2121
}
2222
};
2323

24-
// CHECK: #[[$ATTR_0:.+]] = loc("auto_kernel-1.cpp":17:3)
2524
// CHECK-LABEL: func.func @__nvqpp__mlirgen__ak1(
26-
// CHECK-SAME: %[[ARG0:.*]]: i32 loc("auto_kernel-1.cpp":17:3)) -> !quake.measure attributes {"cudaq-kernel"} {
27-
// CHECK: %[[ALLOCA_0:.*]] = cc.alloca i32 loc(#loc2)
28-
// CHECK: cc.store %[[ARG0]], %[[ALLOCA_0]] : !cc.ptr<i32> loc(#loc2)
29-
// CHECK: %[[ALLOCA_1:.*]] = quake.alloca !quake.veq<2> loc(#loc3)
30-
// CHECK: %[[MZ_0:.*]] = quake.mz %[[ALLOCA_1]] : (!quake.veq<2>) -> !cc.stdvec<!quake.measure> loc(#loc4)
31-
// CHECK: %[[STDVEC_DATA_0:.*]] = cc.stdvec_data %[[MZ_0]] : (!cc.stdvec<!quake.measure>) -> !cc.ptr<!cc.array<!quake.measure x ?>> loc(#loc5)
32-
// CHECK: %[[CAST_0:.*]] = cc.cast %[[STDVEC_DATA_0]] : (!cc.ptr<!cc.array<!quake.measure x ?>>) -> !cc.ptr<!quake.measure> loc(#loc5)
33-
// CHECK: %[[LOAD_0:.*]] = cc.load %[[CAST_0]] : !cc.ptr<!quake.measure> loc(#loc5)
34-
// CHECK: return %[[LOAD_0]] : !quake.measure loc(#loc6)
35-
// CHECK: } loc(#[[$ATTR_0]])
25+
// CHECK-SAME: %[[VAL_0:.*]]: i32) -> !quake.measure attributes {"cudaq-kernel"} {
26+
// CHECK: %[[VAL_1:.*]] = cc.alloca i32
27+
// CHECK: cc.store %[[VAL_0]], %[[VAL_1]] : !cc.ptr<i32>
28+
// CHECK: %[[VAL_2:.*]] = quake.alloca !quake.veq<2>
29+
// CHECK: %[[VAL_3:.*]] = quake.mz %[[VAL_2]] name "vec" : (!quake.veq<2>) -> !cc.stdvec<!quake.measure>
30+
// CHECK: %[[VAL_4:.*]] = cc.stdvec_data %[[VAL_3]] : (!cc.stdvec<!quake.measure>) -> !cc.ptr<!cc.array<!quake.measure x ?>>
31+
// CHECK: %[[VAL_5:.*]] = cc.cast %[[VAL_4]] : (!cc.ptr<!cc.array<!quake.measure x ?>>) -> !cc.ptr<!quake.measure>
32+
// CHECK: %[[VAL_6:.*]] = cc.load %[[VAL_5]] : !cc.ptr<!quake.measure>
33+
// CHECK: return %[[VAL_6]] : !quake.measure
34+
// CHECK: }

test/AST-Quake/call_qpu.cpp

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
std::vector<bool> func_achat(cudaq::qview<> &qv) __qpu__ {
1414
// measure the entire register
15-
return mz(qv);
15+
return cudaq::to_bool_vector(mz(qv));
1616
}
1717

1818
// CHECK-LABEL: func.func @__nvqpp__mlirgen__function_func_achat._Z10func_achatRN5cudaq5qviewILm2EEE(
@@ -52,21 +52,21 @@ int func_shiim(cudaq::qvector<> &qv) __qpu__ {
5252
// CHECK: %[[VAL_10:.*]] = cc.cast %[[VAL_9]] : (!cc.ptr<!cc.array<i8 x ?>>) -> !cc.ptr<i8>
5353
// CHECK: call @__nvqpp_vectorCopyToStack(%[[VAL_10]], %[[VAL_7]], %[[VAL_8]]) : (!cc.ptr<i8>, !cc.ptr<i8>, i64) -> ()
5454
// CHECK: %[[VAL_11:.*]] = cc.undef i32
55-
// CHECK: %[[VAL_13:.*]]:2 = cc.loop while ((%[[VAL_14:.*]] = %[[VAL_2]], %[[VAL_15:.*]] = %[[VAL_11]]) -> (i64, i32)) {
56-
// CHECK: %[[VAL_16:.*]] = arith.cmpi slt, %[[VAL_14]], %[[VAL_8]] : i64
57-
// CHECK: cc.condition %[[VAL_16]](%[[VAL_14]], %[[VAL_15]] : i64, i32)
55+
// CHECK: %[[VAL_12:.*]]:2 = cc.loop while ((%[[VAL_13:.*]] = %[[VAL_2]], %[[VAL_14:.*]] = %[[VAL_11]]) -> (i64, i32)) {
56+
// CHECK: %[[VAL_15:.*]] = arith.cmpi slt, %[[VAL_13]], %[[VAL_8]] : i64
57+
// CHECK: cc.condition %[[VAL_15]](%[[VAL_13]], %[[VAL_14]] : i64, i32)
5858
// CHECK: } do {
59-
// CHECK: ^bb0(%[[VAL_17:.*]]: i64, %[[VAL_18:.*]]: i32):
60-
// CHECK: %[[VAL_19:.*]] = cc.compute_ptr %[[VAL_9]][%[[VAL_17]]] : (!cc.ptr<!cc.array<i8 x ?>>, i64) -> !cc.ptr<i8>
61-
// CHECK: %[[VAL_20:.*]] = cc.load %[[VAL_19]] : !cc.ptr<i8>
62-
// CHECK: %[[VAL_12:.*]] = cc.cast %[[VAL_20]] : (i8) -> i1
63-
// CHECK: %[[VAL_21:.*]] = cc.if(%[[VAL_12]]) -> i32 {
64-
// CHECK: %[[VAL_22:.*]] = arith.addi %[[VAL_18]], %[[VAL_3]] : i32
59+
// CHECK: ^bb0(%[[VAL_16:.*]]: i64, %[[VAL_17:.*]]: i32):
60+
// CHECK: %[[VAL_18:.*]] = cc.compute_ptr %[[VAL_9]]{{\[}}%[[VAL_16]]] : (!cc.ptr<!cc.array<i8 x ?>>, i64) -> !cc.ptr<i8>
61+
// CHECK: %[[VAL_19:.*]] = cc.load %[[VAL_18]] : !cc.ptr<i8>
62+
// CHECK: %[[VAL_20:.*]] = cc.cast %[[VAL_19]] : (i8) -> i1
63+
// CHECK: %[[VAL_21:.*]] = cc.if(%[[VAL_20]]) -> i32 {
64+
// CHECK: %[[VAL_22:.*]] = arith.addi %[[VAL_17]], %[[VAL_3]] : i32
6565
// CHECK: cc.continue %[[VAL_22]] : i32
6666
// CHECK: } else {
67-
// CHECK: cc.continue %[[VAL_18]] : i32
67+
// CHECK: cc.continue %[[VAL_17]] : i32
6868
// CHECK: }
69-
// CHECK: cc.continue %[[VAL_17]], %[[VAL_23:.*]] : i64, i32
69+
// CHECK: cc.continue %[[VAL_16]], %[[VAL_23:.*]] : i64, i32
7070
// CHECK: } step {
7171
// CHECK: ^bb0(%[[VAL_24:.*]]: i64, %[[VAL_25:.*]]: i32):
7272
// CHECK: %[[VAL_26:.*]] = arith.addi %[[VAL_24]], %[[VAL_1]] : i64
@@ -132,6 +132,7 @@ void func_arba() __qpu__ {
132132
// CHECK: %[[VAL_19:.*]] = arith.addi %[[VAL_18]], %[[VAL_1]] : i64
133133
// CHECK: cc.continue %[[VAL_19]] : i64
134134
// CHECK: } {invariant}
135+
// CHECK: } else {
135136
// CHECK: }
136137
// CHECK: %[[VAL_20:.*]] = cc.loop while ((%[[VAL_21:.*]] = %[[VAL_2]]) -> (i64)) {
137138
// CHECK: %[[VAL_22:.*]] = arith.cmpi slt, %[[VAL_21]], %[[VAL_0]] : i64

0 commit comments

Comments
 (0)