Skip to content

Commit

Permalink
[clang] Implement __builtin_popcountg (#82359)
Browse files Browse the repository at this point in the history
Fixes #82058.
  • Loading branch information
overmighty committed Feb 26, 2024
1 parent 841a416 commit 21d8332
Show file tree
Hide file tree
Showing 7 changed files with 120 additions and 2 deletions.
31 changes: 31 additions & 0 deletions clang/docs/LanguageExtensions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3473,6 +3473,37 @@ builtin, the mangler emits their usual pattern without any special treatment.
// Computes a unique stable name for the given type.
constexpr const char * __builtin_sycl_unique_stable_name( type-id );
``__builtin_popcountg``
-----------------------
``__builtin_popcountg`` returns the number of 1 bits in the argument. The
argument can be of any integer type.
**Syntax**:
.. code-block:: c++
int __builtin_popcountg(type x)
**Examples**:
.. code-block:: c++
int x = 1;
int x_pop = __builtin_popcountg(x);
unsigned long y = 3;
int y_pop = __builtin_popcountg(y);
_BitInt(128) z = 7;
int z_pop = __builtin_popcountg(z);
**Description**:
``__builtin_popcountg`` is meant to be a type-generic alternative to the
``__builtin_popcount{,l,ll}`` builtins, with support for other integer types,
such as ``__int128`` and C23 ``_BitInt(N)``.
Multiprecision Arithmetic Builtins
----------------------------------
Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/Builtins.td
Original file line number Diff line number Diff line change
Expand Up @@ -688,6 +688,12 @@ def Popcount : Builtin, BitInt_Long_LongLongTemplate {
let Prototype = "int(unsigned T)";
}

def Popcountg : Builtin {
let Spellings = ["__builtin_popcountg"];
let Attributes = [NoThrow, Const];
let Prototype = "int(...)";
}

def Clrsb : Builtin, BitInt_Long_LongLongTemplate {
let Spellings = ["__builtin_clrsb"];
let Attributes = [NoThrow, Const, Constexpr];
Expand Down
3 changes: 2 additions & 1 deletion clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -11983,7 +11983,8 @@ def err_builtin_invalid_arg_type: Error <
"pointer to a valid matrix element type|"
"signed integer or floating point type|vector type|"
"floating point type|"
"vector of integers}1 (was %2)">;
"vector of integers|"
"type of integer}1 (was %2)">;

def err_builtin_matrix_disabled: Error<
"matrix types extension is disabled. Pass -fenable-matrix to enable it">;
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3217,7 +3217,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__popcnt64:
case Builtin::BI__builtin_popcount:
case Builtin::BI__builtin_popcountl:
case Builtin::BI__builtin_popcountll: {
case Builtin::BI__builtin_popcountll:
case Builtin::BI__builtin_popcountg: {
Value *ArgValue = EmitScalarExpr(E->getArg(0));

llvm::Type *ArgType = ArgValue->getType();
Expand Down
22 changes: 22 additions & 0 deletions clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2189,6 +2189,23 @@ static bool SemaBuiltinCpu(Sema &S, const TargetInfo &TI, CallExpr *TheCall,
return false;
}

/// Checks that __builtin_popcountg was called with a single argument, which is
/// an integer.
static bool SemaBuiltinPopcountg(Sema &S, CallExpr *TheCall) {
if (checkArgCount(S, TheCall, 1))
return true;

Expr *Arg = TheCall->getArg(0);
QualType ArgTy = Arg->getType();

if (!ArgTy->isIntegerType()) {
S.Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type)
<< 1 << /*integer ty*/ 7 << ArgTy;
return true;
}
return false;
}

ExprResult
Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
CallExpr *TheCall) {
Expand Down Expand Up @@ -2959,7 +2976,12 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
diag::err_hip_invalid_args_builtin_mangled_name);
return ExprError();
}
break;
}
case Builtin::BI__builtin_popcountg:
if (SemaBuiltinPopcountg(*this, TheCall))
return ExprError();
break;
}

if (getLangOpts().HLSL && CheckHLSLBuiltinFunctionCall(BuiltinID, TheCall))
Expand Down
43 changes: 43 additions & 0 deletions clang/test/CodeGen/builtins.c
Original file line number Diff line number Diff line change
Expand Up @@ -940,4 +940,47 @@ void test_builtin_os_log_long_double(void *buf, long double ld) {
// CHECK: %[[V3:.*]] = load i128, ptr %[[ARG0_ADDR]], align 16
// CHECK: store i128 %[[V3]], ptr %[[ARGDATA]], align 1

// CHECK-LABEL: define{{.*}} void @test_builtin_popcountg
void test_builtin_popcountg(unsigned char uc, unsigned short us,
unsigned int ui, unsigned long ul,
unsigned long long ull, unsigned __int128 ui128,
unsigned _BitInt(128) ubi128) {
volatile int pop;
pop = __builtin_popcountg(uc);
// CHECK: %1 = load i8, ptr %uc.addr, align 1
// CHECK-NEXT: %conv = zext i8 %1 to i32
// CHECK-NEXT: %2 = call i32 @llvm.ctpop.i32(i32 %conv)
// CHECK-NEXT: store volatile i32 %2, ptr %pop, align 4
pop = __builtin_popcountg(us);
// CHECK-NEXT: %3 = load i16, ptr %us.addr, align 2
// CHECK-NEXT: %conv1 = zext i16 %3 to i32
// CHECK-NEXT: %4 = call i32 @llvm.ctpop.i32(i32 %conv1)
// CHECK-NEXT: store volatile i32 %4, ptr %pop, align 4
pop = __builtin_popcountg(ui);
// CHECK-NEXT: %5 = load i32, ptr %ui.addr, align 4
// CHECK-NEXT: %6 = call i32 @llvm.ctpop.i32(i32 %5)
// CHECK-NEXT: store volatile i32 %6, ptr %pop, align 4
pop = __builtin_popcountg(ul);
// CHECK-NEXT: %7 = load i64, ptr %ul.addr, align 8
// CHECK-NEXT: %8 = call i64 @llvm.ctpop.i64(i64 %7)
// CHECK-NEXT: %cast = trunc i64 %8 to i32
// CHECK-NEXT: store volatile i32 %cast, ptr %pop, align 4
pop = __builtin_popcountg(ull);
// CHECK-NEXT: %9 = load i64, ptr %ull.addr, align 8
// CHECK-NEXT: %10 = call i64 @llvm.ctpop.i64(i64 %9)
// CHECK-NEXT: %cast2 = trunc i64 %10 to i32
// CHECK-NEXT: store volatile i32 %cast2, ptr %pop, align 4
pop = __builtin_popcountg(ui128);
// CHECK-NEXT: %11 = load i128, ptr %ui128.addr, align 16
// CHECK-NEXT: %12 = call i128 @llvm.ctpop.i128(i128 %11)
// CHECK-NEXT: %cast3 = trunc i128 %12 to i32
// CHECK-NEXT: store volatile i32 %cast3, ptr %pop, align 4
pop = __builtin_popcountg(ubi128);
// CHECK-NEXT: %13 = load i128, ptr %ubi128.addr, align 8
// CHECK-NEXT: %14 = call i128 @llvm.ctpop.i128(i128 %13)
// CHECK-NEXT: %cast4 = trunc i128 %14 to i32
// CHECK-NEXT: store volatile i32 %cast4, ptr %pop, align 4
// CHECK-NEXT: ret void
}

#endif
14 changes: 14 additions & 0 deletions clang/test/Sema/builtin-popcountg.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -fsyntax-only -verify -Wpedantic %s

typedef int int2 __attribute__((ext_vector_type(2)));

void test_builtin_popcountg(int i, double d, int2 i2) {
__builtin_popcountg();
// expected-error@-1 {{too few arguments to function call, expected 1, have 0}}
__builtin_popcountg(i, i);
// expected-error@-1 {{too many arguments to function call, expected 1, have 2}}
__builtin_popcountg(d);
// expected-error@-1 {{1st argument must be a type of integer (was 'double')}}
__builtin_popcountg(i2);
// expected-error@-1 {{1st argument must be a type of integer (was 'int2' (vector of 2 'int' values))}}
}

0 comments on commit 21d8332

Please sign in to comment.