1818#include " clang/Basic/TargetBuiltins.h"
1919#include " clang/Basic/TargetInfo.h"
2020#include " llvm/ADT/StringExtras.h"
21+ #include " llvm/Support/ErrorHandling.h"
2122#include " llvm/Support/SipHash.h"
2223
2324namespace clang {
@@ -1673,6 +1674,12 @@ static bool interp__builtin_vector_reduce(InterpState &S, CodePtr OpPC,
16731674 (void )T::bitOr (Result, Elem, BitWidth, &Result);
16741675 } else if (ID == Builtin::BI__builtin_reduce_xor) {
16751676 (void )T::bitXor (Result, Elem, BitWidth, &Result);
1677+ } else if (ID == Builtin::BI__builtin_reduce_min) {
1678+ if (Elem < Result)
1679+ Result = Elem;
1680+ } else if (ID == Builtin::BI__builtin_reduce_max) {
1681+ if (Elem > Result)
1682+ Result = Elem;
16761683 } else {
16771684 llvm_unreachable (" Unhandled vector reduce builtin" );
16781685 }
@@ -1686,12 +1693,18 @@ static bool interp__builtin_vector_reduce(InterpState &S, CodePtr OpPC,
16861693// / Can be called with an integer or vector as the first and only parameter.
16871694static bool interp__builtin_elementwise_popcount (InterpState &S, CodePtr OpPC,
16881695 const InterpFrame *Frame,
1689- const CallExpr *Call) {
1696+ const CallExpr *Call,
1697+ unsigned BuiltinID) {
16901698 assert (Call->getNumArgs () == 1 );
16911699 if (Call->getArg (0 )->getType ()->isIntegerType ()) {
16921700 PrimType ArgT = *S.getContext ().classify (Call->getArg (0 )->getType ());
16931701 APSInt Val = popToAPSInt (S.Stk , ArgT);
1694- pushInteger (S, Val.popcount (), Call->getType ());
1702+
1703+ if (BuiltinID == Builtin::BI__builtin_elementwise_popcount) {
1704+ pushInteger (S, Val.popcount (), Call->getType ());
1705+ } else {
1706+ pushInteger (S, Val.reverseBits (), Call->getType ());
1707+ }
16951708 return true ;
16961709 }
16971710 // Otherwise, the argument must be a vector.
@@ -1710,8 +1723,13 @@ static bool interp__builtin_elementwise_popcount(InterpState &S, CodePtr OpPC,
17101723 // FIXME: Reading from uninitialized vector elements?
17111724 for (unsigned I = 0 ; I != NumElems; ++I) {
17121725 INT_TYPE_SWITCH_NO_BOOL (ElemT, {
1713- Dst.atIndex (I).deref <T>() =
1714- T::from (Arg.atIndex (I).deref <T>().toAPSInt ().popcount ());
1726+ if (BuiltinID == Builtin::BI__builtin_elementwise_popcount) {
1727+ Dst.atIndex (I).deref <T>() =
1728+ T::from (Arg.atIndex (I).deref <T>().toAPSInt ().popcount ());
1729+ } else {
1730+ Dst.atIndex (I).deref <T>() = T::from (
1731+ Arg.atIndex (I).deref <T>().toAPSInt ().reverseBits ().getZExtValue ());
1732+ }
17151733 Dst.atIndex (I).initialize ();
17161734 });
17171735 }
@@ -2234,6 +2252,78 @@ static bool interp__builtin_is_within_lifetime(InterpState &S, CodePtr OpPC,
22342252 return true ;
22352253}
22362254
2255+ static bool interp__builtin_elementwise_sat (InterpState &S, CodePtr OpPC,
2256+ const CallExpr *Call,
2257+ unsigned BuiltinID) {
2258+ Call->dumpColor ();
2259+ assert (Call->getNumArgs () == 2 );
2260+
2261+ // Single integer case.
2262+ if (!Call->getArg (0 )->getType ()->isVectorType ()) {
2263+ assert (!Call->getArg (1 )->getType ()->isVectorType ());
2264+ APSInt RHS = popToAPSInt (
2265+ S.Stk , *S.getContext ().classify (Call->getArg (1 )->getType ()));
2266+ APSInt LHS = popToAPSInt (
2267+ S.Stk , *S.getContext ().classify (Call->getArg (0 )->getType ()));
2268+ APInt Result;
2269+ if (BuiltinID == Builtin::BI__builtin_elementwise_add_sat) {
2270+ Result = LHS.isSigned () ? LHS.sadd_sat (RHS) : LHS.uadd_sat (RHS);
2271+ } else if (BuiltinID == Builtin::BI__builtin_elementwise_sub_sat) {
2272+ Result = LHS.isSigned () ? LHS.ssub_sat (RHS) : LHS.usub_sat (RHS);
2273+ } else {
2274+ llvm_unreachable (" Wrong builtin ID" );
2275+ }
2276+
2277+ pushInteger (S, APSInt (Result, !LHS.isSigned ()), Call->getType ());
2278+ return true ;
2279+ }
2280+
2281+ // Vector case.
2282+ assert (Call->getArg (0 )->getType ()->isVectorType () &&
2283+ Call->getArg (1 )->getType ()->isVectorType ());
2284+ const auto *VT = Call->getArg (0 )->getType ()->castAs <VectorType>();
2285+ assert (VT->getElementType () ==
2286+ Call->getArg (1 )->getType ()->castAs <VectorType>()->getElementType ());
2287+ assert (VT->getNumElements () ==
2288+ Call->getArg (1 )->getType ()->castAs <VectorType>()->getNumElements ());
2289+ assert (VT->getElementType ()->isIntegralOrEnumerationType ());
2290+
2291+ const Pointer &RHS = S.Stk .pop <Pointer>();
2292+ const Pointer &LHS = S.Stk .pop <Pointer>();
2293+ const Pointer &Dst = S.Stk .peek <Pointer>();
2294+ PrimType ElemT = *S.getContext ().classify (VT->getElementType ());
2295+ unsigned NumElems = VT->getNumElements ();
2296+ for (unsigned I = 0 ; I != NumElems; ++I) {
2297+ APSInt Elem1;
2298+ APSInt Elem2;
2299+ INT_TYPE_SWITCH_NO_BOOL (ElemT, {
2300+ Elem1 = LHS.atIndex (I).deref <T>().toAPSInt ();
2301+ Elem2 = RHS.atIndex (I).deref <T>().toAPSInt ();
2302+ });
2303+
2304+ APSInt Result;
2305+ if (BuiltinID == Builtin::BI__builtin_elementwise_add_sat) {
2306+ Result = APSInt (Elem1.isSigned () ? Elem1.sadd_sat (Elem2)
2307+ : Elem1.uadd_sat (Elem2),
2308+ Call->getType ()->isUnsignedIntegerOrEnumerationType ());
2309+ } else if (BuiltinID == Builtin::BI__builtin_elementwise_sub_sat) {
2310+ Result = APSInt (Elem1.isSigned () ? Elem1.ssub_sat (Elem2)
2311+ : Elem1.usub_sat (Elem2),
2312+ Call->getType ()->isUnsignedIntegerOrEnumerationType ());
2313+ } else {
2314+ llvm_unreachable (" Wrong builtin ID" );
2315+ }
2316+
2317+ INT_TYPE_SWITCH_NO_BOOL (ElemT, {
2318+ const Pointer &E = Dst.atIndex (I);
2319+ E.deref <T>() = static_cast <T>(Result);
2320+ E.initialize ();
2321+ });
2322+ }
2323+
2324+ return true ;
2325+ }
2326+
22372327bool InterpretBuiltin (InterpState &S, CodePtr OpPC, const CallExpr *Call,
22382328 uint32_t BuiltinID) {
22392329 if (!S.getASTContext ().BuiltinInfo .isConstantEvaluated (BuiltinID))
@@ -2592,10 +2682,14 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
25922682 case Builtin::BI__builtin_reduce_and:
25932683 case Builtin::BI__builtin_reduce_or:
25942684 case Builtin::BI__builtin_reduce_xor:
2685+ case Builtin::BI__builtin_reduce_min:
2686+ case Builtin::BI__builtin_reduce_max:
25952687 return interp__builtin_vector_reduce (S, OpPC, Call, BuiltinID);
25962688
25972689 case Builtin::BI__builtin_elementwise_popcount:
2598- return interp__builtin_elementwise_popcount (S, OpPC, Frame, Call);
2690+ case Builtin::BI__builtin_elementwise_bitreverse:
2691+ return interp__builtin_elementwise_popcount (S, OpPC, Frame, Call,
2692+ BuiltinID);
25992693
26002694 case Builtin::BI__builtin_memcpy:
26012695 case Builtin::BImemcpy:
@@ -2633,6 +2727,10 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
26332727 case Builtin::BI__builtin_is_within_lifetime:
26342728 return interp__builtin_is_within_lifetime (S, OpPC, Call);
26352729
2730+ case Builtin::BI__builtin_elementwise_add_sat:
2731+ case Builtin::BI__builtin_elementwise_sub_sat:
2732+ return interp__builtin_elementwise_sat (S, OpPC, Call, BuiltinID);
2733+
26362734 default :
26372735 S.FFDiag (S.Current ->getLocation (OpPC),
26382736 diag::note_invalid_subexpr_in_const_expr)
0 commit comments