@@ -658,14 +658,34 @@ bool QuakeBridgeVisitor::VisitCastExpr(clang::CastExpr *x) {
658658 }
659659 case clang::CastKind::CK_UserDefinedConversion: {
660660 auto sub = popValue ();
661- // castToTy is the converion function signature.
661+ // castToTy is the conversion function signature.
662662 castToTy = popType ();
663663 if (isa<IntegerType>(castToTy) && isa<IntegerType>(sub.getType ())) {
664664 auto locSub = toLocation (x->getSubExpr ());
665665 bool result = intToIntCast (locSub, sub);
666666 assert (result && " integer conversion failed" );
667667 return result;
668668 }
669+ 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));
674+
675+ // Handle conversion of `std::vector<measure_result>` to `std::vector<bool>`
676+ if (auto vecTy = dyn_cast<cc::StdvecType>(sub.getType ()))
677+ if (isa<quake::MeasureType>(vecTy.getElementType ()))
678+ return pushValue (builder.create <quake::DiscriminateOp>(
679+ loc, cc::StdvecType::get (i1Type), sub));
680+
681+ // Handle pointer to `measure_result` (from vector element access)
682+ if (auto ptrTy = dyn_cast<cc::PointerType>(sub.getType ()))
683+ if (isa<quake::MeasureType>(ptrTy.getElementType ())) {
684+ auto loaded = builder.create <cc::LoadOp>(loc, sub);
685+ return pushValue (
686+ builder.create <quake::DiscriminateOp>(loc, i1Type, loaded));
687+ }
688+
669689 TODO_loc (loc, " unhandled user-defined implicit conversion" );
670690 }
671691 case clang::CastKind::CK_ConstructorConversion: {
@@ -1015,7 +1035,7 @@ bool QuakeBridgeVisitor::VisitMaterializeTemporaryExpr(
10151035 // In those cases, there is nothing to materialize, so we can just pass the
10161036 // Value on the top of the stack.
10171037 if (isa<cc::CallableType, quake::VeqType, quake::RefType, cc::SpanLikeType,
1018- quake::StateType>(ty))
1038+ quake::StateType, quake::MeasureType >(ty))
10191039 return true ;
10201040
10211041 // If not one of the above special cases, then materialize the value to a
@@ -1520,7 +1540,13 @@ bool QuakeBridgeVisitor::VisitCallExpr(clang::CallExpr *x) {
15201540 auto funcArity = func->getNumParams ();
15211541 SmallVector<Value> args = lastValues (funcArity);
15221542 if (isa<clang::CXXMethodDecl>(func)) {
1523- [[maybe_unused]] auto thisPtrValue = popValue ();
1543+ auto thisPtrValue = popValue ();
1544+
1545+ // Handle `measure_result` conversion operators
1546+ if (isa<clang::CXXConversionDecl>(func) &&
1547+ isInClassInNamespace (func, " measure_result" , " cudaq" )) {
1548+ return pushValue (thisPtrValue);
1549+ }
15241550 }
15251551 auto calleeOp = popValue ();
15261552
@@ -1646,7 +1672,6 @@ bool QuakeBridgeVisitor::VisitCallExpr(clang::CallExpr *x) {
16461672 }
16471673
16481674 if (funcName == " mx" || funcName == " my" || funcName == " mz" ) {
1649- // Measurements always return a bool or a std::vector<bool>.
16501675 bool useStdvec =
16511676 (args.size () > 1 ) ||
16521677 (args.size () == 1 && isa<quake::VeqType>(args[0 ].getType ()));
@@ -1660,11 +1685,8 @@ bool QuakeBridgeVisitor::VisitCallExpr(clang::CallExpr *x) {
16601685 return builder.create <quake::MyOp>(loc, measTy, args).getMeasOut ();
16611686 return builder.create <quake::MzOp>(loc, measTy, args).getMeasOut ();
16621687 }();
1663- Type resTy = builder.getI1Type ();
1664- if (useStdvec)
1665- resTy = cc::StdvecType::get (resTy);
1666- return pushValue (
1667- builder.create <quake::DiscriminateOp>(loc, resTy, measure));
1688+ // No more discrimination needed, just return the measurement.
1689+ return pushValue (measure);
16681690 }
16691691
16701692 // Handle the quantum gate set.
@@ -2136,6 +2158,28 @@ bool QuakeBridgeVisitor::VisitCallExpr(clang::CallExpr *x) {
21362158 .getResult (0 ));
21372159 }
21382160
2161+ if (funcName == " to_bool_vector" ) {
2162+ // args[0] is !cc.stdvec<!quake.measure> from mz()
2163+ auto arg = args[0 ];
2164+ // Insert discriminate if needed
2165+ if (auto vecTy = dyn_cast<cc::StdvecType>(arg.getType ())) {
2166+ if (isa<quake::MeasureType>(vecTy.getElementType ())) {
2167+ auto i1Ty = builder.getI1Type ();
2168+ arg = builder.create <quake::DiscriminateOp>(
2169+ loc, cc::StdvecType::get (i1Ty), arg);
2170+ }
2171+ }
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 ));
2181+ }
2182+
21392183 if (funcName == " slice_vector" ) {
21402184 auto svecTy = dyn_cast<cc::SpanLikeType>(args[0 ].getType ());
21412185 auto eleTy = svecTy.getElementType ();
@@ -3217,6 +3261,18 @@ bool QuakeBridgeVisitor::VisitCXXConstructExpr(clang::CXXConstructExpr *x) {
32173261 return pushValue (builder.create <cc::LoadOp>(loc, copyObj));
32183262 }
32193263
3264+ // Handle `measure_result` copy constructor
3265+ if (ctor->isCopyConstructor () &&
3266+ isInClassInNamespace (ctor, " measure_result" , " cudaq" )) {
3267+ // The source is a pointer to measure_result (!cc.ptr<!quake.measure>)
3268+ // Just load and return the value
3269+ assert (x->getNumArgs () == 1 );
3270+ auto srcPtr = popValue ();
3271+ if (auto ptrTy = dyn_cast<cc::PointerType>(srcPtr.getType ()))
3272+ if (isa<quake::MeasureType>(ptrTy.getElementType ()))
3273+ return pushValue (builder.create <cc::LoadOp>(loc, srcPtr));
3274+ }
3275+
32203276 // TODO: remove this when we can handle ctors more generally.
32213277 if (!ctor->isDefaultConstructor ()) {
32223278 LLVM_DEBUG (llvm::dbgs () << ctorName << " - unhandled ctor:\n " ; x->dump ());
0 commit comments