Skip to content

Commit 827ebf8

Browse files
authored
[clang] constexpr built-in elementwise popcount function. (#117473)
Part of #51787. This patch adds constexpr support for the built-in elementwise popcount function.
1 parent 90df664 commit 827ebf8

File tree

6 files changed

+60
-7
lines changed

6 files changed

+60
-7
lines changed

clang/docs/LanguageExtensions.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,9 @@ elementwise to the input.
647647

648648
Unless specified otherwise operation(±0) = ±0 and operation(±infinity) = ±infinity
649649

650+
The integer elementwise intrinsics, including ``__builtin_elementwise_popcount``,
651+
can be called in a ``constexpr`` context.
652+
650653
============================================== ====================================================================== =========================================
651654
Name Operation Supported element types
652655
============================================== ====================================================================== =========================================

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,7 @@ Non-comprehensive list of changes in this release
375375
- ``__builtin_reduce_mul`` function can now be used in constant expressions.
376376
- ``__builtin_reduce_and`` function can now be used in constant expressions.
377377
- ``__builtin_reduce_or`` and ``__builtin_reduce_xor`` functions can now be used in constant expressions.
378+
- ``__builtin_elementwise_popcount`` function can now be used in constant expressions.
378379

379380
New Compiler Flags
380381
------------------

clang/include/clang/Basic/Builtins.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1354,7 +1354,7 @@ def ElementwiseLog10 : Builtin {
13541354

13551355
def ElementwisePopcount : Builtin {
13561356
let Spellings = ["__builtin_elementwise_popcount"];
1357-
let Attributes = [NoThrow, Const, CustomTypeChecking];
1357+
let Attributes = [NoThrow, Const, CustomTypeChecking, Constexpr];
13581358
let Prototype = "void(...)";
13591359
}
13601360

clang/lib/AST/ExprConstant.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11005,6 +11005,7 @@ namespace {
1100511005
bool VisitUnaryImag(const UnaryOperator *E);
1100611006
bool VisitBinaryOperator(const BinaryOperator *E);
1100711007
bool VisitUnaryOperator(const UnaryOperator *E);
11008+
bool VisitCallExpr(const CallExpr *E);
1100811009
bool VisitConvertVectorExpr(const ConvertVectorExpr *E);
1100911010
bool VisitShuffleVectorExpr(const ShuffleVectorExpr *E);
1101011011

@@ -11302,6 +11303,35 @@ static bool handleVectorElementCast(EvalInfo &Info, const FPOptions FPO,
1130211303
return false;
1130311304
}
1130411305

11306+
bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) {
11307+
if (!IsConstantEvaluatedBuiltinCall(E))
11308+
return ExprEvaluatorBaseTy::VisitCallExpr(E);
11309+
11310+
switch (E->getBuiltinCallee()) {
11311+
default:
11312+
return false;
11313+
case Builtin::BI__builtin_elementwise_popcount: {
11314+
APValue Source;
11315+
if (!EvaluateAsRValue(Info, E->getArg(0), Source))
11316+
return false;
11317+
11318+
QualType DestEltTy = E->getType()->castAs<VectorType>()->getElementType();
11319+
unsigned SourceLen = Source.getVectorLength();
11320+
SmallVector<APValue, 4> ResultElements;
11321+
ResultElements.reserve(SourceLen);
11322+
11323+
for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) {
11324+
APSInt Elt = Source.getVectorElt(EltNum).getInt();
11325+
ResultElements.push_back(
11326+
APValue(APSInt(APInt(Info.Ctx.getIntWidth(DestEltTy), Elt.popcount()),
11327+
DestEltTy->isUnsignedIntegerOrEnumerationType())));
11328+
}
11329+
11330+
return Success(APValue(ResultElements.data(), ResultElements.size()), E);
11331+
}
11332+
}
11333+
}
11334+
1130511335
bool VectorExprEvaluator::VisitConvertVectorExpr(const ConvertVectorExpr *E) {
1130611336
APValue Source;
1130711337
QualType SourceVecType = E->getSrcExpr()->getType();
@@ -13118,6 +13148,7 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
1311813148
case Builtin::BI__builtin_popcountl:
1311913149
case Builtin::BI__builtin_popcountll:
1312013150
case Builtin::BI__builtin_popcountg:
13151+
case Builtin::BI__builtin_elementwise_popcount:
1312113152
case Builtin::BI__popcnt16: // Microsoft variants of popcount
1312213153
case Builtin::BI__popcnt:
1312313154
case Builtin::BI__popcnt64: {

clang/test/CodeGen/builtins-elementwise-math.c

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -666,11 +666,9 @@ void test_builtin_elementwise_log2(float f1, float f2, double d1, double d2,
666666
vf2 = __builtin_elementwise_log2(vf1);
667667
}
668668

669-
void test_builtin_elementwise_popcount(si8 vi1, si8 vi2,
670-
long long int i1, long long int i2, short si,
671-
_BitInt(31) bi1, _BitInt(31) bi2) {
672-
673-
669+
void test_builtin_elementwise_popcount(si8 vi1, si8 vi2, long long int i1,
670+
long long int i2, short si,
671+
_BitInt(31) bi1, _BitInt(31) bi2) {
674672
// CHECK: [[I1:%.+]] = load i64, ptr %i1.addr, align 8
675673
// CHECK-NEXT: call i64 @llvm.ctpop.i64(i64 [[I1]])
676674
i2 = __builtin_elementwise_popcount(i1);
@@ -693,7 +691,7 @@ void test_builtin_elementwise_popcount(si8 vi1, si8 vi2,
693691
// CHECK-NEXT: call i32 @llvm.ctpop.i32(i32 [[IA1]])
694692
b = __builtin_elementwise_popcount(int_as_one);
695693

696-
// CHECK: call i32 @llvm.ctpop.i32(i32 -10)
694+
// CHECK: store i32 30, ptr @b, align 4
697695
b = __builtin_elementwise_popcount(-10);
698696

699697
// CHECK: [[SI:%.+]] = load i16, ptr %si.addr, align 2

clang/test/Sema/constant_builtins_vector.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -797,3 +797,23 @@ static_assert(__builtin_reduce_xor((vector4int){(int)0x11111111, (int)0x22222222
797797
static_assert(__builtin_reduce_xor((vector4long){(long long)0x1111111111111111L, (long long)0x2222222222222222L, (long long)0x4444444444444444L, (long long)0x8888888888888888L}) == (long long)0xFFFFFFFFFFFFFFFFL);
798798
static_assert(__builtin_reduce_xor((vector4uint){0x11111111U, 0x22222222U, 0x44444444U, 0x88888888U}) == 0xFFFFFFFFU);
799799
static_assert(__builtin_reduce_xor((vector4ulong){0x1111111111111111UL, 0x2222222222222222UL, 0x4444444444444444UL, 0x8888888888888888UL}) == 0xFFFFFFFFFFFFFFFFUL);
800+
801+
static_assert(__builtin_bit_cast(unsigned, __builtin_elementwise_popcount((vector4char){1, 2, 3, 4})) == (LITTLE_END ? 0x01020101 : 0x01010201));
802+
static_assert(__builtin_bit_cast(unsigned long long, __builtin_elementwise_popcount((vector4short){0, 0x0F0F, ~0, ~0x0F0F})) == (LITTLE_END ? 0x0008001000080000 : 0x0000000800100008));
803+
static_assert(__builtin_reduce_add(__builtin_elementwise_popcount((vector4int){1, 2, 3, 4})) == 5);
804+
static_assert(__builtin_reduce_add(__builtin_elementwise_popcount((vector4int){0, 0xF0F0, ~0, ~0xF0F0})) == 16 * sizeof(int));
805+
static_assert(__builtin_reduce_add(__builtin_elementwise_popcount((vector4long){1L, 2L, 3L, 4L})) == 5L);
806+
static_assert(__builtin_reduce_add(__builtin_elementwise_popcount((vector4long){0L, 0xF0F0L, ~0L, ~0xF0F0L})) == 16 * sizeof(long long));
807+
static_assert(__builtin_reduce_add(__builtin_elementwise_popcount((vector4uint){1U, 2U, 3U, 4U})) == 5U);
808+
static_assert(__builtin_reduce_add(__builtin_elementwise_popcount((vector4uint){0U, 0xF0F0U, ~0U, ~0xF0F0U})) == 16 * sizeof(int));
809+
static_assert(__builtin_reduce_add(__builtin_elementwise_popcount((vector4ulong){1UL, 2UL, 3UL, 4UL})) == 5UL);
810+
static_assert(__builtin_reduce_add(__builtin_elementwise_popcount((vector4ulong){0ULL, 0xF0F0ULL, ~0ULL, ~0xF0F0ULL})) == 16 * sizeof(unsigned long long));
811+
static_assert(__builtin_elementwise_popcount(0) == 0);
812+
static_assert(__builtin_elementwise_popcount(0xF0F0) == 8);
813+
static_assert(__builtin_elementwise_popcount(~0) == 8 * sizeof(int));
814+
static_assert(__builtin_elementwise_popcount(0U) == 0);
815+
static_assert(__builtin_elementwise_popcount(0xF0F0U) == 8);
816+
static_assert(__builtin_elementwise_popcount(~0U) == 8 * sizeof(int));
817+
static_assert(__builtin_elementwise_popcount(0L) == 0);
818+
static_assert(__builtin_elementwise_popcount(0xF0F0L) == 8);
819+
static_assert(__builtin_elementwise_popcount(~0LL) == 8 * sizeof(long long));

0 commit comments

Comments
 (0)