[clang] [clang]Implement the c23 stdc bit builtins (PR #185978)
NagaChaitanya Vellanki via cfe-commits
cfe-commits at lists.llvm.org
Fri Apr 3 16:21:02 PDT 2026
https://github.com/chaitanyav updated https://github.com/llvm/llvm-project/pull/185978
>From 1dcdaf79e6eb33a542c0e00b59076445521ff093 Mon Sep 17 00:00:00 2001
From: NagaChaitanya Vellanki <pnagato at protonmail.com>
Date: Thu, 29 Jan 2026 16:14:24 -0800
Subject: [PATCH 01/14] [clang] Implement C23 stdc bit builtins
This patch implements the following builtins:
- __builtin_stdc_bit_ceil
- __builtin_stdc_bit_floor
- __builtin_stdc_bit_width
- __builtin_stdc_count_ones
- __builtin_stdc_count_zeros
- __builtin_stdc_first_leading_one
- __builtin_stdc_first_leading_zero
- __builtin_stdc_first_trailing_one
- __builtin_stdc_first_trailing_zero
- __builtin_stdc_has_single_bit
- __builtin_stdc_leading_ones
- __builtin_stdc_leading_zeros
- __builtin_stdc_trailing_ones
- __builtin_stdc_trailing_zeros
Additional notes:
- Constexpr evaluation support
- Works for all unsigned integer types, including _BitInt
Resolves:#79630
---
clang/docs/LanguageExtensions.rst | 45 ++++
clang/docs/ReleaseNotes.rst | 9 +
clang/include/clang/Basic/Builtins.td | 84 ++++++
clang/lib/AST/ByteCode/InterpBuiltin.cpp | 123 +++++++++
clang/lib/AST/ExprConstant.cpp | 84 ++++++
clang/lib/CodeGen/CGBuiltin.cpp | 189 ++++++++++++++
clang/lib/Sema/SemaChecking.cpp | 59 +++++
.../test/CodeGen/builtin-stdc-bit-functions.c | 239 +++++++++++++++++
clang/test/Sema/builtin-stdc-bit-functions.c | 173 +++++++++++++
.../constexpr-builtin-stdc-bit-functions.cpp | 242 ++++++++++++++++++
10 files changed, 1247 insertions(+)
create mode 100644 clang/test/CodeGen/builtin-stdc-bit-functions.c
create mode 100644 clang/test/Sema/builtin-stdc-bit-functions.c
create mode 100644 clang/test/SemaCXX/constexpr-builtin-stdc-bit-functions.cpp
diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index 549e1a6a58617..34ef88f5f2949 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -3999,6 +3999,51 @@ be used within constant expressions.
unsigned _BitInt(20) value = 0xABCDE;
unsigned _BitInt(20) rotated = __builtin_stdc_rotate_left(value, 5);
+``__builtin_stdc_*`` bit utilities
+----------------------------------
+
+**Syntax**:
+
+.. code-block:: c
+
+ unsigned int __builtin_stdc_leading_zeros(T value);
+ unsigned int __builtin_stdc_leading_ones(T value);
+ unsigned int __builtin_stdc_trailing_zeros(T value);
+ unsigned int __builtin_stdc_trailing_ones(T value);
+ unsigned int __builtin_stdc_first_leading_zero(T value);
+ unsigned int __builtin_stdc_first_leading_one(T value);
+ unsigned int __builtin_stdc_first_trailing_zero(T value);
+ unsigned int __builtin_stdc_first_trailing_one(T value);
+ unsigned int __builtin_stdc_count_zeros(T value);
+ unsigned int __builtin_stdc_count_ones(T value);
+ bool __builtin_stdc_has_single_bit(T value);
+ unsigned int __builtin_stdc_bit_width(T value);
+ T __builtin_stdc_bit_floor(T value);
+ T __builtin_stdc_bit_ceil(T value);
+
+where ``T`` is any unsigned integer type, including ``_BitInt`` types.
+
+**Description**:
+
+These builtins implement the C23 ``<stdbit.h>`` operations. Counts and position
+queries return ``unsigned int``; ``has_single_bit`` returns ``bool``; and
+``bit_floor``/``bit_ceil`` return the same type as the operand. Zero and
+all-ones cases follow the C23 definitions. All are usable in constant
+expressions.
+
+**Examples**:
+
+.. code-block:: c
+
+ unsigned _BitInt(9) x = 0x11;
+ unsigned int lz = __builtin_stdc_leading_zeros(x);
+ unsigned int tz = __builtin_stdc_trailing_zeros(x);
+ unsigned int fto = __builtin_stdc_first_trailing_one(x);
+ unsigned int cz = __builtin_stdc_count_zeros(x);
+ bool has_one = __builtin_stdc_has_single_bit(x);
+ unsigned _BitInt(9) ceilv = __builtin_stdc_bit_ceil((unsigned _BitInt(9))5);
+ unsigned _BitInt(9) floorv = __builtin_stdc_bit_floor((unsigned _BitInt(9))5);
+
``__builtin_unreachable``
-------------------------
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 2fe76e60946f5..d8d7ab226fead 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -173,6 +173,15 @@ Non-comprehensive list of changes in this release
counts are normalized modulo the bit-width and support negative values.
Usable in constant expressions. Implicit conversion is supported for
class/struct types with conversion operators.
+- Implemented the following C23 ``<stdbit.h>`` builtins with ``_BitInt``
+ support and constexpr evaluation:
+ ``__builtin_stdc_leading_zeros``, ``__builtin_stdc_leading_ones``,
+ ``__builtin_stdc_trailing_zeros``, ``__builtin_stdc_trailing_ones``,
+ ``__builtin_stdc_first_leading_zero``, ``__builtin_stdc_first_leading_one``,
+ ``__builtin_stdc_first_trailing_zero``, ``__builtin_stdc_first_trailing_one``,
+ ``__builtin_stdc_count_zeros``, ``__builtin_stdc_count_ones``,
+ ``__builtin_stdc_has_single_bit``, ``__builtin_stdc_bit_width``,
+ ``__builtin_stdc_bit_floor``, and ``__builtin_stdc_bit_ceil``.
- A new generic bit-reverse builtin function ``__builtin_bitreverseg`` that
extends bit-reversal support to all standard integers type, including
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index b8bbc544595e2..f386e2f1ea741 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -797,6 +797,90 @@ def StdcRotateRight : Builtin {
let Prototype = "void(...)";
}
+def StdcLeadingZeros: Builtin {
+ let Spellings = ["__builtin_stdc_leading_zeros"];
+ let Attributes = [NoThrow, Const, Constexpr, CustomTypeChecking];
+ let Prototype = "void(...)";
+}
+
+def StdcLeadingOnes: Builtin {
+ let Spellings = ["__builtin_stdc_leading_ones"];
+ let Attributes = [NoThrow, Const, Constexpr, CustomTypeChecking];
+ let Prototype = "void(...)";
+}
+
+def StdcTrailingZeros: Builtin {
+ let Spellings = ["__builtin_stdc_trailing_zeros"];
+ let Attributes = [NoThrow, Const, Constexpr, CustomTypeChecking];
+ let Prototype = "void(...)";
+}
+
+def StdcTrailingOnes: Builtin {
+ let Spellings = ["__builtin_stdc_trailing_ones"];
+ let Attributes = [NoThrow, Const, Constexpr, CustomTypeChecking];
+ let Prototype = "void(...)";
+}
+
+def StdcFirstLeadingZero: Builtin {
+ let Spellings = ["__builtin_stdc_first_leading_zero"];
+ let Attributes = [NoThrow, Const, Constexpr, CustomTypeChecking];
+ let Prototype = "void(...)";
+}
+
+def StdcFirstLeadingOne: Builtin {
+ let Spellings = ["__builtin_stdc_first_leading_one"];
+ let Attributes = [NoThrow, Const, Constexpr, CustomTypeChecking];
+ let Prototype = "void(...)";
+}
+
+def StdcFirstTrailingZero: Builtin {
+ let Spellings = ["__builtin_stdc_first_trailing_zero"];
+ let Attributes = [NoThrow, Const, Constexpr, CustomTypeChecking];
+ let Prototype = "void(...)";
+}
+
+def StdcFirstTrailingOne: Builtin {
+ let Spellings = ["__builtin_stdc_first_trailing_one"];
+ let Attributes = [NoThrow, Const, Constexpr, CustomTypeChecking];
+ let Prototype = "void(...)";
+}
+
+def StdcCountZeros: Builtin {
+ let Spellings = ["__builtin_stdc_count_zeros"];
+ let Attributes = [NoThrow, Const, Constexpr, CustomTypeChecking];
+ let Prototype = "void(...)";
+}
+
+def StdcCountOnes: Builtin {
+ let Spellings = ["__builtin_stdc_count_ones"];
+ let Attributes = [NoThrow, Const, Constexpr, CustomTypeChecking];
+ let Prototype = "void(...)";
+}
+
+def StdcHasSingleBit: Builtin {
+ let Spellings = ["__builtin_stdc_has_single_bit"];
+ let Attributes = [NoThrow, Const, Constexpr, CustomTypeChecking];
+ let Prototype = "bool(...)";
+}
+
+def StdcBitWidth: Builtin {
+ let Spellings = ["__builtin_stdc_bit_width"];
+ let Attributes = [NoThrow, Const, Constexpr, CustomTypeChecking];
+ let Prototype = "void(...)";
+}
+
+def StdcBitFloor: Builtin {
+ let Spellings = ["__builtin_stdc_bit_floor"];
+ let Attributes = [NoThrow, Const, Constexpr, CustomTypeChecking];
+ let Prototype = "void(...)";
+}
+
+def StdcBitCeil: Builtin {
+ let Spellings = ["__builtin_stdc_bit_ceil"];
+ let Attributes = [NoThrow, Const, Constexpr, CustomTypeChecking];
+ let Prototype = "void(...)";
+}
+
// Random GCC builtins
// FIXME: The builtins marked FunctionWithBuiltinPrefix below should be
// merged with the library definitions. They are currently not because
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index e7b3ef6ce1510..84d38ca2973ff 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -4420,6 +4420,129 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
});
}
+ case Builtin::BI__builtin_stdc_leading_zeros: {
+ unsigned ResWidth = S.getASTContext().getIntWidth(Call->getType());
+ return interp__builtin_elementwise_int_unaryop(
+ S, OpPC, Call, [ResWidth](const APSInt &Val) {
+ return APInt(ResWidth, Val.countl_zero());
+ });
+ }
+
+ case Builtin::BI__builtin_stdc_leading_ones: {
+ unsigned ResWidth = S.getASTContext().getIntWidth(Call->getType());
+ return interp__builtin_elementwise_int_unaryop(
+ S, OpPC, Call, [ResWidth](const APSInt &Val) {
+ return APInt(ResWidth, Val.countl_one());
+ });
+ }
+
+ case Builtin::BI__builtin_stdc_trailing_zeros: {
+ unsigned ResWidth = S.getASTContext().getIntWidth(Call->getType());
+ return interp__builtin_elementwise_int_unaryop(
+ S, OpPC, Call, [ResWidth](const APSInt &Val) {
+ return APInt(ResWidth, Val.countr_zero());
+ });
+ }
+
+ case Builtin::BI__builtin_stdc_trailing_ones: {
+ unsigned ResWidth = S.getASTContext().getIntWidth(Call->getType());
+ return interp__builtin_elementwise_int_unaryop(
+ S, OpPC, Call, [ResWidth](const APSInt &Val) {
+ return APInt(ResWidth, Val.countr_one());
+ });
+ }
+
+ case Builtin::BI__builtin_stdc_first_leading_zero: {
+ unsigned ResWidth = S.getASTContext().getIntWidth(Call->getType());
+ return interp__builtin_elementwise_int_unaryop(
+ S, OpPC, Call, [ResWidth](const APSInt &Val) {
+ return APInt(ResWidth, Val.isAllOnes() ? 0 : Val.countl_one() + 1);
+ });
+ }
+
+ case Builtin::BI__builtin_stdc_first_leading_one: {
+ unsigned ResWidth = S.getASTContext().getIntWidth(Call->getType());
+ return interp__builtin_elementwise_int_unaryop(
+ S, OpPC, Call, [ResWidth](const APSInt &Val) {
+ return APInt(ResWidth, Val.isZero() ? 0 : Val.countl_zero() + 1);
+ });
+ }
+
+ case Builtin::BI__builtin_stdc_first_trailing_zero: {
+ unsigned ResWidth = S.getASTContext().getIntWidth(Call->getType());
+ return interp__builtin_elementwise_int_unaryop(
+ S, OpPC, Call, [ResWidth](const APSInt &Val) {
+ return APInt(ResWidth, Val.isAllOnes() ? 0 : Val.countr_one() + 1);
+ });
+ }
+
+ case Builtin::BI__builtin_stdc_first_trailing_one: {
+ unsigned ResWidth = S.getASTContext().getIntWidth(Call->getType());
+ return interp__builtin_elementwise_int_unaryop(
+ S, OpPC, Call, [ResWidth](const APSInt &Val) {
+ return APInt(ResWidth, Val.isZero() ? 0 : Val.countr_zero() + 1);
+ });
+ }
+
+ case Builtin::BI__builtin_stdc_count_zeros: {
+ unsigned ResWidth = S.getASTContext().getIntWidth(Call->getType());
+ return interp__builtin_elementwise_int_unaryop(
+ S, OpPC, Call, [ResWidth](const APSInt &Val) {
+ unsigned BitWidth = Val.getBitWidth();
+ return APInt(ResWidth, BitWidth - Val.popcount());
+ });
+ }
+
+ case Builtin::BI__builtin_stdc_count_ones: {
+ unsigned ResWidth = S.getASTContext().getIntWidth(Call->getType());
+ return interp__builtin_elementwise_int_unaryop(
+ S, OpPC, Call, [ResWidth](const APSInt &Val) {
+ return APInt(ResWidth, Val.popcount());
+ });
+ }
+
+ case Builtin::BI__builtin_stdc_has_single_bit: {
+ unsigned ResWidth = S.getASTContext().getIntWidth(Call->getType());
+ return interp__builtin_elementwise_int_unaryop(
+ S, OpPC, Call, [ResWidth](const APSInt &Val) {
+ return APInt(ResWidth, Val.popcount() == 1 ? 1 : 0);
+ });
+ }
+
+ case Builtin::BI__builtin_stdc_bit_width: {
+ unsigned ResWidth = S.getASTContext().getIntWidth(Call->getType());
+ return interp__builtin_elementwise_int_unaryop(
+ S, OpPC, Call, [ResWidth](const APSInt &Val) {
+ unsigned BitWidth = Val.getBitWidth();
+ return APInt(ResWidth, BitWidth - Val.countl_zero());
+ });
+ }
+
+ case Builtin::BI__builtin_stdc_bit_floor:
+ return interp__builtin_elementwise_int_unaryop(
+ S, OpPC, Call, [](const APSInt &Val) {
+ unsigned BitWidth = Val.getBitWidth();
+ if (Val.isZero())
+ return APInt::getZero(BitWidth);
+ return APInt::getOneBitSet(BitWidth,
+ BitWidth - Val.countl_zero() - 1);
+ });
+
+ case Builtin::BI__builtin_stdc_bit_ceil:
+ return interp__builtin_elementwise_int_unaryop(
+ S, OpPC, Call, [](const APSInt &Val) {
+ unsigned BitWidth = Val.getBitWidth();
+ if (Val.ule(1))
+ return llvm::APInt(BitWidth, 1);
+ if (Val.isAllOnes())
+ return static_cast<const llvm::APInt &>(Val);
+ llvm::APInt ValMinusOne = static_cast<const llvm::APInt &>(Val) - 1;
+ unsigned LeadingZeros = ValMinusOne.countl_zero();
+ if (LeadingZeros == 0)
+ return static_cast<const llvm::APInt &>(Val); // would overflow
+ return llvm::APInt::getOneBitSet(BitWidth, BitWidth - LeadingZeros);
+ });
+
case Builtin::BI__builtin_ffs:
case Builtin::BI__builtin_ffsl:
case Builtin::BI__builtin_ffsll:
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 4f45fa728c605..d3179d13b310f 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -16825,6 +16825,90 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
}
}
+ case Builtin::BI__builtin_stdc_leading_zeros:
+ case Builtin::BI__builtin_stdc_leading_ones:
+ case Builtin::BI__builtin_stdc_trailing_zeros:
+ case Builtin::BI__builtin_stdc_trailing_ones:
+ case Builtin::BI__builtin_stdc_first_leading_zero:
+ case Builtin::BI__builtin_stdc_first_leading_one:
+ case Builtin::BI__builtin_stdc_first_trailing_zero:
+ case Builtin::BI__builtin_stdc_first_trailing_one:
+ case Builtin::BI__builtin_stdc_count_zeros:
+ case Builtin::BI__builtin_stdc_count_ones:
+ case Builtin::BI__builtin_stdc_has_single_bit:
+ case Builtin::BI__builtin_stdc_bit_width:
+ case Builtin::BI__builtin_stdc_bit_floor:
+ case Builtin::BI__builtin_stdc_bit_ceil: {
+ APSInt Val;
+ if (!EvaluateInteger(E->getArg(0), Val, Info))
+ return false;
+
+ unsigned BitWidth = Val.getBitWidth();
+ const unsigned ResBitWidth = Info.Ctx.getIntWidth(E->getType());
+
+ switch (BuiltinOp) {
+ case Builtin::BI__builtin_stdc_leading_zeros:
+ return Success(APInt(ResBitWidth, Val.countLeadingZeros()), E);
+ case Builtin::BI__builtin_stdc_leading_ones:
+ return Success(APInt(ResBitWidth, Val.countLeadingOnes()), E);
+ case Builtin::BI__builtin_stdc_trailing_zeros:
+ return Success(APInt(ResBitWidth, Val.countTrailingZeros()), E);
+ case Builtin::BI__builtin_stdc_trailing_ones:
+ return Success(APInt(ResBitWidth, Val.countTrailingOnes()), E);
+ case Builtin::BI__builtin_stdc_first_leading_zero:
+ return Success(
+ APInt(ResBitWidth, Val.isAllOnes() ? 0 : Val.countLeadingOnes() + 1),
+ E);
+ case Builtin::BI__builtin_stdc_first_leading_one:
+ return Success(
+ APInt(ResBitWidth, Val.isZero() ? 0 : Val.countLeadingZeros() + 1),
+ E);
+ case Builtin::BI__builtin_stdc_first_trailing_zero:
+ return Success(
+ APInt(ResBitWidth, Val.isAllOnes() ? 0 : Val.countTrailingOnes() + 1),
+ E);
+ case Builtin::BI__builtin_stdc_first_trailing_one:
+ return Success(
+ APInt(ResBitWidth, Val.isZero() ? 0 : Val.countTrailingZeros() + 1),
+ E);
+ case Builtin::BI__builtin_stdc_count_zeros: {
+ APInt Cnt(ResBitWidth, BitWidth - Val.popcount());
+ return Success(APSInt(Cnt, /*IsUnsigned*/ true), E);
+ }
+ case Builtin::BI__builtin_stdc_count_ones: {
+ APInt Cnt(ResBitWidth, Val.popcount());
+ return Success(APSInt(Cnt, /*IsUnsigned*/ true), E);
+ }
+ case Builtin::BI__builtin_stdc_has_single_bit: {
+ APInt Res(ResBitWidth, Val.popcount() == 1 ? 1 : 0);
+ return Success(APSInt(Res, /*IsUnsigned*/ true), E);
+ }
+ case Builtin::BI__builtin_stdc_bit_width:
+ return Success(APInt(ResBitWidth, BitWidth - Val.countLeadingZeros()), E);
+ case Builtin::BI__builtin_stdc_bit_floor: {
+ if (Val.isZero())
+ return Success(APInt(ResBitWidth, 0), E);
+ unsigned Exp = BitWidth - Val.countLeadingZeros() - 1;
+ return Success(
+ APSInt(APInt::getOneBitSet(BitWidth, Exp), /*IsUnsigned*/ true), E);
+ }
+ case Builtin::BI__builtin_stdc_bit_ceil: {
+ if (Val.ule(1))
+ return Success(APSInt(APInt(BitWidth, 1), /*IsUnsigned*/ true), E);
+ if (Val.isAllOnes())
+ return Success(APSInt(Val), E);
+ APInt ValMinusOne = Val - 1;
+ unsigned LZ = ValMinusOne.countLeadingZeros();
+ if (LZ == 0)
+ return Success(APSInt(Val), E); // would overflow; clamp
+ APInt Result = APInt::getOneBitSet(BitWidth, BitWidth - LZ);
+ return Success(APSInt(Result, /*IsUnsigned*/ true), E);
+ }
+ default:
+ llvm_unreachable("Unknown stdc builtin");
+ }
+ }
+
case Builtin::BI__builtin_elementwise_add_sat: {
APSInt LHS, RHS;
if (!EvaluateInteger(E->getArg(0), LHS, Info) ||
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 4d74d681cd320..da64bf70df3b9 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3733,6 +3733,195 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI_rotr64:
return emitRotate(E, true);
+ case Builtin::BI__builtin_stdc_leading_zeros:
+ case Builtin::BI__builtin_stdc_leading_ones:
+ case Builtin::BI__builtin_stdc_trailing_zeros:
+ case Builtin::BI__builtin_stdc_trailing_ones:
+ case Builtin::BI__builtin_stdc_first_leading_zero:
+ case Builtin::BI__builtin_stdc_first_leading_one:
+ case Builtin::BI__builtin_stdc_first_trailing_zero:
+ case Builtin::BI__builtin_stdc_first_trailing_one:
+ case Builtin::BI__builtin_stdc_count_zeros:
+ case Builtin::BI__builtin_stdc_count_ones:
+ case Builtin::BI__builtin_stdc_has_single_bit:
+ case Builtin::BI__builtin_stdc_bit_width:
+ case Builtin::BI__builtin_stdc_bit_floor:
+ case Builtin::BI__builtin_stdc_bit_ceil: {
+ Value *ArgValue = EmitScalarExpr(E->getArg(0));
+ llvm::Type *ArgType = ArgValue->getType();
+ llvm::Type *ResultType = ConvertType(E->getType());
+ unsigned BitWidth = ArgType->getIntegerBitWidth();
+ Value *Zero = ConstantInt::get(ArgType, 0);
+ Value *One = ConstantInt::get(ArgType, 1);
+ Value *Result;
+
+ switch (BuiltinIDIfNoAsmLabel) {
+ case Builtin::BI__builtin_stdc_leading_zeros: {
+ Function *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType);
+ Result = Builder.CreateCall(F, {ArgValue, Builder.getFalse()});
+ break;
+ }
+ case Builtin::BI__builtin_stdc_leading_ones: {
+ Function *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType);
+ Result = Builder.CreateCall(
+ F, {Builder.CreateNot(ArgValue), Builder.getFalse()});
+ break;
+ }
+ case Builtin::BI__builtin_stdc_trailing_zeros: {
+ Function *F = CGM.getIntrinsic(Intrinsic::cttz, ArgType);
+ Result = Builder.CreateCall(F, {ArgValue, Builder.getFalse()});
+ break;
+ }
+ case Builtin::BI__builtin_stdc_trailing_ones: {
+ Function *F = CGM.getIntrinsic(Intrinsic::cttz, ArgType);
+ Result = Builder.CreateCall(
+ F, {Builder.CreateNot(ArgValue), Builder.getFalse()});
+ break;
+ }
+ case Builtin::BI__builtin_stdc_first_leading_zero: {
+ Function *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType);
+ Value *Cnt = Builder.CreateCall(
+ F, {Builder.CreateNot(ArgValue), Builder.getFalse()});
+ Value *Tmp = Builder.CreateAdd(Cnt, One);
+ Value *IsAllOnes =
+ Builder.CreateICmpEQ(ArgValue, Constant::getAllOnesValue(ArgType));
+ Result = Builder.CreateSelect(IsAllOnes, Zero, Tmp);
+ break;
+ }
+ case Builtin::BI__builtin_stdc_first_leading_one: {
+ Function *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType);
+ Value *Cnt = Builder.CreateCall(F, {ArgValue, Builder.getFalse()});
+ Value *Tmp = Builder.CreateAdd(Cnt, One);
+ Value *IsZero = Builder.CreateICmpEQ(ArgValue, Zero);
+ Result = Builder.CreateSelect(IsZero, Zero, Tmp);
+ break;
+ }
+ case Builtin::BI__builtin_stdc_first_trailing_zero: {
+ Function *F = CGM.getIntrinsic(Intrinsic::cttz, ArgType);
+ Value *Cnt = Builder.CreateCall(
+ F, {Builder.CreateNot(ArgValue), Builder.getFalse()});
+ Value *Tmp = Builder.CreateAdd(Cnt, One);
+ Value *IsAllOnes =
+ Builder.CreateICmpEQ(ArgValue, Constant::getAllOnesValue(ArgType));
+ Result = Builder.CreateSelect(IsAllOnes, Zero, Tmp);
+ break;
+ }
+ case Builtin::BI__builtin_stdc_first_trailing_one: {
+ Function *F = CGM.getIntrinsic(Intrinsic::cttz, ArgType);
+ Value *Cnt = Builder.CreateCall(F, {ArgValue, Builder.getFalse()});
+ Value *Tmp = Builder.CreateAdd(Cnt, One);
+ Value *IsZero = Builder.CreateICmpEQ(ArgValue, Zero);
+ Result = Builder.CreateSelect(IsZero, Zero, Tmp);
+ break;
+ }
+ case Builtin::BI__builtin_stdc_count_zeros: {
+ Function *F = CGM.getIntrinsic(Intrinsic::ctpop, ArgType);
+ Value *PopCnt = Builder.CreateCall(F, ArgValue);
+ Result = Builder.CreateSub(ConstantInt::get(ArgType, BitWidth), PopCnt);
+ break;
+ }
+ case Builtin::BI__builtin_stdc_count_ones: {
+ Function *F = CGM.getIntrinsic(Intrinsic::ctpop, ArgType);
+ Result = Builder.CreateCall(F, ArgValue);
+ break;
+ }
+ case Builtin::BI__builtin_stdc_has_single_bit: {
+ Function *F = CGM.getIntrinsic(Intrinsic::ctpop, ArgType);
+ Value *PopCnt = Builder.CreateCall(F, ArgValue);
+ return RValue::get(Builder.CreateICmpEQ(PopCnt, One));
+ }
+ case Builtin::BI__builtin_stdc_bit_width: {
+ Function *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType);
+ Value *LZ = Builder.CreateCall(F, {ArgValue, Builder.getFalse()});
+ Result = Builder.CreateSub(ConstantInt::get(ArgType, BitWidth), LZ);
+ break;
+ }
+ case Builtin::BI__builtin_stdc_bit_floor: {
+ // Spec: arg == 0 ? 0 : 1 << (prec - 1 - clz(arg))
+ Value *IsZero = Builder.CreateICmpEQ(ArgValue, Zero);
+ BasicBlock *ZeroBB = createBasicBlock("bitfloor.zero", CurFn);
+ BasicBlock *CalcBB = createBasicBlock("bitfloor.calc", CurFn);
+ BasicBlock *MergeBB = createBasicBlock("bitfloor.merge", CurFn);
+
+ Builder.CreateCondBr(IsZero, ZeroBB, CalcBB);
+
+ // Zero path.
+ Builder.SetInsertPoint(ZeroBB);
+ Builder.CreateBr(MergeBB);
+
+ // General path.
+ Builder.SetInsertPoint(CalcBB);
+ Function *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType);
+ Value *LZ = Builder.CreateCall(F, {ArgValue, Builder.getFalse()});
+ Value *ShiftAmt =
+ Builder.CreateSub(ConstantInt::get(ArgType, BitWidth - 1), LZ);
+ Value *Tmp = Builder.CreateShl(One, ShiftAmt);
+ Builder.CreateBr(MergeBB);
+
+ // Merge.
+ Builder.SetInsertPoint(MergeBB);
+ PHINode *Phi = Builder.CreatePHI(ArgType, 2);
+ Phi->addIncoming(Zero, ZeroBB);
+ Phi->addIncoming(Tmp, CalcBB);
+ Result = Phi;
+ break;
+ }
+ case Builtin::BI__builtin_stdc_bit_ceil: {
+ // Spec: arg <= 1 ? 1 : 2 << (prec - 1 - clz(arg - 1))
+ if (auto *CI = dyn_cast<ConstantInt>(ArgValue)) {
+ if (CI->isMinusOne())
+ return RValue::get(CI);
+ if (CI->isZero() || CI->isOne())
+ return RValue::get(ConstantInt::get(ArgType, 1));
+ }
+
+ Value *AllOnes = Constant::getAllOnesValue(ArgType);
+ Value *IsAllOnes = Builder.CreateICmpEQ(ArgValue, AllOnes, "isallones");
+ Value *IsLEOne = Builder.CreateICmpULE(ArgValue, One, "isleone");
+
+ BasicBlock *AllOnesBB = createBasicBlock("bitceil.allones", CurFn);
+ BasicBlock *LEOneBB = createBasicBlock("bitceil.leone", CurFn);
+ BasicBlock *CalcBB = createBasicBlock("bitceil.calc", CurFn);
+ BasicBlock *MergeBB = createBasicBlock("bitceil.merge", CurFn);
+
+ // If all ones -> return operand
+ Builder.CreateCondBr(IsAllOnes, AllOnesBB, LEOneBB);
+
+ Builder.SetInsertPoint(AllOnesBB);
+ Builder.CreateBr(MergeBB);
+
+ // If <= 1 -> return 1, else compute.
+ Builder.SetInsertPoint(LEOneBB);
+ Builder.CreateCondBr(IsLEOne, MergeBB, CalcBB);
+
+ Builder.SetInsertPoint(CalcBB);
+ Function *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType);
+ Value *ArgMinusOne = Builder.CreateSub(ArgValue, One);
+ Value *LZ = Builder.CreateCall(F, {ArgMinusOne, Builder.getFalse()});
+ Value *LZIsZero = Builder.CreateICmpEQ(LZ, Zero, "lzzero");
+ Value *ShiftAmt =
+ Builder.CreateSub(ConstantInt::get(ArgType, BitWidth), LZ);
+ Value *Tmp = Builder.CreateShl(One, ShiftAmt);
+ Tmp = Builder.CreateSelect(LZIsZero, ArgValue, Tmp);
+ Builder.CreateBr(MergeBB);
+
+ Builder.SetInsertPoint(MergeBB);
+ PHINode *Phi = Builder.CreatePHI(ArgType, 3);
+ Phi->addIncoming(ArgValue, AllOnesBB);
+ Phi->addIncoming(One, LEOneBB);
+ Phi->addIncoming(Tmp, CalcBB);
+ Result = Phi;
+ break;
+ }
+ default:
+ llvm_unreachable("Unknown stdc builtin");
+ }
+
+ if (Result->getType() != ResultType)
+ Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/ false);
+ return RValue::get(Result);
+ }
+
case Builtin::BI__builtin_constant_p: {
llvm::Type *ResultType = ConvertType(E->getType());
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 1c1cd0f292753..0124c247eea4c 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2347,6 +2347,47 @@ static bool BuiltinPopcountg(Sema &S, CallExpr *TheCall) {
return false;
}
+/// Checks stdc bit-utility builtins (__builtin_stdc_*):
+/// bit_ceil, bit_floor, bit_width, count_ones, count_zeros,
+/// first_leading_one, first_leading_zero, first_trailing_one,
+/// first_trailing_zero, has_single_bit, leading_ones, leading_zeros,
+/// trailing_ones, trailing_zeros. They all take a single unsigned integer
+/// argument and return either int, bool, or the argument type depending on the
+/// specific builtin.
+static bool BuiltinStdCBuiltin(Sema &S, CallExpr *TheCall) {
+ if (S.checkArgCount(TheCall, 1))
+ return true;
+
+ ExprResult ArgRes = S.DefaultLvalueConversion(TheCall->getArg(0));
+ if (ArgRes.isInvalid())
+ return true;
+
+ Expr *Arg = ArgRes.get();
+ TheCall->setArg(0, Arg);
+
+ QualType ArgTy = Arg->getType();
+ if (!ArgTy->isUnsignedIntegerType() && !ArgTy->isExtVectorBoolType()) {
+ S.Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type)
+ << 1 << /* scalar */ 1 << /* unsigned integer ty */ 3 << /* no fp */ 0
+ << ArgTy;
+ return true;
+ }
+
+ switch (TheCall->getBuiltinCallee()) {
+ case Builtin::BI__builtin_stdc_bit_floor:
+ case Builtin::BI__builtin_stdc_bit_ceil:
+ TheCall->setType(ArgTy);
+ break;
+ case Builtin::BI__builtin_stdc_has_single_bit:
+ TheCall->setType(S.Context.BoolTy);
+ break;
+ default:
+ TheCall->setType(S.Context.UnsignedIntTy);
+ break;
+ }
+ return false;
+}
+
/// Checks that __builtin_{clzg,ctzg} was called with a first argument, which is
/// an unsigned integer, and an optional second argument, which is promoted to
/// an 'int'.
@@ -3802,6 +3843,24 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
return ExprError();
break;
+ case Builtin::BI__builtin_stdc_leading_zeros:
+ case Builtin::BI__builtin_stdc_leading_ones:
+ case Builtin::BI__builtin_stdc_trailing_zeros:
+ case Builtin::BI__builtin_stdc_trailing_ones:
+ case Builtin::BI__builtin_stdc_first_leading_zero:
+ case Builtin::BI__builtin_stdc_first_leading_one:
+ case Builtin::BI__builtin_stdc_first_trailing_zero:
+ case Builtin::BI__builtin_stdc_first_trailing_one:
+ case Builtin::BI__builtin_stdc_count_zeros:
+ case Builtin::BI__builtin_stdc_count_ones:
+ case Builtin::BI__builtin_stdc_has_single_bit:
+ case Builtin::BI__builtin_stdc_bit_width:
+ case Builtin::BI__builtin_stdc_bit_floor:
+ case Builtin::BI__builtin_stdc_bit_ceil:
+ if (BuiltinStdCBuiltin(*this, TheCall))
+ return ExprError();
+ break;
+
case Builtin::BI__builtin_allow_runtime_check: {
Expr *Arg = TheCall->getArg(0);
// Check if the argument is a string literal.
diff --git a/clang/test/CodeGen/builtin-stdc-bit-functions.c b/clang/test/CodeGen/builtin-stdc-bit-functions.c
new file mode 100644
index 0000000000000..1be9f3e640285
--- /dev/null
+++ b/clang/test/CodeGen/builtin-stdc-bit-functions.c
@@ -0,0 +1,239 @@
+// RUN: %clang_cc1 -ffreestanding %s -emit-llvm -o - | FileCheck %s
+// RUN: %if clang-target-64-bits %{ %clang_cc1 -ffreestanding %s -emit-llvm -o - | FileCheck %s --check-prefix=INT128 %}
+
+// CHECK-LABEL: test_leading_zeros
+// CHECK: call i8 @llvm.ctlz.i8(i8 %{{.*}}, i1 false)
+// CHECK: call i16 @llvm.ctlz.i16(i16 %{{.*}}, i1 false)
+// CHECK: call i32 @llvm.ctlz.i32(i32 %{{.*}}, i1 false)
+// CHECK: call i64 @llvm.ctlz.i64(i64 %{{.*}}, i1 false)
+void test_leading_zeros(unsigned char uc, unsigned short us, unsigned int ui, unsigned long long ull) {
+ volatile int r;
+ r = __builtin_stdc_leading_zeros(uc);
+ r = __builtin_stdc_leading_zeros(us);
+ r = __builtin_stdc_leading_zeros(ui);
+ r = __builtin_stdc_leading_zeros(ull);
+}
+
+// CHECK-LABEL: test_leading_ones
+// CHECK: xor i8 %{{.*}}, -1
+// CHECK: call i8 @llvm.ctlz.i8(i8 %{{.*}}, i1 false)
+// CHECK: xor i16 %{{.*}}, -1
+// CHECK: call i16 @llvm.ctlz.i16(i16 %{{.*}}, i1 false)
+// CHECK: xor i32 %{{.*}}, -1
+// CHECK: call i32 @llvm.ctlz.i32(i32 %{{.*}}, i1 false)
+// CHECK: xor i64 %{{.*}}, -1
+// CHECK: call i64 @llvm.ctlz.i64(i64 %{{.*}}, i1 false)
+void test_leading_ones(unsigned char uc, unsigned short us, unsigned int ui, unsigned long long ull) {
+ volatile int r;
+ r = __builtin_stdc_leading_ones(uc);
+ r = __builtin_stdc_leading_ones(us);
+ r = __builtin_stdc_leading_ones(ui);
+ r = __builtin_stdc_leading_ones(ull);
+}
+
+// CHECK-LABEL: test_trailing_zeros
+// CHECK: call i8 @llvm.cttz.i8(i8 %{{.*}}, i1 false)
+// CHECK: call i16 @llvm.cttz.i16(i16 %{{.*}}, i1 false)
+// CHECK: call i32 @llvm.cttz.i32(i32 %{{.*}}, i1 false)
+// CHECK: call i64 @llvm.cttz.i64(i64 %{{.*}}, i1 false)
+void test_trailing_zeros(unsigned char uc, unsigned short us, unsigned int ui, unsigned long long ull) {
+ volatile int r;
+ r = __builtin_stdc_trailing_zeros(uc);
+ r = __builtin_stdc_trailing_zeros(us);
+ r = __builtin_stdc_trailing_zeros(ui);
+ r = __builtin_stdc_trailing_zeros(ull);
+}
+
+// CHECK-LABEL: test_trailing_ones
+// CHECK: xor i8 %{{.*}}, -1
+// CHECK: call i8 @llvm.cttz.i8(i8 %{{.*}}, i1 false)
+// CHECK: xor i16 %{{.*}}, -1
+// CHECK: call i16 @llvm.cttz.i16(i16 %{{.*}}, i1 false)
+// CHECK: xor i32 %{{.*}}, -1
+// CHECK: call i32 @llvm.cttz.i32(i32 %{{.*}}, i1 false)
+// CHECK: xor i64 %{{.*}}, -1
+// CHECK: call i64 @llvm.cttz.i64(i64 %{{.*}}, i1 false)
+void test_trailing_ones(unsigned char uc, unsigned short us, unsigned int ui, unsigned long long ull) {
+ volatile int r;
+ r = __builtin_stdc_trailing_ones(uc);
+ r = __builtin_stdc_trailing_ones(us);
+ r = __builtin_stdc_trailing_ones(ui);
+ r = __builtin_stdc_trailing_ones(ull);
+}
+
+// CHECK-LABEL: test_first_leading_zero
+// CHECK: xor i8 %{{.*}}, -1
+// CHECK: call i8 @llvm.ctlz.i8(i8 %{{.*}}, i1 false)
+// CHECK: xor i32 %{{.*}}, -1
+// CHECK: call i32 @llvm.ctlz.i32(i32 %{{.*}}, i1 false)
+void test_first_leading_zero(unsigned char uc, unsigned int ui) {
+ volatile int r;
+ r = __builtin_stdc_first_leading_zero(uc);
+ r = __builtin_stdc_first_leading_zero(ui);
+}
+
+// CHECK-LABEL: test_first_leading_one
+// CHECK: call i8 @llvm.ctlz.i8(i8 %{{.*}}, i1 false)
+// CHECK: call i32 @llvm.ctlz.i32(i32 %{{.*}}, i1 false)
+void test_first_leading_one(unsigned char uc, unsigned int ui) {
+ volatile int r;
+ r = __builtin_stdc_first_leading_one(uc);
+ r = __builtin_stdc_first_leading_one(ui);
+}
+
+// CHECK-LABEL: test_first_trailing_zero
+// CHECK: xor i8 %{{.*}}, -1
+// CHECK: call i8 @llvm.cttz.i8(i8 %{{.*}}, i1 false)
+// CHECK: xor i32 %{{.*}}, -1
+// CHECK: call i32 @llvm.cttz.i32(i32 %{{.*}}, i1 false)
+void test_first_trailing_zero(unsigned char uc, unsigned int ui) {
+ volatile int r;
+ r = __builtin_stdc_first_trailing_zero(uc);
+ r = __builtin_stdc_first_trailing_zero(ui);
+}
+
+// CHECK-LABEL: test_first_trailing_one
+// CHECK: call i8 @llvm.cttz.i8(i8 %{{.*}}, i1 false)
+// CHECK: call i32 @llvm.cttz.i32(i32 %{{.*}}, i1 false)
+void test_first_trailing_one(unsigned char uc, unsigned int ui) {
+ volatile int r;
+ r = __builtin_stdc_first_trailing_one(uc);
+ r = __builtin_stdc_first_trailing_one(ui);
+}
+
+// CHECK-LABEL: test_count_zeros
+// CHECK: call i8 @llvm.ctpop.i8(i8 %{{.*}})
+// CHECK: call i16 @llvm.ctpop.i16(i16 %{{.*}})
+// CHECK: call i32 @llvm.ctpop.i32(i32 %{{.*}})
+// CHECK: call i64 @llvm.ctpop.i64(i64 %{{.*}})
+void test_count_zeros(unsigned char uc, unsigned short us, unsigned int ui, unsigned long long ull) {
+ volatile int r;
+ r = __builtin_stdc_count_zeros(uc);
+ r = __builtin_stdc_count_zeros(us);
+ r = __builtin_stdc_count_zeros(ui);
+ r = __builtin_stdc_count_zeros(ull);
+}
+
+// CHECK-LABEL: test_count_ones
+// CHECK: call i8 @llvm.ctpop.i8(i8 %{{.*}})
+// CHECK: call i16 @llvm.ctpop.i16(i16 %{{.*}})
+// CHECK: call i32 @llvm.ctpop.i32(i32 %{{.*}})
+// CHECK: call i64 @llvm.ctpop.i64(i64 %{{.*}})
+void test_count_ones(unsigned char uc, unsigned short us, unsigned int ui, unsigned long long ull) {
+ volatile int r;
+ r = __builtin_stdc_count_ones(uc);
+ r = __builtin_stdc_count_ones(us);
+ r = __builtin_stdc_count_ones(ui);
+ r = __builtin_stdc_count_ones(ull);
+}
+
+// CHECK-LABEL: test_has_single_bit
+// CHECK: call i8 @llvm.ctpop.i8(i8 %{{.*}})
+// CHECK: call i32 @llvm.ctpop.i32(i32 %{{.*}})
+void test_has_single_bit(unsigned char uc, unsigned int ui) {
+ volatile int r;
+ r = __builtin_stdc_has_single_bit(uc);
+ r = __builtin_stdc_has_single_bit(ui);
+}
+
+// CHECK-LABEL: test_bit_width
+// CHECK: call i8 @llvm.ctlz.i8(i8 %{{.*}}, i1 false)
+// CHECK: call i32 @llvm.ctlz.i32(i32 %{{.*}}, i1 false)
+void test_bit_width(unsigned char uc, unsigned int ui) {
+ volatile int r;
+ r = __builtin_stdc_bit_width(uc);
+ r = __builtin_stdc_bit_width(ui);
+}
+
+// CHECK-LABEL: test_bit_floor
+// CHECK: call i8 @llvm.ctlz.i8(i8 %{{.*}}, i1 false)
+// CHECK: call i32 @llvm.ctlz.i32(i32 %{{.*}}, i1 false)
+void test_bit_floor(unsigned char uc, unsigned int ui) {
+ volatile unsigned char rc;
+ volatile unsigned int ri;
+ rc = __builtin_stdc_bit_floor(uc);
+ ri = __builtin_stdc_bit_floor(ui);
+}
+
+// CHECK-LABEL: test_bit_ceil
+// CHECK: call i8 @llvm.ctlz.i8(i8 %{{.*}}, i1 false)
+// CHECK: call i32 @llvm.ctlz.i32(i32 %{{.*}}, i1 false)
+void test_bit_ceil(unsigned char uc, unsigned int ui) {
+ volatile unsigned char rc;
+ volatile unsigned int ri;
+ rc = __builtin_stdc_bit_ceil(uc);
+ ri = __builtin_stdc_bit_ceil(ui);
+}
+
+// Test with _BitInt types
+// CHECK-LABEL: test_bitint
+// CHECK: call i37 @llvm.ctlz.i37(i37 %{{.*}}, i1 false)
+// CHECK: call i37 @llvm.cttz.i37(i37 %{{.*}}, i1 false)
+// CHECK: call i37 @llvm.ctpop.i37(i37 %{{.*}})
+void test_bitint(unsigned _BitInt(37) bi) {
+ volatile int r;
+ r = __builtin_stdc_leading_zeros(bi);
+ r = __builtin_stdc_trailing_zeros(bi);
+ r = __builtin_stdc_count_ones(bi);
+}
+
+// Additional _BitInt coverage
+// CHECK-LABEL: test_bitint_floor_ceil
+// CHECK: call i9 @llvm.ctlz.i9(i9 %{{.*}}, i1 false)
+// CHECK: call i9 @llvm.ctlz.i9(i9 %{{.*}}, i1 false)
+void test_bitint_floor_ceil(unsigned _BitInt(9) bi9) {
+ volatile unsigned _BitInt(9) rb;
+ rb = __builtin_stdc_bit_floor(bi9);
+ rb = __builtin_stdc_bit_ceil(bi9);
+}
+
+// CHECK-LABEL: test_bitint_first_and_count
+// CHECK: call i9 @llvm.ctlz.i9(i9 %{{.*}}, i1 false)
+// CHECK: call i9 @llvm.cttz.i9(i9 %{{.*}}, i1 false)
+// CHECK: call i9 @llvm.ctpop.i9(i9 %{{.*}})
+void test_bitint_first_and_count(unsigned _BitInt(9) bi9) {
+ volatile int r;
+ r = __builtin_stdc_first_leading_zero(bi9);
+ r = __builtin_stdc_first_trailing_zero(bi9);
+ r = __builtin_stdc_count_zeros(bi9);
+}
+
+// CHECK-LABEL: test_bit_ceil_all_ones
+// CHECK: store volatile i32 -1, ptr %r
+void test_bit_ceil_all_ones(void) {
+ volatile unsigned int r = __builtin_stdc_bit_ceil(0xFFFFFFFFU);
+}
+
+// CHECK-LABEL: test_bit_ceil_all_ones_bitint
+// CHECK: store volatile i32 131071, ptr %r
+void test_bit_ceil_all_ones_bitint(void) {
+ volatile unsigned _BitInt(17) r =
+ __builtin_stdc_bit_ceil((unsigned _BitInt(17))(-1));
+}
+
+// CHECK-LABEL: test_bit_floor_all_ones_bitint
+// CHECK: store volatile i32 65536, ptr %r
+void test_bit_floor_all_ones_bitint(void) {
+ volatile unsigned _BitInt(17) r =
+ __builtin_stdc_bit_floor((unsigned _BitInt(17))(-1));
+}
+
+// CHECK-LABEL: test_first_trailing_zero_all_ones_bitint
+// CHECK: store volatile i32 0, ptr %r
+void test_first_trailing_zero_all_ones_bitint(void) {
+ volatile unsigned _BitInt(17) r =
+ __builtin_stdc_first_trailing_zero((unsigned _BitInt(17))(-1));
+}
+
+#ifdef __SIZEOF_INT128__
+// INT128-LABEL: test_int128
+// INT128: call i128 @llvm.ctlz.i128(i128 %{{.*}}, i1 false)
+// INT128: call i128 @llvm.cttz.i128(i128 %{{.*}}, i1 false)
+// INT128: call i128 @llvm.ctpop.i128(i128 %{{.*}})
+void test_int128(unsigned __int128 u128) {
+ volatile int r;
+ r = __builtin_stdc_leading_zeros(u128);
+ r = __builtin_stdc_trailing_zeros(u128);
+ r = __builtin_stdc_count_ones(u128);
+}
+#endif
diff --git a/clang/test/Sema/builtin-stdc-bit-functions.c b/clang/test/Sema/builtin-stdc-bit-functions.c
new file mode 100644
index 0000000000000..aa440e2ea6eb9
--- /dev/null
+++ b/clang/test/Sema/builtin-stdc-bit-functions.c
@@ -0,0 +1,173 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fsyntax-only -verify %s
+
+// Test stdc_leading_zeros
+_Static_assert(__builtin_stdc_leading_zeros((unsigned char)0) == 8, "");
+_Static_assert(__builtin_stdc_leading_zeros((unsigned char)1) == 7, "");
+_Static_assert(__builtin_stdc_leading_zeros((unsigned char)0x80) == 0, "");
+_Static_assert(__builtin_stdc_leading_zeros((unsigned char)0xFF) == 0, "");
+_Static_assert(__builtin_stdc_leading_zeros((unsigned short)0) == 16, "");
+_Static_assert(__builtin_stdc_leading_zeros((unsigned short)0x8000) == 0, "");
+_Static_assert(__builtin_stdc_leading_zeros(0U) == 32, "");
+_Static_assert(__builtin_stdc_leading_zeros(1U) == 31, "");
+_Static_assert(__builtin_stdc_leading_zeros(0x80000000U) == 0, "");
+_Static_assert(__builtin_stdc_leading_zeros(0ULL) == 64, "");
+_Static_assert(__builtin_stdc_leading_zeros(1ULL) == 63, "");
+_Static_assert(__builtin_stdc_leading_zeros(0x8000000000000000ULL) == 0, "");
+
+// Test stdc_leading_ones
+_Static_assert(__builtin_stdc_leading_ones((unsigned char)0) == 0, "");
+_Static_assert(__builtin_stdc_leading_ones((unsigned char)0xFF) == 8, "");
+_Static_assert(__builtin_stdc_leading_ones((unsigned char)0xF0) == 4, "");
+_Static_assert(__builtin_stdc_leading_ones((unsigned short)0xFFFF) == 16, "");
+_Static_assert(__builtin_stdc_leading_ones(0xFFFFFFFFU) == 32, "");
+_Static_assert(__builtin_stdc_leading_ones(0xF0000000U) == 4, "");
+_Static_assert(__builtin_stdc_leading_ones(0xFFFFFFFFFFFFFFFFULL) == 64, "");
+
+// Test stdc_trailing_zeros
+_Static_assert(__builtin_stdc_trailing_zeros((unsigned char)0) == 8, "");
+_Static_assert(__builtin_stdc_trailing_zeros((unsigned char)1) == 0, "");
+_Static_assert(__builtin_stdc_trailing_zeros((unsigned char)0x80) == 7, "");
+_Static_assert(__builtin_stdc_trailing_zeros((unsigned short)0) == 16, "");
+_Static_assert(__builtin_stdc_trailing_zeros(0U) == 32, "");
+_Static_assert(__builtin_stdc_trailing_zeros(0x80000000U) == 31, "");
+_Static_assert(__builtin_stdc_trailing_zeros(0ULL) == 64, "");
+_Static_assert(__builtin_stdc_trailing_zeros(0x8000000000000000ULL) == 63, "");
+
+// Test stdc_trailing_ones
+_Static_assert(__builtin_stdc_trailing_ones((unsigned char)0) == 0, "");
+_Static_assert(__builtin_stdc_trailing_ones((unsigned char)0xFF) == 8, "");
+_Static_assert(__builtin_stdc_trailing_ones((unsigned char)0x0F) == 4, "");
+_Static_assert(__builtin_stdc_trailing_ones(0xFFFFFFFFU) == 32, "");
+_Static_assert(__builtin_stdc_trailing_ones(0x0000000FU) == 4, "");
+_Static_assert(__builtin_stdc_trailing_ones(0xFFFFFFFFFFFFFFFFULL) == 64, "");
+
+// Test stdc_first_leading_zero
+_Static_assert(__builtin_stdc_first_leading_zero((unsigned char)0) == 1, "");
+_Static_assert(__builtin_stdc_first_leading_zero((unsigned char)0xFF) == 0, "");
+_Static_assert(__builtin_stdc_first_leading_zero((unsigned char)0xF0) == 5, "");
+_Static_assert(__builtin_stdc_first_leading_zero((unsigned char)0x80) == 2, "");
+_Static_assert(__builtin_stdc_first_leading_zero(0xFFFFFFFFU) == 0, "");
+_Static_assert(__builtin_stdc_first_leading_zero(0xF0000000U) == 5, "");
+
+// Test stdc_first_leading_one
+_Static_assert(__builtin_stdc_first_leading_one((unsigned char)0) == 0, "");
+_Static_assert(__builtin_stdc_first_leading_one((unsigned char)0x80) == 1, "");
+_Static_assert(__builtin_stdc_first_leading_one((unsigned char)0x01) == 8, "");
+_Static_assert(__builtin_stdc_first_leading_one((unsigned char)0x0F) == 5, "");
+_Static_assert(__builtin_stdc_first_leading_one(0U) == 0, "");
+_Static_assert(__builtin_stdc_first_leading_one(0x80000000U) == 1, "");
+_Static_assert(__builtin_stdc_first_leading_one(1U) == 32, "");
+
+// Test stdc_first_trailing_zero
+_Static_assert(__builtin_stdc_first_trailing_zero((unsigned char)0) == 1, "");
+_Static_assert(__builtin_stdc_first_trailing_zero((unsigned char)0xFF) == 0, "");
+_Static_assert(__builtin_stdc_first_trailing_zero((unsigned char)0x0F) == 5, "");
+_Static_assert(__builtin_stdc_first_trailing_zero((unsigned char)0x01) == 2, "");
+_Static_assert(__builtin_stdc_first_trailing_zero(0xFFFFFFFFU) == 0, "");
+_Static_assert(__builtin_stdc_first_trailing_zero(0x0000000FU) == 5, "");
+
+// Test stdc_first_trailing_one
+_Static_assert(__builtin_stdc_first_trailing_one((unsigned char)0) == 0, "");
+_Static_assert(__builtin_stdc_first_trailing_one((unsigned char)0x01) == 1, "");
+_Static_assert(__builtin_stdc_first_trailing_one((unsigned char)0x80) == 8, "");
+_Static_assert(__builtin_stdc_first_trailing_one((unsigned char)0xF0) == 5, "");
+_Static_assert(__builtin_stdc_first_trailing_one(0U) == 0, "");
+_Static_assert(__builtin_stdc_first_trailing_one(0x80000000U) == 32, "");
+_Static_assert(__builtin_stdc_first_trailing_one(1U) == 1, "");
+
+// Test stdc_count_zeros
+_Static_assert(__builtin_stdc_count_zeros((unsigned char)0) == 8, "");
+_Static_assert(__builtin_stdc_count_zeros((unsigned char)0xFF) == 0, "");
+_Static_assert(__builtin_stdc_count_zeros((unsigned char)0xAA) == 4, "");
+_Static_assert(__builtin_stdc_count_zeros(0U) == 32, "");
+_Static_assert(__builtin_stdc_count_zeros(0xFFFFFFFFU) == 0, "");
+_Static_assert(__builtin_stdc_count_zeros(0xAAAAAAAAU) == 16, "");
+
+// Test stdc_count_ones
+_Static_assert(__builtin_stdc_count_ones((unsigned char)0) == 0, "");
+_Static_assert(__builtin_stdc_count_ones((unsigned char)0xFF) == 8, "");
+_Static_assert(__builtin_stdc_count_ones((unsigned char)0xAA) == 4, "");
+_Static_assert(__builtin_stdc_count_ones(0U) == 0, "");
+_Static_assert(__builtin_stdc_count_ones(0xFFFFFFFFU) == 32, "");
+_Static_assert(__builtin_stdc_count_ones(0xAAAAAAAAU) == 16, "");
+
+// Test stdc_has_single_bit
+_Static_assert(__builtin_stdc_has_single_bit((unsigned char)0) == 0, "");
+_Static_assert(__builtin_stdc_has_single_bit((unsigned char)1) == 1, "");
+_Static_assert(__builtin_stdc_has_single_bit((unsigned char)2) == 1, "");
+_Static_assert(__builtin_stdc_has_single_bit((unsigned char)3) == 0, "");
+_Static_assert(__builtin_stdc_has_single_bit((unsigned char)0x80) == 1, "");
+_Static_assert(__builtin_stdc_has_single_bit(0U) == 0, "");
+_Static_assert(__builtin_stdc_has_single_bit(1U) == 1, "");
+_Static_assert(__builtin_stdc_has_single_bit(0x80000000U) == 1, "");
+_Static_assert(__builtin_stdc_has_single_bit(0xFFFFFFFFU) == 0, "");
+
+// Test stdc_bit_width
+_Static_assert(__builtin_stdc_bit_width((unsigned char)0) == 0, "");
+_Static_assert(__builtin_stdc_bit_width((unsigned char)1) == 1, "");
+_Static_assert(__builtin_stdc_bit_width((unsigned char)2) == 2, "");
+_Static_assert(__builtin_stdc_bit_width((unsigned char)3) == 2, "");
+_Static_assert(__builtin_stdc_bit_width((unsigned char)0x80) == 8, "");
+_Static_assert(__builtin_stdc_bit_width((unsigned char)0xFF) == 8, "");
+_Static_assert(__builtin_stdc_bit_width(0U) == 0, "");
+_Static_assert(__builtin_stdc_bit_width(1U) == 1, "");
+_Static_assert(__builtin_stdc_bit_width(0x80000000U) == 32, "");
+
+// Test stdc_bit_floor
+_Static_assert(__builtin_stdc_bit_floor((unsigned char)0) == 0, "");
+_Static_assert(__builtin_stdc_bit_floor((unsigned char)1) == 1, "");
+_Static_assert(__builtin_stdc_bit_floor((unsigned char)2) == 2, "");
+_Static_assert(__builtin_stdc_bit_floor((unsigned char)3) == 2, "");
+_Static_assert(__builtin_stdc_bit_floor((unsigned char)4) == 4, "");
+_Static_assert(__builtin_stdc_bit_floor((unsigned char)5) == 4, "");
+_Static_assert(__builtin_stdc_bit_floor((unsigned char)0x80) == 0x80, "");
+_Static_assert(__builtin_stdc_bit_floor((unsigned char)0xFF) == 0x80, "");
+_Static_assert(__builtin_stdc_bit_floor(0U) == 0U, "");
+_Static_assert(__builtin_stdc_bit_floor(1U) == 1U, "");
+_Static_assert(__builtin_stdc_bit_floor(7U) == 4U, "");
+_Static_assert(__builtin_stdc_bit_floor(0x80000000U) == 0x80000000U, "");
+_Static_assert(__builtin_stdc_bit_floor(0xFFFFFFFFU) == 0x80000000U, "");
+
+// Test stdc_bit_ceil
+_Static_assert(__builtin_stdc_bit_ceil((unsigned char)0) == 1, "");
+_Static_assert(__builtin_stdc_bit_ceil((unsigned char)1) == 1, "");
+_Static_assert(__builtin_stdc_bit_ceil((unsigned char)2) == 2, "");
+_Static_assert(__builtin_stdc_bit_ceil((unsigned char)3) == 4, "");
+_Static_assert(__builtin_stdc_bit_ceil((unsigned char)4) == 4, "");
+_Static_assert(__builtin_stdc_bit_ceil((unsigned char)5) == 8, "");
+_Static_assert(__builtin_stdc_bit_ceil((unsigned char)0x80) == 0x80, "");
+_Static_assert(__builtin_stdc_bit_ceil(0U) == 1U, "");
+_Static_assert(__builtin_stdc_bit_ceil(1U) == 1U, "");
+_Static_assert(__builtin_stdc_bit_ceil(7U) == 8U, "");
+_Static_assert(__builtin_stdc_bit_ceil(0x80000000U) == 0x80000000U, "");
+
+// Test with _BitInt types
+_Static_assert(__builtin_stdc_leading_zeros((unsigned _BitInt(37))0) == 37, "");
+_Static_assert(__builtin_stdc_leading_zeros((unsigned _BitInt(37))1) == 36, "");
+_Static_assert(__builtin_stdc_trailing_zeros((unsigned _BitInt(37))0) == 37, "");
+_Static_assert(__builtin_stdc_count_ones((unsigned _BitInt(37))0x1F) == 5, "");
+_Static_assert(__builtin_stdc_has_single_bit((unsigned _BitInt(37))0x10) == 1, "");
+_Static_assert(__builtin_stdc_bit_width((unsigned _BitInt(37))0x10) == 5, "");
+_Static_assert(__builtin_stdc_bit_floor((unsigned _BitInt(37))0x1F) == 0x10, "");
+_Static_assert(__builtin_stdc_bit_ceil((unsigned _BitInt(37))0x11) == 0x20, "");
+
+// Test with __int128
+_Static_assert(__builtin_stdc_leading_zeros((unsigned __int128)0) == 128, "");
+_Static_assert(__builtin_stdc_leading_zeros((unsigned __int128)1) == 127, "");
+_Static_assert(__builtin_stdc_trailing_zeros((unsigned __int128)0) == 128, "");
+_Static_assert(__builtin_stdc_count_ones((unsigned __int128)0xFFFFFFFF) == 32, "");
+_Static_assert(__builtin_stdc_has_single_bit((unsigned __int128)1) == 1, "");
+_Static_assert(__builtin_stdc_bit_width((unsigned __int128)1) == 1, "");
+
+// Error cases
+void test_errors(int si, float f) {
+ unsigned int ui = 5;
+
+ __builtin_stdc_leading_zeros(si); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
+ __builtin_stdc_leading_zeros(f); // expected-error {{1st argument must be a scalar unsigned integer type (was 'float')}}
+ __builtin_stdc_leading_zeros(-1); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
+
+ __builtin_stdc_count_ones(si); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
+ __builtin_stdc_has_single_bit(si); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
+ __builtin_stdc_bit_ceil(si); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
+}
diff --git a/clang/test/SemaCXX/constexpr-builtin-stdc-bit-functions.cpp b/clang/test/SemaCXX/constexpr-builtin-stdc-bit-functions.cpp
new file mode 100644
index 0000000000000..635ff6b4347f3
--- /dev/null
+++ b/clang/test/SemaCXX/constexpr-builtin-stdc-bit-functions.cpp
@@ -0,0 +1,242 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -std=c++14 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -std=c++14 -fsyntax-only -verify %s -fexperimental-new-constant-interpreter
+
+namespace test_stdc_leading_zeros {
+
+static_assert(__builtin_stdc_leading_zeros((unsigned char)0) == 8, "");
+static_assert(__builtin_stdc_leading_zeros((unsigned char)1) == 7, "");
+static_assert(__builtin_stdc_leading_zeros((unsigned char)0x80) == 0, "");
+static_assert(__builtin_stdc_leading_zeros((unsigned char)0xFF) == 0, "");
+static_assert(__builtin_stdc_leading_zeros((unsigned short)0) == 16, "");
+static_assert(__builtin_stdc_leading_zeros((unsigned short)0x8000) == 0, "");
+static_assert(__builtin_stdc_leading_zeros(0U) == 32, "");
+static_assert(__builtin_stdc_leading_zeros(1U) == 31, "");
+static_assert(__builtin_stdc_leading_zeros(0x80000000U) == 0, "");
+static_assert(__builtin_stdc_leading_zeros(0ULL) == 64, "");
+static_assert(__builtin_stdc_leading_zeros(1ULL) == 63, "");
+static_assert(__builtin_stdc_leading_zeros(0x8000000000000000ULL) == 0, "");
+
+} // namespace test_stdc_leading_zeros
+
+namespace test_stdc_leading_ones {
+
+static_assert(__builtin_stdc_leading_ones((unsigned char)0) == 0, "");
+static_assert(__builtin_stdc_leading_ones((unsigned char)0xFF) == 8, "");
+static_assert(__builtin_stdc_leading_ones((unsigned char)0xF0) == 4, "");
+static_assert(__builtin_stdc_leading_ones((unsigned short)0xFFFF) == 16, "");
+static_assert(__builtin_stdc_leading_ones(0xFFFFFFFFU) == 32, "");
+static_assert(__builtin_stdc_leading_ones(0xF0000000U) == 4, "");
+static_assert(__builtin_stdc_leading_ones(0xFFFFFFFFFFFFFFFFULL) == 64, "");
+
+} // namespace test_stdc_leading_ones
+
+namespace test_stdc_trailing_zeros {
+
+static_assert(__builtin_stdc_trailing_zeros((unsigned char)0) == 8, "");
+static_assert(__builtin_stdc_trailing_zeros((unsigned char)1) == 0, "");
+static_assert(__builtin_stdc_trailing_zeros((unsigned char)0x80) == 7, "");
+static_assert(__builtin_stdc_trailing_zeros((unsigned short)0) == 16, "");
+static_assert(__builtin_stdc_trailing_zeros(0U) == 32, "");
+static_assert(__builtin_stdc_trailing_zeros(0x80000000U) == 31, "");
+static_assert(__builtin_stdc_trailing_zeros(0ULL) == 64, "");
+static_assert(__builtin_stdc_trailing_zeros(0x8000000000000000ULL) == 63, "");
+
+} // namespace test_stdc_trailing_zeros
+
+namespace test_stdc_trailing_ones {
+
+static_assert(__builtin_stdc_trailing_ones((unsigned char)0) == 0, "");
+static_assert(__builtin_stdc_trailing_ones((unsigned char)0xFF) == 8, "");
+static_assert(__builtin_stdc_trailing_ones((unsigned char)0x0F) == 4, "");
+static_assert(__builtin_stdc_trailing_ones(0xFFFFFFFFU) == 32, "");
+static_assert(__builtin_stdc_trailing_ones(0x0000000FU) == 4, "");
+static_assert(__builtin_stdc_trailing_ones(0xFFFFFFFFFFFFFFFFULL) == 64, "");
+
+} // namespace test_stdc_trailing_ones
+
+namespace test_stdc_first_leading_zero {
+
+static_assert(__builtin_stdc_first_leading_zero((unsigned char)0) == 1, "");
+static_assert(__builtin_stdc_first_leading_zero((unsigned char)0xFF) == 0, "");
+static_assert(__builtin_stdc_first_leading_zero((unsigned char)0xF0) == 5, "");
+static_assert(__builtin_stdc_first_leading_zero((unsigned char)0x80) == 2, "");
+static_assert(__builtin_stdc_first_leading_zero(0xFFFFFFFFU) == 0, "");
+static_assert(__builtin_stdc_first_leading_zero(0xF0000000U) == 5, "");
+
+} // namespace test_stdc_first_leading_zero
+
+namespace test_stdc_first_leading_one {
+
+static_assert(__builtin_stdc_first_leading_one((unsigned char)0) == 0, "");
+static_assert(__builtin_stdc_first_leading_one((unsigned char)0x80) == 1, "");
+static_assert(__builtin_stdc_first_leading_one((unsigned char)0x01) == 8, "");
+static_assert(__builtin_stdc_first_leading_one((unsigned char)0x0F) == 5, "");
+static_assert(__builtin_stdc_first_leading_one(0U) == 0, "");
+static_assert(__builtin_stdc_first_leading_one(0x80000000U) == 1, "");
+static_assert(__builtin_stdc_first_leading_one(1U) == 32, "");
+
+} // namespace test_stdc_first_leading_one
+
+namespace test_stdc_first_trailing_zero {
+
+static_assert(__builtin_stdc_first_trailing_zero((unsigned char)0) == 1, "");
+static_assert(__builtin_stdc_first_trailing_zero((unsigned char)0xFF) == 0, "");
+static_assert(__builtin_stdc_first_trailing_zero((unsigned char)0x0F) == 5, "");
+static_assert(__builtin_stdc_first_trailing_zero((unsigned char)0x01) == 2, "");
+static_assert(__builtin_stdc_first_trailing_zero(0xFFFFFFFFU) == 0, "");
+static_assert(__builtin_stdc_first_trailing_zero(0x0000000FU) == 5, "");
+
+} // namespace test_stdc_first_trailing_zero
+
+namespace test_stdc_first_trailing_one {
+
+static_assert(__builtin_stdc_first_trailing_one((unsigned char)0) == 0, "");
+static_assert(__builtin_stdc_first_trailing_one((unsigned char)0x01) == 1, "");
+static_assert(__builtin_stdc_first_trailing_one((unsigned char)0x80) == 8, "");
+static_assert(__builtin_stdc_first_trailing_one((unsigned char)0xF0) == 5, "");
+static_assert(__builtin_stdc_first_trailing_one(0U) == 0, "");
+static_assert(__builtin_stdc_first_trailing_one(0x80000000U) == 32, "");
+static_assert(__builtin_stdc_first_trailing_one(1U) == 1, "");
+
+} // namespace test_stdc_first_trailing_one
+
+namespace test_stdc_count_zeros {
+
+static_assert(__builtin_stdc_count_zeros((unsigned char)0) == 8, "");
+static_assert(__builtin_stdc_count_zeros((unsigned char)0xFF) == 0, "");
+static_assert(__builtin_stdc_count_zeros((unsigned char)0xAA) == 4, "");
+static_assert(__builtin_stdc_count_zeros(0U) == 32, "");
+static_assert(__builtin_stdc_count_zeros(0xFFFFFFFFU) == 0, "");
+static_assert(__builtin_stdc_count_zeros(0xAAAAAAAAU) == 16, "");
+
+} // namespace test_stdc_count_zeros
+
+namespace test_stdc_count_ones {
+
+static_assert(__builtin_stdc_count_ones((unsigned char)0) == 0, "");
+static_assert(__builtin_stdc_count_ones((unsigned char)0xFF) == 8, "");
+static_assert(__builtin_stdc_count_ones((unsigned char)0xAA) == 4, "");
+static_assert(__builtin_stdc_count_ones(0U) == 0, "");
+static_assert(__builtin_stdc_count_ones(0xFFFFFFFFU) == 32, "");
+static_assert(__builtin_stdc_count_ones(0xAAAAAAAAU) == 16, "");
+
+} // namespace test_stdc_count_ones
+
+namespace test_stdc_has_single_bit {
+
+static_assert(__builtin_stdc_has_single_bit((unsigned char)0) == 0, "");
+static_assert(__builtin_stdc_has_single_bit((unsigned char)1) == 1, "");
+static_assert(__builtin_stdc_has_single_bit((unsigned char)2) == 1, "");
+static_assert(__builtin_stdc_has_single_bit((unsigned char)3) == 0, "");
+static_assert(__builtin_stdc_has_single_bit((unsigned char)0x80) == 1, "");
+static_assert(__builtin_stdc_has_single_bit(0U) == 0, "");
+static_assert(__builtin_stdc_has_single_bit(1U) == 1, "");
+static_assert(__builtin_stdc_has_single_bit(0x80000000U) == 1, "");
+static_assert(__builtin_stdc_has_single_bit(0xFFFFFFFFU) == 0, "");
+
+} // namespace test_stdc_has_single_bit
+
+namespace test_stdc_bit_width {
+
+static_assert(__builtin_stdc_bit_width((unsigned char)0) == 0, "");
+static_assert(__builtin_stdc_bit_width((unsigned char)1) == 1, "");
+static_assert(__builtin_stdc_bit_width((unsigned char)2) == 2, "");
+static_assert(__builtin_stdc_bit_width((unsigned char)3) == 2, "");
+static_assert(__builtin_stdc_bit_width((unsigned char)0x80) == 8, "");
+static_assert(__builtin_stdc_bit_width((unsigned char)0xFF) == 8, "");
+static_assert(__builtin_stdc_bit_width(0U) == 0, "");
+static_assert(__builtin_stdc_bit_width(1U) == 1, "");
+static_assert(__builtin_stdc_bit_width(0x80000000U) == 32, "");
+
+} // namespace test_stdc_bit_width
+
+namespace test_stdc_bit_floor {
+
+static_assert(__builtin_stdc_bit_floor((unsigned char)0) == 0, "");
+static_assert(__builtin_stdc_bit_floor((unsigned char)1) == 1, "");
+static_assert(__builtin_stdc_bit_floor((unsigned char)2) == 2, "");
+static_assert(__builtin_stdc_bit_floor((unsigned char)3) == 2, "");
+static_assert(__builtin_stdc_bit_floor((unsigned char)4) == 4, "");
+static_assert(__builtin_stdc_bit_floor((unsigned char)5) == 4, "");
+static_assert(__builtin_stdc_bit_floor((unsigned char)0x80) == 0x80, "");
+static_assert(__builtin_stdc_bit_floor((unsigned char)0xFF) == 0x80, "");
+static_assert(__builtin_stdc_bit_floor(0U) == 0U, "");
+static_assert(__builtin_stdc_bit_floor(1U) == 1U, "");
+static_assert(__builtin_stdc_bit_floor(7U) == 4U, "");
+static_assert(__builtin_stdc_bit_floor(0x80000000U) == 0x80000000U, "");
+static_assert(__builtin_stdc_bit_floor(0xFFFFFFFFU) == 0x80000000U, "");
+
+} // namespace test_stdc_bit_floor
+
+namespace test_stdc_bit_ceil {
+
+static_assert(__builtin_stdc_bit_ceil((unsigned char)0) == 1, "");
+static_assert(__builtin_stdc_bit_ceil((unsigned char)1) == 1, "");
+static_assert(__builtin_stdc_bit_ceil((unsigned char)2) == 2, "");
+static_assert(__builtin_stdc_bit_ceil((unsigned char)3) == 4, "");
+static_assert(__builtin_stdc_bit_ceil((unsigned char)4) == 4, "");
+static_assert(__builtin_stdc_bit_ceil((unsigned char)5) == 8, "");
+static_assert(__builtin_stdc_bit_ceil((unsigned char)0x80) == 0x80, "");
+static_assert(__builtin_stdc_bit_ceil(0U) == 1U, "");
+static_assert(__builtin_stdc_bit_ceil(1U) == 1U, "");
+static_assert(__builtin_stdc_bit_ceil(7U) == 8U, "");
+static_assert(__builtin_stdc_bit_ceil(0x80000000U) == 0x80000000U, "");
+static_assert(__builtin_stdc_bit_ceil(0xFFFFFFFFU) == 0xFFFFFFFFU, "");
+
+} // namespace test_stdc_bit_ceil
+
+namespace test_int128 {
+
+static_assert(__builtin_stdc_leading_zeros((unsigned __int128)0) == 128, "");
+static_assert(__builtin_stdc_leading_zeros((unsigned __int128)1) == 127, "");
+static_assert(__builtin_stdc_trailing_zeros((unsigned __int128)0) == 128, "");
+static_assert(__builtin_stdc_count_ones((unsigned __int128)0xFFFFFFFF) == 32, "");
+static_assert(__builtin_stdc_has_single_bit((unsigned __int128)1) == 1, "");
+static_assert(__builtin_stdc_bit_width((unsigned __int128)1) == 1, "");
+
+constexpr unsigned __int128 int128_one = 1;
+constexpr unsigned __int128 int128_msb = int128_one << 127;
+static_assert(__builtin_stdc_leading_zeros(int128_msb) == 0, "");
+static_assert(__builtin_stdc_trailing_zeros(int128_msb) == 127, "");
+static_assert(__builtin_stdc_has_single_bit(int128_msb) == 1, "");
+static_assert(__builtin_stdc_bit_width(int128_msb) == 128, "");
+static_assert(__builtin_stdc_bit_floor(int128_msb) == int128_msb, "");
+
+} // namespace test_int128
+
+namespace test_bitint {
+
+static_assert(__builtin_stdc_leading_zeros((unsigned _BitInt(37))0) == 37, "");
+static_assert(__builtin_stdc_leading_zeros((unsigned _BitInt(37))1) == 36, "");
+static_assert(__builtin_stdc_trailing_zeros((unsigned _BitInt(37))0) == 37, "");
+static_assert(__builtin_stdc_count_ones((unsigned _BitInt(37))0x1F) == 5, "");
+static_assert(__builtin_stdc_has_single_bit((unsigned _BitInt(37))0x10) == 1, "");
+static_assert(__builtin_stdc_bit_width((unsigned _BitInt(37))0x10) == 5, "");
+static_assert(__builtin_stdc_bit_floor((unsigned _BitInt(37))0x1F) == 0x10, "");
+static_assert(__builtin_stdc_bit_ceil((unsigned _BitInt(37))0x11) == 0x20, "");
+static_assert(__builtin_stdc_bit_ceil((unsigned _BitInt(17))(-1)) ==
+ (unsigned _BitInt(17))(-1), "");
+
+constexpr unsigned _BitInt(128) bi128_pattern = 0x123456789ABCDEF0ULL;
+static_assert(__builtin_stdc_count_ones(bi128_pattern) == 32, "");
+static_assert(__builtin_stdc_leading_zeros(bi128_pattern) == 67, "");
+
+static_assert(__builtin_stdc_leading_zeros((unsigned _BitInt(9))0) == 9, "");
+static_assert(__builtin_stdc_trailing_zeros((unsigned _BitInt(9))0x100) == 8, "");
+static_assert(__builtin_stdc_count_ones((unsigned _BitInt(9))0x1FF) == 9, "");
+
+} // namespace test_bitint
+
+namespace test_errors {
+
+void test_invalid_types(int si, float f) {
+ __builtin_stdc_leading_zeros(si); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
+ __builtin_stdc_leading_zeros(f); // expected-error {{1st argument must be a scalar unsigned integer type (was 'float')}}
+ __builtin_stdc_leading_zeros(-1); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
+
+ __builtin_stdc_count_ones(si); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
+ __builtin_stdc_has_single_bit(si); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
+ __builtin_stdc_bit_ceil(si); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
+}
+
+} // namespace test_errors
>From 5ea33647f22718828998a9581c32a3461087977f Mon Sep 17 00:00:00 2001
From: NagaChaitanya Vellanki <pnagato at protonmail.com>
Date: Wed, 25 Feb 2026 11:30:26 -0800
Subject: [PATCH 02/14] Add more tests for the builtins
---
.../test/CodeGen/builtin-stdc-bit-functions.c | 104 +++++++-
clang/test/Sema/builtin-stdc-bit-functions.c | 219 ++++++++++++++++-
.../constexpr-builtin-stdc-bit-functions.cpp | 230 +++++++++++++++++-
3 files changed, 533 insertions(+), 20 deletions(-)
diff --git a/clang/test/CodeGen/builtin-stdc-bit-functions.c b/clang/test/CodeGen/builtin-stdc-bit-functions.c
index 1be9f3e640285..7687510b52321 100644
--- a/clang/test/CodeGen/builtin-stdc-bit-functions.c
+++ b/clang/test/CodeGen/builtin-stdc-bit-functions.c
@@ -64,41 +64,61 @@ void test_trailing_ones(unsigned char uc, unsigned short us, unsigned int ui, un
// CHECK-LABEL: test_first_leading_zero
// CHECK: xor i8 %{{.*}}, -1
// CHECK: call i8 @llvm.ctlz.i8(i8 %{{.*}}, i1 false)
+// CHECK: xor i16 %{{.*}}, -1
+// CHECK: call i16 @llvm.ctlz.i16(i16 %{{.*}}, i1 false)
// CHECK: xor i32 %{{.*}}, -1
// CHECK: call i32 @llvm.ctlz.i32(i32 %{{.*}}, i1 false)
-void test_first_leading_zero(unsigned char uc, unsigned int ui) {
+// CHECK: xor i64 %{{.*}}, -1
+// CHECK: call i64 @llvm.ctlz.i64(i64 %{{.*}}, i1 false)
+void test_first_leading_zero(unsigned char uc, unsigned short us, unsigned int ui, unsigned long long ull) {
volatile int r;
r = __builtin_stdc_first_leading_zero(uc);
+ r = __builtin_stdc_first_leading_zero(us);
r = __builtin_stdc_first_leading_zero(ui);
+ r = __builtin_stdc_first_leading_zero(ull);
}
// CHECK-LABEL: test_first_leading_one
// CHECK: call i8 @llvm.ctlz.i8(i8 %{{.*}}, i1 false)
+// CHECK: call i16 @llvm.ctlz.i16(i16 %{{.*}}, i1 false)
// CHECK: call i32 @llvm.ctlz.i32(i32 %{{.*}}, i1 false)
-void test_first_leading_one(unsigned char uc, unsigned int ui) {
+// CHECK: call i64 @llvm.ctlz.i64(i64 %{{.*}}, i1 false)
+void test_first_leading_one(unsigned char uc, unsigned short us, unsigned int ui, unsigned long long ull) {
volatile int r;
r = __builtin_stdc_first_leading_one(uc);
+ r = __builtin_stdc_first_leading_one(us);
r = __builtin_stdc_first_leading_one(ui);
+ r = __builtin_stdc_first_leading_one(ull);
}
// CHECK-LABEL: test_first_trailing_zero
// CHECK: xor i8 %{{.*}}, -1
// CHECK: call i8 @llvm.cttz.i8(i8 %{{.*}}, i1 false)
+// CHECK: xor i16 %{{.*}}, -1
+// CHECK: call i16 @llvm.cttz.i16(i16 %{{.*}}, i1 false)
// CHECK: xor i32 %{{.*}}, -1
// CHECK: call i32 @llvm.cttz.i32(i32 %{{.*}}, i1 false)
-void test_first_trailing_zero(unsigned char uc, unsigned int ui) {
+// CHECK: xor i64 %{{.*}}, -1
+// CHECK: call i64 @llvm.cttz.i64(i64 %{{.*}}, i1 false)
+void test_first_trailing_zero(unsigned char uc, unsigned short us, unsigned int ui, unsigned long long ull) {
volatile int r;
r = __builtin_stdc_first_trailing_zero(uc);
+ r = __builtin_stdc_first_trailing_zero(us);
r = __builtin_stdc_first_trailing_zero(ui);
+ r = __builtin_stdc_first_trailing_zero(ull);
}
// CHECK-LABEL: test_first_trailing_one
// CHECK: call i8 @llvm.cttz.i8(i8 %{{.*}}, i1 false)
+// CHECK: call i16 @llvm.cttz.i16(i16 %{{.*}}, i1 false)
// CHECK: call i32 @llvm.cttz.i32(i32 %{{.*}}, i1 false)
-void test_first_trailing_one(unsigned char uc, unsigned int ui) {
+// CHECK: call i64 @llvm.cttz.i64(i64 %{{.*}}, i1 false)
+void test_first_trailing_one(unsigned char uc, unsigned short us, unsigned int ui, unsigned long long ull) {
volatile int r;
r = __builtin_stdc_first_trailing_one(uc);
+ r = __builtin_stdc_first_trailing_one(us);
r = __builtin_stdc_first_trailing_one(ui);
+ r = __builtin_stdc_first_trailing_one(ull);
}
// CHECK-LABEL: test_count_zeros
@@ -129,40 +149,60 @@ void test_count_ones(unsigned char uc, unsigned short us, unsigned int ui, unsig
// CHECK-LABEL: test_has_single_bit
// CHECK: call i8 @llvm.ctpop.i8(i8 %{{.*}})
+// CHECK: call i16 @llvm.ctpop.i16(i16 %{{.*}})
// CHECK: call i32 @llvm.ctpop.i32(i32 %{{.*}})
-void test_has_single_bit(unsigned char uc, unsigned int ui) {
+// CHECK: call i64 @llvm.ctpop.i64(i64 %{{.*}})
+void test_has_single_bit(unsigned char uc, unsigned short us, unsigned int ui, unsigned long long ull) {
volatile int r;
r = __builtin_stdc_has_single_bit(uc);
+ r = __builtin_stdc_has_single_bit(us);
r = __builtin_stdc_has_single_bit(ui);
+ r = __builtin_stdc_has_single_bit(ull);
}
// CHECK-LABEL: test_bit_width
// CHECK: call i8 @llvm.ctlz.i8(i8 %{{.*}}, i1 false)
+// CHECK: call i16 @llvm.ctlz.i16(i16 %{{.*}}, i1 false)
// CHECK: call i32 @llvm.ctlz.i32(i32 %{{.*}}, i1 false)
-void test_bit_width(unsigned char uc, unsigned int ui) {
+// CHECK: call i64 @llvm.ctlz.i64(i64 %{{.*}}, i1 false)
+void test_bit_width(unsigned char uc, unsigned short us, unsigned int ui, unsigned long long ull) {
volatile int r;
r = __builtin_stdc_bit_width(uc);
+ r = __builtin_stdc_bit_width(us);
r = __builtin_stdc_bit_width(ui);
+ r = __builtin_stdc_bit_width(ull);
}
// CHECK-LABEL: test_bit_floor
// CHECK: call i8 @llvm.ctlz.i8(i8 %{{.*}}, i1 false)
+// CHECK: call i16 @llvm.ctlz.i16(i16 %{{.*}}, i1 false)
// CHECK: call i32 @llvm.ctlz.i32(i32 %{{.*}}, i1 false)
-void test_bit_floor(unsigned char uc, unsigned int ui) {
+// CHECK: call i64 @llvm.ctlz.i64(i64 %{{.*}}, i1 false)
+void test_bit_floor(unsigned char uc, unsigned short us, unsigned int ui, unsigned long long ull) {
volatile unsigned char rc;
+ volatile unsigned short rs;
volatile unsigned int ri;
+ volatile unsigned long long rll;
rc = __builtin_stdc_bit_floor(uc);
+ rs = __builtin_stdc_bit_floor(us);
ri = __builtin_stdc_bit_floor(ui);
+ rll = __builtin_stdc_bit_floor(ull);
}
// CHECK-LABEL: test_bit_ceil
// CHECK: call i8 @llvm.ctlz.i8(i8 %{{.*}}, i1 false)
+// CHECK: call i16 @llvm.ctlz.i16(i16 %{{.*}}, i1 false)
// CHECK: call i32 @llvm.ctlz.i32(i32 %{{.*}}, i1 false)
-void test_bit_ceil(unsigned char uc, unsigned int ui) {
+// CHECK: call i64 @llvm.ctlz.i64(i64 %{{.*}}, i1 false)
+void test_bit_ceil(unsigned char uc, unsigned short us, unsigned int ui, unsigned long long ull) {
volatile unsigned char rc;
+ volatile unsigned short rs;
volatile unsigned int ri;
+ volatile unsigned long long rll;
rc = __builtin_stdc_bit_ceil(uc);
+ rs = __builtin_stdc_bit_ceil(us);
ri = __builtin_stdc_bit_ceil(ui);
+ rll = __builtin_stdc_bit_ceil(ull);
}
// Test with _BitInt types
@@ -236,4 +276,52 @@ void test_int128(unsigned __int128 u128) {
r = __builtin_stdc_trailing_zeros(u128);
r = __builtin_stdc_count_ones(u128);
}
+
+// INT128-LABEL: test_int128_leading_trailing_ones
+// INT128: xor i128 %{{.*}}, -1
+// INT128: call i128 @llvm.ctlz.i128(i128 %{{.*}}, i1 false)
+// INT128: xor i128 %{{.*}}, -1
+// INT128: call i128 @llvm.cttz.i128(i128 %{{.*}}, i1 false)
+void test_int128_leading_trailing_ones(unsigned __int128 u128) {
+ volatile int r;
+ r = __builtin_stdc_leading_ones(u128);
+ r = __builtin_stdc_trailing_ones(u128);
+}
+
+// INT128-LABEL: test_int128_first
+// INT128: xor i128 %{{.*}}, -1
+// INT128: call i128 @llvm.ctlz.i128(i128 %{{.*}}, i1 false)
+// INT128: call i128 @llvm.ctlz.i128(i128 %{{.*}}, i1 false)
+// INT128: xor i128 %{{.*}}, -1
+// INT128: call i128 @llvm.cttz.i128(i128 %{{.*}}, i1 false)
+// INT128: call i128 @llvm.cttz.i128(i128 %{{.*}}, i1 false)
+void test_int128_first(unsigned __int128 u128) {
+ volatile int r;
+ r = __builtin_stdc_first_leading_zero(u128);
+ r = __builtin_stdc_first_leading_one(u128);
+ r = __builtin_stdc_first_trailing_zero(u128);
+ r = __builtin_stdc_first_trailing_one(u128);
+}
+
+// INT128-LABEL: test_int128_count_has_width
+// INT128: call i128 @llvm.ctpop.i128(i128 %{{.*}})
+// INT128: call i128 @llvm.ctpop.i128(i128 %{{.*}})
+// INT128: call i128 @llvm.ctpop.i128(i128 %{{.*}})
+// INT128: call i128 @llvm.ctlz.i128(i128 %{{.*}}, i1 false)
+void test_int128_count_has_width(unsigned __int128 u128) {
+ volatile int r;
+ r = __builtin_stdc_count_zeros(u128);
+ r = __builtin_stdc_count_ones(u128);
+ r = __builtin_stdc_has_single_bit(u128);
+ r = __builtin_stdc_bit_width(u128);
+}
+
+// INT128-LABEL: test_int128_floor_ceil
+// INT128: call i128 @llvm.ctlz.i128(i128 %{{.*}}, i1 false)
+// INT128: call i128 @llvm.ctlz.i128(i128 %{{.*}}, i1 false)
+void test_int128_floor_ceil(unsigned __int128 u128) {
+ volatile unsigned __int128 r;
+ r = __builtin_stdc_bit_floor(u128);
+ r = __builtin_stdc_bit_ceil(u128);
+}
#endif
diff --git a/clang/test/Sema/builtin-stdc-bit-functions.c b/clang/test/Sema/builtin-stdc-bit-functions.c
index aa440e2ea6eb9..92fdef352de1c 100644
--- a/clang/test/Sema/builtin-stdc-bit-functions.c
+++ b/clang/test/Sema/builtin-stdc-bit-functions.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fsyntax-only -verify %s
+// RUN: %if clang-target-64-bits %{ %clang_cc1 -fsyntax-only -verify %s %}
// Test stdc_leading_zeros
_Static_assert(__builtin_stdc_leading_zeros((unsigned char)0) == 8, "");
@@ -6,10 +7,14 @@ _Static_assert(__builtin_stdc_leading_zeros((unsigned char)1) == 7, "");
_Static_assert(__builtin_stdc_leading_zeros((unsigned char)0x80) == 0, "");
_Static_assert(__builtin_stdc_leading_zeros((unsigned char)0xFF) == 0, "");
_Static_assert(__builtin_stdc_leading_zeros((unsigned short)0) == 16, "");
+_Static_assert(__builtin_stdc_leading_zeros((unsigned short)1) == 15, "");
_Static_assert(__builtin_stdc_leading_zeros((unsigned short)0x8000) == 0, "");
_Static_assert(__builtin_stdc_leading_zeros(0U) == 32, "");
_Static_assert(__builtin_stdc_leading_zeros(1U) == 31, "");
_Static_assert(__builtin_stdc_leading_zeros(0x80000000U) == 0, "");
+_Static_assert(__builtin_stdc_leading_zeros(0UL) == 64, "");
+_Static_assert(__builtin_stdc_leading_zeros(1UL) == 63, "");
+_Static_assert(__builtin_stdc_leading_zeros(0x8000000000000000UL) == 0, "");
_Static_assert(__builtin_stdc_leading_zeros(0ULL) == 64, "");
_Static_assert(__builtin_stdc_leading_zeros(1ULL) == 63, "");
_Static_assert(__builtin_stdc_leading_zeros(0x8000000000000000ULL) == 0, "");
@@ -18,9 +23,16 @@ _Static_assert(__builtin_stdc_leading_zeros(0x8000000000000000ULL) == 0, "");
_Static_assert(__builtin_stdc_leading_ones((unsigned char)0) == 0, "");
_Static_assert(__builtin_stdc_leading_ones((unsigned char)0xFF) == 8, "");
_Static_assert(__builtin_stdc_leading_ones((unsigned char)0xF0) == 4, "");
+_Static_assert(__builtin_stdc_leading_ones((unsigned short)0) == 0, "");
_Static_assert(__builtin_stdc_leading_ones((unsigned short)0xFFFF) == 16, "");
+_Static_assert(__builtin_stdc_leading_ones((unsigned short)0xF000) == 4, "");
+_Static_assert(__builtin_stdc_leading_ones(0U) == 0, "");
_Static_assert(__builtin_stdc_leading_ones(0xFFFFFFFFU) == 32, "");
_Static_assert(__builtin_stdc_leading_ones(0xF0000000U) == 4, "");
+_Static_assert(__builtin_stdc_leading_ones(0UL) == 0, "");
+_Static_assert(__builtin_stdc_leading_ones(0xFFFFFFFFFFFFFFFFUL) == 64, "");
+_Static_assert(__builtin_stdc_leading_ones(0xF000000000000000UL) == 4, "");
+_Static_assert(__builtin_stdc_leading_ones(0ULL) == 0, "");
_Static_assert(__builtin_stdc_leading_ones(0xFFFFFFFFFFFFFFFFULL) == 64, "");
// Test stdc_trailing_zeros
@@ -28,17 +40,34 @@ _Static_assert(__builtin_stdc_trailing_zeros((unsigned char)0) == 8, "");
_Static_assert(__builtin_stdc_trailing_zeros((unsigned char)1) == 0, "");
_Static_assert(__builtin_stdc_trailing_zeros((unsigned char)0x80) == 7, "");
_Static_assert(__builtin_stdc_trailing_zeros((unsigned short)0) == 16, "");
+_Static_assert(__builtin_stdc_trailing_zeros((unsigned short)1) == 0, "");
+_Static_assert(__builtin_stdc_trailing_zeros((unsigned short)0x8000) == 15, "");
_Static_assert(__builtin_stdc_trailing_zeros(0U) == 32, "");
+_Static_assert(__builtin_stdc_trailing_zeros(1U) == 0, "");
_Static_assert(__builtin_stdc_trailing_zeros(0x80000000U) == 31, "");
+_Static_assert(__builtin_stdc_trailing_zeros(0UL) == 64, "");
+_Static_assert(__builtin_stdc_trailing_zeros(1UL) == 0, "");
+_Static_assert(__builtin_stdc_trailing_zeros(0x8000000000000000UL) == 63, "");
_Static_assert(__builtin_stdc_trailing_zeros(0ULL) == 64, "");
+_Static_assert(__builtin_stdc_trailing_zeros(1ULL) == 0, "");
_Static_assert(__builtin_stdc_trailing_zeros(0x8000000000000000ULL) == 63, "");
// Test stdc_trailing_ones
_Static_assert(__builtin_stdc_trailing_ones((unsigned char)0) == 0, "");
_Static_assert(__builtin_stdc_trailing_ones((unsigned char)0xFF) == 8, "");
_Static_assert(__builtin_stdc_trailing_ones((unsigned char)0x0F) == 4, "");
+_Static_assert(__builtin_stdc_trailing_ones((unsigned short)0) == 0, "");
+_Static_assert(__builtin_stdc_trailing_ones((unsigned short)0xFFFF) == 16, "");
+_Static_assert(__builtin_stdc_trailing_ones((unsigned short)0x000F) == 4, "");
+_Static_assert(__builtin_stdc_trailing_ones(0U) == 0, "");
+_Static_assert(__builtin_stdc_trailing_ones(1U) == 1, "");
_Static_assert(__builtin_stdc_trailing_ones(0xFFFFFFFFU) == 32, "");
_Static_assert(__builtin_stdc_trailing_ones(0x0000000FU) == 4, "");
+_Static_assert(__builtin_stdc_trailing_ones(0UL) == 0, "");
+_Static_assert(__builtin_stdc_trailing_ones(0xFFFFFFFFFFFFFFFFUL) == 64, "");
+_Static_assert(__builtin_stdc_trailing_ones(0x000000000000000FUL) == 4, "");
+_Static_assert(__builtin_stdc_trailing_ones(0ULL) == 0, "");
+_Static_assert(__builtin_stdc_trailing_ones(1ULL) == 1, "");
_Static_assert(__builtin_stdc_trailing_ones(0xFFFFFFFFFFFFFFFFULL) == 64, "");
// Test stdc_first_leading_zero
@@ -46,50 +75,104 @@ _Static_assert(__builtin_stdc_first_leading_zero((unsigned char)0) == 1, "");
_Static_assert(__builtin_stdc_first_leading_zero((unsigned char)0xFF) == 0, "");
_Static_assert(__builtin_stdc_first_leading_zero((unsigned char)0xF0) == 5, "");
_Static_assert(__builtin_stdc_first_leading_zero((unsigned char)0x80) == 2, "");
+_Static_assert(__builtin_stdc_first_leading_zero((unsigned short)0) == 1, "");
+_Static_assert(__builtin_stdc_first_leading_zero((unsigned short)0xFFFF) == 0, "");
+_Static_assert(__builtin_stdc_first_leading_zero((unsigned short)0xF000) == 5, "");
_Static_assert(__builtin_stdc_first_leading_zero(0xFFFFFFFFU) == 0, "");
_Static_assert(__builtin_stdc_first_leading_zero(0xF0000000U) == 5, "");
+_Static_assert(__builtin_stdc_first_leading_zero(0UL) == 1, "");
+_Static_assert(__builtin_stdc_first_leading_zero(0xFFFFFFFFFFFFFFFFUL) == 0, "");
+_Static_assert(__builtin_stdc_first_leading_zero(0xF000000000000000UL) == 5, "");
+_Static_assert(__builtin_stdc_first_leading_zero(0ULL) == 1, "");
+_Static_assert(__builtin_stdc_first_leading_zero(0xFFFFFFFFFFFFFFFFULL) == 0, "");
+_Static_assert(__builtin_stdc_first_leading_zero(0xF000000000000000ULL) == 5, "");
// Test stdc_first_leading_one
_Static_assert(__builtin_stdc_first_leading_one((unsigned char)0) == 0, "");
_Static_assert(__builtin_stdc_first_leading_one((unsigned char)0x80) == 1, "");
_Static_assert(__builtin_stdc_first_leading_one((unsigned char)0x01) == 8, "");
_Static_assert(__builtin_stdc_first_leading_one((unsigned char)0x0F) == 5, "");
+_Static_assert(__builtin_stdc_first_leading_one((unsigned short)0) == 0, "");
+_Static_assert(__builtin_stdc_first_leading_one((unsigned short)0x8000) == 1, "");
+_Static_assert(__builtin_stdc_first_leading_one((unsigned short)1) == 16, "");
_Static_assert(__builtin_stdc_first_leading_one(0U) == 0, "");
_Static_assert(__builtin_stdc_first_leading_one(0x80000000U) == 1, "");
_Static_assert(__builtin_stdc_first_leading_one(1U) == 32, "");
+_Static_assert(__builtin_stdc_first_leading_one(0UL) == 0, "");
+_Static_assert(__builtin_stdc_first_leading_one(0x8000000000000000UL) == 1, "");
+_Static_assert(__builtin_stdc_first_leading_one(1UL) == 64, "");
+_Static_assert(__builtin_stdc_first_leading_one(0ULL) == 0, "");
+_Static_assert(__builtin_stdc_first_leading_one(0x8000000000000000ULL) == 1, "");
+_Static_assert(__builtin_stdc_first_leading_one(1ULL) == 64, "");
// Test stdc_first_trailing_zero
_Static_assert(__builtin_stdc_first_trailing_zero((unsigned char)0) == 1, "");
_Static_assert(__builtin_stdc_first_trailing_zero((unsigned char)0xFF) == 0, "");
_Static_assert(__builtin_stdc_first_trailing_zero((unsigned char)0x0F) == 5, "");
_Static_assert(__builtin_stdc_first_trailing_zero((unsigned char)0x01) == 2, "");
+_Static_assert(__builtin_stdc_first_trailing_zero((unsigned short)0) == 1, "");
+_Static_assert(__builtin_stdc_first_trailing_zero((unsigned short)0xFFFF) == 0, "");
+_Static_assert(__builtin_stdc_first_trailing_zero((unsigned short)0x000F) == 5, "");
_Static_assert(__builtin_stdc_first_trailing_zero(0xFFFFFFFFU) == 0, "");
_Static_assert(__builtin_stdc_first_trailing_zero(0x0000000FU) == 5, "");
+_Static_assert(__builtin_stdc_first_trailing_zero(0UL) == 1, "");
+_Static_assert(__builtin_stdc_first_trailing_zero(0xFFFFFFFFFFFFFFFFUL) == 0, "");
+_Static_assert(__builtin_stdc_first_trailing_zero(0x000000000000000FUL) == 5, "");
+_Static_assert(__builtin_stdc_first_trailing_zero(0ULL) == 1, "");
+_Static_assert(__builtin_stdc_first_trailing_zero(0xFFFFFFFFFFFFFFFFULL) == 0, "");
+_Static_assert(__builtin_stdc_first_trailing_zero(0x000000000000000FULL) == 5, "");
// Test stdc_first_trailing_one
_Static_assert(__builtin_stdc_first_trailing_one((unsigned char)0) == 0, "");
_Static_assert(__builtin_stdc_first_trailing_one((unsigned char)0x01) == 1, "");
_Static_assert(__builtin_stdc_first_trailing_one((unsigned char)0x80) == 8, "");
_Static_assert(__builtin_stdc_first_trailing_one((unsigned char)0xF0) == 5, "");
+_Static_assert(__builtin_stdc_first_trailing_one((unsigned short)0) == 0, "");
+_Static_assert(__builtin_stdc_first_trailing_one((unsigned short)1) == 1, "");
+_Static_assert(__builtin_stdc_first_trailing_one((unsigned short)0x8000) == 16, "");
_Static_assert(__builtin_stdc_first_trailing_one(0U) == 0, "");
_Static_assert(__builtin_stdc_first_trailing_one(0x80000000U) == 32, "");
_Static_assert(__builtin_stdc_first_trailing_one(1U) == 1, "");
+_Static_assert(__builtin_stdc_first_trailing_one(0UL) == 0, "");
+_Static_assert(__builtin_stdc_first_trailing_one(1UL) == 1, "");
+_Static_assert(__builtin_stdc_first_trailing_one(0x8000000000000000UL) == 64, "");
+_Static_assert(__builtin_stdc_first_trailing_one(0ULL) == 0, "");
+_Static_assert(__builtin_stdc_first_trailing_one(1ULL) == 1, "");
+_Static_assert(__builtin_stdc_first_trailing_one(0x8000000000000000ULL) == 64, "");
// Test stdc_count_zeros
_Static_assert(__builtin_stdc_count_zeros((unsigned char)0) == 8, "");
_Static_assert(__builtin_stdc_count_zeros((unsigned char)0xFF) == 0, "");
_Static_assert(__builtin_stdc_count_zeros((unsigned char)0xAA) == 4, "");
+_Static_assert(__builtin_stdc_count_zeros((unsigned short)0) == 16, "");
+_Static_assert(__builtin_stdc_count_zeros((unsigned short)0xFFFF) == 0, "");
+_Static_assert(__builtin_stdc_count_zeros((unsigned short)0xAAAA) == 8, "");
_Static_assert(__builtin_stdc_count_zeros(0U) == 32, "");
_Static_assert(__builtin_stdc_count_zeros(0xFFFFFFFFU) == 0, "");
_Static_assert(__builtin_stdc_count_zeros(0xAAAAAAAAU) == 16, "");
+_Static_assert(__builtin_stdc_count_zeros(0UL) == 64, "");
+_Static_assert(__builtin_stdc_count_zeros(0xFFFFFFFFFFFFFFFFUL) == 0, "");
+_Static_assert(__builtin_stdc_count_zeros(0xAAAAAAAAAAAAAAAAUL) == 32, "");
+_Static_assert(__builtin_stdc_count_zeros(0ULL) == 64, "");
+_Static_assert(__builtin_stdc_count_zeros(0xFFFFFFFFFFFFFFFFULL) == 0, "");
+_Static_assert(__builtin_stdc_count_zeros(0xAAAAAAAAAAAAAAAAULL) == 32, "");
// Test stdc_count_ones
_Static_assert(__builtin_stdc_count_ones((unsigned char)0) == 0, "");
_Static_assert(__builtin_stdc_count_ones((unsigned char)0xFF) == 8, "");
_Static_assert(__builtin_stdc_count_ones((unsigned char)0xAA) == 4, "");
+_Static_assert(__builtin_stdc_count_ones((unsigned short)0) == 0, "");
+_Static_assert(__builtin_stdc_count_ones((unsigned short)0xFFFF) == 16, "");
+_Static_assert(__builtin_stdc_count_ones((unsigned short)0xAAAA) == 8, "");
_Static_assert(__builtin_stdc_count_ones(0U) == 0, "");
_Static_assert(__builtin_stdc_count_ones(0xFFFFFFFFU) == 32, "");
_Static_assert(__builtin_stdc_count_ones(0xAAAAAAAAU) == 16, "");
+_Static_assert(__builtin_stdc_count_ones(0UL) == 0, "");
+_Static_assert(__builtin_stdc_count_ones(0xFFFFFFFFFFFFFFFFUL) == 64, "");
+_Static_assert(__builtin_stdc_count_ones(0xAAAAAAAAAAAAAAAAUL) == 32, "");
+_Static_assert(__builtin_stdc_count_ones(0ULL) == 0, "");
+_Static_assert(__builtin_stdc_count_ones(0xFFFFFFFFFFFFFFFFULL) == 64, "");
+_Static_assert(__builtin_stdc_count_ones(0xAAAAAAAAAAAAAAAAULL) == 32, "");
// Test stdc_has_single_bit
_Static_assert(__builtin_stdc_has_single_bit((unsigned char)0) == 0, "");
@@ -97,10 +180,22 @@ _Static_assert(__builtin_stdc_has_single_bit((unsigned char)1) == 1, "");
_Static_assert(__builtin_stdc_has_single_bit((unsigned char)2) == 1, "");
_Static_assert(__builtin_stdc_has_single_bit((unsigned char)3) == 0, "");
_Static_assert(__builtin_stdc_has_single_bit((unsigned char)0x80) == 1, "");
+_Static_assert(__builtin_stdc_has_single_bit((unsigned short)0) == 0, "");
+_Static_assert(__builtin_stdc_has_single_bit((unsigned short)1) == 1, "");
+_Static_assert(__builtin_stdc_has_single_bit((unsigned short)0x8000) == 1, "");
+_Static_assert(__builtin_stdc_has_single_bit((unsigned short)0xFFFF) == 0, "");
_Static_assert(__builtin_stdc_has_single_bit(0U) == 0, "");
_Static_assert(__builtin_stdc_has_single_bit(1U) == 1, "");
_Static_assert(__builtin_stdc_has_single_bit(0x80000000U) == 1, "");
_Static_assert(__builtin_stdc_has_single_bit(0xFFFFFFFFU) == 0, "");
+_Static_assert(__builtin_stdc_has_single_bit(0UL) == 0, "");
+_Static_assert(__builtin_stdc_has_single_bit(1UL) == 1, "");
+_Static_assert(__builtin_stdc_has_single_bit(0x8000000000000000UL) == 1, "");
+_Static_assert(__builtin_stdc_has_single_bit(0xFFFFFFFFFFFFFFFFUL) == 0, "");
+_Static_assert(__builtin_stdc_has_single_bit(0ULL) == 0, "");
+_Static_assert(__builtin_stdc_has_single_bit(1ULL) == 1, "");
+_Static_assert(__builtin_stdc_has_single_bit(0x8000000000000000ULL) == 1, "");
+_Static_assert(__builtin_stdc_has_single_bit(0xFFFFFFFFFFFFFFFFULL) == 0, "");
// Test stdc_bit_width
_Static_assert(__builtin_stdc_bit_width((unsigned char)0) == 0, "");
@@ -109,9 +204,18 @@ _Static_assert(__builtin_stdc_bit_width((unsigned char)2) == 2, "");
_Static_assert(__builtin_stdc_bit_width((unsigned char)3) == 2, "");
_Static_assert(__builtin_stdc_bit_width((unsigned char)0x80) == 8, "");
_Static_assert(__builtin_stdc_bit_width((unsigned char)0xFF) == 8, "");
+_Static_assert(__builtin_stdc_bit_width((unsigned short)0) == 0, "");
+_Static_assert(__builtin_stdc_bit_width((unsigned short)1) == 1, "");
+_Static_assert(__builtin_stdc_bit_width((unsigned short)0x8000) == 16, "");
_Static_assert(__builtin_stdc_bit_width(0U) == 0, "");
_Static_assert(__builtin_stdc_bit_width(1U) == 1, "");
_Static_assert(__builtin_stdc_bit_width(0x80000000U) == 32, "");
+_Static_assert(__builtin_stdc_bit_width(0UL) == 0, "");
+_Static_assert(__builtin_stdc_bit_width(1UL) == 1, "");
+_Static_assert(__builtin_stdc_bit_width(0x8000000000000000UL) == 64, "");
+_Static_assert(__builtin_stdc_bit_width(0ULL) == 0, "");
+_Static_assert(__builtin_stdc_bit_width(1ULL) == 1, "");
+_Static_assert(__builtin_stdc_bit_width(0x8000000000000000ULL) == 64, "");
// Test stdc_bit_floor
_Static_assert(__builtin_stdc_bit_floor((unsigned char)0) == 0, "");
@@ -122,11 +226,20 @@ _Static_assert(__builtin_stdc_bit_floor((unsigned char)4) == 4, "");
_Static_assert(__builtin_stdc_bit_floor((unsigned char)5) == 4, "");
_Static_assert(__builtin_stdc_bit_floor((unsigned char)0x80) == 0x80, "");
_Static_assert(__builtin_stdc_bit_floor((unsigned char)0xFF) == 0x80, "");
+_Static_assert(__builtin_stdc_bit_floor((unsigned short)0) == 0, "");
+_Static_assert(__builtin_stdc_bit_floor((unsigned short)1) == 1, "");
+_Static_assert(__builtin_stdc_bit_floor((unsigned short)0xFFFF) == 0x8000, "");
_Static_assert(__builtin_stdc_bit_floor(0U) == 0U, "");
_Static_assert(__builtin_stdc_bit_floor(1U) == 1U, "");
_Static_assert(__builtin_stdc_bit_floor(7U) == 4U, "");
_Static_assert(__builtin_stdc_bit_floor(0x80000000U) == 0x80000000U, "");
_Static_assert(__builtin_stdc_bit_floor(0xFFFFFFFFU) == 0x80000000U, "");
+_Static_assert(__builtin_stdc_bit_floor(0UL) == 0UL, "");
+_Static_assert(__builtin_stdc_bit_floor(1UL) == 1UL, "");
+_Static_assert(__builtin_stdc_bit_floor(0xFFFFFFFFFFFFFFFFUL) == 0x8000000000000000UL, "");
+_Static_assert(__builtin_stdc_bit_floor(0ULL) == 0ULL, "");
+_Static_assert(__builtin_stdc_bit_floor(1ULL) == 1ULL, "");
+_Static_assert(__builtin_stdc_bit_floor(0xFFFFFFFFFFFFFFFFULL) == 0x8000000000000000ULL, "");
// Test stdc_bit_ceil
_Static_assert(__builtin_stdc_bit_ceil((unsigned char)0) == 1, "");
@@ -136,38 +249,126 @@ _Static_assert(__builtin_stdc_bit_ceil((unsigned char)3) == 4, "");
_Static_assert(__builtin_stdc_bit_ceil((unsigned char)4) == 4, "");
_Static_assert(__builtin_stdc_bit_ceil((unsigned char)5) == 8, "");
_Static_assert(__builtin_stdc_bit_ceil((unsigned char)0x80) == 0x80, "");
+_Static_assert(__builtin_stdc_bit_ceil((unsigned short)0) == 1, "");
+_Static_assert(__builtin_stdc_bit_ceil((unsigned short)1) == 1, "");
+_Static_assert(__builtin_stdc_bit_ceil((unsigned short)7) == 8, "");
+_Static_assert(__builtin_stdc_bit_ceil((unsigned short)0x8000) == 0x8000, "");
_Static_assert(__builtin_stdc_bit_ceil(0U) == 1U, "");
_Static_assert(__builtin_stdc_bit_ceil(1U) == 1U, "");
_Static_assert(__builtin_stdc_bit_ceil(7U) == 8U, "");
_Static_assert(__builtin_stdc_bit_ceil(0x80000000U) == 0x80000000U, "");
+_Static_assert(__builtin_stdc_bit_ceil(0UL) == 1UL, "");
+_Static_assert(__builtin_stdc_bit_ceil(1UL) == 1UL, "");
+_Static_assert(__builtin_stdc_bit_ceil(7UL) == 8UL, "");
+_Static_assert(__builtin_stdc_bit_ceil(0x8000000000000000UL) == 0x8000000000000000UL, "");
+_Static_assert(__builtin_stdc_bit_ceil(0ULL) == 1ULL, "");
+_Static_assert(__builtin_stdc_bit_ceil(1ULL) == 1ULL, "");
+_Static_assert(__builtin_stdc_bit_ceil(7ULL) == 8ULL, "");
+_Static_assert(__builtin_stdc_bit_ceil(0x8000000000000000ULL) == 0x8000000000000000ULL, "");
-// Test with _BitInt types
+// Test with _BitInt types - cover all 14 builtins
_Static_assert(__builtin_stdc_leading_zeros((unsigned _BitInt(37))0) == 37, "");
_Static_assert(__builtin_stdc_leading_zeros((unsigned _BitInt(37))1) == 36, "");
+_Static_assert(__builtin_stdc_leading_ones((unsigned _BitInt(37))0) == 0, "");
+_Static_assert(__builtin_stdc_leading_ones((unsigned _BitInt(37))-1) == 37, "");
_Static_assert(__builtin_stdc_trailing_zeros((unsigned _BitInt(37))0) == 37, "");
+_Static_assert(__builtin_stdc_trailing_zeros((unsigned _BitInt(37))1) == 0, "");
+_Static_assert(__builtin_stdc_trailing_ones((unsigned _BitInt(37))0) == 0, "");
+_Static_assert(__builtin_stdc_trailing_ones((unsigned _BitInt(37))-1) == 37, "");
+_Static_assert(__builtin_stdc_first_leading_zero((unsigned _BitInt(37))0) == 1, "");
+_Static_assert(__builtin_stdc_first_leading_zero((unsigned _BitInt(37))-1) == 0, "");
+_Static_assert(__builtin_stdc_first_leading_one((unsigned _BitInt(37))0) == 0, "");
+_Static_assert(__builtin_stdc_first_leading_one((unsigned _BitInt(37))1) == 37, "");
+_Static_assert(__builtin_stdc_first_trailing_zero((unsigned _BitInt(37))0) == 1, "");
+_Static_assert(__builtin_stdc_first_trailing_zero((unsigned _BitInt(37))-1) == 0, "");
+_Static_assert(__builtin_stdc_first_trailing_one((unsigned _BitInt(37))0) == 0, "");
+_Static_assert(__builtin_stdc_first_trailing_one((unsigned _BitInt(37))1) == 1, "");
_Static_assert(__builtin_stdc_count_ones((unsigned _BitInt(37))0x1F) == 5, "");
+_Static_assert(__builtin_stdc_count_zeros((unsigned _BitInt(37))0) == 37, "");
+_Static_assert(__builtin_stdc_count_zeros((unsigned _BitInt(37))-1) == 0, "");
_Static_assert(__builtin_stdc_has_single_bit((unsigned _BitInt(37))0x10) == 1, "");
+_Static_assert(__builtin_stdc_has_single_bit((unsigned _BitInt(37))0) == 0, "");
+_Static_assert(__builtin_stdc_has_single_bit((unsigned _BitInt(37))3) == 0, "");
_Static_assert(__builtin_stdc_bit_width((unsigned _BitInt(37))0x10) == 5, "");
+_Static_assert(__builtin_stdc_bit_width((unsigned _BitInt(37))0) == 0, "");
+_Static_assert(__builtin_stdc_bit_width((unsigned _BitInt(37))-1) == 37, "");
_Static_assert(__builtin_stdc_bit_floor((unsigned _BitInt(37))0x1F) == 0x10, "");
_Static_assert(__builtin_stdc_bit_ceil((unsigned _BitInt(37))0x11) == 0x20, "");
-// Test with __int128
+#ifdef __SIZEOF_INT128__
+// Test with __int128 - cover all 14 builtins
_Static_assert(__builtin_stdc_leading_zeros((unsigned __int128)0) == 128, "");
_Static_assert(__builtin_stdc_leading_zeros((unsigned __int128)1) == 127, "");
+_Static_assert(__builtin_stdc_leading_ones((unsigned __int128)0) == 0, "");
+_Static_assert(__builtin_stdc_leading_ones((unsigned __int128)-1) == 128, "");
_Static_assert(__builtin_stdc_trailing_zeros((unsigned __int128)0) == 128, "");
+_Static_assert(__builtin_stdc_trailing_zeros((unsigned __int128)1) == 0, "");
+_Static_assert(__builtin_stdc_trailing_ones((unsigned __int128)0) == 0, "");
+_Static_assert(__builtin_stdc_trailing_ones((unsigned __int128)-1) == 128, "");
+_Static_assert(__builtin_stdc_first_leading_zero((unsigned __int128)0) == 1, "");
+_Static_assert(__builtin_stdc_first_leading_zero((unsigned __int128)-1) == 0, "");
+_Static_assert(__builtin_stdc_first_leading_one((unsigned __int128)0) == 0, "");
+_Static_assert(__builtin_stdc_first_trailing_zero((unsigned __int128)0) == 1, "");
+_Static_assert(__builtin_stdc_first_trailing_zero((unsigned __int128)-1) == 0, "");
+_Static_assert(__builtin_stdc_first_trailing_one((unsigned __int128)0) == 0, "");
+_Static_assert(__builtin_stdc_first_trailing_one((unsigned __int128)1) == 1, "");
_Static_assert(__builtin_stdc_count_ones((unsigned __int128)0xFFFFFFFF) == 32, "");
+_Static_assert(__builtin_stdc_count_zeros((unsigned __int128)0) == 128, "");
+_Static_assert(__builtin_stdc_count_zeros((unsigned __int128)-1) == 0, "");
_Static_assert(__builtin_stdc_has_single_bit((unsigned __int128)1) == 1, "");
+_Static_assert(__builtin_stdc_has_single_bit((unsigned __int128)0) == 0, "");
+_Static_assert(__builtin_stdc_has_single_bit((unsigned __int128)3) == 0, "");
_Static_assert(__builtin_stdc_bit_width((unsigned __int128)1) == 1, "");
+_Static_assert(__builtin_stdc_bit_width((unsigned __int128)0) == 0, "");
+_Static_assert(__builtin_stdc_bit_floor((unsigned __int128)0) == 0, "");
+_Static_assert(__builtin_stdc_bit_floor((unsigned __int128)1) == 1, "");
+_Static_assert(__builtin_stdc_bit_ceil((unsigned __int128)0) == 1, "");
+_Static_assert(__builtin_stdc_bit_ceil((unsigned __int128)1) == 1, "");
+_Static_assert(__builtin_stdc_bit_ceil((unsigned __int128)3) == 4, "");
+#endif // __SIZEOF_INT128__
-// Error cases
+// Error cases - all 14 builtins reject signed and floating-point arguments
void test_errors(int si, float f) {
- unsigned int ui = 5;
+ __builtin_stdc_leading_zeros(si); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
+ __builtin_stdc_leading_zeros(f); // expected-error {{1st argument must be a scalar unsigned integer type (was 'float')}}
+ __builtin_stdc_leading_zeros(-1); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
- __builtin_stdc_leading_zeros(si); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
- __builtin_stdc_leading_zeros(f); // expected-error {{1st argument must be a scalar unsigned integer type (was 'float')}}
- __builtin_stdc_leading_zeros(-1); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
+ __builtin_stdc_leading_ones(si); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
+ __builtin_stdc_leading_ones(f); // expected-error {{1st argument must be a scalar unsigned integer type (was 'float')}}
+
+ __builtin_stdc_trailing_zeros(si); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
+ __builtin_stdc_trailing_zeros(f); // expected-error {{1st argument must be a scalar unsigned integer type (was 'float')}}
+
+ __builtin_stdc_trailing_ones(si); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
+ __builtin_stdc_trailing_ones(f); // expected-error {{1st argument must be a scalar unsigned integer type (was 'float')}}
+
+ __builtin_stdc_first_leading_zero(si); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
+ __builtin_stdc_first_leading_zero(f); // expected-error {{1st argument must be a scalar unsigned integer type (was 'float')}}
+
+ __builtin_stdc_first_leading_one(si); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
+ __builtin_stdc_first_leading_one(f); // expected-error {{1st argument must be a scalar unsigned integer type (was 'float')}}
+
+ __builtin_stdc_first_trailing_zero(si); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
+ __builtin_stdc_first_trailing_zero(f); // expected-error {{1st argument must be a scalar unsigned integer type (was 'float')}}
+
+ __builtin_stdc_first_trailing_one(si); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
+ __builtin_stdc_first_trailing_one(f); // expected-error {{1st argument must be a scalar unsigned integer type (was 'float')}}
+
+ __builtin_stdc_count_ones(si); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
+ __builtin_stdc_count_ones(f); // expected-error {{1st argument must be a scalar unsigned integer type (was 'float')}}
+
+ __builtin_stdc_count_zeros(si); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
+ __builtin_stdc_count_zeros(f); // expected-error {{1st argument must be a scalar unsigned integer type (was 'float')}}
- __builtin_stdc_count_ones(si); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
__builtin_stdc_has_single_bit(si); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
- __builtin_stdc_bit_ceil(si); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
+ __builtin_stdc_has_single_bit(f); // expected-error {{1st argument must be a scalar unsigned integer type (was 'float')}}
+
+ __builtin_stdc_bit_width(si); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
+ __builtin_stdc_bit_width(f); // expected-error {{1st argument must be a scalar unsigned integer type (was 'float')}}
+
+ __builtin_stdc_bit_floor(si); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
+ __builtin_stdc_bit_floor(f); // expected-error {{1st argument must be a scalar unsigned integer type (was 'float')}}
+
+ __builtin_stdc_bit_ceil(si); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
+ __builtin_stdc_bit_ceil(f); // expected-error {{1st argument must be a scalar unsigned integer type (was 'float')}}
}
diff --git a/clang/test/SemaCXX/constexpr-builtin-stdc-bit-functions.cpp b/clang/test/SemaCXX/constexpr-builtin-stdc-bit-functions.cpp
index 635ff6b4347f3..b72c4ea574281 100644
--- a/clang/test/SemaCXX/constexpr-builtin-stdc-bit-functions.cpp
+++ b/clang/test/SemaCXX/constexpr-builtin-stdc-bit-functions.cpp
@@ -1,5 +1,7 @@
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -std=c++14 -fsyntax-only -verify %s
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -std=c++14 -fsyntax-only -verify %s -fexperimental-new-constant-interpreter
+// RUN: %if clang-target-64-bits %{ %clang_cc1 -std=c++14 -fsyntax-only -verify %s %}
+// RUN: %if clang-target-64-bits %{ %clang_cc1 -std=c++14 -fsyntax-only -verify %s -fexperimental-new-constant-interpreter %}
namespace test_stdc_leading_zeros {
@@ -8,10 +10,14 @@ static_assert(__builtin_stdc_leading_zeros((unsigned char)1) == 7, "");
static_assert(__builtin_stdc_leading_zeros((unsigned char)0x80) == 0, "");
static_assert(__builtin_stdc_leading_zeros((unsigned char)0xFF) == 0, "");
static_assert(__builtin_stdc_leading_zeros((unsigned short)0) == 16, "");
+static_assert(__builtin_stdc_leading_zeros((unsigned short)1) == 15, "");
static_assert(__builtin_stdc_leading_zeros((unsigned short)0x8000) == 0, "");
static_assert(__builtin_stdc_leading_zeros(0U) == 32, "");
static_assert(__builtin_stdc_leading_zeros(1U) == 31, "");
static_assert(__builtin_stdc_leading_zeros(0x80000000U) == 0, "");
+static_assert(__builtin_stdc_leading_zeros(0UL) == 64, "");
+static_assert(__builtin_stdc_leading_zeros(1UL) == 63, "");
+static_assert(__builtin_stdc_leading_zeros(0x8000000000000000UL) == 0, "");
static_assert(__builtin_stdc_leading_zeros(0ULL) == 64, "");
static_assert(__builtin_stdc_leading_zeros(1ULL) == 63, "");
static_assert(__builtin_stdc_leading_zeros(0x8000000000000000ULL) == 0, "");
@@ -23,9 +29,16 @@ namespace test_stdc_leading_ones {
static_assert(__builtin_stdc_leading_ones((unsigned char)0) == 0, "");
static_assert(__builtin_stdc_leading_ones((unsigned char)0xFF) == 8, "");
static_assert(__builtin_stdc_leading_ones((unsigned char)0xF0) == 4, "");
+static_assert(__builtin_stdc_leading_ones((unsigned short)0) == 0, "");
static_assert(__builtin_stdc_leading_ones((unsigned short)0xFFFF) == 16, "");
+static_assert(__builtin_stdc_leading_ones((unsigned short)0xF000) == 4, "");
+static_assert(__builtin_stdc_leading_ones(0U) == 0, "");
static_assert(__builtin_stdc_leading_ones(0xFFFFFFFFU) == 32, "");
static_assert(__builtin_stdc_leading_ones(0xF0000000U) == 4, "");
+static_assert(__builtin_stdc_leading_ones(0UL) == 0, "");
+static_assert(__builtin_stdc_leading_ones(0xFFFFFFFFFFFFFFFFUL) == 64, "");
+static_assert(__builtin_stdc_leading_ones(0xF000000000000000UL) == 4, "");
+static_assert(__builtin_stdc_leading_ones(0ULL) == 0, "");
static_assert(__builtin_stdc_leading_ones(0xFFFFFFFFFFFFFFFFULL) == 64, "");
} // namespace test_stdc_leading_ones
@@ -36,9 +49,16 @@ static_assert(__builtin_stdc_trailing_zeros((unsigned char)0) == 8, "");
static_assert(__builtin_stdc_trailing_zeros((unsigned char)1) == 0, "");
static_assert(__builtin_stdc_trailing_zeros((unsigned char)0x80) == 7, "");
static_assert(__builtin_stdc_trailing_zeros((unsigned short)0) == 16, "");
+static_assert(__builtin_stdc_trailing_zeros((unsigned short)1) == 0, "");
+static_assert(__builtin_stdc_trailing_zeros((unsigned short)0x8000) == 15, "");
static_assert(__builtin_stdc_trailing_zeros(0U) == 32, "");
+static_assert(__builtin_stdc_trailing_zeros(1U) == 0, "");
static_assert(__builtin_stdc_trailing_zeros(0x80000000U) == 31, "");
+static_assert(__builtin_stdc_trailing_zeros(0UL) == 64, "");
+static_assert(__builtin_stdc_trailing_zeros(1UL) == 0, "");
+static_assert(__builtin_stdc_trailing_zeros(0x8000000000000000UL) == 63, "");
static_assert(__builtin_stdc_trailing_zeros(0ULL) == 64, "");
+static_assert(__builtin_stdc_trailing_zeros(1ULL) == 0, "");
static_assert(__builtin_stdc_trailing_zeros(0x8000000000000000ULL) == 63, "");
} // namespace test_stdc_trailing_zeros
@@ -48,8 +68,18 @@ namespace test_stdc_trailing_ones {
static_assert(__builtin_stdc_trailing_ones((unsigned char)0) == 0, "");
static_assert(__builtin_stdc_trailing_ones((unsigned char)0xFF) == 8, "");
static_assert(__builtin_stdc_trailing_ones((unsigned char)0x0F) == 4, "");
+static_assert(__builtin_stdc_trailing_ones((unsigned short)0) == 0, "");
+static_assert(__builtin_stdc_trailing_ones((unsigned short)0xFFFF) == 16, "");
+static_assert(__builtin_stdc_trailing_ones((unsigned short)0x000F) == 4, "");
+static_assert(__builtin_stdc_trailing_ones(0U) == 0, "");
+static_assert(__builtin_stdc_trailing_ones(1U) == 1, "");
static_assert(__builtin_stdc_trailing_ones(0xFFFFFFFFU) == 32, "");
static_assert(__builtin_stdc_trailing_ones(0x0000000FU) == 4, "");
+static_assert(__builtin_stdc_trailing_ones(0UL) == 0, "");
+static_assert(__builtin_stdc_trailing_ones(0xFFFFFFFFFFFFFFFFUL) == 64, "");
+static_assert(__builtin_stdc_trailing_ones(0x000000000000000FUL) == 4, "");
+static_assert(__builtin_stdc_trailing_ones(0ULL) == 0, "");
+static_assert(__builtin_stdc_trailing_ones(1ULL) == 1, "");
static_assert(__builtin_stdc_trailing_ones(0xFFFFFFFFFFFFFFFFULL) == 64, "");
} // namespace test_stdc_trailing_ones
@@ -60,8 +90,17 @@ static_assert(__builtin_stdc_first_leading_zero((unsigned char)0) == 1, "");
static_assert(__builtin_stdc_first_leading_zero((unsigned char)0xFF) == 0, "");
static_assert(__builtin_stdc_first_leading_zero((unsigned char)0xF0) == 5, "");
static_assert(__builtin_stdc_first_leading_zero((unsigned char)0x80) == 2, "");
+static_assert(__builtin_stdc_first_leading_zero((unsigned short)0) == 1, "");
+static_assert(__builtin_stdc_first_leading_zero((unsigned short)0xFFFF) == 0, "");
+static_assert(__builtin_stdc_first_leading_zero((unsigned short)0xF000) == 5, "");
static_assert(__builtin_stdc_first_leading_zero(0xFFFFFFFFU) == 0, "");
static_assert(__builtin_stdc_first_leading_zero(0xF0000000U) == 5, "");
+static_assert(__builtin_stdc_first_leading_zero(0UL) == 1, "");
+static_assert(__builtin_stdc_first_leading_zero(0xFFFFFFFFFFFFFFFFUL) == 0, "");
+static_assert(__builtin_stdc_first_leading_zero(0xF000000000000000UL) == 5, "");
+static_assert(__builtin_stdc_first_leading_zero(0ULL) == 1, "");
+static_assert(__builtin_stdc_first_leading_zero(0xFFFFFFFFFFFFFFFFULL) == 0, "");
+static_assert(__builtin_stdc_first_leading_zero(0xF000000000000000ULL) == 5, "");
} // namespace test_stdc_first_leading_zero
@@ -71,9 +110,18 @@ static_assert(__builtin_stdc_first_leading_one((unsigned char)0) == 0, "");
static_assert(__builtin_stdc_first_leading_one((unsigned char)0x80) == 1, "");
static_assert(__builtin_stdc_first_leading_one((unsigned char)0x01) == 8, "");
static_assert(__builtin_stdc_first_leading_one((unsigned char)0x0F) == 5, "");
+static_assert(__builtin_stdc_first_leading_one((unsigned short)0) == 0, "");
+static_assert(__builtin_stdc_first_leading_one((unsigned short)0x8000) == 1, "");
+static_assert(__builtin_stdc_first_leading_one((unsigned short)1) == 16, "");
static_assert(__builtin_stdc_first_leading_one(0U) == 0, "");
static_assert(__builtin_stdc_first_leading_one(0x80000000U) == 1, "");
static_assert(__builtin_stdc_first_leading_one(1U) == 32, "");
+static_assert(__builtin_stdc_first_leading_one(0UL) == 0, "");
+static_assert(__builtin_stdc_first_leading_one(0x8000000000000000UL) == 1, "");
+static_assert(__builtin_stdc_first_leading_one(1UL) == 64, "");
+static_assert(__builtin_stdc_first_leading_one(0ULL) == 0, "");
+static_assert(__builtin_stdc_first_leading_one(0x8000000000000000ULL) == 1, "");
+static_assert(__builtin_stdc_first_leading_one(1ULL) == 64, "");
} // namespace test_stdc_first_leading_one
@@ -83,8 +131,17 @@ static_assert(__builtin_stdc_first_trailing_zero((unsigned char)0) == 1, "");
static_assert(__builtin_stdc_first_trailing_zero((unsigned char)0xFF) == 0, "");
static_assert(__builtin_stdc_first_trailing_zero((unsigned char)0x0F) == 5, "");
static_assert(__builtin_stdc_first_trailing_zero((unsigned char)0x01) == 2, "");
+static_assert(__builtin_stdc_first_trailing_zero((unsigned short)0) == 1, "");
+static_assert(__builtin_stdc_first_trailing_zero((unsigned short)0xFFFF) == 0, "");
+static_assert(__builtin_stdc_first_trailing_zero((unsigned short)0x000F) == 5, "");
static_assert(__builtin_stdc_first_trailing_zero(0xFFFFFFFFU) == 0, "");
static_assert(__builtin_stdc_first_trailing_zero(0x0000000FU) == 5, "");
+static_assert(__builtin_stdc_first_trailing_zero(0UL) == 1, "");
+static_assert(__builtin_stdc_first_trailing_zero(0xFFFFFFFFFFFFFFFFUL) == 0, "");
+static_assert(__builtin_stdc_first_trailing_zero(0x000000000000000FUL) == 5, "");
+static_assert(__builtin_stdc_first_trailing_zero(0ULL) == 1, "");
+static_assert(__builtin_stdc_first_trailing_zero(0xFFFFFFFFFFFFFFFFULL) == 0, "");
+static_assert(__builtin_stdc_first_trailing_zero(0x000000000000000FULL) == 5, "");
} // namespace test_stdc_first_trailing_zero
@@ -94,9 +151,18 @@ static_assert(__builtin_stdc_first_trailing_one((unsigned char)0) == 0, "");
static_assert(__builtin_stdc_first_trailing_one((unsigned char)0x01) == 1, "");
static_assert(__builtin_stdc_first_trailing_one((unsigned char)0x80) == 8, "");
static_assert(__builtin_stdc_first_trailing_one((unsigned char)0xF0) == 5, "");
+static_assert(__builtin_stdc_first_trailing_one((unsigned short)0) == 0, "");
+static_assert(__builtin_stdc_first_trailing_one((unsigned short)1) == 1, "");
+static_assert(__builtin_stdc_first_trailing_one((unsigned short)0x8000) == 16, "");
static_assert(__builtin_stdc_first_trailing_one(0U) == 0, "");
static_assert(__builtin_stdc_first_trailing_one(0x80000000U) == 32, "");
static_assert(__builtin_stdc_first_trailing_one(1U) == 1, "");
+static_assert(__builtin_stdc_first_trailing_one(0UL) == 0, "");
+static_assert(__builtin_stdc_first_trailing_one(1UL) == 1, "");
+static_assert(__builtin_stdc_first_trailing_one(0x8000000000000000UL) == 64, "");
+static_assert(__builtin_stdc_first_trailing_one(0ULL) == 0, "");
+static_assert(__builtin_stdc_first_trailing_one(1ULL) == 1, "");
+static_assert(__builtin_stdc_first_trailing_one(0x8000000000000000ULL) == 64, "");
} // namespace test_stdc_first_trailing_one
@@ -105,9 +171,18 @@ namespace test_stdc_count_zeros {
static_assert(__builtin_stdc_count_zeros((unsigned char)0) == 8, "");
static_assert(__builtin_stdc_count_zeros((unsigned char)0xFF) == 0, "");
static_assert(__builtin_stdc_count_zeros((unsigned char)0xAA) == 4, "");
+static_assert(__builtin_stdc_count_zeros((unsigned short)0) == 16, "");
+static_assert(__builtin_stdc_count_zeros((unsigned short)0xFFFF) == 0, "");
+static_assert(__builtin_stdc_count_zeros((unsigned short)0xAAAA) == 8, "");
static_assert(__builtin_stdc_count_zeros(0U) == 32, "");
static_assert(__builtin_stdc_count_zeros(0xFFFFFFFFU) == 0, "");
static_assert(__builtin_stdc_count_zeros(0xAAAAAAAAU) == 16, "");
+static_assert(__builtin_stdc_count_zeros(0UL) == 64, "");
+static_assert(__builtin_stdc_count_zeros(0xFFFFFFFFFFFFFFFFUL) == 0, "");
+static_assert(__builtin_stdc_count_zeros(0xAAAAAAAAAAAAAAAAUL) == 32, "");
+static_assert(__builtin_stdc_count_zeros(0ULL) == 64, "");
+static_assert(__builtin_stdc_count_zeros(0xFFFFFFFFFFFFFFFFULL) == 0, "");
+static_assert(__builtin_stdc_count_zeros(0xAAAAAAAAAAAAAAAAULL) == 32, "");
} // namespace test_stdc_count_zeros
@@ -116,9 +191,18 @@ namespace test_stdc_count_ones {
static_assert(__builtin_stdc_count_ones((unsigned char)0) == 0, "");
static_assert(__builtin_stdc_count_ones((unsigned char)0xFF) == 8, "");
static_assert(__builtin_stdc_count_ones((unsigned char)0xAA) == 4, "");
+static_assert(__builtin_stdc_count_ones((unsigned short)0) == 0, "");
+static_assert(__builtin_stdc_count_ones((unsigned short)0xFFFF) == 16, "");
+static_assert(__builtin_stdc_count_ones((unsigned short)0xAAAA) == 8, "");
static_assert(__builtin_stdc_count_ones(0U) == 0, "");
static_assert(__builtin_stdc_count_ones(0xFFFFFFFFU) == 32, "");
static_assert(__builtin_stdc_count_ones(0xAAAAAAAAU) == 16, "");
+static_assert(__builtin_stdc_count_ones(0UL) == 0, "");
+static_assert(__builtin_stdc_count_ones(0xFFFFFFFFFFFFFFFFUL) == 64, "");
+static_assert(__builtin_stdc_count_ones(0xAAAAAAAAAAAAAAAAUL) == 32, "");
+static_assert(__builtin_stdc_count_ones(0ULL) == 0, "");
+static_assert(__builtin_stdc_count_ones(0xFFFFFFFFFFFFFFFFULL) == 64, "");
+static_assert(__builtin_stdc_count_ones(0xAAAAAAAAAAAAAAAAULL) == 32, "");
} // namespace test_stdc_count_ones
@@ -129,10 +213,22 @@ static_assert(__builtin_stdc_has_single_bit((unsigned char)1) == 1, "");
static_assert(__builtin_stdc_has_single_bit((unsigned char)2) == 1, "");
static_assert(__builtin_stdc_has_single_bit((unsigned char)3) == 0, "");
static_assert(__builtin_stdc_has_single_bit((unsigned char)0x80) == 1, "");
+static_assert(__builtin_stdc_has_single_bit((unsigned short)0) == 0, "");
+static_assert(__builtin_stdc_has_single_bit((unsigned short)1) == 1, "");
+static_assert(__builtin_stdc_has_single_bit((unsigned short)0x8000) == 1, "");
+static_assert(__builtin_stdc_has_single_bit((unsigned short)0xFFFF) == 0, "");
static_assert(__builtin_stdc_has_single_bit(0U) == 0, "");
static_assert(__builtin_stdc_has_single_bit(1U) == 1, "");
static_assert(__builtin_stdc_has_single_bit(0x80000000U) == 1, "");
static_assert(__builtin_stdc_has_single_bit(0xFFFFFFFFU) == 0, "");
+static_assert(__builtin_stdc_has_single_bit(0UL) == 0, "");
+static_assert(__builtin_stdc_has_single_bit(1UL) == 1, "");
+static_assert(__builtin_stdc_has_single_bit(0x8000000000000000UL) == 1, "");
+static_assert(__builtin_stdc_has_single_bit(0xFFFFFFFFFFFFFFFFUL) == 0, "");
+static_assert(__builtin_stdc_has_single_bit(0ULL) == 0, "");
+static_assert(__builtin_stdc_has_single_bit(1ULL) == 1, "");
+static_assert(__builtin_stdc_has_single_bit(0x8000000000000000ULL) == 1, "");
+static_assert(__builtin_stdc_has_single_bit(0xFFFFFFFFFFFFFFFFULL) == 0, "");
} // namespace test_stdc_has_single_bit
@@ -144,9 +240,18 @@ static_assert(__builtin_stdc_bit_width((unsigned char)2) == 2, "");
static_assert(__builtin_stdc_bit_width((unsigned char)3) == 2, "");
static_assert(__builtin_stdc_bit_width((unsigned char)0x80) == 8, "");
static_assert(__builtin_stdc_bit_width((unsigned char)0xFF) == 8, "");
+static_assert(__builtin_stdc_bit_width((unsigned short)0) == 0, "");
+static_assert(__builtin_stdc_bit_width((unsigned short)1) == 1, "");
+static_assert(__builtin_stdc_bit_width((unsigned short)0x8000) == 16, "");
static_assert(__builtin_stdc_bit_width(0U) == 0, "");
static_assert(__builtin_stdc_bit_width(1U) == 1, "");
static_assert(__builtin_stdc_bit_width(0x80000000U) == 32, "");
+static_assert(__builtin_stdc_bit_width(0UL) == 0, "");
+static_assert(__builtin_stdc_bit_width(1UL) == 1, "");
+static_assert(__builtin_stdc_bit_width(0x8000000000000000UL) == 64, "");
+static_assert(__builtin_stdc_bit_width(0ULL) == 0, "");
+static_assert(__builtin_stdc_bit_width(1ULL) == 1, "");
+static_assert(__builtin_stdc_bit_width(0x8000000000000000ULL) == 64, "");
} // namespace test_stdc_bit_width
@@ -160,11 +265,20 @@ static_assert(__builtin_stdc_bit_floor((unsigned char)4) == 4, "");
static_assert(__builtin_stdc_bit_floor((unsigned char)5) == 4, "");
static_assert(__builtin_stdc_bit_floor((unsigned char)0x80) == 0x80, "");
static_assert(__builtin_stdc_bit_floor((unsigned char)0xFF) == 0x80, "");
+static_assert(__builtin_stdc_bit_floor((unsigned short)0) == 0, "");
+static_assert(__builtin_stdc_bit_floor((unsigned short)1) == 1, "");
+static_assert(__builtin_stdc_bit_floor((unsigned short)0xFFFF) == 0x8000, "");
static_assert(__builtin_stdc_bit_floor(0U) == 0U, "");
static_assert(__builtin_stdc_bit_floor(1U) == 1U, "");
static_assert(__builtin_stdc_bit_floor(7U) == 4U, "");
static_assert(__builtin_stdc_bit_floor(0x80000000U) == 0x80000000U, "");
static_assert(__builtin_stdc_bit_floor(0xFFFFFFFFU) == 0x80000000U, "");
+static_assert(__builtin_stdc_bit_floor(0UL) == 0UL, "");
+static_assert(__builtin_stdc_bit_floor(1UL) == 1UL, "");
+static_assert(__builtin_stdc_bit_floor(0xFFFFFFFFFFFFFFFFUL) == 0x8000000000000000UL, "");
+static_assert(__builtin_stdc_bit_floor(0ULL) == 0ULL, "");
+static_assert(__builtin_stdc_bit_floor(1ULL) == 1ULL, "");
+static_assert(__builtin_stdc_bit_floor(0xFFFFFFFFFFFFFFFFULL) == 0x8000000000000000ULL, "");
} // namespace test_stdc_bit_floor
@@ -177,66 +291,176 @@ static_assert(__builtin_stdc_bit_ceil((unsigned char)3) == 4, "");
static_assert(__builtin_stdc_bit_ceil((unsigned char)4) == 4, "");
static_assert(__builtin_stdc_bit_ceil((unsigned char)5) == 8, "");
static_assert(__builtin_stdc_bit_ceil((unsigned char)0x80) == 0x80, "");
+static_assert(__builtin_stdc_bit_ceil((unsigned short)0) == 1, "");
+static_assert(__builtin_stdc_bit_ceil((unsigned short)1) == 1, "");
+static_assert(__builtin_stdc_bit_ceil((unsigned short)7) == 8, "");
+static_assert(__builtin_stdc_bit_ceil((unsigned short)0x8000) == 0x8000, "");
static_assert(__builtin_stdc_bit_ceil(0U) == 1U, "");
static_assert(__builtin_stdc_bit_ceil(1U) == 1U, "");
static_assert(__builtin_stdc_bit_ceil(7U) == 8U, "");
static_assert(__builtin_stdc_bit_ceil(0x80000000U) == 0x80000000U, "");
+// Overflow: next power of 2 exceeds type width; implementation wraps.
static_assert(__builtin_stdc_bit_ceil(0xFFFFFFFFU) == 0xFFFFFFFFU, "");
+static_assert(__builtin_stdc_bit_ceil(0UL) == 1UL, "");
+static_assert(__builtin_stdc_bit_ceil(1UL) == 1UL, "");
+static_assert(__builtin_stdc_bit_ceil(7UL) == 8UL, "");
+static_assert(__builtin_stdc_bit_ceil(0x8000000000000000UL) == 0x8000000000000000UL, "");
+static_assert(__builtin_stdc_bit_ceil(0ULL) == 1ULL, "");
+static_assert(__builtin_stdc_bit_ceil(1ULL) == 1ULL, "");
+static_assert(__builtin_stdc_bit_ceil(7ULL) == 8ULL, "");
+static_assert(__builtin_stdc_bit_ceil(0x8000000000000000ULL) == 0x8000000000000000ULL, "");
} // namespace test_stdc_bit_ceil
+#ifdef __SIZEOF_INT128__
namespace test_int128 {
static_assert(__builtin_stdc_leading_zeros((unsigned __int128)0) == 128, "");
static_assert(__builtin_stdc_leading_zeros((unsigned __int128)1) == 127, "");
+static_assert(__builtin_stdc_leading_ones((unsigned __int128)0) == 0, "");
+static_assert(__builtin_stdc_leading_ones((unsigned __int128)-1) == 128, "");
static_assert(__builtin_stdc_trailing_zeros((unsigned __int128)0) == 128, "");
+static_assert(__builtin_stdc_trailing_zeros((unsigned __int128)1) == 0, "");
+static_assert(__builtin_stdc_trailing_ones((unsigned __int128)0) == 0, "");
+static_assert(__builtin_stdc_trailing_ones((unsigned __int128)-1) == 128, "");
+static_assert(__builtin_stdc_first_leading_zero((unsigned __int128)0) == 1, "");
+static_assert(__builtin_stdc_first_leading_zero((unsigned __int128)-1) == 0, "");
+static_assert(__builtin_stdc_first_leading_one((unsigned __int128)0) == 0, "");
+static_assert(__builtin_stdc_first_trailing_zero((unsigned __int128)0) == 1, "");
+static_assert(__builtin_stdc_first_trailing_zero((unsigned __int128)-1) == 0, "");
+static_assert(__builtin_stdc_first_trailing_one((unsigned __int128)0) == 0, "");
+static_assert(__builtin_stdc_first_trailing_one((unsigned __int128)1) == 1, "");
static_assert(__builtin_stdc_count_ones((unsigned __int128)0xFFFFFFFF) == 32, "");
+static_assert(__builtin_stdc_count_zeros((unsigned __int128)0) == 128, "");
+static_assert(__builtin_stdc_count_zeros((unsigned __int128)-1) == 0, "");
static_assert(__builtin_stdc_has_single_bit((unsigned __int128)1) == 1, "");
+static_assert(__builtin_stdc_has_single_bit((unsigned __int128)0) == 0, "");
+static_assert(__builtin_stdc_has_single_bit((unsigned __int128)3) == 0, "");
+static_assert(__builtin_stdc_bit_width((unsigned __int128)0) == 0, "");
static_assert(__builtin_stdc_bit_width((unsigned __int128)1) == 1, "");
+static_assert(__builtin_stdc_bit_floor((unsigned __int128)0) == 0, "");
+static_assert(__builtin_stdc_bit_floor((unsigned __int128)1) == 1, "");
+static_assert(__builtin_stdc_bit_ceil((unsigned __int128)0) == 1, "");
+static_assert(__builtin_stdc_bit_ceil((unsigned __int128)1) == 1, "");
+static_assert(__builtin_stdc_bit_ceil((unsigned __int128)3) == 4, "");
+// MSB tests using constexpr to form the value.
constexpr unsigned __int128 int128_one = 1;
constexpr unsigned __int128 int128_msb = int128_one << 127;
static_assert(__builtin_stdc_leading_zeros(int128_msb) == 0, "");
+static_assert(__builtin_stdc_leading_ones(int128_msb) == 1, "");
static_assert(__builtin_stdc_trailing_zeros(int128_msb) == 127, "");
+static_assert(__builtin_stdc_trailing_ones(int128_msb) == 0, "");
+static_assert(__builtin_stdc_first_leading_zero(int128_msb) == 2, "");
+static_assert(__builtin_stdc_first_leading_one(int128_msb) == 1, "");
+static_assert(__builtin_stdc_first_trailing_zero(int128_msb) == 1, "");
+static_assert(__builtin_stdc_first_trailing_one(int128_msb) == 128, "");
+static_assert(__builtin_stdc_count_ones(int128_msb) == 1, "");
+static_assert(__builtin_stdc_count_zeros(int128_msb) == 127, "");
static_assert(__builtin_stdc_has_single_bit(int128_msb) == 1, "");
static_assert(__builtin_stdc_bit_width(int128_msb) == 128, "");
static_assert(__builtin_stdc_bit_floor(int128_msb) == int128_msb, "");
+static_assert(__builtin_stdc_bit_ceil(int128_msb) == int128_msb, "");
} // namespace test_int128
+#endif // __SIZEOF_INT128__
namespace test_bitint {
+// _BitInt(37): all 14 builtins
static_assert(__builtin_stdc_leading_zeros((unsigned _BitInt(37))0) == 37, "");
static_assert(__builtin_stdc_leading_zeros((unsigned _BitInt(37))1) == 36, "");
+static_assert(__builtin_stdc_leading_ones((unsigned _BitInt(37))0) == 0, "");
+static_assert(__builtin_stdc_leading_ones((unsigned _BitInt(37))-1) == 37, "");
static_assert(__builtin_stdc_trailing_zeros((unsigned _BitInt(37))0) == 37, "");
+static_assert(__builtin_stdc_trailing_zeros((unsigned _BitInt(37))1) == 0, "");
+static_assert(__builtin_stdc_trailing_ones((unsigned _BitInt(37))0) == 0, "");
+static_assert(__builtin_stdc_trailing_ones((unsigned _BitInt(37))-1) == 37, "");
+static_assert(__builtin_stdc_first_leading_zero((unsigned _BitInt(37))0) == 1, "");
+static_assert(__builtin_stdc_first_leading_zero((unsigned _BitInt(37))-1) == 0, "");
+static_assert(__builtin_stdc_first_leading_one((unsigned _BitInt(37))0) == 0, "");
+static_assert(__builtin_stdc_first_leading_one((unsigned _BitInt(37))1) == 37, "");
+static_assert(__builtin_stdc_first_trailing_zero((unsigned _BitInt(37))0) == 1, "");
+static_assert(__builtin_stdc_first_trailing_zero((unsigned _BitInt(37))-1) == 0, "");
+static_assert(__builtin_stdc_first_trailing_one((unsigned _BitInt(37))0) == 0, "");
+static_assert(__builtin_stdc_first_trailing_one((unsigned _BitInt(37))1) == 1, "");
static_assert(__builtin_stdc_count_ones((unsigned _BitInt(37))0x1F) == 5, "");
+static_assert(__builtin_stdc_count_zeros((unsigned _BitInt(37))0) == 37, "");
+static_assert(__builtin_stdc_count_zeros((unsigned _BitInt(37))-1) == 0, "");
static_assert(__builtin_stdc_has_single_bit((unsigned _BitInt(37))0x10) == 1, "");
+static_assert(__builtin_stdc_has_single_bit((unsigned _BitInt(37))0) == 0, "");
+static_assert(__builtin_stdc_has_single_bit((unsigned _BitInt(37))3) == 0, "");
static_assert(__builtin_stdc_bit_width((unsigned _BitInt(37))0x10) == 5, "");
+static_assert(__builtin_stdc_bit_width((unsigned _BitInt(37))0) == 0, "");
+static_assert(__builtin_stdc_bit_width((unsigned _BitInt(37))-1) == 37, "");
static_assert(__builtin_stdc_bit_floor((unsigned _BitInt(37))0x1F) == 0x10, "");
static_assert(__builtin_stdc_bit_ceil((unsigned _BitInt(37))0x11) == 0x20, "");
+// Overflow: next power of 2 exceeds _BitInt(17) width; implementation wraps.
static_assert(__builtin_stdc_bit_ceil((unsigned _BitInt(17))(-1)) ==
(unsigned _BitInt(17))(-1), "");
+// _BitInt(128): sparse pattern, leading zero count, popcount.
constexpr unsigned _BitInt(128) bi128_pattern = 0x123456789ABCDEF0ULL;
static_assert(__builtin_stdc_count_ones(bi128_pattern) == 32, "");
static_assert(__builtin_stdc_leading_zeros(bi128_pattern) == 67, "");
+static_assert(__builtin_stdc_count_zeros(bi128_pattern) == 96, "");
+// _BitInt(9): boundary width near a byte.
static_assert(__builtin_stdc_leading_zeros((unsigned _BitInt(9))0) == 9, "");
static_assert(__builtin_stdc_trailing_zeros((unsigned _BitInt(9))0x100) == 8, "");
static_assert(__builtin_stdc_count_ones((unsigned _BitInt(9))0x1FF) == 9, "");
+static_assert(__builtin_stdc_count_zeros((unsigned _BitInt(9))0x1FF) == 0, "");
+static_assert(__builtin_stdc_has_single_bit((unsigned _BitInt(9))0x100) == 1, "");
+static_assert(__builtin_stdc_bit_width((unsigned _BitInt(9))0x100) == 9, "");
+static_assert(__builtin_stdc_bit_floor((unsigned _BitInt(9))0x1FF) == 0x100, "");
} // namespace test_bitint
namespace test_errors {
void test_invalid_types(int si, float f) {
- __builtin_stdc_leading_zeros(si); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
- __builtin_stdc_leading_zeros(f); // expected-error {{1st argument must be a scalar unsigned integer type (was 'float')}}
- __builtin_stdc_leading_zeros(-1); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
+ __builtin_stdc_leading_zeros(si); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
+ __builtin_stdc_leading_zeros(f); // expected-error {{1st argument must be a scalar unsigned integer type (was 'float')}}
+ __builtin_stdc_leading_zeros(-1); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
+
+ __builtin_stdc_leading_ones(si); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
+ __builtin_stdc_leading_ones(f); // expected-error {{1st argument must be a scalar unsigned integer type (was 'float')}}
+
+ __builtin_stdc_trailing_zeros(si); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
+ __builtin_stdc_trailing_zeros(f); // expected-error {{1st argument must be a scalar unsigned integer type (was 'float')}}
+
+ __builtin_stdc_trailing_ones(si); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
+ __builtin_stdc_trailing_ones(f); // expected-error {{1st argument must be a scalar unsigned integer type (was 'float')}}
+
+ __builtin_stdc_first_leading_zero(si); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
+ __builtin_stdc_first_leading_zero(f); // expected-error {{1st argument must be a scalar unsigned integer type (was 'float')}}
+
+ __builtin_stdc_first_leading_one(si); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
+ __builtin_stdc_first_leading_one(f); // expected-error {{1st argument must be a scalar unsigned integer type (was 'float')}}
+
+ __builtin_stdc_first_trailing_zero(si); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
+ __builtin_stdc_first_trailing_zero(f); // expected-error {{1st argument must be a scalar unsigned integer type (was 'float')}}
+
+ __builtin_stdc_first_trailing_one(si); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
+ __builtin_stdc_first_trailing_one(f); // expected-error {{1st argument must be a scalar unsigned integer type (was 'float')}}
__builtin_stdc_count_ones(si); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
+ __builtin_stdc_count_ones(f); // expected-error {{1st argument must be a scalar unsigned integer type (was 'float')}}
+
+ __builtin_stdc_count_zeros(si); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
+ __builtin_stdc_count_zeros(f); // expected-error {{1st argument must be a scalar unsigned integer type (was 'float')}}
+
__builtin_stdc_has_single_bit(si); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
+ __builtin_stdc_has_single_bit(f); // expected-error {{1st argument must be a scalar unsigned integer type (was 'float')}}
+
+ __builtin_stdc_bit_width(si); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
+ __builtin_stdc_bit_width(f); // expected-error {{1st argument must be a scalar unsigned integer type (was 'float')}}
+
+ __builtin_stdc_bit_floor(si); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
+ __builtin_stdc_bit_floor(f); // expected-error {{1st argument must be a scalar unsigned integer type (was 'float')}}
+
__builtin_stdc_bit_ceil(si); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
+ __builtin_stdc_bit_ceil(f); // expected-error {{1st argument must be a scalar unsigned integer type (was 'float')}}
}
} // namespace test_errors
>From 03cfc5224131d1376ef41aae19b36849decd144f Mon Sep 17 00:00:00 2001
From: NagaChaitanya Vellanki <pnagato at protonmail.com>
Date: Thu, 26 Feb 2026 13:26:25 -0800
Subject: [PATCH 03/14] Add missing edge test cases; Refactor to use
countl_zero, countl_one, countr_zero, countr_one
---
clang/lib/AST/ByteCode/InterpBuiltin.cpp | 11 ++---
clang/lib/AST/ExprConstant.cpp | 32 +++++-------
clang/lib/CodeGen/CGBuiltin.cpp | 49 +++++--------------
.../test/CodeGen/builtin-stdc-bit-functions.c | 12 ++---
4 files changed, 36 insertions(+), 68 deletions(-)
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index 84d38ca2973ff..042ca8d0b6574 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -4533,14 +4533,13 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
S, OpPC, Call, [](const APSInt &Val) {
unsigned BitWidth = Val.getBitWidth();
if (Val.ule(1))
- return llvm::APInt(BitWidth, 1);
- if (Val.isAllOnes())
- return static_cast<const llvm::APInt &>(Val);
- llvm::APInt ValMinusOne = static_cast<const llvm::APInt &>(Val) - 1;
+ return APInt(BitWidth, 1);
+ APInt V = Val;
+ APInt ValMinusOne = V - 1;
unsigned LeadingZeros = ValMinusOne.countl_zero();
if (LeadingZeros == 0)
- return static_cast<const llvm::APInt &>(Val); // would overflow
- return llvm::APInt::getOneBitSet(BitWidth, BitWidth - LeadingZeros);
+ return V; // would overflow; return input unchanged
+ return APInt::getOneBitSet(BitWidth, BitWidth - LeadingZeros);
});
case Builtin::BI__builtin_ffs:
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index d3179d13b310f..85faee2eb38a4 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -16848,29 +16848,25 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
switch (BuiltinOp) {
case Builtin::BI__builtin_stdc_leading_zeros:
- return Success(APInt(ResBitWidth, Val.countLeadingZeros()), E);
+ return Success(APInt(ResBitWidth, Val.countl_zero()), E);
case Builtin::BI__builtin_stdc_leading_ones:
- return Success(APInt(ResBitWidth, Val.countLeadingOnes()), E);
+ return Success(APInt(ResBitWidth, Val.countl_one()), E);
case Builtin::BI__builtin_stdc_trailing_zeros:
- return Success(APInt(ResBitWidth, Val.countTrailingZeros()), E);
+ return Success(APInt(ResBitWidth, Val.countr_zero()), E);
case Builtin::BI__builtin_stdc_trailing_ones:
- return Success(APInt(ResBitWidth, Val.countTrailingOnes()), E);
+ return Success(APInt(ResBitWidth, Val.countr_one()), E);
case Builtin::BI__builtin_stdc_first_leading_zero:
return Success(
- APInt(ResBitWidth, Val.isAllOnes() ? 0 : Val.countLeadingOnes() + 1),
- E);
+ APInt(ResBitWidth, Val.isAllOnes() ? 0 : Val.countl_one() + 1), E);
case Builtin::BI__builtin_stdc_first_leading_one:
return Success(
- APInt(ResBitWidth, Val.isZero() ? 0 : Val.countLeadingZeros() + 1),
- E);
+ APInt(ResBitWidth, Val.isZero() ? 0 : Val.countl_zero() + 1), E);
case Builtin::BI__builtin_stdc_first_trailing_zero:
return Success(
- APInt(ResBitWidth, Val.isAllOnes() ? 0 : Val.countTrailingOnes() + 1),
- E);
+ APInt(ResBitWidth, Val.isAllOnes() ? 0 : Val.countr_one() + 1), E);
case Builtin::BI__builtin_stdc_first_trailing_one:
return Success(
- APInt(ResBitWidth, Val.isZero() ? 0 : Val.countTrailingZeros() + 1),
- E);
+ APInt(ResBitWidth, Val.isZero() ? 0 : Val.countr_zero() + 1), E);
case Builtin::BI__builtin_stdc_count_zeros: {
APInt Cnt(ResBitWidth, BitWidth - Val.popcount());
return Success(APSInt(Cnt, /*IsUnsigned*/ true), E);
@@ -16884,23 +16880,21 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
return Success(APSInt(Res, /*IsUnsigned*/ true), E);
}
case Builtin::BI__builtin_stdc_bit_width:
- return Success(APInt(ResBitWidth, BitWidth - Val.countLeadingZeros()), E);
+ return Success(APInt(ResBitWidth, BitWidth - Val.countl_zero()), E);
case Builtin::BI__builtin_stdc_bit_floor: {
if (Val.isZero())
- return Success(APInt(ResBitWidth, 0), E);
- unsigned Exp = BitWidth - Val.countLeadingZeros() - 1;
+ return Success(APInt(BitWidth, 0), E);
+ unsigned Exp = BitWidth - Val.countl_zero() - 1;
return Success(
APSInt(APInt::getOneBitSet(BitWidth, Exp), /*IsUnsigned*/ true), E);
}
case Builtin::BI__builtin_stdc_bit_ceil: {
if (Val.ule(1))
return Success(APSInt(APInt(BitWidth, 1), /*IsUnsigned*/ true), E);
- if (Val.isAllOnes())
- return Success(APSInt(Val), E);
APInt ValMinusOne = Val - 1;
- unsigned LZ = ValMinusOne.countLeadingZeros();
+ unsigned LZ = ValMinusOne.countl_zero();
if (LZ == 0)
- return Success(APSInt(Val), E); // would overflow; clamp
+ return Success(APSInt(Val), E); // would overflow; return input unchanged
APInt Result = APInt::getOneBitSet(BitWidth, BitWidth - LZ);
return Success(APSInt(Result, /*IsUnsigned*/ true), E);
}
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index da64bf70df3b9..7cf3c62e5ef86 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3838,32 +3838,16 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
}
case Builtin::BI__builtin_stdc_bit_floor: {
// Spec: arg == 0 ? 0 : 1 << (prec - 1 - clz(arg))
- Value *IsZero = Builder.CreateICmpEQ(ArgValue, Zero);
- BasicBlock *ZeroBB = createBasicBlock("bitfloor.zero", CurFn);
- BasicBlock *CalcBB = createBasicBlock("bitfloor.calc", CurFn);
- BasicBlock *MergeBB = createBasicBlock("bitfloor.merge", CurFn);
-
- Builder.CreateCondBr(IsZero, ZeroBB, CalcBB);
-
- // Zero path.
- Builder.SetInsertPoint(ZeroBB);
- Builder.CreateBr(MergeBB);
-
- // General path.
- Builder.SetInsertPoint(CalcBB);
+ // Use ctlz with is_zero_poison=true and a select so the zero case never
+ // materialises the poison value. This avoids a branch and PHI node and
+ // allows the backend to emit a conditional move.
Function *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType);
- Value *LZ = Builder.CreateCall(F, {ArgValue, Builder.getFalse()});
+ Value *LZ = Builder.CreateCall(F, {ArgValue, Builder.getTrue()});
Value *ShiftAmt =
Builder.CreateSub(ConstantInt::get(ArgType, BitWidth - 1), LZ);
- Value *Tmp = Builder.CreateShl(One, ShiftAmt);
- Builder.CreateBr(MergeBB);
-
- // Merge.
- Builder.SetInsertPoint(MergeBB);
- PHINode *Phi = Builder.CreatePHI(ArgType, 2);
- Phi->addIncoming(Zero, ZeroBB);
- Phi->addIncoming(Tmp, CalcBB);
- Result = Phi;
+ Value *Shifted = Builder.CreateShl(One, ShiftAmt);
+ Value *IsZero = Builder.CreateICmpEQ(ArgValue, Zero);
+ Result = Builder.CreateSelect(IsZero, Zero, Shifted);
break;
}
case Builtin::BI__builtin_stdc_bit_ceil: {
@@ -3875,29 +3859,21 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
return RValue::get(ConstantInt::get(ArgType, 1));
}
- Value *AllOnes = Constant::getAllOnesValue(ArgType);
- Value *IsAllOnes = Builder.CreateICmpEQ(ArgValue, AllOnes, "isallones");
Value *IsLEOne = Builder.CreateICmpULE(ArgValue, One, "isleone");
- BasicBlock *AllOnesBB = createBasicBlock("bitceil.allones", CurFn);
- BasicBlock *LEOneBB = createBasicBlock("bitceil.leone", CurFn);
+ BasicBlock *EntryBB = Builder.GetInsertBlock();
BasicBlock *CalcBB = createBasicBlock("bitceil.calc", CurFn);
BasicBlock *MergeBB = createBasicBlock("bitceil.merge", CurFn);
- // If all ones -> return operand
- Builder.CreateCondBr(IsAllOnes, AllOnesBB, LEOneBB);
-
- Builder.SetInsertPoint(AllOnesBB);
- Builder.CreateBr(MergeBB);
-
// If <= 1 -> return 1, else compute.
- Builder.SetInsertPoint(LEOneBB);
Builder.CreateCondBr(IsLEOne, MergeBB, CalcBB);
Builder.SetInsertPoint(CalcBB);
Function *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType);
Value *ArgMinusOne = Builder.CreateSub(ArgValue, One);
Value *LZ = Builder.CreateCall(F, {ArgMinusOne, Builder.getFalse()});
+ // LZ == 0 means arg-1 has the MSB set, so the next power of 2 would
+ // overflow the type; return arg unchanged.
Value *LZIsZero = Builder.CreateICmpEQ(LZ, Zero, "lzzero");
Value *ShiftAmt =
Builder.CreateSub(ConstantInt::get(ArgType, BitWidth), LZ);
@@ -3906,9 +3882,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
Builder.CreateBr(MergeBB);
Builder.SetInsertPoint(MergeBB);
- PHINode *Phi = Builder.CreatePHI(ArgType, 3);
- Phi->addIncoming(ArgValue, AllOnesBB);
- Phi->addIncoming(One, LEOneBB);
+ PHINode *Phi = Builder.CreatePHI(ArgType, 2);
+ Phi->addIncoming(One, EntryBB);
Phi->addIncoming(Tmp, CalcBB);
Result = Phi;
break;
diff --git a/clang/test/CodeGen/builtin-stdc-bit-functions.c b/clang/test/CodeGen/builtin-stdc-bit-functions.c
index 7687510b52321..bbccd6114f797 100644
--- a/clang/test/CodeGen/builtin-stdc-bit-functions.c
+++ b/clang/test/CodeGen/builtin-stdc-bit-functions.c
@@ -174,10 +174,10 @@ void test_bit_width(unsigned char uc, unsigned short us, unsigned int ui, unsign
}
// CHECK-LABEL: test_bit_floor
-// CHECK: call i8 @llvm.ctlz.i8(i8 %{{.*}}, i1 false)
-// CHECK: call i16 @llvm.ctlz.i16(i16 %{{.*}}, i1 false)
-// CHECK: call i32 @llvm.ctlz.i32(i32 %{{.*}}, i1 false)
-// CHECK: call i64 @llvm.ctlz.i64(i64 %{{.*}}, i1 false)
+// CHECK: call i8 @llvm.ctlz.i8(i8 %{{.*}}, i1 true)
+// CHECK: call i16 @llvm.ctlz.i16(i16 %{{.*}}, i1 true)
+// CHECK: call i32 @llvm.ctlz.i32(i32 %{{.*}}, i1 true)
+// CHECK: call i64 @llvm.ctlz.i64(i64 %{{.*}}, i1 true)
void test_bit_floor(unsigned char uc, unsigned short us, unsigned int ui, unsigned long long ull) {
volatile unsigned char rc;
volatile unsigned short rs;
@@ -219,7 +219,7 @@ void test_bitint(unsigned _BitInt(37) bi) {
// Additional _BitInt coverage
// CHECK-LABEL: test_bitint_floor_ceil
-// CHECK: call i9 @llvm.ctlz.i9(i9 %{{.*}}, i1 false)
+// CHECK: call i9 @llvm.ctlz.i9(i9 %{{.*}}, i1 true)
// CHECK: call i9 @llvm.ctlz.i9(i9 %{{.*}}, i1 false)
void test_bitint_floor_ceil(unsigned _BitInt(9) bi9) {
volatile unsigned _BitInt(9) rb;
@@ -317,7 +317,7 @@ void test_int128_count_has_width(unsigned __int128 u128) {
}
// INT128-LABEL: test_int128_floor_ceil
-// INT128: call i128 @llvm.ctlz.i128(i128 %{{.*}}, i1 false)
+// INT128: call i128 @llvm.ctlz.i128(i128 %{{.*}}, i1 true)
// INT128: call i128 @llvm.ctlz.i128(i128 %{{.*}}, i1 false)
void test_int128_floor_ceil(unsigned __int128 u128) {
volatile unsigned __int128 r;
>From f7aad00222eb1ed87886cfadae4b5aab8a3c3d88 Mon Sep 17 00:00:00 2001
From: NagaChaitanya Vellanki <pnagato at protonmail.com>
Date: Wed, 11 Mar 2026 14:17:46 -0700
Subject: [PATCH 04/14] Address clang-format check failure
---
clang/lib/AST/ExprConstant.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 85faee2eb38a4..74bbdf24f13b9 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -16894,7 +16894,8 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
APInt ValMinusOne = Val - 1;
unsigned LZ = ValMinusOne.countl_zero();
if (LZ == 0)
- return Success(APSInt(Val), E); // would overflow; return input unchanged
+ return Success(APSInt(Val),
+ E); // would overflow; return input unchanged
APInt Result = APInt::getOneBitSet(BitWidth, BitWidth - LZ);
return Success(APSInt(Result, /*IsUnsigned*/ true), E);
}
>From bc7e903a38e3fb476d910db4b38aa80cea1d069a Mon Sep 17 00:00:00 2001
From: NagaChaitanya Vellanki <pnagato at protonmail.com>
Date: Wed, 11 Mar 2026 16:33:12 -0700
Subject: [PATCH 05/14] Make unsigned long tests portable
---
clang/test/Sema/builtin-stdc-bit-functions.c | 94 ++++++++--------
.../constexpr-builtin-stdc-bit-functions.cpp | 102 ++++++++++--------
2 files changed, 105 insertions(+), 91 deletions(-)
diff --git a/clang/test/Sema/builtin-stdc-bit-functions.c b/clang/test/Sema/builtin-stdc-bit-functions.c
index 92fdef352de1c..34e05b323fbab 100644
--- a/clang/test/Sema/builtin-stdc-bit-functions.c
+++ b/clang/test/Sema/builtin-stdc-bit-functions.c
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fsyntax-only -verify %s
-// RUN: %if clang-target-64-bits %{ %clang_cc1 -fsyntax-only -verify %s %}
+// RUN: %clang_cc1 -fsyntax-only -verify %s
// Test stdc_leading_zeros
_Static_assert(__builtin_stdc_leading_zeros((unsigned char)0) == 8, "");
@@ -12,9 +12,6 @@ _Static_assert(__builtin_stdc_leading_zeros((unsigned short)0x8000) == 0, "");
_Static_assert(__builtin_stdc_leading_zeros(0U) == 32, "");
_Static_assert(__builtin_stdc_leading_zeros(1U) == 31, "");
_Static_assert(__builtin_stdc_leading_zeros(0x80000000U) == 0, "");
-_Static_assert(__builtin_stdc_leading_zeros(0UL) == 64, "");
-_Static_assert(__builtin_stdc_leading_zeros(1UL) == 63, "");
-_Static_assert(__builtin_stdc_leading_zeros(0x8000000000000000UL) == 0, "");
_Static_assert(__builtin_stdc_leading_zeros(0ULL) == 64, "");
_Static_assert(__builtin_stdc_leading_zeros(1ULL) == 63, "");
_Static_assert(__builtin_stdc_leading_zeros(0x8000000000000000ULL) == 0, "");
@@ -29,9 +26,6 @@ _Static_assert(__builtin_stdc_leading_ones((unsigned short)0xF000) == 4, "");
_Static_assert(__builtin_stdc_leading_ones(0U) == 0, "");
_Static_assert(__builtin_stdc_leading_ones(0xFFFFFFFFU) == 32, "");
_Static_assert(__builtin_stdc_leading_ones(0xF0000000U) == 4, "");
-_Static_assert(__builtin_stdc_leading_ones(0UL) == 0, "");
-_Static_assert(__builtin_stdc_leading_ones(0xFFFFFFFFFFFFFFFFUL) == 64, "");
-_Static_assert(__builtin_stdc_leading_ones(0xF000000000000000UL) == 4, "");
_Static_assert(__builtin_stdc_leading_ones(0ULL) == 0, "");
_Static_assert(__builtin_stdc_leading_ones(0xFFFFFFFFFFFFFFFFULL) == 64, "");
@@ -45,9 +39,6 @@ _Static_assert(__builtin_stdc_trailing_zeros((unsigned short)0x8000) == 15, "");
_Static_assert(__builtin_stdc_trailing_zeros(0U) == 32, "");
_Static_assert(__builtin_stdc_trailing_zeros(1U) == 0, "");
_Static_assert(__builtin_stdc_trailing_zeros(0x80000000U) == 31, "");
-_Static_assert(__builtin_stdc_trailing_zeros(0UL) == 64, "");
-_Static_assert(__builtin_stdc_trailing_zeros(1UL) == 0, "");
-_Static_assert(__builtin_stdc_trailing_zeros(0x8000000000000000UL) == 63, "");
_Static_assert(__builtin_stdc_trailing_zeros(0ULL) == 64, "");
_Static_assert(__builtin_stdc_trailing_zeros(1ULL) == 0, "");
_Static_assert(__builtin_stdc_trailing_zeros(0x8000000000000000ULL) == 63, "");
@@ -63,9 +54,6 @@ _Static_assert(__builtin_stdc_trailing_ones(0U) == 0, "");
_Static_assert(__builtin_stdc_trailing_ones(1U) == 1, "");
_Static_assert(__builtin_stdc_trailing_ones(0xFFFFFFFFU) == 32, "");
_Static_assert(__builtin_stdc_trailing_ones(0x0000000FU) == 4, "");
-_Static_assert(__builtin_stdc_trailing_ones(0UL) == 0, "");
-_Static_assert(__builtin_stdc_trailing_ones(0xFFFFFFFFFFFFFFFFUL) == 64, "");
-_Static_assert(__builtin_stdc_trailing_ones(0x000000000000000FUL) == 4, "");
_Static_assert(__builtin_stdc_trailing_ones(0ULL) == 0, "");
_Static_assert(__builtin_stdc_trailing_ones(1ULL) == 1, "");
_Static_assert(__builtin_stdc_trailing_ones(0xFFFFFFFFFFFFFFFFULL) == 64, "");
@@ -80,9 +68,6 @@ _Static_assert(__builtin_stdc_first_leading_zero((unsigned short)0xFFFF) == 0, "
_Static_assert(__builtin_stdc_first_leading_zero((unsigned short)0xF000) == 5, "");
_Static_assert(__builtin_stdc_first_leading_zero(0xFFFFFFFFU) == 0, "");
_Static_assert(__builtin_stdc_first_leading_zero(0xF0000000U) == 5, "");
-_Static_assert(__builtin_stdc_first_leading_zero(0UL) == 1, "");
-_Static_assert(__builtin_stdc_first_leading_zero(0xFFFFFFFFFFFFFFFFUL) == 0, "");
-_Static_assert(__builtin_stdc_first_leading_zero(0xF000000000000000UL) == 5, "");
_Static_assert(__builtin_stdc_first_leading_zero(0ULL) == 1, "");
_Static_assert(__builtin_stdc_first_leading_zero(0xFFFFFFFFFFFFFFFFULL) == 0, "");
_Static_assert(__builtin_stdc_first_leading_zero(0xF000000000000000ULL) == 5, "");
@@ -98,9 +83,6 @@ _Static_assert(__builtin_stdc_first_leading_one((unsigned short)1) == 16, "");
_Static_assert(__builtin_stdc_first_leading_one(0U) == 0, "");
_Static_assert(__builtin_stdc_first_leading_one(0x80000000U) == 1, "");
_Static_assert(__builtin_stdc_first_leading_one(1U) == 32, "");
-_Static_assert(__builtin_stdc_first_leading_one(0UL) == 0, "");
-_Static_assert(__builtin_stdc_first_leading_one(0x8000000000000000UL) == 1, "");
-_Static_assert(__builtin_stdc_first_leading_one(1UL) == 64, "");
_Static_assert(__builtin_stdc_first_leading_one(0ULL) == 0, "");
_Static_assert(__builtin_stdc_first_leading_one(0x8000000000000000ULL) == 1, "");
_Static_assert(__builtin_stdc_first_leading_one(1ULL) == 64, "");
@@ -115,9 +97,6 @@ _Static_assert(__builtin_stdc_first_trailing_zero((unsigned short)0xFFFF) == 0,
_Static_assert(__builtin_stdc_first_trailing_zero((unsigned short)0x000F) == 5, "");
_Static_assert(__builtin_stdc_first_trailing_zero(0xFFFFFFFFU) == 0, "");
_Static_assert(__builtin_stdc_first_trailing_zero(0x0000000FU) == 5, "");
-_Static_assert(__builtin_stdc_first_trailing_zero(0UL) == 1, "");
-_Static_assert(__builtin_stdc_first_trailing_zero(0xFFFFFFFFFFFFFFFFUL) == 0, "");
-_Static_assert(__builtin_stdc_first_trailing_zero(0x000000000000000FUL) == 5, "");
_Static_assert(__builtin_stdc_first_trailing_zero(0ULL) == 1, "");
_Static_assert(__builtin_stdc_first_trailing_zero(0xFFFFFFFFFFFFFFFFULL) == 0, "");
_Static_assert(__builtin_stdc_first_trailing_zero(0x000000000000000FULL) == 5, "");
@@ -133,9 +112,6 @@ _Static_assert(__builtin_stdc_first_trailing_one((unsigned short)0x8000) == 16,
_Static_assert(__builtin_stdc_first_trailing_one(0U) == 0, "");
_Static_assert(__builtin_stdc_first_trailing_one(0x80000000U) == 32, "");
_Static_assert(__builtin_stdc_first_trailing_one(1U) == 1, "");
-_Static_assert(__builtin_stdc_first_trailing_one(0UL) == 0, "");
-_Static_assert(__builtin_stdc_first_trailing_one(1UL) == 1, "");
-_Static_assert(__builtin_stdc_first_trailing_one(0x8000000000000000UL) == 64, "");
_Static_assert(__builtin_stdc_first_trailing_one(0ULL) == 0, "");
_Static_assert(__builtin_stdc_first_trailing_one(1ULL) == 1, "");
_Static_assert(__builtin_stdc_first_trailing_one(0x8000000000000000ULL) == 64, "");
@@ -150,9 +126,6 @@ _Static_assert(__builtin_stdc_count_zeros((unsigned short)0xAAAA) == 8, "");
_Static_assert(__builtin_stdc_count_zeros(0U) == 32, "");
_Static_assert(__builtin_stdc_count_zeros(0xFFFFFFFFU) == 0, "");
_Static_assert(__builtin_stdc_count_zeros(0xAAAAAAAAU) == 16, "");
-_Static_assert(__builtin_stdc_count_zeros(0UL) == 64, "");
-_Static_assert(__builtin_stdc_count_zeros(0xFFFFFFFFFFFFFFFFUL) == 0, "");
-_Static_assert(__builtin_stdc_count_zeros(0xAAAAAAAAAAAAAAAAUL) == 32, "");
_Static_assert(__builtin_stdc_count_zeros(0ULL) == 64, "");
_Static_assert(__builtin_stdc_count_zeros(0xFFFFFFFFFFFFFFFFULL) == 0, "");
_Static_assert(__builtin_stdc_count_zeros(0xAAAAAAAAAAAAAAAAULL) == 32, "");
@@ -167,9 +140,6 @@ _Static_assert(__builtin_stdc_count_ones((unsigned short)0xAAAA) == 8, "");
_Static_assert(__builtin_stdc_count_ones(0U) == 0, "");
_Static_assert(__builtin_stdc_count_ones(0xFFFFFFFFU) == 32, "");
_Static_assert(__builtin_stdc_count_ones(0xAAAAAAAAU) == 16, "");
-_Static_assert(__builtin_stdc_count_ones(0UL) == 0, "");
-_Static_assert(__builtin_stdc_count_ones(0xFFFFFFFFFFFFFFFFUL) == 64, "");
-_Static_assert(__builtin_stdc_count_ones(0xAAAAAAAAAAAAAAAAUL) == 32, "");
_Static_assert(__builtin_stdc_count_ones(0ULL) == 0, "");
_Static_assert(__builtin_stdc_count_ones(0xFFFFFFFFFFFFFFFFULL) == 64, "");
_Static_assert(__builtin_stdc_count_ones(0xAAAAAAAAAAAAAAAAULL) == 32, "");
@@ -188,10 +158,6 @@ _Static_assert(__builtin_stdc_has_single_bit(0U) == 0, "");
_Static_assert(__builtin_stdc_has_single_bit(1U) == 1, "");
_Static_assert(__builtin_stdc_has_single_bit(0x80000000U) == 1, "");
_Static_assert(__builtin_stdc_has_single_bit(0xFFFFFFFFU) == 0, "");
-_Static_assert(__builtin_stdc_has_single_bit(0UL) == 0, "");
-_Static_assert(__builtin_stdc_has_single_bit(1UL) == 1, "");
-_Static_assert(__builtin_stdc_has_single_bit(0x8000000000000000UL) == 1, "");
-_Static_assert(__builtin_stdc_has_single_bit(0xFFFFFFFFFFFFFFFFUL) == 0, "");
_Static_assert(__builtin_stdc_has_single_bit(0ULL) == 0, "");
_Static_assert(__builtin_stdc_has_single_bit(1ULL) == 1, "");
_Static_assert(__builtin_stdc_has_single_bit(0x8000000000000000ULL) == 1, "");
@@ -210,9 +176,6 @@ _Static_assert(__builtin_stdc_bit_width((unsigned short)0x8000) == 16, "");
_Static_assert(__builtin_stdc_bit_width(0U) == 0, "");
_Static_assert(__builtin_stdc_bit_width(1U) == 1, "");
_Static_assert(__builtin_stdc_bit_width(0x80000000U) == 32, "");
-_Static_assert(__builtin_stdc_bit_width(0UL) == 0, "");
-_Static_assert(__builtin_stdc_bit_width(1UL) == 1, "");
-_Static_assert(__builtin_stdc_bit_width(0x8000000000000000UL) == 64, "");
_Static_assert(__builtin_stdc_bit_width(0ULL) == 0, "");
_Static_assert(__builtin_stdc_bit_width(1ULL) == 1, "");
_Static_assert(__builtin_stdc_bit_width(0x8000000000000000ULL) == 64, "");
@@ -234,9 +197,6 @@ _Static_assert(__builtin_stdc_bit_floor(1U) == 1U, "");
_Static_assert(__builtin_stdc_bit_floor(7U) == 4U, "");
_Static_assert(__builtin_stdc_bit_floor(0x80000000U) == 0x80000000U, "");
_Static_assert(__builtin_stdc_bit_floor(0xFFFFFFFFU) == 0x80000000U, "");
-_Static_assert(__builtin_stdc_bit_floor(0UL) == 0UL, "");
-_Static_assert(__builtin_stdc_bit_floor(1UL) == 1UL, "");
-_Static_assert(__builtin_stdc_bit_floor(0xFFFFFFFFFFFFFFFFUL) == 0x8000000000000000UL, "");
_Static_assert(__builtin_stdc_bit_floor(0ULL) == 0ULL, "");
_Static_assert(__builtin_stdc_bit_floor(1ULL) == 1ULL, "");
_Static_assert(__builtin_stdc_bit_floor(0xFFFFFFFFFFFFFFFFULL) == 0x8000000000000000ULL, "");
@@ -257,10 +217,6 @@ _Static_assert(__builtin_stdc_bit_ceil(0U) == 1U, "");
_Static_assert(__builtin_stdc_bit_ceil(1U) == 1U, "");
_Static_assert(__builtin_stdc_bit_ceil(7U) == 8U, "");
_Static_assert(__builtin_stdc_bit_ceil(0x80000000U) == 0x80000000U, "");
-_Static_assert(__builtin_stdc_bit_ceil(0UL) == 1UL, "");
-_Static_assert(__builtin_stdc_bit_ceil(1UL) == 1UL, "");
-_Static_assert(__builtin_stdc_bit_ceil(7UL) == 8UL, "");
-_Static_assert(__builtin_stdc_bit_ceil(0x8000000000000000UL) == 0x8000000000000000UL, "");
_Static_assert(__builtin_stdc_bit_ceil(0ULL) == 1ULL, "");
_Static_assert(__builtin_stdc_bit_ceil(1ULL) == 1ULL, "");
_Static_assert(__builtin_stdc_bit_ceil(7ULL) == 8ULL, "");
@@ -327,6 +283,54 @@ _Static_assert(__builtin_stdc_bit_ceil((unsigned __int128)1) == 1, "");
_Static_assert(__builtin_stdc_bit_ceil((unsigned __int128)3) == 4, "");
#endif // __SIZEOF_INT128__
+// Test with unsigned long across all targets.
+enum { ULONG_WIDTH = __SIZEOF_LONG__ * 8 };
+
+_Static_assert(__builtin_stdc_leading_zeros(0UL) == ULONG_WIDTH, "");
+_Static_assert(__builtin_stdc_leading_zeros(1UL) == ULONG_WIDTH - 1, "");
+_Static_assert(__builtin_stdc_leading_zeros(1UL << (ULONG_WIDTH - 1)) == 0, "");
+_Static_assert(__builtin_stdc_leading_ones(0UL) == 0, "");
+_Static_assert(__builtin_stdc_leading_ones(~0UL) == ULONG_WIDTH, "");
+_Static_assert(__builtin_stdc_leading_ones(~0UL << (ULONG_WIDTH - 4)) == 4, "");
+_Static_assert(__builtin_stdc_trailing_zeros(0UL) == ULONG_WIDTH, "");
+_Static_assert(__builtin_stdc_trailing_zeros(1UL) == 0, "");
+_Static_assert(__builtin_stdc_trailing_zeros(1UL << (ULONG_WIDTH - 1)) == ULONG_WIDTH - 1, "");
+_Static_assert(__builtin_stdc_trailing_ones(0UL) == 0, "");
+_Static_assert(__builtin_stdc_trailing_ones(~0UL) == ULONG_WIDTH, "");
+_Static_assert(__builtin_stdc_trailing_ones(0xFUL) == 4, "");
+_Static_assert(__builtin_stdc_first_leading_zero(0UL) == 1, "");
+_Static_assert(__builtin_stdc_first_leading_zero(~0UL) == 0, "");
+_Static_assert(__builtin_stdc_first_leading_zero(~0UL << (ULONG_WIDTH - 4)) == 5, "");
+_Static_assert(__builtin_stdc_first_leading_one(0UL) == 0, "");
+_Static_assert(__builtin_stdc_first_leading_one(1UL << (ULONG_WIDTH - 1)) == 1, "");
+_Static_assert(__builtin_stdc_first_leading_one(1UL) == ULONG_WIDTH, "");
+_Static_assert(__builtin_stdc_first_trailing_zero(0UL) == 1, "");
+_Static_assert(__builtin_stdc_first_trailing_zero(~0UL) == 0, "");
+_Static_assert(__builtin_stdc_first_trailing_zero(0xFUL) == 5, "");
+_Static_assert(__builtin_stdc_first_trailing_one(0UL) == 0, "");
+_Static_assert(__builtin_stdc_first_trailing_one(1UL) == 1, "");
+_Static_assert(__builtin_stdc_first_trailing_one(1UL << (ULONG_WIDTH - 1)) == ULONG_WIDTH, "");
+_Static_assert(__builtin_stdc_count_zeros(0UL) == ULONG_WIDTH, "");
+_Static_assert(__builtin_stdc_count_zeros(~0UL) == 0, "");
+_Static_assert(__builtin_stdc_count_zeros(1UL << (ULONG_WIDTH - 1)) == ULONG_WIDTH - 1, "");
+_Static_assert(__builtin_stdc_count_ones(0UL) == 0, "");
+_Static_assert(__builtin_stdc_count_ones(~0UL) == ULONG_WIDTH, "");
+_Static_assert(__builtin_stdc_count_ones(1UL << (ULONG_WIDTH - 1)) == 1, "");
+_Static_assert(__builtin_stdc_has_single_bit(0UL) == 0, "");
+_Static_assert(__builtin_stdc_has_single_bit(1UL) == 1, "");
+_Static_assert(__builtin_stdc_has_single_bit(1UL << (ULONG_WIDTH - 1)) == 1, "");
+_Static_assert(__builtin_stdc_has_single_bit(~0UL) == 0, "");
+_Static_assert(__builtin_stdc_bit_width(0UL) == 0, "");
+_Static_assert(__builtin_stdc_bit_width(1UL) == 1, "");
+_Static_assert(__builtin_stdc_bit_width(1UL << (ULONG_WIDTH - 1)) == ULONG_WIDTH, "");
+_Static_assert(__builtin_stdc_bit_floor(0UL) == 0UL, "");
+_Static_assert(__builtin_stdc_bit_floor(1UL) == 1UL, "");
+_Static_assert(__builtin_stdc_bit_floor(~0UL) == (1UL << (ULONG_WIDTH - 1)), "");
+_Static_assert(__builtin_stdc_bit_ceil(0UL) == 1UL, "");
+_Static_assert(__builtin_stdc_bit_ceil(1UL) == 1UL, "");
+_Static_assert(__builtin_stdc_bit_ceil(7UL) == 8UL, "");
+_Static_assert(__builtin_stdc_bit_ceil(1UL << (ULONG_WIDTH - 1)) == (1UL << (ULONG_WIDTH - 1)), "");
+
// Error cases - all 14 builtins reject signed and floating-point arguments
void test_errors(int si, float f) {
__builtin_stdc_leading_zeros(si); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
diff --git a/clang/test/SemaCXX/constexpr-builtin-stdc-bit-functions.cpp b/clang/test/SemaCXX/constexpr-builtin-stdc-bit-functions.cpp
index b72c4ea574281..b66639d867d74 100644
--- a/clang/test/SemaCXX/constexpr-builtin-stdc-bit-functions.cpp
+++ b/clang/test/SemaCXX/constexpr-builtin-stdc-bit-functions.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -std=c++14 -fsyntax-only -verify %s
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -std=c++14 -fsyntax-only -verify %s -fexperimental-new-constant-interpreter
-// RUN: %if clang-target-64-bits %{ %clang_cc1 -std=c++14 -fsyntax-only -verify %s %}
-// RUN: %if clang-target-64-bits %{ %clang_cc1 -std=c++14 -fsyntax-only -verify %s -fexperimental-new-constant-interpreter %}
+// RUN: %clang_cc1 -std=c++14 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++14 -fsyntax-only -verify %s -fexperimental-new-constant-interpreter
namespace test_stdc_leading_zeros {
@@ -15,9 +15,6 @@ static_assert(__builtin_stdc_leading_zeros((unsigned short)0x8000) == 0, "");
static_assert(__builtin_stdc_leading_zeros(0U) == 32, "");
static_assert(__builtin_stdc_leading_zeros(1U) == 31, "");
static_assert(__builtin_stdc_leading_zeros(0x80000000U) == 0, "");
-static_assert(__builtin_stdc_leading_zeros(0UL) == 64, "");
-static_assert(__builtin_stdc_leading_zeros(1UL) == 63, "");
-static_assert(__builtin_stdc_leading_zeros(0x8000000000000000UL) == 0, "");
static_assert(__builtin_stdc_leading_zeros(0ULL) == 64, "");
static_assert(__builtin_stdc_leading_zeros(1ULL) == 63, "");
static_assert(__builtin_stdc_leading_zeros(0x8000000000000000ULL) == 0, "");
@@ -35,9 +32,6 @@ static_assert(__builtin_stdc_leading_ones((unsigned short)0xF000) == 4, "");
static_assert(__builtin_stdc_leading_ones(0U) == 0, "");
static_assert(__builtin_stdc_leading_ones(0xFFFFFFFFU) == 32, "");
static_assert(__builtin_stdc_leading_ones(0xF0000000U) == 4, "");
-static_assert(__builtin_stdc_leading_ones(0UL) == 0, "");
-static_assert(__builtin_stdc_leading_ones(0xFFFFFFFFFFFFFFFFUL) == 64, "");
-static_assert(__builtin_stdc_leading_ones(0xF000000000000000UL) == 4, "");
static_assert(__builtin_stdc_leading_ones(0ULL) == 0, "");
static_assert(__builtin_stdc_leading_ones(0xFFFFFFFFFFFFFFFFULL) == 64, "");
@@ -54,9 +48,6 @@ static_assert(__builtin_stdc_trailing_zeros((unsigned short)0x8000) == 15, "");
static_assert(__builtin_stdc_trailing_zeros(0U) == 32, "");
static_assert(__builtin_stdc_trailing_zeros(1U) == 0, "");
static_assert(__builtin_stdc_trailing_zeros(0x80000000U) == 31, "");
-static_assert(__builtin_stdc_trailing_zeros(0UL) == 64, "");
-static_assert(__builtin_stdc_trailing_zeros(1UL) == 0, "");
-static_assert(__builtin_stdc_trailing_zeros(0x8000000000000000UL) == 63, "");
static_assert(__builtin_stdc_trailing_zeros(0ULL) == 64, "");
static_assert(__builtin_stdc_trailing_zeros(1ULL) == 0, "");
static_assert(__builtin_stdc_trailing_zeros(0x8000000000000000ULL) == 63, "");
@@ -75,9 +66,6 @@ static_assert(__builtin_stdc_trailing_ones(0U) == 0, "");
static_assert(__builtin_stdc_trailing_ones(1U) == 1, "");
static_assert(__builtin_stdc_trailing_ones(0xFFFFFFFFU) == 32, "");
static_assert(__builtin_stdc_trailing_ones(0x0000000FU) == 4, "");
-static_assert(__builtin_stdc_trailing_ones(0UL) == 0, "");
-static_assert(__builtin_stdc_trailing_ones(0xFFFFFFFFFFFFFFFFUL) == 64, "");
-static_assert(__builtin_stdc_trailing_ones(0x000000000000000FUL) == 4, "");
static_assert(__builtin_stdc_trailing_ones(0ULL) == 0, "");
static_assert(__builtin_stdc_trailing_ones(1ULL) == 1, "");
static_assert(__builtin_stdc_trailing_ones(0xFFFFFFFFFFFFFFFFULL) == 64, "");
@@ -95,9 +83,6 @@ static_assert(__builtin_stdc_first_leading_zero((unsigned short)0xFFFF) == 0, ""
static_assert(__builtin_stdc_first_leading_zero((unsigned short)0xF000) == 5, "");
static_assert(__builtin_stdc_first_leading_zero(0xFFFFFFFFU) == 0, "");
static_assert(__builtin_stdc_first_leading_zero(0xF0000000U) == 5, "");
-static_assert(__builtin_stdc_first_leading_zero(0UL) == 1, "");
-static_assert(__builtin_stdc_first_leading_zero(0xFFFFFFFFFFFFFFFFUL) == 0, "");
-static_assert(__builtin_stdc_first_leading_zero(0xF000000000000000UL) == 5, "");
static_assert(__builtin_stdc_first_leading_zero(0ULL) == 1, "");
static_assert(__builtin_stdc_first_leading_zero(0xFFFFFFFFFFFFFFFFULL) == 0, "");
static_assert(__builtin_stdc_first_leading_zero(0xF000000000000000ULL) == 5, "");
@@ -116,9 +101,6 @@ static_assert(__builtin_stdc_first_leading_one((unsigned short)1) == 16, "");
static_assert(__builtin_stdc_first_leading_one(0U) == 0, "");
static_assert(__builtin_stdc_first_leading_one(0x80000000U) == 1, "");
static_assert(__builtin_stdc_first_leading_one(1U) == 32, "");
-static_assert(__builtin_stdc_first_leading_one(0UL) == 0, "");
-static_assert(__builtin_stdc_first_leading_one(0x8000000000000000UL) == 1, "");
-static_assert(__builtin_stdc_first_leading_one(1UL) == 64, "");
static_assert(__builtin_stdc_first_leading_one(0ULL) == 0, "");
static_assert(__builtin_stdc_first_leading_one(0x8000000000000000ULL) == 1, "");
static_assert(__builtin_stdc_first_leading_one(1ULL) == 64, "");
@@ -136,9 +118,6 @@ static_assert(__builtin_stdc_first_trailing_zero((unsigned short)0xFFFF) == 0, "
static_assert(__builtin_stdc_first_trailing_zero((unsigned short)0x000F) == 5, "");
static_assert(__builtin_stdc_first_trailing_zero(0xFFFFFFFFU) == 0, "");
static_assert(__builtin_stdc_first_trailing_zero(0x0000000FU) == 5, "");
-static_assert(__builtin_stdc_first_trailing_zero(0UL) == 1, "");
-static_assert(__builtin_stdc_first_trailing_zero(0xFFFFFFFFFFFFFFFFUL) == 0, "");
-static_assert(__builtin_stdc_first_trailing_zero(0x000000000000000FUL) == 5, "");
static_assert(__builtin_stdc_first_trailing_zero(0ULL) == 1, "");
static_assert(__builtin_stdc_first_trailing_zero(0xFFFFFFFFFFFFFFFFULL) == 0, "");
static_assert(__builtin_stdc_first_trailing_zero(0x000000000000000FULL) == 5, "");
@@ -157,9 +136,6 @@ static_assert(__builtin_stdc_first_trailing_one((unsigned short)0x8000) == 16, "
static_assert(__builtin_stdc_first_trailing_one(0U) == 0, "");
static_assert(__builtin_stdc_first_trailing_one(0x80000000U) == 32, "");
static_assert(__builtin_stdc_first_trailing_one(1U) == 1, "");
-static_assert(__builtin_stdc_first_trailing_one(0UL) == 0, "");
-static_assert(__builtin_stdc_first_trailing_one(1UL) == 1, "");
-static_assert(__builtin_stdc_first_trailing_one(0x8000000000000000UL) == 64, "");
static_assert(__builtin_stdc_first_trailing_one(0ULL) == 0, "");
static_assert(__builtin_stdc_first_trailing_one(1ULL) == 1, "");
static_assert(__builtin_stdc_first_trailing_one(0x8000000000000000ULL) == 64, "");
@@ -177,9 +153,6 @@ static_assert(__builtin_stdc_count_zeros((unsigned short)0xAAAA) == 8, "");
static_assert(__builtin_stdc_count_zeros(0U) == 32, "");
static_assert(__builtin_stdc_count_zeros(0xFFFFFFFFU) == 0, "");
static_assert(__builtin_stdc_count_zeros(0xAAAAAAAAU) == 16, "");
-static_assert(__builtin_stdc_count_zeros(0UL) == 64, "");
-static_assert(__builtin_stdc_count_zeros(0xFFFFFFFFFFFFFFFFUL) == 0, "");
-static_assert(__builtin_stdc_count_zeros(0xAAAAAAAAAAAAAAAAUL) == 32, "");
static_assert(__builtin_stdc_count_zeros(0ULL) == 64, "");
static_assert(__builtin_stdc_count_zeros(0xFFFFFFFFFFFFFFFFULL) == 0, "");
static_assert(__builtin_stdc_count_zeros(0xAAAAAAAAAAAAAAAAULL) == 32, "");
@@ -197,9 +170,6 @@ static_assert(__builtin_stdc_count_ones((unsigned short)0xAAAA) == 8, "");
static_assert(__builtin_stdc_count_ones(0U) == 0, "");
static_assert(__builtin_stdc_count_ones(0xFFFFFFFFU) == 32, "");
static_assert(__builtin_stdc_count_ones(0xAAAAAAAAU) == 16, "");
-static_assert(__builtin_stdc_count_ones(0UL) == 0, "");
-static_assert(__builtin_stdc_count_ones(0xFFFFFFFFFFFFFFFFUL) == 64, "");
-static_assert(__builtin_stdc_count_ones(0xAAAAAAAAAAAAAAAAUL) == 32, "");
static_assert(__builtin_stdc_count_ones(0ULL) == 0, "");
static_assert(__builtin_stdc_count_ones(0xFFFFFFFFFFFFFFFFULL) == 64, "");
static_assert(__builtin_stdc_count_ones(0xAAAAAAAAAAAAAAAAULL) == 32, "");
@@ -221,10 +191,6 @@ static_assert(__builtin_stdc_has_single_bit(0U) == 0, "");
static_assert(__builtin_stdc_has_single_bit(1U) == 1, "");
static_assert(__builtin_stdc_has_single_bit(0x80000000U) == 1, "");
static_assert(__builtin_stdc_has_single_bit(0xFFFFFFFFU) == 0, "");
-static_assert(__builtin_stdc_has_single_bit(0UL) == 0, "");
-static_assert(__builtin_stdc_has_single_bit(1UL) == 1, "");
-static_assert(__builtin_stdc_has_single_bit(0x8000000000000000UL) == 1, "");
-static_assert(__builtin_stdc_has_single_bit(0xFFFFFFFFFFFFFFFFUL) == 0, "");
static_assert(__builtin_stdc_has_single_bit(0ULL) == 0, "");
static_assert(__builtin_stdc_has_single_bit(1ULL) == 1, "");
static_assert(__builtin_stdc_has_single_bit(0x8000000000000000ULL) == 1, "");
@@ -246,9 +212,6 @@ static_assert(__builtin_stdc_bit_width((unsigned short)0x8000) == 16, "");
static_assert(__builtin_stdc_bit_width(0U) == 0, "");
static_assert(__builtin_stdc_bit_width(1U) == 1, "");
static_assert(__builtin_stdc_bit_width(0x80000000U) == 32, "");
-static_assert(__builtin_stdc_bit_width(0UL) == 0, "");
-static_assert(__builtin_stdc_bit_width(1UL) == 1, "");
-static_assert(__builtin_stdc_bit_width(0x8000000000000000UL) == 64, "");
static_assert(__builtin_stdc_bit_width(0ULL) == 0, "");
static_assert(__builtin_stdc_bit_width(1ULL) == 1, "");
static_assert(__builtin_stdc_bit_width(0x8000000000000000ULL) == 64, "");
@@ -273,9 +236,6 @@ static_assert(__builtin_stdc_bit_floor(1U) == 1U, "");
static_assert(__builtin_stdc_bit_floor(7U) == 4U, "");
static_assert(__builtin_stdc_bit_floor(0x80000000U) == 0x80000000U, "");
static_assert(__builtin_stdc_bit_floor(0xFFFFFFFFU) == 0x80000000U, "");
-static_assert(__builtin_stdc_bit_floor(0UL) == 0UL, "");
-static_assert(__builtin_stdc_bit_floor(1UL) == 1UL, "");
-static_assert(__builtin_stdc_bit_floor(0xFFFFFFFFFFFFFFFFUL) == 0x8000000000000000UL, "");
static_assert(__builtin_stdc_bit_floor(0ULL) == 0ULL, "");
static_assert(__builtin_stdc_bit_floor(1ULL) == 1ULL, "");
static_assert(__builtin_stdc_bit_floor(0xFFFFFFFFFFFFFFFFULL) == 0x8000000000000000ULL, "");
@@ -301,10 +261,6 @@ static_assert(__builtin_stdc_bit_ceil(7U) == 8U, "");
static_assert(__builtin_stdc_bit_ceil(0x80000000U) == 0x80000000U, "");
// Overflow: next power of 2 exceeds type width; implementation wraps.
static_assert(__builtin_stdc_bit_ceil(0xFFFFFFFFU) == 0xFFFFFFFFU, "");
-static_assert(__builtin_stdc_bit_ceil(0UL) == 1UL, "");
-static_assert(__builtin_stdc_bit_ceil(1UL) == 1UL, "");
-static_assert(__builtin_stdc_bit_ceil(7UL) == 8UL, "");
-static_assert(__builtin_stdc_bit_ceil(0x8000000000000000UL) == 0x8000000000000000UL, "");
static_assert(__builtin_stdc_bit_ceil(0ULL) == 1ULL, "");
static_assert(__builtin_stdc_bit_ceil(1ULL) == 1ULL, "");
static_assert(__builtin_stdc_bit_ceil(7ULL) == 8ULL, "");
@@ -416,6 +372,60 @@ static_assert(__builtin_stdc_bit_floor((unsigned _BitInt(9))0x1FF) == 0x100, "")
} // namespace test_bitint
+namespace test_stdc_ulong {
+
+constexpr unsigned long ULongWidth = __SIZEOF_LONG__ * 8;
+constexpr unsigned long ULongMSB = 1UL << (ULongWidth - 1);
+constexpr unsigned long ULongAllOnes = ~0UL;
+constexpr unsigned long ULongTopNibbleOnes = ULongAllOnes << (ULongWidth - 4);
+
+static_assert(__builtin_stdc_leading_zeros(0UL) == ULongWidth, "");
+static_assert(__builtin_stdc_leading_zeros(1UL) == ULongWidth - 1, "");
+static_assert(__builtin_stdc_leading_zeros(ULongMSB) == 0, "");
+static_assert(__builtin_stdc_leading_ones(0UL) == 0, "");
+static_assert(__builtin_stdc_leading_ones(ULongAllOnes) == ULongWidth, "");
+static_assert(__builtin_stdc_leading_ones(ULongTopNibbleOnes) == 4, "");
+static_assert(__builtin_stdc_trailing_zeros(0UL) == ULongWidth, "");
+static_assert(__builtin_stdc_trailing_zeros(1UL) == 0, "");
+static_assert(__builtin_stdc_trailing_zeros(ULongMSB) == ULongWidth - 1, "");
+static_assert(__builtin_stdc_trailing_ones(0UL) == 0, "");
+static_assert(__builtin_stdc_trailing_ones(ULongAllOnes) == ULongWidth, "");
+static_assert(__builtin_stdc_trailing_ones(0xFUL) == 4, "");
+static_assert(__builtin_stdc_first_leading_zero(0UL) == 1, "");
+static_assert(__builtin_stdc_first_leading_zero(ULongAllOnes) == 0, "");
+static_assert(__builtin_stdc_first_leading_zero(ULongTopNibbleOnes) == 5, "");
+static_assert(__builtin_stdc_first_leading_one(0UL) == 0, "");
+static_assert(__builtin_stdc_first_leading_one(ULongMSB) == 1, "");
+static_assert(__builtin_stdc_first_leading_one(1UL) == ULongWidth, "");
+static_assert(__builtin_stdc_first_trailing_zero(0UL) == 1, "");
+static_assert(__builtin_stdc_first_trailing_zero(ULongAllOnes) == 0, "");
+static_assert(__builtin_stdc_first_trailing_zero(0xFUL) == 5, "");
+static_assert(__builtin_stdc_first_trailing_one(0UL) == 0, "");
+static_assert(__builtin_stdc_first_trailing_one(1UL) == 1, "");
+static_assert(__builtin_stdc_first_trailing_one(ULongMSB) == ULongWidth, "");
+static_assert(__builtin_stdc_count_zeros(0UL) == ULongWidth, "");
+static_assert(__builtin_stdc_count_zeros(ULongAllOnes) == 0, "");
+static_assert(__builtin_stdc_count_zeros(ULongMSB) == ULongWidth - 1, "");
+static_assert(__builtin_stdc_count_ones(0UL) == 0, "");
+static_assert(__builtin_stdc_count_ones(ULongAllOnes) == ULongWidth, "");
+static_assert(__builtin_stdc_count_ones(ULongMSB) == 1, "");
+static_assert(__builtin_stdc_has_single_bit(0UL) == 0, "");
+static_assert(__builtin_stdc_has_single_bit(1UL) == 1, "");
+static_assert(__builtin_stdc_has_single_bit(ULongMSB) == 1, "");
+static_assert(__builtin_stdc_has_single_bit(ULongAllOnes) == 0, "");
+static_assert(__builtin_stdc_bit_width(0UL) == 0, "");
+static_assert(__builtin_stdc_bit_width(1UL) == 1, "");
+static_assert(__builtin_stdc_bit_width(ULongMSB) == ULongWidth, "");
+static_assert(__builtin_stdc_bit_floor(0UL) == 0UL, "");
+static_assert(__builtin_stdc_bit_floor(1UL) == 1UL, "");
+static_assert(__builtin_stdc_bit_floor(ULongAllOnes) == ULongMSB, "");
+static_assert(__builtin_stdc_bit_ceil(0UL) == 1UL, "");
+static_assert(__builtin_stdc_bit_ceil(1UL) == 1UL, "");
+static_assert(__builtin_stdc_bit_ceil(7UL) == 8UL, "");
+static_assert(__builtin_stdc_bit_ceil(ULongMSB) == ULongMSB, "");
+
+} // namespace test_stdc_ulong
+
namespace test_errors {
void test_invalid_types(int si, float f) {
>From 685f9a8049f608cdf9896d85d6156c2d3b8f138d Mon Sep 17 00:00:00 2001
From: NagaChaitanya Vellanki <pnagato at protonmail.com>
Date: Thu, 12 Mar 2026 13:50:05 -0700
Subject: [PATCH 06/14] Update BuiltinStdCBuiltin documentation comment to
describe behavior
---
clang/lib/Sema/SemaChecking.cpp | 9 ++-------
1 file changed, 2 insertions(+), 7 deletions(-)
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 0124c247eea4c..c11b4a732fa7f 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2347,13 +2347,8 @@ static bool BuiltinPopcountg(Sema &S, CallExpr *TheCall) {
return false;
}
-/// Checks stdc bit-utility builtins (__builtin_stdc_*):
-/// bit_ceil, bit_floor, bit_width, count_ones, count_zeros,
-/// first_leading_one, first_leading_zero, first_trailing_one,
-/// first_trailing_zero, has_single_bit, leading_ones, leading_zeros,
-/// trailing_ones, trailing_zeros. They all take a single unsigned integer
-/// argument and return either int, bool, or the argument type depending on the
-/// specific builtin.
+/// Checks the __builtin_stdc_* builtins that take a single unsigned integer
+/// argument and return either int, bool, or the argument type.
static bool BuiltinStdCBuiltin(Sema &S, CallExpr *TheCall) {
if (S.checkArgCount(TheCall, 1))
return true;
>From 10fe0688150ec17ca211706bf9efc95a2bec097f Mon Sep 17 00:00:00 2001
From: NagaChaitanya Vellanki <pnagato at protonmail.com>
Date: Fri, 20 Mar 2026 08:56:31 -0700
Subject: [PATCH 07/14] Check only for unsigned integer type
---
clang/lib/Sema/SemaChecking.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index c11b4a732fa7f..2c85b4231631e 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2361,7 +2361,7 @@ static bool BuiltinStdCBuiltin(Sema &S, CallExpr *TheCall) {
TheCall->setArg(0, Arg);
QualType ArgTy = Arg->getType();
- if (!ArgTy->isUnsignedIntegerType() && !ArgTy->isExtVectorBoolType()) {
+ if (!ArgTy->isUnsignedIntegerType()) {
S.Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type)
<< 1 << /* scalar */ 1 << /* unsigned integer ty */ 3 << /* no fp */ 0
<< ArgTy;
>From c518f38fe40309b48ec38b071ede633001fb36ce Mon Sep 17 00:00:00 2001
From: NagaChaitanya Vellanki <pnagato at protonmail.com>
Date: Fri, 20 Mar 2026 10:55:23 -0700
Subject: [PATCH 08/14] Simplify diagnostic and remove duplicate switch
---
.../clang/Basic/DiagnosticSemaKinds.td | 3 ++
clang/lib/Sema/SemaChecking.cpp | 39 ++++++++-----------
2 files changed, 19 insertions(+), 23 deletions(-)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index d5904bd1d6f26..90497749e9213 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -13299,6 +13299,9 @@ def err_builtin_requires_double_type: Error<
def err_bswapg_invalid_bit_width : Error<
"_BitInt type %0 (%1 bits) must be a multiple of 16 bits for byte swapping">;
+def err_builtin_stdc_invalid_arg_type: Error<
+ "%ordinal0 argument must be a scalar unsigned integer type (was %1)">;
+
def err_builtin_trivially_relocate_invalid_arg_type: Error <
"first%select{||| and second}0 argument%select{|||s}0 to "
"'__builtin_trivially_relocate' must be"
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 2c85b4231631e..c79281c390d46 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2349,7 +2349,8 @@ static bool BuiltinPopcountg(Sema &S, CallExpr *TheCall) {
/// Checks the __builtin_stdc_* builtins that take a single unsigned integer
/// argument and return either int, bool, or the argument type.
-static bool BuiltinStdCBuiltin(Sema &S, CallExpr *TheCall) {
+static bool BuiltinStdCBuiltin(Sema &S, CallExpr *TheCall,
+ QualType ReturnType) {
if (S.checkArgCount(TheCall, 1))
return true;
@@ -2361,25 +2362,11 @@ static bool BuiltinStdCBuiltin(Sema &S, CallExpr *TheCall) {
TheCall->setArg(0, Arg);
QualType ArgTy = Arg->getType();
- if (!ArgTy->isUnsignedIntegerType()) {
- S.Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type)
- << 1 << /* scalar */ 1 << /* unsigned integer ty */ 3 << /* no fp */ 0
- << ArgTy;
- return true;
- }
+ if (!ArgTy->isUnsignedIntegerType())
+ return S.Diag(Arg->getBeginLoc(), diag::err_builtin_stdc_invalid_arg_type)
+ << 1 << ArgTy;
- switch (TheCall->getBuiltinCallee()) {
- case Builtin::BI__builtin_stdc_bit_floor:
- case Builtin::BI__builtin_stdc_bit_ceil:
- TheCall->setType(ArgTy);
- break;
- case Builtin::BI__builtin_stdc_has_single_bit:
- TheCall->setType(S.Context.BoolTy);
- break;
- default:
- TheCall->setType(S.Context.UnsignedIntTy);
- break;
- }
+ TheCall->setType(ReturnType.isNull() ? ArgTy : ReturnType);
return false;
}
@@ -3838,6 +3825,15 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
return ExprError();
break;
+ case Builtin::BI__builtin_stdc_bit_floor:
+ case Builtin::BI__builtin_stdc_bit_ceil:
+ if (BuiltinStdCBuiltin(*this, TheCall, QualType()))
+ return ExprError();
+ break;
+ case Builtin::BI__builtin_stdc_has_single_bit:
+ if (BuiltinStdCBuiltin(*this, TheCall, Context.BoolTy))
+ return ExprError();
+ break;
case Builtin::BI__builtin_stdc_leading_zeros:
case Builtin::BI__builtin_stdc_leading_ones:
case Builtin::BI__builtin_stdc_trailing_zeros:
@@ -3848,11 +3844,8 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
case Builtin::BI__builtin_stdc_first_trailing_one:
case Builtin::BI__builtin_stdc_count_zeros:
case Builtin::BI__builtin_stdc_count_ones:
- case Builtin::BI__builtin_stdc_has_single_bit:
case Builtin::BI__builtin_stdc_bit_width:
- case Builtin::BI__builtin_stdc_bit_floor:
- case Builtin::BI__builtin_stdc_bit_ceil:
- if (BuiltinStdCBuiltin(*this, TheCall))
+ if (BuiltinStdCBuiltin(*this, TheCall, Context.UnsignedIntTy))
return ExprError();
break;
>From 63aef6a219dad0247a3f66479eac47439ec399f1 Mon Sep 17 00:00:00 2001
From: NagaChaitanya Vellanki <pnagato at protonmail.com>
Date: Fri, 20 Mar 2026 12:52:46 -0700
Subject: [PATCH 09/14] Remove nested switch and make each builtin
implementation an individual case statement
---
clang/lib/CodeGen/CGBuiltin.cpp | 340 ++++++++++++++++++--------------
1 file changed, 190 insertions(+), 150 deletions(-)
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 7cf3c62e5ef86..c45c1b1113d18 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3733,168 +3733,208 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI_rotr64:
return emitRotate(E, true);
- case Builtin::BI__builtin_stdc_leading_zeros:
- case Builtin::BI__builtin_stdc_leading_ones:
- case Builtin::BI__builtin_stdc_trailing_zeros:
- case Builtin::BI__builtin_stdc_trailing_ones:
- case Builtin::BI__builtin_stdc_first_leading_zero:
- case Builtin::BI__builtin_stdc_first_leading_one:
- case Builtin::BI__builtin_stdc_first_trailing_zero:
- case Builtin::BI__builtin_stdc_first_trailing_one:
- case Builtin::BI__builtin_stdc_count_zeros:
- case Builtin::BI__builtin_stdc_count_ones:
- case Builtin::BI__builtin_stdc_has_single_bit:
- case Builtin::BI__builtin_stdc_bit_width:
- case Builtin::BI__builtin_stdc_bit_floor:
- case Builtin::BI__builtin_stdc_bit_ceil: {
+ case Builtin::BI__builtin_stdc_leading_zeros: {
+ Value *ArgValue = EmitScalarExpr(E->getArg(0));
+ llvm::Type *ArgType = ArgValue->getType();
+ llvm::Type *ResultType = ConvertType(E->getType());
+ Function *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType);
+ Value *Result = Builder.CreateCall(F, {ArgValue, Builder.getFalse()});
+ if (Result->getType() != ResultType)
+ Result = Builder.CreateIntCast(Result, ResultType, false);
+ return RValue::get(Result);
+ }
+ case Builtin::BI__builtin_stdc_leading_ones: {
+ Value *ArgValue = EmitScalarExpr(E->getArg(0));
+ llvm::Type *ArgType = ArgValue->getType();
+ llvm::Type *ResultType = ConvertType(E->getType());
+ Function *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType);
+ Value *Result = Builder.CreateCall(
+ F, {Builder.CreateNot(ArgValue), Builder.getFalse()});
+ if (Result->getType() != ResultType)
+ Result = Builder.CreateIntCast(Result, ResultType, false);
+ return RValue::get(Result);
+ }
+ case Builtin::BI__builtin_stdc_trailing_zeros: {
+ Value *ArgValue = EmitScalarExpr(E->getArg(0));
+ llvm::Type *ArgType = ArgValue->getType();
+ llvm::Type *ResultType = ConvertType(E->getType());
+ Function *F = CGM.getIntrinsic(Intrinsic::cttz, ArgType);
+ Value *Result = Builder.CreateCall(F, {ArgValue, Builder.getFalse()});
+ if (Result->getType() != ResultType)
+ Result = Builder.CreateIntCast(Result, ResultType, false);
+ return RValue::get(Result);
+ }
+ case Builtin::BI__builtin_stdc_trailing_ones: {
+ Value *ArgValue = EmitScalarExpr(E->getArg(0));
+ llvm::Type *ArgType = ArgValue->getType();
+ llvm::Type *ResultType = ConvertType(E->getType());
+ Function *F = CGM.getIntrinsic(Intrinsic::cttz, ArgType);
+ Value *Result = Builder.CreateCall(
+ F, {Builder.CreateNot(ArgValue), Builder.getFalse()});
+ if (Result->getType() != ResultType)
+ Result = Builder.CreateIntCast(Result, ResultType, false);
+ return RValue::get(Result);
+ }
+ case Builtin::BI__builtin_stdc_first_leading_zero: {
+ Value *ArgValue = EmitScalarExpr(E->getArg(0));
+ llvm::Type *ArgType = ArgValue->getType();
+ llvm::Type *ResultType = ConvertType(E->getType());
+ Value *Zero = ConstantInt::get(ArgType, 0);
+ Value *One = ConstantInt::get(ArgType, 1);
+ Function *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType);
+ Value *Cnt = Builder.CreateCall(
+ F, {Builder.CreateNot(ArgValue), Builder.getFalse()});
+ Value *Tmp = Builder.CreateAdd(Cnt, One);
+ Value *IsAllOnes =
+ Builder.CreateICmpEQ(ArgValue, Constant::getAllOnesValue(ArgType));
+ Value *Result = Builder.CreateSelect(IsAllOnes, Zero, Tmp);
+ if (Result->getType() != ResultType)
+ Result = Builder.CreateIntCast(Result, ResultType, false);
+ return RValue::get(Result);
+ }
+ case Builtin::BI__builtin_stdc_first_leading_one: {
+ Value *ArgValue = EmitScalarExpr(E->getArg(0));
+ llvm::Type *ArgType = ArgValue->getType();
+ llvm::Type *ResultType = ConvertType(E->getType());
+ Value *Zero = ConstantInt::get(ArgType, 0);
+ Value *One = ConstantInt::get(ArgType, 1);
+ Function *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType);
+ Value *Cnt = Builder.CreateCall(F, {ArgValue, Builder.getFalse()});
+ Value *Tmp = Builder.CreateAdd(Cnt, One);
+ Value *IsZero = Builder.CreateICmpEQ(ArgValue, Zero);
+ Value *Result = Builder.CreateSelect(IsZero, Zero, Tmp);
+ if (Result->getType() != ResultType)
+ Result = Builder.CreateIntCast(Result, ResultType, false);
+ return RValue::get(Result);
+ }
+ case Builtin::BI__builtin_stdc_first_trailing_zero: {
+ Value *ArgValue = EmitScalarExpr(E->getArg(0));
+ llvm::Type *ArgType = ArgValue->getType();
+ llvm::Type *ResultType = ConvertType(E->getType());
+ Value *Zero = ConstantInt::get(ArgType, 0);
+ Value *One = ConstantInt::get(ArgType, 1);
+ Function *F = CGM.getIntrinsic(Intrinsic::cttz, ArgType);
+ Value *Cnt = Builder.CreateCall(
+ F, {Builder.CreateNot(ArgValue), Builder.getFalse()});
+ Value *Tmp = Builder.CreateAdd(Cnt, One);
+ Value *IsAllOnes =
+ Builder.CreateICmpEQ(ArgValue, Constant::getAllOnesValue(ArgType));
+ Value *Result = Builder.CreateSelect(IsAllOnes, Zero, Tmp);
+ if (Result->getType() != ResultType)
+ Result = Builder.CreateIntCast(Result, ResultType, false);
+ return RValue::get(Result);
+ }
+ case Builtin::BI__builtin_stdc_first_trailing_one: {
+ Value *ArgValue = EmitScalarExpr(E->getArg(0));
+ llvm::Type *ArgType = ArgValue->getType();
+ llvm::Type *ResultType = ConvertType(E->getType());
+ Value *Zero = ConstantInt::get(ArgType, 0);
+ Value *One = ConstantInt::get(ArgType, 1);
+ Function *F = CGM.getIntrinsic(Intrinsic::cttz, ArgType);
+ Value *Cnt = Builder.CreateCall(F, {ArgValue, Builder.getFalse()});
+ Value *Tmp = Builder.CreateAdd(Cnt, One);
+ Value *IsZero = Builder.CreateICmpEQ(ArgValue, Zero);
+ Value *Result = Builder.CreateSelect(IsZero, Zero, Tmp);
+ if (Result->getType() != ResultType)
+ Result = Builder.CreateIntCast(Result, ResultType, false);
+ return RValue::get(Result);
+ }
+ case Builtin::BI__builtin_stdc_count_zeros: {
Value *ArgValue = EmitScalarExpr(E->getArg(0));
llvm::Type *ArgType = ArgValue->getType();
llvm::Type *ResultType = ConvertType(E->getType());
unsigned BitWidth = ArgType->getIntegerBitWidth();
+ Function *F = CGM.getIntrinsic(Intrinsic::ctpop, ArgType);
+ Value *PopCnt = Builder.CreateCall(F, ArgValue);
+ Value *Result =
+ Builder.CreateSub(ConstantInt::get(ArgType, BitWidth), PopCnt);
+ if (Result->getType() != ResultType)
+ Result = Builder.CreateIntCast(Result, ResultType, false);
+ return RValue::get(Result);
+ }
+ case Builtin::BI__builtin_stdc_count_ones: {
+ Value *ArgValue = EmitScalarExpr(E->getArg(0));
+ llvm::Type *ArgType = ArgValue->getType();
+ llvm::Type *ResultType = ConvertType(E->getType());
+ Function *F = CGM.getIntrinsic(Intrinsic::ctpop, ArgType);
+ Value *Result = Builder.CreateCall(F, ArgValue);
+ if (Result->getType() != ResultType)
+ Result = Builder.CreateIntCast(Result, ResultType, false);
+ return RValue::get(Result);
+ }
+ case Builtin::BI__builtin_stdc_has_single_bit: {
+ Value *ArgValue = EmitScalarExpr(E->getArg(0));
+ llvm::Type *ArgType = ArgValue->getType();
+ Value *One = ConstantInt::get(ArgType, 1);
+ Function *F = CGM.getIntrinsic(Intrinsic::ctpop, ArgType);
+ Value *PopCnt = Builder.CreateCall(F, ArgValue);
+ return RValue::get(Builder.CreateICmpEQ(PopCnt, One));
+ }
+ case Builtin::BI__builtin_stdc_bit_width: {
+ Value *ArgValue = EmitScalarExpr(E->getArg(0));
+ llvm::Type *ArgType = ArgValue->getType();
+ llvm::Type *ResultType = ConvertType(E->getType());
+ unsigned BitWidth = ArgType->getIntegerBitWidth();
+ Function *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType);
+ Value *LZ = Builder.CreateCall(F, {ArgValue, Builder.getFalse()});
+ Value *Result = Builder.CreateSub(ConstantInt::get(ArgType, BitWidth), LZ);
+ if (Result->getType() != ResultType)
+ Result = Builder.CreateIntCast(Result, ResultType, false);
+ return RValue::get(Result);
+ }
+ case Builtin::BI__builtin_stdc_bit_floor: {
+ Value *ArgValue = EmitScalarExpr(E->getArg(0));
+ llvm::Type *ArgType = ArgValue->getType();
+ unsigned BitWidth = ArgType->getIntegerBitWidth();
+ Value *Zero = ConstantInt::get(ArgType, 0);
+ Value *One = ConstantInt::get(ArgType, 1);
+ Function *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType);
+ Value *LZ = Builder.CreateCall(F, {ArgValue, Builder.getTrue()});
+ Value *ShiftAmt =
+ Builder.CreateSub(ConstantInt::get(ArgType, BitWidth - 1), LZ);
+ Value *Shifted = Builder.CreateShl(One, ShiftAmt);
+ Value *IsZero = Builder.CreateICmpEQ(ArgValue, Zero);
+ Value *Result = Builder.CreateSelect(IsZero, Zero, Shifted);
+ return RValue::get(Result);
+ }
+ case Builtin::BI__builtin_stdc_bit_ceil: {
+ Value *ArgValue = EmitScalarExpr(E->getArg(0));
+ llvm::Type *ArgType = ArgValue->getType();
+ unsigned BitWidth = ArgType->getIntegerBitWidth();
Value *Zero = ConstantInt::get(ArgType, 0);
Value *One = ConstantInt::get(ArgType, 1);
- Value *Result;
- switch (BuiltinIDIfNoAsmLabel) {
- case Builtin::BI__builtin_stdc_leading_zeros: {
- Function *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType);
- Result = Builder.CreateCall(F, {ArgValue, Builder.getFalse()});
- break;
- }
- case Builtin::BI__builtin_stdc_leading_ones: {
- Function *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType);
- Result = Builder.CreateCall(
- F, {Builder.CreateNot(ArgValue), Builder.getFalse()});
- break;
- }
- case Builtin::BI__builtin_stdc_trailing_zeros: {
- Function *F = CGM.getIntrinsic(Intrinsic::cttz, ArgType);
- Result = Builder.CreateCall(F, {ArgValue, Builder.getFalse()});
- break;
- }
- case Builtin::BI__builtin_stdc_trailing_ones: {
- Function *F = CGM.getIntrinsic(Intrinsic::cttz, ArgType);
- Result = Builder.CreateCall(
- F, {Builder.CreateNot(ArgValue), Builder.getFalse()});
- break;
- }
- case Builtin::BI__builtin_stdc_first_leading_zero: {
- Function *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType);
- Value *Cnt = Builder.CreateCall(
- F, {Builder.CreateNot(ArgValue), Builder.getFalse()});
- Value *Tmp = Builder.CreateAdd(Cnt, One);
- Value *IsAllOnes =
- Builder.CreateICmpEQ(ArgValue, Constant::getAllOnesValue(ArgType));
- Result = Builder.CreateSelect(IsAllOnes, Zero, Tmp);
- break;
- }
- case Builtin::BI__builtin_stdc_first_leading_one: {
- Function *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType);
- Value *Cnt = Builder.CreateCall(F, {ArgValue, Builder.getFalse()});
- Value *Tmp = Builder.CreateAdd(Cnt, One);
- Value *IsZero = Builder.CreateICmpEQ(ArgValue, Zero);
- Result = Builder.CreateSelect(IsZero, Zero, Tmp);
- break;
- }
- case Builtin::BI__builtin_stdc_first_trailing_zero: {
- Function *F = CGM.getIntrinsic(Intrinsic::cttz, ArgType);
- Value *Cnt = Builder.CreateCall(
- F, {Builder.CreateNot(ArgValue), Builder.getFalse()});
- Value *Tmp = Builder.CreateAdd(Cnt, One);
- Value *IsAllOnes =
- Builder.CreateICmpEQ(ArgValue, Constant::getAllOnesValue(ArgType));
- Result = Builder.CreateSelect(IsAllOnes, Zero, Tmp);
- break;
- }
- case Builtin::BI__builtin_stdc_first_trailing_one: {
- Function *F = CGM.getIntrinsic(Intrinsic::cttz, ArgType);
- Value *Cnt = Builder.CreateCall(F, {ArgValue, Builder.getFalse()});
- Value *Tmp = Builder.CreateAdd(Cnt, One);
- Value *IsZero = Builder.CreateICmpEQ(ArgValue, Zero);
- Result = Builder.CreateSelect(IsZero, Zero, Tmp);
- break;
- }
- case Builtin::BI__builtin_stdc_count_zeros: {
- Function *F = CGM.getIntrinsic(Intrinsic::ctpop, ArgType);
- Value *PopCnt = Builder.CreateCall(F, ArgValue);
- Result = Builder.CreateSub(ConstantInt::get(ArgType, BitWidth), PopCnt);
- break;
+ if (auto *CI = dyn_cast<ConstantInt>(ArgValue)) {
+ if (CI->isMinusOne())
+ return RValue::get(CI);
+ if (CI->isZero() || CI->isOne())
+ return RValue::get(ConstantInt::get(ArgType, 1));
}
- case Builtin::BI__builtin_stdc_count_ones: {
- Function *F = CGM.getIntrinsic(Intrinsic::ctpop, ArgType);
- Result = Builder.CreateCall(F, ArgValue);
- break;
- }
- case Builtin::BI__builtin_stdc_has_single_bit: {
- Function *F = CGM.getIntrinsic(Intrinsic::ctpop, ArgType);
- Value *PopCnt = Builder.CreateCall(F, ArgValue);
- return RValue::get(Builder.CreateICmpEQ(PopCnt, One));
- }
- case Builtin::BI__builtin_stdc_bit_width: {
- Function *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType);
- Value *LZ = Builder.CreateCall(F, {ArgValue, Builder.getFalse()});
- Result = Builder.CreateSub(ConstantInt::get(ArgType, BitWidth), LZ);
- break;
- }
- case Builtin::BI__builtin_stdc_bit_floor: {
- // Spec: arg == 0 ? 0 : 1 << (prec - 1 - clz(arg))
- // Use ctlz with is_zero_poison=true and a select so the zero case never
- // materialises the poison value. This avoids a branch and PHI node and
- // allows the backend to emit a conditional move.
- Function *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType);
- Value *LZ = Builder.CreateCall(F, {ArgValue, Builder.getTrue()});
- Value *ShiftAmt =
- Builder.CreateSub(ConstantInt::get(ArgType, BitWidth - 1), LZ);
- Value *Shifted = Builder.CreateShl(One, ShiftAmt);
- Value *IsZero = Builder.CreateICmpEQ(ArgValue, Zero);
- Result = Builder.CreateSelect(IsZero, Zero, Shifted);
- break;
- }
- case Builtin::BI__builtin_stdc_bit_ceil: {
- // Spec: arg <= 1 ? 1 : 2 << (prec - 1 - clz(arg - 1))
- if (auto *CI = dyn_cast<ConstantInt>(ArgValue)) {
- if (CI->isMinusOne())
- return RValue::get(CI);
- if (CI->isZero() || CI->isOne())
- return RValue::get(ConstantInt::get(ArgType, 1));
- }
- Value *IsLEOne = Builder.CreateICmpULE(ArgValue, One, "isleone");
+ Value *IsLEOne = Builder.CreateICmpULE(ArgValue, One, "isleone");
- BasicBlock *EntryBB = Builder.GetInsertBlock();
- BasicBlock *CalcBB = createBasicBlock("bitceil.calc", CurFn);
- BasicBlock *MergeBB = createBasicBlock("bitceil.merge", CurFn);
+ BasicBlock *EntryBB = Builder.GetInsertBlock();
+ BasicBlock *CalcBB = createBasicBlock("bitceil.calc", CurFn);
+ BasicBlock *MergeBB = createBasicBlock("bitceil.merge", CurFn);
- // If <= 1 -> return 1, else compute.
- Builder.CreateCondBr(IsLEOne, MergeBB, CalcBB);
+ Builder.CreateCondBr(IsLEOne, MergeBB, CalcBB);
- Builder.SetInsertPoint(CalcBB);
- Function *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType);
- Value *ArgMinusOne = Builder.CreateSub(ArgValue, One);
- Value *LZ = Builder.CreateCall(F, {ArgMinusOne, Builder.getFalse()});
- // LZ == 0 means arg-1 has the MSB set, so the next power of 2 would
- // overflow the type; return arg unchanged.
- Value *LZIsZero = Builder.CreateICmpEQ(LZ, Zero, "lzzero");
- Value *ShiftAmt =
- Builder.CreateSub(ConstantInt::get(ArgType, BitWidth), LZ);
- Value *Tmp = Builder.CreateShl(One, ShiftAmt);
- Tmp = Builder.CreateSelect(LZIsZero, ArgValue, Tmp);
- Builder.CreateBr(MergeBB);
-
- Builder.SetInsertPoint(MergeBB);
- PHINode *Phi = Builder.CreatePHI(ArgType, 2);
- Phi->addIncoming(One, EntryBB);
- Phi->addIncoming(Tmp, CalcBB);
- Result = Phi;
- break;
- }
- default:
- llvm_unreachable("Unknown stdc builtin");
- }
-
- if (Result->getType() != ResultType)
- Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/ false);
- return RValue::get(Result);
+ Builder.SetInsertPoint(CalcBB);
+ Function *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType);
+ Value *ArgMinusOne = Builder.CreateSub(ArgValue, One);
+ Value *LZ = Builder.CreateCall(F, {ArgMinusOne, Builder.getFalse()});
+ Value *LZIsZero = Builder.CreateICmpEQ(LZ, Zero, "lzzero");
+ Value *ShiftAmt =
+ Builder.CreateSub(ConstantInt::get(ArgType, BitWidth), LZ);
+ Value *Tmp = Builder.CreateShl(One, ShiftAmt);
+ Tmp = Builder.CreateSelect(LZIsZero, ArgValue, Tmp);
+ Builder.CreateBr(MergeBB);
+
+ Builder.SetInsertPoint(MergeBB);
+ PHINode *Phi = Builder.CreatePHI(ArgType, 2);
+ Phi->addIncoming(One, EntryBB);
+ Phi->addIncoming(Tmp, CalcBB);
+ return RValue::get(Phi);
}
case Builtin::BI__builtin_constant_p: {
>From b42ffbd6d32e96890dc833356b45cf3598ed6c07 Mon Sep 17 00:00:00 2001
From: NagaChaitanya Vellanki <pnagato at protonmail.com>
Date: Fri, 3 Apr 2026 11:03:13 -0700
Subject: [PATCH 10/14] Add LibBuiltin spellings and stdbit.h header for C23
stdc builtins
---
clang/include/clang/Basic/BuiltinHeaders.def | 1 +
clang/include/clang/Basic/Builtins.td | 85 +++++++++++++++
clang/lib/AST/ByteCode/InterpBuiltin.cpp | 14 +++
clang/lib/AST/ExprConstant.cpp | 14 +++
clang/lib/CodeGen/CGBuiltin.cpp | 14 +++
clang/lib/Sema/SemaChecking.cpp | 14 +++
clang/test/CodeGen/Inputs/stdbit.h | 19 ++++
.../test/CodeGen/builtin-stdc-bit-functions.c | 100 +++++++++++++++++-
clang/test/Sema/Inputs/stdbit.h | 1 +
clang/test/Sema/builtin-stdc-bit-functions.c | 27 ++++-
10 files changed, 285 insertions(+), 4 deletions(-)
create mode 100644 clang/test/CodeGen/Inputs/stdbit.h
create mode 100644 clang/test/Sema/Inputs/stdbit.h
diff --git a/clang/include/clang/Basic/BuiltinHeaders.def b/clang/include/clang/Basic/BuiltinHeaders.def
index bca40c0e4deea..23889a22769ed 100644
--- a/clang/include/clang/Basic/BuiltinHeaders.def
+++ b/clang/include/clang/Basic/BuiltinHeaders.def
@@ -32,6 +32,7 @@ HEADER(OBJC_RUNTIME_H, "objc/runtime.h")
HEADER(PTHREAD_H, "pthread.h")
HEADER(SETJMPEX_H, "setjmpex.h")
HEADER(SETJMP_H, "setjmp.h")
+HEADER(STDBIT_H, "stdbit.h")
HEADER(STDARG_H, "stdarg.h")
HEADER(STDIO_H, "stdio.h")
HEADER(STDLIB_H, "stdlib.h")
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index f386e2f1ea741..5b6e45de14994 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -881,6 +881,91 @@ def StdcBitCeil: Builtin {
let Prototype = "void(...)";
}
+def StdcLeadingZerosLib: LibBuiltin<"stdbit.h", "C23_LANG"> {
+ let Spellings = ["stdc_leading_zeros"];
+ let Attributes = [NoThrow, Const, CustomTypeChecking];
+ let Prototype = "void(...)";
+}
+
+def StdcLeadingOnesLib: LibBuiltin<"stdbit.h", "C23_LANG"> {
+ let Spellings = ["stdc_leading_ones"];
+ let Attributes = [NoThrow, Const, CustomTypeChecking];
+ let Prototype = "void(...)";
+}
+
+def StdcTrailingZerosLib: LibBuiltin<"stdbit.h", "C23_LANG"> {
+ let Spellings = ["stdc_trailing_zeros"];
+ let Attributes = [NoThrow, Const, CustomTypeChecking];
+ let Prototype = "void(...)";
+}
+
+def StdcTrailingOnesLib: LibBuiltin<"stdbit.h", "C23_LANG"> {
+ let Spellings = ["stdc_trailing_ones"];
+ let Attributes = [NoThrow, Const, CustomTypeChecking];
+ let Prototype = "void(...)";
+}
+
+def StdcFirstLeadingZeroLib: LibBuiltin<"stdbit.h", "C23_LANG"> {
+ let Spellings = ["stdc_first_leading_zero"];
+ let Attributes = [NoThrow, Const, CustomTypeChecking];
+ let Prototype = "void(...)";
+}
+
+def StdcFirstLeadingOneLib: LibBuiltin<"stdbit.h", "C23_LANG"> {
+ let Spellings = ["stdc_first_leading_one"];
+ let Attributes = [NoThrow, Const, CustomTypeChecking];
+ let Prototype = "void(...)";
+}
+
+def StdcFirstTrailingZeroLib: LibBuiltin<"stdbit.h", "C23_LANG"> {
+ let Spellings = ["stdc_first_trailing_zero"];
+ let Attributes = [NoThrow, Const, CustomTypeChecking];
+ let Prototype = "void(...)";
+}
+
+def StdcFirstTrailingOneLib: LibBuiltin<"stdbit.h", "C23_LANG"> {
+ let Spellings = ["stdc_first_trailing_one"];
+ let Attributes = [NoThrow, Const, CustomTypeChecking];
+ let Prototype = "void(...)";
+}
+
+def StdcCountZerosLib: LibBuiltin<"stdbit.h", "C23_LANG"> {
+ let Spellings = ["stdc_count_zeros"];
+ let Attributes = [NoThrow, Const, CustomTypeChecking];
+ let Prototype = "void(...)";
+}
+
+def StdcCountOnesLib: LibBuiltin<"stdbit.h", "C23_LANG"> {
+ let Spellings = ["stdc_count_ones"];
+ let Attributes = [NoThrow, Const, CustomTypeChecking];
+ let Prototype = "void(...)";
+}
+
+def StdcHasSingleBitLib: LibBuiltin<"stdbit.h", "C23_LANG"> {
+ let Spellings = ["stdc_has_single_bit"];
+ let Attributes = [NoThrow, Const, CustomTypeChecking];
+ let Prototype = "bool(...)";
+}
+
+def StdcBitWidthLib: LibBuiltin<"stdbit.h", "C23_LANG"> {
+ let Spellings = ["stdc_bit_width"];
+ let Attributes = [NoThrow, Const, CustomTypeChecking];
+ let Prototype = "void(...)";
+}
+
+def StdcBitFloorLib: LibBuiltin<"stdbit.h", "C23_LANG"> {
+ let Spellings = ["stdc_bit_floor"];
+ let Attributes = [NoThrow, Const, CustomTypeChecking];
+ let Prototype = "void(...)";
+}
+
+def StdcBitCeilLib: LibBuiltin<"stdbit.h", "C23_LANG"> {
+ let Spellings = ["stdc_bit_ceil"];
+ let Attributes = [NoThrow, Const, CustomTypeChecking];
+ let Prototype = "void(...)";
+}
+
+
// Random GCC builtins
// FIXME: The builtins marked FunctionWithBuiltinPrefix below should be
// merged with the library definitions. They are currently not because
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index 042ca8d0b6574..e9b3692201985 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -4420,6 +4420,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
});
}
+ case Builtin::BIstdc_leading_zeros:
case Builtin::BI__builtin_stdc_leading_zeros: {
unsigned ResWidth = S.getASTContext().getIntWidth(Call->getType());
return interp__builtin_elementwise_int_unaryop(
@@ -4428,6 +4429,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
});
}
+ case Builtin::BIstdc_leading_ones:
case Builtin::BI__builtin_stdc_leading_ones: {
unsigned ResWidth = S.getASTContext().getIntWidth(Call->getType());
return interp__builtin_elementwise_int_unaryop(
@@ -4436,6 +4438,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
});
}
+ case Builtin::BIstdc_trailing_zeros:
case Builtin::BI__builtin_stdc_trailing_zeros: {
unsigned ResWidth = S.getASTContext().getIntWidth(Call->getType());
return interp__builtin_elementwise_int_unaryop(
@@ -4444,6 +4447,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
});
}
+ case Builtin::BIstdc_trailing_ones:
case Builtin::BI__builtin_stdc_trailing_ones: {
unsigned ResWidth = S.getASTContext().getIntWidth(Call->getType());
return interp__builtin_elementwise_int_unaryop(
@@ -4452,6 +4456,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
});
}
+ case Builtin::BIstdc_first_leading_zero:
case Builtin::BI__builtin_stdc_first_leading_zero: {
unsigned ResWidth = S.getASTContext().getIntWidth(Call->getType());
return interp__builtin_elementwise_int_unaryop(
@@ -4460,6 +4465,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
});
}
+ case Builtin::BIstdc_first_leading_one:
case Builtin::BI__builtin_stdc_first_leading_one: {
unsigned ResWidth = S.getASTContext().getIntWidth(Call->getType());
return interp__builtin_elementwise_int_unaryop(
@@ -4468,6 +4474,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
});
}
+ case Builtin::BIstdc_first_trailing_zero:
case Builtin::BI__builtin_stdc_first_trailing_zero: {
unsigned ResWidth = S.getASTContext().getIntWidth(Call->getType());
return interp__builtin_elementwise_int_unaryop(
@@ -4476,6 +4483,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
});
}
+ case Builtin::BIstdc_first_trailing_one:
case Builtin::BI__builtin_stdc_first_trailing_one: {
unsigned ResWidth = S.getASTContext().getIntWidth(Call->getType());
return interp__builtin_elementwise_int_unaryop(
@@ -4484,6 +4492,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
});
}
+ case Builtin::BIstdc_count_zeros:
case Builtin::BI__builtin_stdc_count_zeros: {
unsigned ResWidth = S.getASTContext().getIntWidth(Call->getType());
return interp__builtin_elementwise_int_unaryop(
@@ -4493,6 +4502,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
});
}
+ case Builtin::BIstdc_count_ones:
case Builtin::BI__builtin_stdc_count_ones: {
unsigned ResWidth = S.getASTContext().getIntWidth(Call->getType());
return interp__builtin_elementwise_int_unaryop(
@@ -4501,6 +4511,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
});
}
+ case Builtin::BIstdc_has_single_bit:
case Builtin::BI__builtin_stdc_has_single_bit: {
unsigned ResWidth = S.getASTContext().getIntWidth(Call->getType());
return interp__builtin_elementwise_int_unaryop(
@@ -4509,6 +4520,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
});
}
+ case Builtin::BIstdc_bit_width:
case Builtin::BI__builtin_stdc_bit_width: {
unsigned ResWidth = S.getASTContext().getIntWidth(Call->getType());
return interp__builtin_elementwise_int_unaryop(
@@ -4518,6 +4530,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
});
}
+ case Builtin::BIstdc_bit_floor:
case Builtin::BI__builtin_stdc_bit_floor:
return interp__builtin_elementwise_int_unaryop(
S, OpPC, Call, [](const APSInt &Val) {
@@ -4528,6 +4541,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
BitWidth - Val.countl_zero() - 1);
});
+ case Builtin::BIstdc_bit_ceil:
case Builtin::BI__builtin_stdc_bit_ceil:
return interp__builtin_elementwise_int_unaryop(
S, OpPC, Call, [](const APSInt &Val) {
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 74bbdf24f13b9..dbcedcdd59fc4 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -16825,6 +16825,20 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
}
}
+ case Builtin::BIstdc_leading_zeros:
+ case Builtin::BIstdc_leading_ones:
+ case Builtin::BIstdc_trailing_zeros:
+ case Builtin::BIstdc_trailing_ones:
+ case Builtin::BIstdc_first_leading_zero:
+ case Builtin::BIstdc_first_leading_one:
+ case Builtin::BIstdc_first_trailing_zero:
+ case Builtin::BIstdc_first_trailing_one:
+ case Builtin::BIstdc_count_zeros:
+ case Builtin::BIstdc_count_ones:
+ case Builtin::BIstdc_has_single_bit:
+ case Builtin::BIstdc_bit_width:
+ case Builtin::BIstdc_bit_floor:
+ case Builtin::BIstdc_bit_ceil:
case Builtin::BI__builtin_stdc_leading_zeros:
case Builtin::BI__builtin_stdc_leading_ones:
case Builtin::BI__builtin_stdc_trailing_zeros:
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index c45c1b1113d18..e9b4403a3442f 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3733,6 +3733,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI_rotr64:
return emitRotate(E, true);
+ case Builtin::BIstdc_leading_zeros:
case Builtin::BI__builtin_stdc_leading_zeros: {
Value *ArgValue = EmitScalarExpr(E->getArg(0));
llvm::Type *ArgType = ArgValue->getType();
@@ -3743,6 +3744,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
Result = Builder.CreateIntCast(Result, ResultType, false);
return RValue::get(Result);
}
+ case Builtin::BIstdc_leading_ones:
case Builtin::BI__builtin_stdc_leading_ones: {
Value *ArgValue = EmitScalarExpr(E->getArg(0));
llvm::Type *ArgType = ArgValue->getType();
@@ -3754,6 +3756,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
Result = Builder.CreateIntCast(Result, ResultType, false);
return RValue::get(Result);
}
+ case Builtin::BIstdc_trailing_zeros:
case Builtin::BI__builtin_stdc_trailing_zeros: {
Value *ArgValue = EmitScalarExpr(E->getArg(0));
llvm::Type *ArgType = ArgValue->getType();
@@ -3764,6 +3767,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
Result = Builder.CreateIntCast(Result, ResultType, false);
return RValue::get(Result);
}
+ case Builtin::BIstdc_trailing_ones:
case Builtin::BI__builtin_stdc_trailing_ones: {
Value *ArgValue = EmitScalarExpr(E->getArg(0));
llvm::Type *ArgType = ArgValue->getType();
@@ -3775,6 +3779,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
Result = Builder.CreateIntCast(Result, ResultType, false);
return RValue::get(Result);
}
+ case Builtin::BIstdc_first_leading_zero:
case Builtin::BI__builtin_stdc_first_leading_zero: {
Value *ArgValue = EmitScalarExpr(E->getArg(0));
llvm::Type *ArgType = ArgValue->getType();
@@ -3792,6 +3797,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
Result = Builder.CreateIntCast(Result, ResultType, false);
return RValue::get(Result);
}
+ case Builtin::BIstdc_first_leading_one:
case Builtin::BI__builtin_stdc_first_leading_one: {
Value *ArgValue = EmitScalarExpr(E->getArg(0));
llvm::Type *ArgType = ArgValue->getType();
@@ -3807,6 +3813,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
Result = Builder.CreateIntCast(Result, ResultType, false);
return RValue::get(Result);
}
+ case Builtin::BIstdc_first_trailing_zero:
case Builtin::BI__builtin_stdc_first_trailing_zero: {
Value *ArgValue = EmitScalarExpr(E->getArg(0));
llvm::Type *ArgType = ArgValue->getType();
@@ -3824,6 +3831,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
Result = Builder.CreateIntCast(Result, ResultType, false);
return RValue::get(Result);
}
+ case Builtin::BIstdc_first_trailing_one:
case Builtin::BI__builtin_stdc_first_trailing_one: {
Value *ArgValue = EmitScalarExpr(E->getArg(0));
llvm::Type *ArgType = ArgValue->getType();
@@ -3839,6 +3847,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
Result = Builder.CreateIntCast(Result, ResultType, false);
return RValue::get(Result);
}
+ case Builtin::BIstdc_count_zeros:
case Builtin::BI__builtin_stdc_count_zeros: {
Value *ArgValue = EmitScalarExpr(E->getArg(0));
llvm::Type *ArgType = ArgValue->getType();
@@ -3852,6 +3861,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
Result = Builder.CreateIntCast(Result, ResultType, false);
return RValue::get(Result);
}
+ case Builtin::BIstdc_count_ones:
case Builtin::BI__builtin_stdc_count_ones: {
Value *ArgValue = EmitScalarExpr(E->getArg(0));
llvm::Type *ArgType = ArgValue->getType();
@@ -3862,6 +3872,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
Result = Builder.CreateIntCast(Result, ResultType, false);
return RValue::get(Result);
}
+ case Builtin::BIstdc_has_single_bit:
case Builtin::BI__builtin_stdc_has_single_bit: {
Value *ArgValue = EmitScalarExpr(E->getArg(0));
llvm::Type *ArgType = ArgValue->getType();
@@ -3870,6 +3881,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
Value *PopCnt = Builder.CreateCall(F, ArgValue);
return RValue::get(Builder.CreateICmpEQ(PopCnt, One));
}
+ case Builtin::BIstdc_bit_width:
case Builtin::BI__builtin_stdc_bit_width: {
Value *ArgValue = EmitScalarExpr(E->getArg(0));
llvm::Type *ArgType = ArgValue->getType();
@@ -3882,6 +3894,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
Result = Builder.CreateIntCast(Result, ResultType, false);
return RValue::get(Result);
}
+ case Builtin::BIstdc_bit_floor:
case Builtin::BI__builtin_stdc_bit_floor: {
Value *ArgValue = EmitScalarExpr(E->getArg(0));
llvm::Type *ArgType = ArgValue->getType();
@@ -3897,6 +3910,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
Value *Result = Builder.CreateSelect(IsZero, Zero, Shifted);
return RValue::get(Result);
}
+ case Builtin::BIstdc_bit_ceil:
case Builtin::BI__builtin_stdc_bit_ceil: {
Value *ArgValue = EmitScalarExpr(E->getArg(0));
llvm::Type *ArgType = ArgValue->getType();
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index c79281c390d46..6a5d130502ad9 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -3827,10 +3827,13 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
case Builtin::BI__builtin_stdc_bit_floor:
case Builtin::BI__builtin_stdc_bit_ceil:
+ case Builtin::BIstdc_bit_floor:
+ case Builtin::BIstdc_bit_ceil:
if (BuiltinStdCBuiltin(*this, TheCall, QualType()))
return ExprError();
break;
case Builtin::BI__builtin_stdc_has_single_bit:
+ case Builtin::BIstdc_has_single_bit:
if (BuiltinStdCBuiltin(*this, TheCall, Context.BoolTy))
return ExprError();
break;
@@ -3845,6 +3848,17 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
case Builtin::BI__builtin_stdc_count_zeros:
case Builtin::BI__builtin_stdc_count_ones:
case Builtin::BI__builtin_stdc_bit_width:
+ case Builtin::BIstdc_leading_zeros:
+ case Builtin::BIstdc_leading_ones:
+ case Builtin::BIstdc_trailing_zeros:
+ case Builtin::BIstdc_trailing_ones:
+ case Builtin::BIstdc_first_leading_zero:
+ case Builtin::BIstdc_first_leading_one:
+ case Builtin::BIstdc_first_trailing_zero:
+ case Builtin::BIstdc_first_trailing_one:
+ case Builtin::BIstdc_count_zeros:
+ case Builtin::BIstdc_count_ones:
+ case Builtin::BIstdc_bit_width:
if (BuiltinStdCBuiltin(*this, TheCall, Context.UnsignedIntTy))
return ExprError();
break;
diff --git a/clang/test/CodeGen/Inputs/stdbit.h b/clang/test/CodeGen/Inputs/stdbit.h
new file mode 100644
index 0000000000000..f2f7aca355d94
--- /dev/null
+++ b/clang/test/CodeGen/Inputs/stdbit.h
@@ -0,0 +1,19 @@
+#ifndef LLVM_CLANG_TEST_STDBIT_H
+#define LLVM_CLANG_TEST_STDBIT_H
+
+#define stdc_leading_zeros(x) (__builtin_stdc_leading_zeros((x)))
+#define stdc_leading_ones(x) (__builtin_stdc_leading_ones((x)))
+#define stdc_trailing_zeros(x) (__builtin_stdc_trailing_zeros((x)))
+#define stdc_trailing_ones(x) (__builtin_stdc_trailing_ones((x)))
+#define stdc_first_leading_zero(x) (__builtin_stdc_first_leading_zero((x)))
+#define stdc_first_leading_one(x) (__builtin_stdc_first_leading_one((x)))
+#define stdc_first_trailing_zero(x) (__builtin_stdc_first_trailing_zero((x)))
+#define stdc_first_trailing_one(x) (__builtin_stdc_first_trailing_one((x)))
+#define stdc_count_zeros(x) (__builtin_stdc_count_zeros((x)))
+#define stdc_count_ones(x) (__builtin_stdc_count_ones((x)))
+#define stdc_has_single_bit(x) ((_Bool)__builtin_stdc_has_single_bit((x)))
+#define stdc_bit_width(x) (__builtin_stdc_bit_width((x)))
+#define stdc_bit_floor(x) (__builtin_stdc_bit_floor((x)))
+#define stdc_bit_ceil(x) (__builtin_stdc_bit_ceil((x)))
+
+#endif
diff --git a/clang/test/CodeGen/builtin-stdc-bit-functions.c b/clang/test/CodeGen/builtin-stdc-bit-functions.c
index bbccd6114f797..2101f657822b5 100644
--- a/clang/test/CodeGen/builtin-stdc-bit-functions.c
+++ b/clang/test/CodeGen/builtin-stdc-bit-functions.c
@@ -1,5 +1,6 @@
-// RUN: %clang_cc1 -ffreestanding %s -emit-llvm -o - | FileCheck %s
-// RUN: %if clang-target-64-bits %{ %clang_cc1 -ffreestanding %s -emit-llvm -o - | FileCheck %s --check-prefix=INT128 %}
+// RUN: %clang_cc1 -ffreestanding -std=c23 %s -emit-llvm -o - | FileCheck %s
+// RUN: %if clang-target-64-bits %{ %clang_cc1 -ffreestanding -std=c23 %s -emit-llvm -o - | FileCheck %s --check-prefix=INT128 %}
+// RUN: %clang_cc1 -ffreestanding -std=c23 -isystem %S/Inputs -DTEST_LIB_SPELLINGS -Wno-implicit-function-declaration %s -emit-llvm -o - | FileCheck %s --check-prefix=LIB
// CHECK-LABEL: test_leading_zeros
// CHECK: call i8 @llvm.ctlz.i8(i8 %{{.*}}, i1 false)
@@ -325,3 +326,98 @@ void test_int128_floor_ceil(unsigned __int128 u128) {
r = __builtin_stdc_bit_ceil(u128);
}
#endif
+
+#ifdef TEST_LIB_SPELLINGS
+#ifdef __has_include
+#if __has_include(<stdbit.h>)
+#include <stdbit.h>
+
+// LIB-LABEL: test_lib_leading_zeros
+// LIB: call i32 @llvm.ctlz.i32(i32 %{{.*}}, i1 false)
+void test_lib_leading_zeros(unsigned ui) {
+ volatile unsigned r = stdc_leading_zeros(ui);
+}
+
+// LIB-LABEL: test_lib_leading_ones
+// LIB: xor i32 %{{.*}}, -1
+// LIB: call i32 @llvm.ctlz.i32(i32 %{{.*}}, i1 false)
+void test_lib_leading_ones(unsigned ui) {
+ volatile unsigned r = stdc_leading_ones(ui);
+}
+
+// LIB-LABEL: test_lib_trailing_zeros
+// LIB: call i32 @llvm.cttz.i32(i32 %{{.*}}, i1 false)
+void test_lib_trailing_zeros(unsigned ui) {
+ volatile unsigned r = stdc_trailing_zeros(ui);
+}
+
+// LIB-LABEL: test_lib_trailing_ones
+// LIB: xor i32 %{{.*}}, -1
+// LIB: call i32 @llvm.cttz.i32(i32 %{{.*}}, i1 false)
+void test_lib_trailing_ones(unsigned ui) {
+ volatile unsigned r = stdc_trailing_ones(ui);
+}
+
+// LIB-LABEL: test_lib_first_leading_zero
+// LIB: call i32 @llvm.ctlz.i32(i32 %{{.*}}, i1 false)
+void test_lib_first_leading_zero(unsigned ui) {
+ volatile unsigned r = stdc_first_leading_zero(ui);
+}
+
+// LIB-LABEL: test_lib_first_leading_one
+// LIB: call i32 @llvm.ctlz.i32(i32 %{{.*}}, i1 false)
+void test_lib_first_leading_one(unsigned ui) {
+ volatile unsigned r = stdc_first_leading_one(ui);
+}
+
+// LIB-LABEL: test_lib_first_trailing_zero
+// LIB: xor i32 %{{.*}}, -1
+// LIB: call i32 @llvm.cttz.i32(i32 %{{.*}}, i1 false)
+void test_lib_first_trailing_zero(unsigned ui) {
+ volatile unsigned r = stdc_first_trailing_zero(ui);
+}
+
+// LIB-LABEL: test_lib_first_trailing_one
+// LIB: call i32 @llvm.cttz.i32(i32 %{{.*}}, i1 false)
+void test_lib_first_trailing_one(unsigned ui) {
+ volatile unsigned r = stdc_first_trailing_one(ui);
+}
+
+// LIB-LABEL: test_lib_count_zeros
+// LIB: call i32 @llvm.ctpop.i32(i32 %{{.*}})
+void test_lib_count_zeros(unsigned ui) {
+ volatile unsigned r = stdc_count_zeros(ui);
+}
+
+// LIB-LABEL: test_lib_count_ones
+// LIB: call i32 @llvm.ctpop.i32(i32 %{{.*}})
+void test_lib_count_ones(unsigned ui) {
+ volatile unsigned r = stdc_count_ones(ui);
+}
+
+// LIB-LABEL: test_lib_has_single_bit
+// LIB: call i32 @llvm.ctpop.i32(i32 %{{.*}})
+void test_lib_has_single_bit(unsigned ui) {
+ volatile _Bool r = stdc_has_single_bit(ui);
+}
+
+// LIB-LABEL: test_lib_bit_width
+// LIB: call i32 @llvm.ctlz.i32(i32 %{{.*}}, i1 false)
+void test_lib_bit_width(unsigned ui) {
+ volatile unsigned r = stdc_bit_width(ui);
+}
+
+// LIB-LABEL: test_lib_bit_floor
+// LIB: call i32 @llvm.ctlz.i32(i32 %{{.*}}, i1 true)
+void test_lib_bit_floor(unsigned ui) {
+ volatile unsigned r = stdc_bit_floor(ui);
+}
+
+// LIB-LABEL: test_lib_bit_ceil
+// LIB: call i32 @llvm.ctlz.i32(i32 %{{.*}}, i1 false)
+void test_lib_bit_ceil(unsigned ui) {
+ volatile unsigned r = stdc_bit_ceil(ui);
+}
+#endif
+#endif
+#endif
diff --git a/clang/test/Sema/Inputs/stdbit.h b/clang/test/Sema/Inputs/stdbit.h
new file mode 100644
index 0000000000000..8b49d6a11f080
--- /dev/null
+++ b/clang/test/Sema/Inputs/stdbit.h
@@ -0,0 +1 @@
+#include "../../CodeGen/Inputs/stdbit.h"
diff --git a/clang/test/Sema/builtin-stdc-bit-functions.c b/clang/test/Sema/builtin-stdc-bit-functions.c
index 34e05b323fbab..590baba3eb755 100644
--- a/clang/test/Sema/builtin-stdc-bit-functions.c
+++ b/clang/test/Sema/builtin-stdc-bit-functions.c
@@ -1,5 +1,6 @@
-// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fsyntax-only -verify %s
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -std=c23 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c23 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -std=c23 -isystem %S/Inputs -fsyntax-only -verify %s
// Test stdc_leading_zeros
_Static_assert(__builtin_stdc_leading_zeros((unsigned char)0) == 8, "");
@@ -376,3 +377,25 @@ void test_errors(int si, float f) {
__builtin_stdc_bit_ceil(si); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
__builtin_stdc_bit_ceil(f); // expected-error {{1st argument must be a scalar unsigned integer type (was 'float')}}
}
+
+#ifdef __has_include
+#if __has_include(<stdbit.h>)
+#include <stdbit.h>
+
+_Static_assert(stdc_leading_zeros(0U) == 32, "");
+_Static_assert(stdc_leading_zeros(1U) == 31, "");
+_Static_assert(stdc_leading_ones(0xFFFFFFFFU) == 32, "");
+_Static_assert(stdc_trailing_zeros(0U) == 32, "");
+_Static_assert(stdc_trailing_ones(0xFFFFFFFFU) == 32, "");
+_Static_assert(stdc_first_leading_zero(0U) == 1, "");
+_Static_assert(stdc_first_leading_one(0U) == 0, "");
+_Static_assert(stdc_first_trailing_zero(0U) == 1, "");
+_Static_assert(stdc_first_trailing_one(0U) == 0, "");
+_Static_assert(stdc_count_zeros(0U) == 32, "");
+_Static_assert(stdc_count_ones(0xFFFFFFFFU) == 32, "");
+_Static_assert(stdc_has_single_bit(4U) == 1, "");
+_Static_assert(stdc_bit_width(7U) == 3, "");
+_Static_assert(stdc_bit_floor(6U) == 4U, "");
+_Static_assert(stdc_bit_ceil(6U) == 8U, "");
+#endif
+#endif
>From 412e6c3ec60acf1640b22cf26464636bf4385703 Mon Sep 17 00:00:00 2001
From: NagaChaitanya Vellanki <pnagato at protonmail.com>
Date: Fri, 3 Apr 2026 11:23:35 -0700
Subject: [PATCH 11/14] Remove special-casing of constants since they are
constant-folded
---
clang/lib/CodeGen/CGBuiltin.cpp | 7 -------
clang/test/CodeGen/builtin-stdc-bit-functions.c | 13 -------------
2 files changed, 20 deletions(-)
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index e9b4403a3442f..2d58b3bfc6310 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3918,13 +3918,6 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
Value *Zero = ConstantInt::get(ArgType, 0);
Value *One = ConstantInt::get(ArgType, 1);
- if (auto *CI = dyn_cast<ConstantInt>(ArgValue)) {
- if (CI->isMinusOne())
- return RValue::get(CI);
- if (CI->isZero() || CI->isOne())
- return RValue::get(ConstantInt::get(ArgType, 1));
- }
-
Value *IsLEOne = Builder.CreateICmpULE(ArgValue, One, "isleone");
BasicBlock *EntryBB = Builder.GetInsertBlock();
diff --git a/clang/test/CodeGen/builtin-stdc-bit-functions.c b/clang/test/CodeGen/builtin-stdc-bit-functions.c
index 2101f657822b5..8557b5ddb439f 100644
--- a/clang/test/CodeGen/builtin-stdc-bit-functions.c
+++ b/clang/test/CodeGen/builtin-stdc-bit-functions.c
@@ -239,19 +239,6 @@ void test_bitint_first_and_count(unsigned _BitInt(9) bi9) {
r = __builtin_stdc_count_zeros(bi9);
}
-// CHECK-LABEL: test_bit_ceil_all_ones
-// CHECK: store volatile i32 -1, ptr %r
-void test_bit_ceil_all_ones(void) {
- volatile unsigned int r = __builtin_stdc_bit_ceil(0xFFFFFFFFU);
-}
-
-// CHECK-LABEL: test_bit_ceil_all_ones_bitint
-// CHECK: store volatile i32 131071, ptr %r
-void test_bit_ceil_all_ones_bitint(void) {
- volatile unsigned _BitInt(17) r =
- __builtin_stdc_bit_ceil((unsigned _BitInt(17))(-1));
-}
-
// CHECK-LABEL: test_bit_floor_all_ones_bitint
// CHECK: store volatile i32 65536, ptr %r
void test_bit_floor_all_ones_bitint(void) {
>From cb47069b424f0d5478d1872181e9059d833e5328 Mon Sep 17 00:00:00 2001
From: NagaChaitanya Vellanki <pnagato at protonmail.com>
Date: Fri, 3 Apr 2026 14:54:31 -0700
Subject: [PATCH 12/14] Add comment explaining the 1 in the diagnostic
---
clang/lib/Sema/SemaChecking.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 6a5d130502ad9..62a078f92af90 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2364,7 +2364,7 @@ static bool BuiltinStdCBuiltin(Sema &S, CallExpr *TheCall,
QualType ArgTy = Arg->getType();
if (!ArgTy->isUnsignedIntegerType())
return S.Diag(Arg->getBeginLoc(), diag::err_builtin_stdc_invalid_arg_type)
- << 1 << ArgTy;
+ << 1 /*1st argument*/ << ArgTy;
TheCall->setType(ReturnType.isNull() ? ArgTy : ReturnType);
return false;
>From 8e6b9cd55d7710d6fe5b56ef9c8f0e642a070700 Mon Sep 17 00:00:00 2001
From: NagaChaitanya Vellanki <pnagato at protonmail.com>
Date: Fri, 3 Apr 2026 15:29:35 -0700
Subject: [PATCH 13/14] Create helper functions to share codegen across C23
stdbit builtins
---
clang/lib/CodeGen/CGBuiltin.cpp | 220 ++++++++++------------------
clang/lib/CodeGen/CodeGenFunction.h | 7 +
2 files changed, 86 insertions(+), 141 deletions(-)
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 2d58b3bfc6310..e6c8c208554d3 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -2642,6 +2642,62 @@ static RValue EmitHipStdParUnsupportedBuiltin(CodeGenFunction *CGF,
return RValue::get(CGF->Builder.CreateCall(UBF, Args));
}
+// stdc_{leading,trailing}_{zeros,ones} and stdc_count_ones: counts bits using
+// ctlz, cttz, or ctpop (IsPop). InvertArg flips the input to count the
+// opposite bit value.
+RValue CodeGenFunction::emitStdcCountIntrinsic(const CallExpr *E,
+ Intrinsic::ID IntID,
+ bool InvertArg, bool IsPop) {
+ Value *ArgValue = EmitScalarExpr(E->getArg(0));
+ llvm::Type *ArgType = ArgValue->getType();
+ llvm::Type *ResultType = ConvertType(E->getType());
+ Value *ActualArg = InvertArg ? Builder.CreateNot(ArgValue) : ArgValue;
+ Function *F = CGM.getIntrinsic(IntID, ArgType);
+ Value *Result = IsPop ? Builder.CreateCall(F, ActualArg)
+ : Builder.CreateCall(F, {ActualArg, Builder.getFalse()});
+ if (Result->getType() != ResultType)
+ Result = Builder.CreateIntCast(Result, ResultType, false);
+ return RValue::get(Result);
+}
+
+// stdc_count_zeros (BitWidth - ctpop) and stdc_bit_width (BitWidth - ctlz).
+// IsPop selects ctpop; otherwise ctlz is used.
+RValue CodeGenFunction::emitStdcBitWidthMinus(const CallExpr *E,
+ Intrinsic::ID IntID, bool IsPop) {
+ Value *ArgValue = EmitScalarExpr(E->getArg(0));
+ llvm::Type *ArgType = ArgValue->getType();
+ llvm::Type *ResultType = ConvertType(E->getType());
+ unsigned BitWidth = ArgType->getIntegerBitWidth();
+ Function *F = CGM.getIntrinsic(IntID, ArgType);
+ Value *Cnt = IsPop ? Builder.CreateCall(F, ArgValue)
+ : Builder.CreateCall(F, {ArgValue, Builder.getFalse()});
+ Value *Result = Builder.CreateSub(ConstantInt::get(ArgType, BitWidth), Cnt);
+ if (Result->getType() != ResultType)
+ Result = Builder.CreateIntCast(Result, ResultType, false);
+ return RValue::get(Result);
+}
+
+// stdc_first_{leading,trailing}_{zero,one}: returns the 1-based position of
+// the first matching bit, or 0 if no such bit exists. InvertArg flips the
+// input to search for zeros instead of ones.
+RValue CodeGenFunction::emitStdcFirstBit(const CallExpr *E,
+ Intrinsic::ID IntID, bool InvertArg) {
+ Value *ArgValue = EmitScalarExpr(E->getArg(0));
+ llvm::Type *ArgType = ArgValue->getType();
+ llvm::Type *ResultType = ConvertType(E->getType());
+ Value *Zero = ConstantInt::get(ArgType, 0);
+ Value *One = ConstantInt::get(ArgType, 1);
+ Value *ActualArg = InvertArg ? Builder.CreateNot(ArgValue) : ArgValue;
+ Function *F = CGM.getIntrinsic(IntID, ArgType);
+ Value *Cnt = Builder.CreateCall(F, {ActualArg, Builder.getFalse()});
+ Value *Tmp = Builder.CreateAdd(Cnt, One);
+ Value *IsZero = Builder.CreateICmpEQ(ActualArg, Zero);
+ Value *Result = Builder.CreateSelect(IsZero, Zero, Tmp);
+ if (Result->getType() != ResultType)
+ Result = Builder.CreateIntCast(Result, ResultType, false);
+ return RValue::get(Result);
+}
+
RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
const CallExpr *E,
ReturnValueSlot ReturnValue) {
@@ -3734,144 +3790,36 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
return emitRotate(E, true);
case Builtin::BIstdc_leading_zeros:
- case Builtin::BI__builtin_stdc_leading_zeros: {
- Value *ArgValue = EmitScalarExpr(E->getArg(0));
- llvm::Type *ArgType = ArgValue->getType();
- llvm::Type *ResultType = ConvertType(E->getType());
- Function *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType);
- Value *Result = Builder.CreateCall(F, {ArgValue, Builder.getFalse()});
- if (Result->getType() != ResultType)
- Result = Builder.CreateIntCast(Result, ResultType, false);
- return RValue::get(Result);
- }
+ case Builtin::BI__builtin_stdc_leading_zeros:
+ return emitStdcCountIntrinsic(E, Intrinsic::ctlz, /*InvertArg=*/false);
case Builtin::BIstdc_leading_ones:
- case Builtin::BI__builtin_stdc_leading_ones: {
- Value *ArgValue = EmitScalarExpr(E->getArg(0));
- llvm::Type *ArgType = ArgValue->getType();
- llvm::Type *ResultType = ConvertType(E->getType());
- Function *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType);
- Value *Result = Builder.CreateCall(
- F, {Builder.CreateNot(ArgValue), Builder.getFalse()});
- if (Result->getType() != ResultType)
- Result = Builder.CreateIntCast(Result, ResultType, false);
- return RValue::get(Result);
- }
+ case Builtin::BI__builtin_stdc_leading_ones:
+ return emitStdcCountIntrinsic(E, Intrinsic::ctlz, /*InvertArg=*/true);
case Builtin::BIstdc_trailing_zeros:
- case Builtin::BI__builtin_stdc_trailing_zeros: {
- Value *ArgValue = EmitScalarExpr(E->getArg(0));
- llvm::Type *ArgType = ArgValue->getType();
- llvm::Type *ResultType = ConvertType(E->getType());
- Function *F = CGM.getIntrinsic(Intrinsic::cttz, ArgType);
- Value *Result = Builder.CreateCall(F, {ArgValue, Builder.getFalse()});
- if (Result->getType() != ResultType)
- Result = Builder.CreateIntCast(Result, ResultType, false);
- return RValue::get(Result);
- }
+ case Builtin::BI__builtin_stdc_trailing_zeros:
+ return emitStdcCountIntrinsic(E, Intrinsic::cttz, /*InvertArg=*/false);
case Builtin::BIstdc_trailing_ones:
- case Builtin::BI__builtin_stdc_trailing_ones: {
- Value *ArgValue = EmitScalarExpr(E->getArg(0));
- llvm::Type *ArgType = ArgValue->getType();
- llvm::Type *ResultType = ConvertType(E->getType());
- Function *F = CGM.getIntrinsic(Intrinsic::cttz, ArgType);
- Value *Result = Builder.CreateCall(
- F, {Builder.CreateNot(ArgValue), Builder.getFalse()});
- if (Result->getType() != ResultType)
- Result = Builder.CreateIntCast(Result, ResultType, false);
- return RValue::get(Result);
- }
+ case Builtin::BI__builtin_stdc_trailing_ones:
+ return emitStdcCountIntrinsic(E, Intrinsic::cttz, /*InvertArg=*/true);
case Builtin::BIstdc_first_leading_zero:
- case Builtin::BI__builtin_stdc_first_leading_zero: {
- Value *ArgValue = EmitScalarExpr(E->getArg(0));
- llvm::Type *ArgType = ArgValue->getType();
- llvm::Type *ResultType = ConvertType(E->getType());
- Value *Zero = ConstantInt::get(ArgType, 0);
- Value *One = ConstantInt::get(ArgType, 1);
- Function *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType);
- Value *Cnt = Builder.CreateCall(
- F, {Builder.CreateNot(ArgValue), Builder.getFalse()});
- Value *Tmp = Builder.CreateAdd(Cnt, One);
- Value *IsAllOnes =
- Builder.CreateICmpEQ(ArgValue, Constant::getAllOnesValue(ArgType));
- Value *Result = Builder.CreateSelect(IsAllOnes, Zero, Tmp);
- if (Result->getType() != ResultType)
- Result = Builder.CreateIntCast(Result, ResultType, false);
- return RValue::get(Result);
- }
+ case Builtin::BI__builtin_stdc_first_leading_zero:
+ return emitStdcFirstBit(E, Intrinsic::ctlz, /*InvertArg=*/true);
case Builtin::BIstdc_first_leading_one:
- case Builtin::BI__builtin_stdc_first_leading_one: {
- Value *ArgValue = EmitScalarExpr(E->getArg(0));
- llvm::Type *ArgType = ArgValue->getType();
- llvm::Type *ResultType = ConvertType(E->getType());
- Value *Zero = ConstantInt::get(ArgType, 0);
- Value *One = ConstantInt::get(ArgType, 1);
- Function *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType);
- Value *Cnt = Builder.CreateCall(F, {ArgValue, Builder.getFalse()});
- Value *Tmp = Builder.CreateAdd(Cnt, One);
- Value *IsZero = Builder.CreateICmpEQ(ArgValue, Zero);
- Value *Result = Builder.CreateSelect(IsZero, Zero, Tmp);
- if (Result->getType() != ResultType)
- Result = Builder.CreateIntCast(Result, ResultType, false);
- return RValue::get(Result);
- }
+ case Builtin::BI__builtin_stdc_first_leading_one:
+ return emitStdcFirstBit(E, Intrinsic::ctlz, /*InvertArg=*/false);
case Builtin::BIstdc_first_trailing_zero:
- case Builtin::BI__builtin_stdc_first_trailing_zero: {
- Value *ArgValue = EmitScalarExpr(E->getArg(0));
- llvm::Type *ArgType = ArgValue->getType();
- llvm::Type *ResultType = ConvertType(E->getType());
- Value *Zero = ConstantInt::get(ArgType, 0);
- Value *One = ConstantInt::get(ArgType, 1);
- Function *F = CGM.getIntrinsic(Intrinsic::cttz, ArgType);
- Value *Cnt = Builder.CreateCall(
- F, {Builder.CreateNot(ArgValue), Builder.getFalse()});
- Value *Tmp = Builder.CreateAdd(Cnt, One);
- Value *IsAllOnes =
- Builder.CreateICmpEQ(ArgValue, Constant::getAllOnesValue(ArgType));
- Value *Result = Builder.CreateSelect(IsAllOnes, Zero, Tmp);
- if (Result->getType() != ResultType)
- Result = Builder.CreateIntCast(Result, ResultType, false);
- return RValue::get(Result);
- }
+ case Builtin::BI__builtin_stdc_first_trailing_zero:
+ return emitStdcFirstBit(E, Intrinsic::cttz, /*InvertArg=*/true);
case Builtin::BIstdc_first_trailing_one:
- case Builtin::BI__builtin_stdc_first_trailing_one: {
- Value *ArgValue = EmitScalarExpr(E->getArg(0));
- llvm::Type *ArgType = ArgValue->getType();
- llvm::Type *ResultType = ConvertType(E->getType());
- Value *Zero = ConstantInt::get(ArgType, 0);
- Value *One = ConstantInt::get(ArgType, 1);
- Function *F = CGM.getIntrinsic(Intrinsic::cttz, ArgType);
- Value *Cnt = Builder.CreateCall(F, {ArgValue, Builder.getFalse()});
- Value *Tmp = Builder.CreateAdd(Cnt, One);
- Value *IsZero = Builder.CreateICmpEQ(ArgValue, Zero);
- Value *Result = Builder.CreateSelect(IsZero, Zero, Tmp);
- if (Result->getType() != ResultType)
- Result = Builder.CreateIntCast(Result, ResultType, false);
- return RValue::get(Result);
- }
+ case Builtin::BI__builtin_stdc_first_trailing_one:
+ return emitStdcFirstBit(E, Intrinsic::cttz, /*InvertArg=*/false);
case Builtin::BIstdc_count_zeros:
- case Builtin::BI__builtin_stdc_count_zeros: {
- Value *ArgValue = EmitScalarExpr(E->getArg(0));
- llvm::Type *ArgType = ArgValue->getType();
- llvm::Type *ResultType = ConvertType(E->getType());
- unsigned BitWidth = ArgType->getIntegerBitWidth();
- Function *F = CGM.getIntrinsic(Intrinsic::ctpop, ArgType);
- Value *PopCnt = Builder.CreateCall(F, ArgValue);
- Value *Result =
- Builder.CreateSub(ConstantInt::get(ArgType, BitWidth), PopCnt);
- if (Result->getType() != ResultType)
- Result = Builder.CreateIntCast(Result, ResultType, false);
- return RValue::get(Result);
- }
+ case Builtin::BI__builtin_stdc_count_zeros:
+ return emitStdcBitWidthMinus(E, Intrinsic::ctpop, /*IsPop=*/true);
case Builtin::BIstdc_count_ones:
- case Builtin::BI__builtin_stdc_count_ones: {
- Value *ArgValue = EmitScalarExpr(E->getArg(0));
- llvm::Type *ArgType = ArgValue->getType();
- llvm::Type *ResultType = ConvertType(E->getType());
- Function *F = CGM.getIntrinsic(Intrinsic::ctpop, ArgType);
- Value *Result = Builder.CreateCall(F, ArgValue);
- if (Result->getType() != ResultType)
- Result = Builder.CreateIntCast(Result, ResultType, false);
- return RValue::get(Result);
- }
+ case Builtin::BI__builtin_stdc_count_ones:
+ return emitStdcCountIntrinsic(E, Intrinsic::ctpop, /*InvertArg=*/false,
+ /*IsPop=*/true);
case Builtin::BIstdc_has_single_bit:
case Builtin::BI__builtin_stdc_has_single_bit: {
Value *ArgValue = EmitScalarExpr(E->getArg(0));
@@ -3882,18 +3830,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
return RValue::get(Builder.CreateICmpEQ(PopCnt, One));
}
case Builtin::BIstdc_bit_width:
- case Builtin::BI__builtin_stdc_bit_width: {
- Value *ArgValue = EmitScalarExpr(E->getArg(0));
- llvm::Type *ArgType = ArgValue->getType();
- llvm::Type *ResultType = ConvertType(E->getType());
- unsigned BitWidth = ArgType->getIntegerBitWidth();
- Function *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType);
- Value *LZ = Builder.CreateCall(F, {ArgValue, Builder.getFalse()});
- Value *Result = Builder.CreateSub(ConstantInt::get(ArgType, BitWidth), LZ);
- if (Result->getType() != ResultType)
- Result = Builder.CreateIntCast(Result, ResultType, false);
- return RValue::get(Result);
- }
+ case Builtin::BI__builtin_stdc_bit_width:
+ return emitStdcBitWidthMinus(E, Intrinsic::ctlz, /*IsPop=*/false);
case Builtin::BIstdc_bit_floor:
case Builtin::BI__builtin_stdc_bit_floor: {
Value *ArgValue = EmitScalarExpr(E->getArg(0));
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index fd474c09044ef..94015f847341c 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -4768,6 +4768,13 @@ class CodeGenFunction : public CodeGenTypeCache {
RValue emitRotate(const CallExpr *E, bool IsRotateRight);
+ RValue emitStdcCountIntrinsic(const CallExpr *E, llvm::Intrinsic::ID IntID,
+ bool InvertArg, bool IsPop = false);
+ RValue emitStdcBitWidthMinus(const CallExpr *E, llvm::Intrinsic::ID IntID,
+ bool IsPop);
+ RValue emitStdcFirstBit(const CallExpr *E, llvm::Intrinsic::ID IntID,
+ bool InvertArg);
+
/// Emit IR for __builtin_os_log_format.
RValue emitBuiltinOSLogFormat(const CallExpr &E);
>From 06809d0da39ce41d3c4af301dd5a338318d3d247 Mon Sep 17 00:00:00 2001
From: NagaChaitanya Vellanki <pnagato at protonmail.com>
Date: Fri, 3 Apr 2026 15:34:38 -0700
Subject: [PATCH 14/14] Remove redundant __has_include guard in stdbit CodeGen
test
---
clang/test/CodeGen/builtin-stdc-bit-functions.c | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/clang/test/CodeGen/builtin-stdc-bit-functions.c b/clang/test/CodeGen/builtin-stdc-bit-functions.c
index 8557b5ddb439f..99a62aef0a24b 100644
--- a/clang/test/CodeGen/builtin-stdc-bit-functions.c
+++ b/clang/test/CodeGen/builtin-stdc-bit-functions.c
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -ffreestanding -std=c23 %s -emit-llvm -o - | FileCheck %s
// RUN: %if clang-target-64-bits %{ %clang_cc1 -ffreestanding -std=c23 %s -emit-llvm -o - | FileCheck %s --check-prefix=INT128 %}
-// RUN: %clang_cc1 -ffreestanding -std=c23 -isystem %S/Inputs -DTEST_LIB_SPELLINGS -Wno-implicit-function-declaration %s -emit-llvm -o - | FileCheck %s --check-prefix=LIB
+// RUN: %clang_cc1 -ffreestanding -std=c23 -isystem %S/Inputs -DTEST_LIB_SPELLINGS %s -emit-llvm -o - | FileCheck %s --check-prefix=LIB
// CHECK-LABEL: test_leading_zeros
// CHECK: call i8 @llvm.ctlz.i8(i8 %{{.*}}, i1 false)
@@ -315,8 +315,6 @@ void test_int128_floor_ceil(unsigned __int128 u128) {
#endif
#ifdef TEST_LIB_SPELLINGS
-#ifdef __has_include
-#if __has_include(<stdbit.h>)
#include <stdbit.h>
// LIB-LABEL: test_lib_leading_zeros
@@ -406,5 +404,3 @@ void test_lib_bit_ceil(unsigned ui) {
volatile unsigned r = stdc_bit_ceil(ui);
}
#endif
-#endif
-#endif
More information about the cfe-commits
mailing list