Skip to content

Commit 21d8332

Browse files
authored
[clang] Implement __builtin_popcountg (#82359)
Fixes #82058.
1 parent 841a416 commit 21d8332

File tree

7 files changed

+120
-2
lines changed

7 files changed

+120
-2
lines changed

clang/docs/LanguageExtensions.rst

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3473,6 +3473,37 @@ builtin, the mangler emits their usual pattern without any special treatment.
34733473
// Computes a unique stable name for the given type.
34743474
constexpr const char * __builtin_sycl_unique_stable_name( type-id );
34753475
3476+
``__builtin_popcountg``
3477+
-----------------------
3478+
3479+
``__builtin_popcountg`` returns the number of 1 bits in the argument. The
3480+
argument can be of any integer type.
3481+
3482+
**Syntax**:
3483+
3484+
.. code-block:: c++
3485+
3486+
int __builtin_popcountg(type x)
3487+
3488+
**Examples**:
3489+
3490+
.. code-block:: c++
3491+
3492+
int x = 1;
3493+
int x_pop = __builtin_popcountg(x);
3494+
3495+
unsigned long y = 3;
3496+
int y_pop = __builtin_popcountg(y);
3497+
3498+
_BitInt(128) z = 7;
3499+
int z_pop = __builtin_popcountg(z);
3500+
3501+
**Description**:
3502+
3503+
``__builtin_popcountg`` is meant to be a type-generic alternative to the
3504+
``__builtin_popcount{,l,ll}`` builtins, with support for other integer types,
3505+
such as ``__int128`` and C23 ``_BitInt(N)``.
3506+
34763507
Multiprecision Arithmetic Builtins
34773508
----------------------------------
34783509

clang/include/clang/Basic/Builtins.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,12 @@ def Popcount : Builtin, BitInt_Long_LongLongTemplate {
688688
let Prototype = "int(unsigned T)";
689689
}
690690

691+
def Popcountg : Builtin {
692+
let Spellings = ["__builtin_popcountg"];
693+
let Attributes = [NoThrow, Const];
694+
let Prototype = "int(...)";
695+
}
696+
691697
def Clrsb : Builtin, BitInt_Long_LongLongTemplate {
692698
let Spellings = ["__builtin_clrsb"];
693699
let Attributes = [NoThrow, Const, Constexpr];

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11983,7 +11983,8 @@ def err_builtin_invalid_arg_type: Error <
1198311983
"pointer to a valid matrix element type|"
1198411984
"signed integer or floating point type|vector type|"
1198511985
"floating point type|"
11986-
"vector of integers}1 (was %2)">;
11986+
"vector of integers|"
11987+
"type of integer}1 (was %2)">;
1198711988

1198811989
def err_builtin_matrix_disabled: Error<
1198911990
"matrix types extension is disabled. Pass -fenable-matrix to enable it">;

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3217,7 +3217,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
32173217
case Builtin::BI__popcnt64:
32183218
case Builtin::BI__builtin_popcount:
32193219
case Builtin::BI__builtin_popcountl:
3220-
case Builtin::BI__builtin_popcountll: {
3220+
case Builtin::BI__builtin_popcountll:
3221+
case Builtin::BI__builtin_popcountg: {
32213222
Value *ArgValue = EmitScalarExpr(E->getArg(0));
32223223

32233224
llvm::Type *ArgType = ArgValue->getType();

clang/lib/Sema/SemaChecking.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2189,6 +2189,23 @@ static bool SemaBuiltinCpu(Sema &S, const TargetInfo &TI, CallExpr *TheCall,
21892189
return false;
21902190
}
21912191

2192+
/// Checks that __builtin_popcountg was called with a single argument, which is
2193+
/// an integer.
2194+
static bool SemaBuiltinPopcountg(Sema &S, CallExpr *TheCall) {
2195+
if (checkArgCount(S, TheCall, 1))
2196+
return true;
2197+
2198+
Expr *Arg = TheCall->getArg(0);
2199+
QualType ArgTy = Arg->getType();
2200+
2201+
if (!ArgTy->isIntegerType()) {
2202+
S.Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type)
2203+
<< 1 << /*integer ty*/ 7 << ArgTy;
2204+
return true;
2205+
}
2206+
return false;
2207+
}
2208+
21922209
ExprResult
21932210
Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
21942211
CallExpr *TheCall) {
@@ -2959,7 +2976,12 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
29592976
diag::err_hip_invalid_args_builtin_mangled_name);
29602977
return ExprError();
29612978
}
2979+
break;
29622980
}
2981+
case Builtin::BI__builtin_popcountg:
2982+
if (SemaBuiltinPopcountg(*this, TheCall))
2983+
return ExprError();
2984+
break;
29632985
}
29642986

29652987
if (getLangOpts().HLSL && CheckHLSLBuiltinFunctionCall(BuiltinID, TheCall))

clang/test/CodeGen/builtins.c

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -940,4 +940,47 @@ void test_builtin_os_log_long_double(void *buf, long double ld) {
940940
// CHECK: %[[V3:.*]] = load i128, ptr %[[ARG0_ADDR]], align 16
941941
// CHECK: store i128 %[[V3]], ptr %[[ARGDATA]], align 1
942942

943+
// CHECK-LABEL: define{{.*}} void @test_builtin_popcountg
944+
void test_builtin_popcountg(unsigned char uc, unsigned short us,
945+
unsigned int ui, unsigned long ul,
946+
unsigned long long ull, unsigned __int128 ui128,
947+
unsigned _BitInt(128) ubi128) {
948+
volatile int pop;
949+
pop = __builtin_popcountg(uc);
950+
// CHECK: %1 = load i8, ptr %uc.addr, align 1
951+
// CHECK-NEXT: %conv = zext i8 %1 to i32
952+
// CHECK-NEXT: %2 = call i32 @llvm.ctpop.i32(i32 %conv)
953+
// CHECK-NEXT: store volatile i32 %2, ptr %pop, align 4
954+
pop = __builtin_popcountg(us);
955+
// CHECK-NEXT: %3 = load i16, ptr %us.addr, align 2
956+
// CHECK-NEXT: %conv1 = zext i16 %3 to i32
957+
// CHECK-NEXT: %4 = call i32 @llvm.ctpop.i32(i32 %conv1)
958+
// CHECK-NEXT: store volatile i32 %4, ptr %pop, align 4
959+
pop = __builtin_popcountg(ui);
960+
// CHECK-NEXT: %5 = load i32, ptr %ui.addr, align 4
961+
// CHECK-NEXT: %6 = call i32 @llvm.ctpop.i32(i32 %5)
962+
// CHECK-NEXT: store volatile i32 %6, ptr %pop, align 4
963+
pop = __builtin_popcountg(ul);
964+
// CHECK-NEXT: %7 = load i64, ptr %ul.addr, align 8
965+
// CHECK-NEXT: %8 = call i64 @llvm.ctpop.i64(i64 %7)
966+
// CHECK-NEXT: %cast = trunc i64 %8 to i32
967+
// CHECK-NEXT: store volatile i32 %cast, ptr %pop, align 4
968+
pop = __builtin_popcountg(ull);
969+
// CHECK-NEXT: %9 = load i64, ptr %ull.addr, align 8
970+
// CHECK-NEXT: %10 = call i64 @llvm.ctpop.i64(i64 %9)
971+
// CHECK-NEXT: %cast2 = trunc i64 %10 to i32
972+
// CHECK-NEXT: store volatile i32 %cast2, ptr %pop, align 4
973+
pop = __builtin_popcountg(ui128);
974+
// CHECK-NEXT: %11 = load i128, ptr %ui128.addr, align 16
975+
// CHECK-NEXT: %12 = call i128 @llvm.ctpop.i128(i128 %11)
976+
// CHECK-NEXT: %cast3 = trunc i128 %12 to i32
977+
// CHECK-NEXT: store volatile i32 %cast3, ptr %pop, align 4
978+
pop = __builtin_popcountg(ubi128);
979+
// CHECK-NEXT: %13 = load i128, ptr %ubi128.addr, align 8
980+
// CHECK-NEXT: %14 = call i128 @llvm.ctpop.i128(i128 %13)
981+
// CHECK-NEXT: %cast4 = trunc i128 %14 to i32
982+
// CHECK-NEXT: store volatile i32 %cast4, ptr %pop, align 4
983+
// CHECK-NEXT: ret void
984+
}
985+
943986
#endif

clang/test/Sema/builtin-popcountg.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -fsyntax-only -verify -Wpedantic %s
2+
3+
typedef int int2 __attribute__((ext_vector_type(2)));
4+
5+
void test_builtin_popcountg(int i, double d, int2 i2) {
6+
__builtin_popcountg();
7+
// expected-error@-1 {{too few arguments to function call, expected 1, have 0}}
8+
__builtin_popcountg(i, i);
9+
// expected-error@-1 {{too many arguments to function call, expected 1, have 2}}
10+
__builtin_popcountg(d);
11+
// expected-error@-1 {{1st argument must be a type of integer (was 'double')}}
12+
__builtin_popcountg(i2);
13+
// expected-error@-1 {{1st argument must be a type of integer (was 'int2' (vector of 2 'int' values))}}
14+
}

0 commit comments

Comments
 (0)