https://github.com/clingfei updated https://github.com/llvm/llvm-project/pull/162433
>From 92466f3789ce1849ebee8a405efd42e191c591f5 Mon Sep 17 00:00:00 2001 From: clingfei <[email protected]> Date: Wed, 8 Oct 2025 15:05:44 +0800 Subject: [PATCH 1/4] [Clang] Add __builtin_bswapg --- clang/include/clang/Basic/Builtins.td | 6 ++++ clang/lib/AST/ByteCode/InterpBuiltin.cpp | 10 ++++++- clang/lib/AST/ExprConstant.cpp | 11 ++++++++ clang/lib/CodeGen/CGBuiltin.cpp | 1 + clang/lib/Sema/SemaChecking.cpp | 28 +++++++++++++++++++ clang/test/AST/ByteCode/builtin-functions.cpp | 4 +++ clang/test/CodeGen/builtins.c | 2 +- clang/test/Sema/constant-builtins-2.c | 4 +++ clang/test/Sema/constant-builtins.c | 5 +++- 9 files changed, 68 insertions(+), 3 deletions(-) diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 468121f7d20ab..e65ed2f20be97 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -755,6 +755,12 @@ def BSwap : Builtin, Template<["unsigned short", "uint32_t", "uint64_t"], let Prototype = "T(T)"; } +def BSwapg : Builtin { + let Spellings = ["__builtin_bswapg"]; + let Attributes = [NoThrow, Const, Constexpr, CustomTypeChecking]; + let Prototype = "int(...)"; +} + def Bitreverse : BitInt8_16_32_64BuiltinsTemplate, Builtin { let Spellings = ["__builtin_bitreverse"]; let Attributes = [NoThrow, Const, Constexpr]; diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp index 1eea813b8c556..b8d17fbce6d4e 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -3288,7 +3288,15 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, case Builtin::BI__builtin_elementwise_ctzg: return interp__builtin_elementwise_countzeroes(S, OpPC, Frame, Call, BuiltinID); - + case Builtin::BI__builtin_bswapg: { + const APSInt &Val = popToAPSInt(S, Call->getArg(0)); + assert(Val.getActiveBits() <= 64); + if (Val.getBitWidth() == 8) + pushInteger(S, Val, Call->getType()); + else + pushInteger(S, Val.byteSwap(), Call->getType()); + return true; + } case Builtin::BI__builtin_bswap16: case Builtin::BI__builtin_bswap32: case Builtin::BI__builtin_bswap64: diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 618e1636e9e53..058905e7fd3c0 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -13982,6 +13982,17 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, return Success(Val.reverseBits(), E); } + case Builtin::BI__builtin_bswapg: { + APSInt Val; + if (!EvaluateInteger(E->getArg(0), Val, Info)) + return false; + if (Val.getBitWidth() == 8) { + bool ret = Success(Val, E); + return ret; + } + + return Success(Val.byteSwap(), E); + } case Builtin::BI__builtin_bswap16: case Builtin::BI__builtin_bswap32: diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 9ee810c9d5775..7733f4dc15f5d 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -3622,6 +3622,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, Builder.CreateArithmeticFence(ArgValue, ConvertType(ArgType))); return RValue::get(ArgValue); } + case Builtin::BI__builtin_bswapg: case Builtin::BI__builtin_bswap16: case Builtin::BI__builtin_bswap32: case Builtin::BI__builtin_bswap64: diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 063db05665af1..362b53676feaa 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -2200,6 +2200,30 @@ static bool BuiltinCpu(Sema &S, const TargetInfo &TI, CallExpr *TheCall, return false; } +/// Checks that __builtin_bswapg was called with a single argument, which is an +/// unsigned integer, and overrides the return value type to the integer type. +static bool BuiltinBswapg(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->isIntegerType()) { + S.Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type) + << 1 << /* scalar */ 1 << /* unsigned integer ty */ 1 << /* no fp */ 0 + << ArgTy; + return true; + } + TheCall->setType(ArgTy); + return false; +} + /// Checks that __builtin_popcountg was called with a single argument, which is /// an unsigned integer. static bool BuiltinPopcountg(Sema &S, CallExpr *TheCall) { @@ -3448,6 +3472,10 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, } break; } + case Builtin::BI__builtin_bswapg: + if (BuiltinBswapg(*this, TheCall)) + return ExprError(); + break; case Builtin::BI__builtin_popcountg: if (BuiltinPopcountg(*this, TheCall)) return ExprError(); diff --git a/clang/test/AST/ByteCode/builtin-functions.cpp b/clang/test/AST/ByteCode/builtin-functions.cpp index f47bc49d9a1a8..84ff9cc137bf3 100644 --- a/clang/test/AST/ByteCode/builtin-functions.cpp +++ b/clang/test/AST/ByteCode/builtin-functions.cpp @@ -824,6 +824,10 @@ namespace bswap { int h3 = __builtin_bswap16(0x1234) == 0x3412 ? 1 : f(); int h4 = __builtin_bswap32(0x1234) == 0x34120000 ? 1 : f(); int h5 = __builtin_bswap64(0x1234) == 0x3412000000000000 ? 1 : f(); + int h6 = __builtin_bswapg(0x12) == 0x12 ? 1 : f(); + int h7 = __builtin_bswapg(0x1234) == 0x3412 ? 1 : f(); + int h8 = __builtin_bswapg(0x00001234) == 0x34120000 ? 1 : f(); + int h9 = __builtin_bswapg(0x0000000000001234) == 0x3412000000000000 ? 1 : f(); } #define CFSTR __builtin___CFStringMakeConstantString diff --git a/clang/test/CodeGen/builtins.c b/clang/test/CodeGen/builtins.c index 738814c88bf56..11d8302816c84 100644 --- a/clang/test/CodeGen/builtins.c +++ b/clang/test/CodeGen/builtins.c @@ -130,7 +130,7 @@ int main(void) { P(object_size, (s0, 3)); // Whatever - + P(bswapg, (N)); P(bswap16, (N)); P(bswap32, (N)); P(bswap64, (N)); diff --git a/clang/test/Sema/constant-builtins-2.c b/clang/test/Sema/constant-builtins-2.c index e465a3c5f0ad8..96bd2c966c2ef 100644 --- a/clang/test/Sema/constant-builtins-2.c +++ b/clang/test/Sema/constant-builtins-2.c @@ -479,6 +479,10 @@ int h0 = __builtin_types_compatible_p(int, float); int h3 = __builtin_bswap16(0x1234) == 0x3412 ? 1 : f(); int h4 = __builtin_bswap32(0x1234) == 0x34120000 ? 1 : f(); int h5 = __builtin_bswap64(0x1234) == 0x3412000000000000 ? 1 : f(); +int h6 = __builtin_bswapg((char)(0x12)) == (char)(0x12) ? 1 : f(); +int h7 = __builtin_bswapg((short)(0x1234)) == (short)(0x3412) ? 1 : f(); +int h8 = __builtin_bswapg(0x00001234) == 0x34120000 ? 1 : f(); +int h9 = __builtin_bswapg(0x0000000000001234ULL) == 0x3412000000000000 ? 1 : f(); extern long int bi0; extern __typeof__(__builtin_expect(0, 0)) bi0; diff --git a/clang/test/Sema/constant-builtins.c b/clang/test/Sema/constant-builtins.c index 964ab59e787c4..6c13fe96b6b4a 100644 --- a/clang/test/Sema/constant-builtins.c +++ b/clang/test/Sema/constant-builtins.c @@ -25,7 +25,10 @@ int h0 = __builtin_types_compatible_p(int,float); int h3 = __builtin_bswap16(0x1234) == 0x3412 ? 1 : f(); int h4 = __builtin_bswap32(0x1234) == 0x34120000 ? 1 : f(); int h5 = __builtin_bswap64(0x1234) == 0x3412000000000000 ? 1 : f(); - +int h6 = __builtin_bswapg((char)0x12) == (char)0x12 ? 1 : f(); +int h7 = __builtin_bswapg((short)(0x1234)) == (short)(0x3412) ? 1 : f(); +int h8 = __builtin_bswapg(0x00001234) == 0x34120000 ? 1 : f(); +int h9 = __builtin_bswapg(0x0000000000001234ULL) == 0x3412000000000000 ? 1 : f(); short somefunc(void); short t = __builtin_constant_p(5353) ? 42 : somefunc(); >From d4ea8686cd97c203ec458e4cd56cd67f941bbfd0 Mon Sep 17 00:00:00 2001 From: clingfei <[email protected]> Date: Thu, 9 Oct 2025 13:14:08 +0800 Subject: [PATCH 2/4] handle special case 8 in interp__builtin_bswap and fix extra space in VisitBuiltinCallExpr --- clang/lib/AST/ByteCode/InterpBuiltin.cpp | 16 +++++----------- clang/lib/AST/ExprConstant.cpp | 6 ++---- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp index b8d17fbce6d4e..01f2cd280b175 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -1004,8 +1004,10 @@ static bool interp__builtin_bswap(InterpState &S, CodePtr OpPC, const CallExpr *Call) { const APSInt &Val = popToAPSInt(S, Call->getArg(0)); assert(Val.getActiveBits() <= 64); - - pushInteger(S, Val.byteSwap(), Call->getType()); + if (Val.getBitWidth() == 8) + pushInteger(S, Val, Call->getType()); + else + pushInteger(S, Val.byteSwap(), Call->getType()); return true; } @@ -3288,15 +3290,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, case Builtin::BI__builtin_elementwise_ctzg: return interp__builtin_elementwise_countzeroes(S, OpPC, Frame, Call, BuiltinID); - case Builtin::BI__builtin_bswapg: { - const APSInt &Val = popToAPSInt(S, Call->getArg(0)); - assert(Val.getActiveBits() <= 64); - if (Val.getBitWidth() == 8) - pushInteger(S, Val, Call->getType()); - else - pushInteger(S, Val.byteSwap(), Call->getType()); - return true; - } + case Builtin::BI__builtin_bswapg: case Builtin::BI__builtin_bswap16: case Builtin::BI__builtin_bswap32: case Builtin::BI__builtin_bswap64: diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 058905e7fd3c0..88c3a1cbcd833 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -13986,10 +13986,8 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, APSInt Val; if (!EvaluateInteger(E->getArg(0), Val, Info)) return false; - if (Val.getBitWidth() == 8) { - bool ret = Success(Val, E); - return ret; - } + if (Val.getBitWidth() == 8) + return Success(Val, E); return Success(Val.byteSwap(), E); } >From fa016a1bf3eb112754d24aac1823abe4e326509f Mon Sep 17 00:00:00 2001 From: clingfei <[email protected]> Date: Thu, 9 Oct 2025 22:54:57 +0800 Subject: [PATCH 3/4] add dependent check for argument --- clang/lib/Sema/SemaChecking.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 362b53676feaa..486fc8d083125 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -2211,6 +2211,8 @@ static bool BuiltinBswapg(Sema &S, CallExpr *TheCall) { Expr *Arg = ArgRes.get(); TheCall->setArg(0, Arg); + if (Arg->isTypeDependent()) + return false; QualType ArgTy = Arg->getType(); >From c0d0f3c179ff0dd0ccf3683cf075de492fbef12c Mon Sep 17 00:00:00 2001 From: clingfei <[email protected]> Date: Fri, 10 Oct 2025 10:56:22 +0800 Subject: [PATCH 4/4] fix bswapg codegen and add c++ tests --- clang/lib/AST/ExprConstant.cpp | 2 +- clang/lib/CodeGen/CGBuiltin.cpp | 10 ++- clang/lib/Sema/SemaChecking.cpp | 2 +- clang/test/CodeGen/builtins.c | 5 +- clang/test/Sema/builtin-bswapg.cpp | 121 +++++++++++++++++++++++++++++ 5 files changed, 136 insertions(+), 4 deletions(-) create mode 100644 clang/test/Sema/builtin-bswapg.cpp diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 88c3a1cbcd833..745e8d9201183 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -13988,7 +13988,7 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, return false; if (Val.getBitWidth() == 8) return Success(Val, E); - + return Success(Val.byteSwap(), E); } diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 7733f4dc15f5d..124351e7f1e59 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -3622,7 +3622,15 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, Builder.CreateArithmeticFence(ArgValue, ConvertType(ArgType))); return RValue::get(ArgValue); } - case Builtin::BI__builtin_bswapg: + case Builtin::BI__builtin_bswapg: { + Value *ArgValue = EmitScalarExpr(E->getArg(0)); + llvm::IntegerType *IntTy = cast<llvm::IntegerType>(ArgValue->getType()); + assert(IntTy && "LLVM's __builtin_bswapg only supports integer variants"); + if (IntTy->getBitWidth() == 8) + return RValue::get(ArgValue); + return RValue::get( + emitBuiltinWithOneOverloadedType<1>(*this, E, Intrinsic::bswap)); + } case Builtin::BI__builtin_bswap16: case Builtin::BI__builtin_bswap32: case Builtin::BI__builtin_bswap64: diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 486fc8d083125..80afa08f3f3af 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -3476,7 +3476,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, } case Builtin::BI__builtin_bswapg: if (BuiltinBswapg(*this, TheCall)) - return ExprError(); + return ExprError(); break; case Builtin::BI__builtin_popcountg: if (BuiltinPopcountg(*this, TheCall)) diff --git a/clang/test/CodeGen/builtins.c b/clang/test/CodeGen/builtins.c index 11d8302816c84..66ac8ad7431fb 100644 --- a/clang/test/CodeGen/builtins.c +++ b/clang/test/CodeGen/builtins.c @@ -130,7 +130,10 @@ int main(void) { P(object_size, (s0, 3)); // Whatever - P(bswapg, (N)); + P(bswapg, ((char)N)); + P(bswapg, ((short)N)); + P(bswapg, ((int)N)); + P(bswapg, ((unsigned long)N)); P(bswap16, (N)); P(bswap32, (N)); P(bswap64, (N)); diff --git a/clang/test/Sema/builtin-bswapg.cpp b/clang/test/Sema/builtin-bswapg.cpp new file mode 100644 index 0000000000000..c7fa6f2410023 --- /dev/null +++ b/clang/test/Sema/builtin-bswapg.cpp @@ -0,0 +1,121 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -verify -fexperimental-new-constant-interpreter %s +// expected-no-diagnostics +template <class A, class B> +static constexpr bool is_same_type = false; + +template <class A> +static constexpr bool is_same_type<A, A> = true; + +void test_basic_type_checks() { + static_assert(is_same_type<char, decltype(__builtin_bswapg((char)0))>, ""); + static_assert(is_same_type<unsigned char, decltype(__builtin_bswapg((unsigned char)0))>, ""); + static_assert(is_same_type<short, decltype(__builtin_bswapg((short)0))>, ""); + static_assert(is_same_type<unsigned short, decltype(__builtin_bswapg((unsigned short)0))>, ""); + static_assert(is_same_type<int, decltype(__builtin_bswapg((int)0))>, ""); + static_assert(is_same_type<unsigned int, decltype(__builtin_bswapg((unsigned int)0))>, ""); + static_assert(is_same_type<long, decltype(__builtin_bswapg((long)0))>, ""); + static_assert(is_same_type<unsigned long, decltype(__builtin_bswapg((unsigned long)0))>, ""); +} + +template<typename T> +void test_template_type_check() { + static_assert(is_same_type<T, decltype(__builtin_bswapg(T{}))>, + "bswapg should return the same type as its argument"); + constexpr T zero{}; + constexpr T max = ~T{}; + constexpr T one = T{1}; + + static_assert(is_same_type<T, decltype(__builtin_bswapg(zero))>, ""); + static_assert(is_same_type<T, decltype(__builtin_bswapg(max))>, ""); + static_assert(is_same_type<T, decltype(__builtin_bswapg(one))>, ""); +} +template void test_template_type_check<char>(); +template void test_template_type_check<unsigned char>(); +template void test_template_type_check<short>(); +template void test_template_type_check<unsigned short>(); +template void test_template_type_check<int>(); +template void test_template_type_check<unsigned int>(); +template void test_template_type_check<long>(); +template void test_template_type_check<unsigned long>(); + +void test_lambda_type_checks() { + auto lambda = [](auto x) { + static_assert(is_same_type<decltype(x), decltype(__builtin_bswapg(x))>, + "bswapg in lambda should preserve type"); + return __builtin_bswapg(x); + }; + auto result_long = lambda(42UL); + static_assert(is_same_type<unsigned long, decltype(result_long)>, ""); + + auto result_int = lambda(42); + static_assert(is_same_type<int, decltype(result_int)>, ""); + + auto result_short = lambda(static_cast<short>(42)); + static_assert(is_same_type<short, decltype(result_short)>, ""); + + auto result_char = lambda(static_cast<char>(42)); + static_assert(is_same_type<char, decltype(result_char)>, ""); +} + +auto test_auto_return_type_long(long x) { + auto result = __builtin_bswapg(x); + static_assert(is_same_type<long, decltype(result)>, ""); + return result; +} + +auto test_auto_return_type_int(int x) { + auto result = __builtin_bswapg(x); + static_assert(is_same_type<int, decltype(result)>, ""); + return result; +} + +auto test_auto_return_type_short(short x) { + auto result = __builtin_bswapg(x); + static_assert(is_same_type<short, decltype(result)>, ""); + return result; +} + +auto test_auto_return_type_char(char x) { + auto result = __builtin_bswapg(x); + static_assert(is_same_type<char, decltype(result)>, ""); + return result; +} + +void test_auto_return_type() { + test_auto_return_type_long(42); + test_auto_return_type_int(42); + test_auto_return_type_short(42); + test_auto_return_type_char(42); +} + +decltype(auto) test_decltype_auto(int x) { + return __builtin_bswapg(x); +} + +void test_decltype_auto_check() { + int x = 42; + auto result = test_decltype_auto(x); + static_assert(is_same_type<int, decltype(result)>, ""); +} + +template<auto Value> +struct ValueTemplateTypeTest { + using value_type = decltype(Value); + using result_type = decltype(__builtin_bswapg(Value)); + + static constexpr bool type_matches = is_same_type<value_type, result_type>; + static_assert(type_matches, "Value template bswapg should preserve type"); + + static constexpr auto swapped_value = __builtin_bswapg(Value); +}; + +template<auto... Values> +void test_template_pack_types() { + static_assert((is_same_type<decltype(Values), decltype(__builtin_bswapg(Values))> && ...), "All pack elements should preserve type"); +} + +template struct ValueTemplateTypeTest<0x1234>; +template struct ValueTemplateTypeTest<0x12345678UL>; +template struct ValueTemplateTypeTest<(short)0x1234>; +template struct ValueTemplateTypeTest<(char)0x12>; \ No newline at end of file _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
