diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index 3c9078bcdf811..c053a5ab3c528 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -647,6 +647,9 @@ elementwise to the input. Unless specified otherwise operation(±0) = ±0 and operation(±infinity) = ±infinity +The integer elementwise intrinsics, including ``__builtin_elementwise_popcount``, +can be called in a ``constexpr`` context. + ============================================== ====================================================================== ========================================= Name Operation Supported element types ============================================== ====================================================================== ========================================= diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 8bd06fadfdc98..16a151da38bb5 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -370,6 +370,7 @@ Non-comprehensive list of changes in this release - ``__builtin_reduce_mul`` function can now be used in constant expressions. - ``__builtin_reduce_and`` function can now be used in constant expressions. - ``__builtin_reduce_or`` and ``__builtin_reduce_xor`` functions can now be used in constant expressions. +- ``__builtin_elementwise_popcount`` function can now be used in constant expressions. New Compiler Flags ------------------ diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 83c90b3d6e681..246250442ef62 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -1354,7 +1354,7 @@ def ElementwiseLog10 : Builtin { def ElementwisePopcount : Builtin { let Spellings = ["__builtin_elementwise_popcount"]; - let Attributes = [NoThrow, Const, CustomTypeChecking]; + let Attributes = [NoThrow, Const, CustomTypeChecking, Constexpr]; let Prototype = "void(...)"; } diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index c6a210459240a..06cb433eaecf2 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -11005,6 +11005,7 @@ namespace { bool VisitUnaryImag(const UnaryOperator *E); bool VisitBinaryOperator(const BinaryOperator *E); bool VisitUnaryOperator(const UnaryOperator *E); + bool VisitCallExpr(const CallExpr *E); bool VisitConvertVectorExpr(const ConvertVectorExpr *E); bool VisitShuffleVectorExpr(const ShuffleVectorExpr *E); @@ -11302,6 +11303,35 @@ static bool handleVectorElementCast(EvalInfo &Info, const FPOptions FPO, return false; } +bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) { + if (!IsConstantEvaluatedBuiltinCall(E)) + return ExprEvaluatorBaseTy::VisitCallExpr(E); + + switch (E->getBuiltinCallee()) { + default: + return false; + case Builtin::BI__builtin_elementwise_popcount: { + APValue Source; + if (!EvaluateAsRValue(Info, E->getArg(0), Source)) + return false; + + QualType DestEltTy = E->getType()->castAs()->getElementType(); + unsigned SourceLen = Source.getVectorLength(); + SmallVector ResultElements; + ResultElements.reserve(SourceLen); + + for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) { + APSInt Elt = Source.getVectorElt(EltNum).getInt(); + ResultElements.push_back( + APValue(APSInt(APInt(Info.Ctx.getIntWidth(DestEltTy), Elt.popcount()), + DestEltTy->isUnsignedIntegerOrEnumerationType()))); + } + + return Success(APValue(ResultElements.data(), ResultElements.size()), E); + } + } +} + bool VectorExprEvaluator::VisitConvertVectorExpr(const ConvertVectorExpr *E) { APValue Source; QualType SourceVecType = E->getSrcExpr()->getType(); @@ -13118,6 +13148,7 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, case Builtin::BI__builtin_popcountl: case Builtin::BI__builtin_popcountll: case Builtin::BI__builtin_popcountg: + case Builtin::BI__builtin_elementwise_popcount: case Builtin::BI__popcnt16: // Microsoft variants of popcount case Builtin::BI__popcnt: case Builtin::BI__popcnt64: { diff --git a/clang/test/CodeGen/builtins-elementwise-math.c b/clang/test/CodeGen/builtins-elementwise-math.c index 748b5e4add7c7..f1f34432ca0ea 100644 --- a/clang/test/CodeGen/builtins-elementwise-math.c +++ b/clang/test/CodeGen/builtins-elementwise-math.c @@ -666,11 +666,9 @@ void test_builtin_elementwise_log2(float f1, float f2, double d1, double d2, vf2 = __builtin_elementwise_log2(vf1); } -void test_builtin_elementwise_popcount(si8 vi1, si8 vi2, - long long int i1, long long int i2, short si, - _BitInt(31) bi1, _BitInt(31) bi2) { - - +void test_builtin_elementwise_popcount(si8 vi1, si8 vi2, long long int i1, + long long int i2, short si, + _BitInt(31) bi1, _BitInt(31) bi2) { // CHECK: [[I1:%.+]] = load i64, ptr %i1.addr, align 8 // CHECK-NEXT: call i64 @llvm.ctpop.i64(i64 [[I1]]) i2 = __builtin_elementwise_popcount(i1); @@ -693,7 +691,7 @@ void test_builtin_elementwise_popcount(si8 vi1, si8 vi2, // CHECK-NEXT: call i32 @llvm.ctpop.i32(i32 [[IA1]]) b = __builtin_elementwise_popcount(int_as_one); - // CHECK: call i32 @llvm.ctpop.i32(i32 -10) + // CHECK: store i32 30, ptr @b, align 4 b = __builtin_elementwise_popcount(-10); // CHECK: [[SI:%.+]] = load i16, ptr %si.addr, align 2 diff --git a/clang/test/Sema/constant_builtins_vector.cpp b/clang/test/Sema/constant_builtins_vector.cpp index e84d09b24672b..772a682141ce4 100644 --- a/clang/test/Sema/constant_builtins_vector.cpp +++ b/clang/test/Sema/constant_builtins_vector.cpp @@ -797,3 +797,23 @@ static_assert(__builtin_reduce_xor((vector4int){(int)0x11111111, (int)0x22222222 static_assert(__builtin_reduce_xor((vector4long){(long long)0x1111111111111111L, (long long)0x2222222222222222L, (long long)0x4444444444444444L, (long long)0x8888888888888888L}) == (long long)0xFFFFFFFFFFFFFFFFL); static_assert(__builtin_reduce_xor((vector4uint){0x11111111U, 0x22222222U, 0x44444444U, 0x88888888U}) == 0xFFFFFFFFU); static_assert(__builtin_reduce_xor((vector4ulong){0x1111111111111111UL, 0x2222222222222222UL, 0x4444444444444444UL, 0x8888888888888888UL}) == 0xFFFFFFFFFFFFFFFFUL); + +static_assert(__builtin_bit_cast(unsigned, __builtin_elementwise_popcount((vector4char){1, 2, 3, 4})) == (LITTLE_END ? 0x01020101 : 0x01010201)); +static_assert(__builtin_bit_cast(unsigned long long, __builtin_elementwise_popcount((vector4short){0, 0x0F0F, ~0, ~0x0F0F})) == (LITTLE_END ? 0x0008001000080000 : 0x0000000800100008)); +static_assert(__builtin_reduce_add(__builtin_elementwise_popcount((vector4int){1, 2, 3, 4})) == 5); +static_assert(__builtin_reduce_add(__builtin_elementwise_popcount((vector4int){0, 0xF0F0, ~0, ~0xF0F0})) == 16 * sizeof(int)); +static_assert(__builtin_reduce_add(__builtin_elementwise_popcount((vector4long){1L, 2L, 3L, 4L})) == 5L); +static_assert(__builtin_reduce_add(__builtin_elementwise_popcount((vector4long){0L, 0xF0F0L, ~0L, ~0xF0F0L})) == 16 * sizeof(long long)); +static_assert(__builtin_reduce_add(__builtin_elementwise_popcount((vector4uint){1U, 2U, 3U, 4U})) == 5U); +static_assert(__builtin_reduce_add(__builtin_elementwise_popcount((vector4uint){0U, 0xF0F0U, ~0U, ~0xF0F0U})) == 16 * sizeof(int)); +static_assert(__builtin_reduce_add(__builtin_elementwise_popcount((vector4ulong){1UL, 2UL, 3UL, 4UL})) == 5UL); +static_assert(__builtin_reduce_add(__builtin_elementwise_popcount((vector4ulong){0ULL, 0xF0F0ULL, ~0ULL, ~0xF0F0ULL})) == 16 * sizeof(unsigned long long)); +static_assert(__builtin_elementwise_popcount(0) == 0); +static_assert(__builtin_elementwise_popcount(0xF0F0) == 8); +static_assert(__builtin_elementwise_popcount(~0) == 8 * sizeof(int)); +static_assert(__builtin_elementwise_popcount(0U) == 0); +static_assert(__builtin_elementwise_popcount(0xF0F0U) == 8); +static_assert(__builtin_elementwise_popcount(~0U) == 8 * sizeof(int)); +static_assert(__builtin_elementwise_popcount(0L) == 0); +static_assert(__builtin_elementwise_popcount(0xF0F0L) == 8); +static_assert(__builtin_elementwise_popcount(~0LL) == 8 * sizeof(long long));