From 92466f3789ce1849ebee8a405efd42e191c591f5 Mon Sep 17 00:00:00 2001 From: clingfei <1599101385@qq.com> Date: Wed, 8 Oct 2025 15:05:44 +0800 Subject: [PATCH 01/13] [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 <1599101385@qq.com> Date: Thu, 9 Oct 2025 13:14:08 +0800 Subject: [PATCH 02/13] 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 <1599101385@qq.com> Date: Thu, 9 Oct 2025 22:54:57 +0800 Subject: [PATCH 03/13] 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 <1599101385@qq.com> Date: Fri, 10 Oct 2025 10:56:22 +0800 Subject: [PATCH 04/13] 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(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 +static constexpr bool is_same_type = false; + +template +static constexpr bool is_same_type = true; + +void test_basic_type_checks() { + static_assert(is_same_type, ""); + static_assert(is_same_type, ""); + static_assert(is_same_type, ""); + static_assert(is_same_type, ""); + static_assert(is_same_type, ""); + static_assert(is_same_type, ""); + static_assert(is_same_type, ""); + static_assert(is_same_type, ""); +} + +template +void test_template_type_check() { + static_assert(is_same_type, + "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, ""); + static_assert(is_same_type, ""); + static_assert(is_same_type, ""); +} +template void test_template_type_check(); +template void test_template_type_check(); +template void test_template_type_check(); +template void test_template_type_check(); +template void test_template_type_check(); +template void test_template_type_check(); +template void test_template_type_check(); +template void test_template_type_check(); + +void test_lambda_type_checks() { + auto lambda = [](auto x) { + static_assert(is_same_type, + "bswapg in lambda should preserve type"); + return __builtin_bswapg(x); + }; + auto result_long = lambda(42UL); + static_assert(is_same_type, ""); + + auto result_int = lambda(42); + static_assert(is_same_type, ""); + + auto result_short = lambda(static_cast(42)); + static_assert(is_same_type, ""); + + auto result_char = lambda(static_cast(42)); + static_assert(is_same_type, ""); +} + +auto test_auto_return_type_long(long x) { + auto result = __builtin_bswapg(x); + static_assert(is_same_type, ""); + return result; +} + +auto test_auto_return_type_int(int x) { + auto result = __builtin_bswapg(x); + static_assert(is_same_type, ""); + return result; +} + +auto test_auto_return_type_short(short x) { + auto result = __builtin_bswapg(x); + static_assert(is_same_type, ""); + return result; +} + +auto test_auto_return_type_char(char x) { + auto result = __builtin_bswapg(x); + static_assert(is_same_type, ""); + 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, ""); +} + +template +struct ValueTemplateTypeTest { + using value_type = decltype(Value); + using result_type = decltype(__builtin_bswapg(Value)); + + static constexpr bool type_matches = is_same_type; + static_assert(type_matches, "Value template bswapg should preserve type"); + + static constexpr auto swapped_value = __builtin_bswapg(Value); +}; + +template +void test_template_pack_types() { + static_assert((is_same_type && ...), "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 From 1e9895c3aa7d648c5a7bdb78f6d3e3dd8bee4430 Mon Sep 17 00:00:00 2001 From: clingfei <1599101385@qq.com> Date: Fri, 10 Oct 2025 16:14:21 +0800 Subject: [PATCH 05/13] fix test for builtin-bswapg --- clang/test/CodeGen/builtins.c | 4 +- clang/test/Sema/builtin-bswapg.cpp | 121 -------------------------- clang/test/SemaCXX/builtin-bswapg.cpp | 85 ++++++++++++++++++ 3 files changed, 87 insertions(+), 123 deletions(-) delete mode 100644 clang/test/Sema/builtin-bswapg.cpp create mode 100644 clang/test/SemaCXX/builtin-bswapg.cpp diff --git a/clang/test/CodeGen/builtins.c b/clang/test/CodeGen/builtins.c index 66ac8ad7431fb..f9bbc26e1473f 100644 --- a/clang/test/CodeGen/builtins.c +++ b/clang/test/CodeGen/builtins.c @@ -132,8 +132,8 @@ int main(void) { // Whatever P(bswapg, ((char)N)); P(bswapg, ((short)N)); - P(bswapg, ((int)N)); - P(bswapg, ((unsigned long)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 deleted file mode 100644 index c7fa6f2410023..0000000000000 --- a/clang/test/Sema/builtin-bswapg.cpp +++ /dev/null @@ -1,121 +0,0 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s -// RUN: %clang_cc1 -fsyntax-only -verify -fexperimental-new-constant-interpreter %s -// expected-no-diagnostics -template -static constexpr bool is_same_type = false; - -template -static constexpr bool is_same_type = true; - -void test_basic_type_checks() { - static_assert(is_same_type, ""); - static_assert(is_same_type, ""); - static_assert(is_same_type, ""); - static_assert(is_same_type, ""); - static_assert(is_same_type, ""); - static_assert(is_same_type, ""); - static_assert(is_same_type, ""); - static_assert(is_same_type, ""); -} - -template -void test_template_type_check() { - static_assert(is_same_type, - "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, ""); - static_assert(is_same_type, ""); - static_assert(is_same_type, ""); -} -template void test_template_type_check(); -template void test_template_type_check(); -template void test_template_type_check(); -template void test_template_type_check(); -template void test_template_type_check(); -template void test_template_type_check(); -template void test_template_type_check(); -template void test_template_type_check(); - -void test_lambda_type_checks() { - auto lambda = [](auto x) { - static_assert(is_same_type, - "bswapg in lambda should preserve type"); - return __builtin_bswapg(x); - }; - auto result_long = lambda(42UL); - static_assert(is_same_type, ""); - - auto result_int = lambda(42); - static_assert(is_same_type, ""); - - auto result_short = lambda(static_cast(42)); - static_assert(is_same_type, ""); - - auto result_char = lambda(static_cast(42)); - static_assert(is_same_type, ""); -} - -auto test_auto_return_type_long(long x) { - auto result = __builtin_bswapg(x); - static_assert(is_same_type, ""); - return result; -} - -auto test_auto_return_type_int(int x) { - auto result = __builtin_bswapg(x); - static_assert(is_same_type, ""); - return result; -} - -auto test_auto_return_type_short(short x) { - auto result = __builtin_bswapg(x); - static_assert(is_same_type, ""); - return result; -} - -auto test_auto_return_type_char(char x) { - auto result = __builtin_bswapg(x); - static_assert(is_same_type, ""); - 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, ""); -} - -template -struct ValueTemplateTypeTest { - using value_type = decltype(Value); - using result_type = decltype(__builtin_bswapg(Value)); - - static constexpr bool type_matches = is_same_type; - static_assert(type_matches, "Value template bswapg should preserve type"); - - static constexpr auto swapped_value = __builtin_bswapg(Value); -}; - -template -void test_template_pack_types() { - static_assert((is_same_type && ...), "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 diff --git a/clang/test/SemaCXX/builtin-bswapg.cpp b/clang/test/SemaCXX/builtin-bswapg.cpp new file mode 100644 index 0000000000000..229c7fcac1522 --- /dev/null +++ b/clang/test/SemaCXX/builtin-bswapg.cpp @@ -0,0 +1,85 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -verify -fexperimental-new-constant-interpreter %s +// expected-no-diagnostics + +void test_basic_type_checks() { + static_assert(__is_same(char, decltype(__builtin_bswapg((char)0))), ""); + static_assert(__is_same(unsigned char, decltype(__builtin_bswapg((unsigned char)0))), ""); + static_assert(__is_same(short, decltype(__builtin_bswapg((short)0))), ""); + static_assert(__is_same(unsigned short, decltype(__builtin_bswapg((unsigned short)0))), ""); + static_assert(__is_same(int, decltype(__builtin_bswapg((int)0))), ""); + static_assert(__is_same(unsigned int, decltype(__builtin_bswapg((unsigned int)0))), ""); + static_assert(__is_same(long, decltype(__builtin_bswapg((long)0))), ""); + static_assert(__is_same(unsigned long, decltype(__builtin_bswapg((unsigned long)0))), ""); +} + +template +void test_template_type_check() { + static_assert(__is_same(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(T, decltype(__builtin_bswapg(zero))), ""); + static_assert(__is_same(T, decltype(__builtin_bswapg(max))), ""); + static_assert(__is_same(T, decltype(__builtin_bswapg(one))), ""); +} +template void test_template_type_check(); +template void test_template_type_check(); +template void test_template_type_check(); +template void test_template_type_check(); +template void test_template_type_check(); +template void test_template_type_check(); +template void test_template_type_check(); +template void test_template_type_check(); + +void test_lambda_type_checks() { + auto lambda = [](auto x) { + static_assert(__is_same(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(unsigned long, decltype(result_long)), ""); + + auto result_int = lambda(42); + static_assert(__is_same(int, decltype(result_int)), ""); + + auto result_short = lambda(static_cast(42)); + static_assert(__is_same(short, decltype(result_short)), ""); + + auto result_char = lambda(static_cast(42)); + static_assert(__is_same(char, decltype(result_char)), ""); +} + +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(int, decltype(result)), ""); +} + +template +struct ValueTemplateTypeTest { + using value_type = decltype(Value); + using result_type = decltype(__builtin_bswapg(Value)); + + static constexpr bool type_matches = __is_same(value_type, result_type); + static_assert(type_matches, "Value template bswapg should preserve type"); + + static constexpr auto swapped_value = __builtin_bswapg(Value); +}; + +template +void test_template_pack_types() { + static_assert((__is_same(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>; From bca24f27114267572db5640ef7fced407ebde443 Mon Sep 17 00:00:00 2001 From: clingfei <1599101385@qq.com> Date: Sun, 12 Oct 2025 18:04:41 +0800 Subject: [PATCH 06/13] add failure tests and reference tests, and adjust checks according to conversation --- clang/lib/AST/ExprConstant.cpp | 13 +--- clang/lib/CodeGen/CGBuiltin.cpp | 2 + clang/lib/Sema/SemaChecking.cpp | 2 +- clang/test/AST/ByteCode/builtin-functions.cpp | 19 +++++ clang/test/CodeGenCXX/builtins.cpp | 37 +++++++++ clang/test/Sema/constant-builtins-2.c | 4 + clang/test/SemaCXX/builtin-bswapg.cpp | 77 ++++++++++++++++++- 7 files changed, 142 insertions(+), 12 deletions(-) diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 745e8d9201183..f4490fcc8ac66 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -13982,22 +13982,15 @@ 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) - return Success(Val, E); - - return Success(Val.byteSwap(), E); - } - + case Builtin::BI__builtin_bswapg: case Builtin::BI__builtin_bswap16: case Builtin::BI__builtin_bswap32: case Builtin::BI__builtin_bswap64: { APSInt Val; if (!EvaluateInteger(E->getArg(0), Val, Info)) 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 124351e7f1e59..cc76024f335db 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -3626,6 +3626,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, Value *ArgValue = EmitScalarExpr(E->getArg(0)); llvm::IntegerType *IntTy = cast(ArgValue->getType()); assert(IntTy && "LLVM's __builtin_bswapg only supports integer variants"); + assert(((IntTy->getBitWidth() % 16 == 0 && IntTy->getBitWidth() != 0) || IntTy->getBitWidth() == 8) && + "LLVM's __builtin_bswapg only supports integer variants that has a multiple of 16 bits as well as a single byte"); if (IntTy->getBitWidth() == 8) return RValue::get(ArgValue); return RValue::get( diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 80afa08f3f3af..6c9ec326f1fde 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -2218,7 +2218,7 @@ static bool BuiltinBswapg(Sema &S, CallExpr *TheCall) { if (!ArgTy->isIntegerType()) { S.Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type) - << 1 << /* scalar */ 1 << /* unsigned integer ty */ 1 << /* no fp */ 0 + << 1 << /*scalar=*/ 1 << /*unsigned integer=*/ 1 << /*floating point=*/ 0 << ArgTy; return true; } diff --git a/clang/test/AST/ByteCode/builtin-functions.cpp b/clang/test/AST/ByteCode/builtin-functions.cpp index 84ff9cc137bf3..9248f835832f3 100644 --- a/clang/test/AST/ByteCode/builtin-functions.cpp +++ b/clang/test/AST/ByteCode/builtin-functions.cpp @@ -828,6 +828,25 @@ namespace bswap { int h7 = __builtin_bswapg(0x1234) == 0x3412 ? 1 : f(); int h8 = __builtin_bswapg(0x00001234) == 0x34120000 ? 1 : f(); int h9 = __builtin_bswapg(0x0000000000001234) == 0x3412000000000000 ? 1 : f(); + + constexpr const int const_expr = 0x1234; + + void test_constexpr_reference() { + const int expr = 0x1234; + const int& ref = expr; // #declare + + constexpr const int& const_ref = const_expr; + + constexpr auto result2 = __builtin_bswapg(ref); + //expected-error@-1 {{constexpr variable 'result2' must be initialized by a constant expression}} + //expected-note@-2 {{initializer of 'ref' is not a constant expression}} + //expected-note@#declare {{declared here}} + //ref-error@-4 {{constexpr variable 'result2' must be initialized by a constant expression}} + //ref-note@-5 {{initializer of 'ref' is not a constant expression}} + //ref-note@#declare {{declared here}} + + constexpr auto result3 = __builtin_bswapg(const_ref); + } } #define CFSTR __builtin___CFStringMakeConstantString diff --git a/clang/test/CodeGenCXX/builtins.cpp b/clang/test/CodeGenCXX/builtins.cpp index 9169f3a3276d3..165f5cdb7cd48 100644 --- a/clang/test/CodeGenCXX/builtins.cpp +++ b/clang/test/CodeGenCXX/builtins.cpp @@ -83,3 +83,40 @@ int structured_binding_size() { return __builtin_structured_binding_size(S2); // CHECK: ret i32 2 } + +void test_int_reference(int& a) { + __builtin_bswapg(a); +} +// CHECK-LABEL: @_Z18test_int_referenceRi +// CHECK: store ptr %a, ptr +// CHECK: load ptr, ptr +// CHECK: load i32, ptr +// CHECK: call i32 @llvm.bswap.i32 + +void test_long_reference(long& a) { + __builtin_bswapg(a); +} +// CHECK-LABEL: @_Z19test_long_referenceRl +// CHECK: store ptr %a, ptr +// CHECK: load ptr, ptr +// CHECK: load i64, ptr +// CHECK: call i64 @llvm.bswap.i64 + +// 2. 不同大小的引用测试 +void test_short_reference(short& a) { + __builtin_bswapg(a); +} +// CHECK-LABEL: @_Z20test_short_referenceRs +// CHECK: store ptr %a, ptr +// CHECK: load ptr, ptr +// CHECK: load i16, ptr +// CHECK: call i16 @llvm.bswap.i16 + +void test_char_reference(char& a) { + __builtin_bswapg(a); +} +// CHECK-LABEL: @_Z19test_char_referenceRc +// CHECK: store ptr %a, ptr +// CHECK: load ptr, ptr +// CHECK-NOT: call i8 @llvm.bswap.i8 +// CHECK: ret void diff --git a/clang/test/Sema/constant-builtins-2.c b/clang/test/Sema/constant-builtins-2.c index 96bd2c966c2ef..ff15715a0c41c 100644 --- a/clang/test/Sema/constant-builtins-2.c +++ b/clang/test/Sema/constant-builtins-2.c @@ -483,6 +483,10 @@ 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(); +float h10 = __builtin_bswapg(1.0f); // expected-error {{1st argument must be a scalar integer type (was 'float')}} +double h12 = __builtin_bswapg(1.0L); // expected-error {{1st argument must be a scalar integer type (was 'long double')}} +char *h13 = __builtin_bswapg("hello"); // expected-error {{1st argument must be a scalar integer type (was 'char[6]')}} +int h14 = __builtin_bswapg(1, 2); // expected-error {{too many arguments to function call, expected 1, have 2}} extern long int bi0; extern __typeof__(__builtin_expect(0, 0)) bi0; diff --git a/clang/test/SemaCXX/builtin-bswapg.cpp b/clang/test/SemaCXX/builtin-bswapg.cpp index 229c7fcac1522..1e7f2790e60cc 100644 --- a/clang/test/SemaCXX/builtin-bswapg.cpp +++ b/clang/test/SemaCXX/builtin-bswapg.cpp @@ -1,6 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s // RUN: %clang_cc1 -fsyntax-only -verify -fexperimental-new-constant-interpreter %s -// expected-no-diagnostics void test_basic_type_checks() { static_assert(__is_same(char, decltype(__builtin_bswapg((char)0))), ""); @@ -83,3 +82,79 @@ template struct ValueTemplateTypeTest<0x1234>; template struct ValueTemplateTypeTest<0x12345678UL>; template struct ValueTemplateTypeTest<(short)0x1234>; template struct ValueTemplateTypeTest<(char)0x12>; + +template +void test_invalid_type() { + __builtin_bswapg(T{}); // #invalid_type_use +} + +void test_basic_errors() { + test_invalid_type(); + // expected-note@-1 {{in instantiation of function template specialization 'test_invalid_type' requested here}} + // expected-error@#invalid_type_use {{1st argument must be a scalar integer type (was 'float')}} + + test_invalid_type(); + // expected-note@-1 {{in instantiation of function template specialization 'test_invalid_type' requested here}} + // expected-error@#invalid_type_use {{1st argument must be a scalar integer type (was 'double')}} + + test_invalid_type(); + // expected-note@-1 {{in instantiation of function template specialization 'test_invalid_type' requested here}} + // expected-error@#invalid_type_use {{1st argument must be a scalar integer type (was 'void *')}} +} + +template +auto test_dependent_context(T value) -> decltype(__builtin_bswapg(value)) { // #dependent_use + return __builtin_bswapg(value); +} + +void test_dependent_errors() { + test_dependent_context(1.0f); + // expected-error@-1 {{no matching function for call to 'test_dependent_context'}} + // expected-note@#dependent_use {{candidate template ignored: substitution failure [with T = float]: 1st argument must be a scalar integer type (was 'float')}} + test_dependent_context(1.0l); + // expected-error@-1 {{no matching function for call to 'test_dependent_context'}} + // expected-note@#dependent_use {{candidate template ignored: substitution failure [with T = long double]: 1st argument must be a scalar integer type (was 'long double')}} + test_dependent_context("hello"); + // expected-error@-1 {{no matching function for call to 'test_dependent_context'}} + // expected-note@#dependent_use {{candidate template ignored: substitution failure [with T = const char *]: 1st argument must be a scalar integer type (was 'const char *')}} +} + +void test_lambda_errors() { + auto lambda = [](auto x) { + return __builtin_bswapg(x); // #lambda_use + }; + + lambda(1.0f); + // expected-error@#lambda_use {{1st argument must be a scalar integer type (was 'float')}} + // expected-note@-2 {{in instantiation of function template specialization 'test_lambda_errors()::(anonymous class)::operator()' requested here}} + lambda(1.0l); + // expected-error@#lambda_use {{1st argument must be a scalar integer type (was 'long double')}} + // expected-note@-2 {{in instantiation of function template specialization 'test_lambda_errors()::(anonymous class)::operator()' requested here}} + lambda("hello"); + // expected-error@#lambda_use {{1st argument must be a scalar integer type (was 'const char *')}} + // expected-note@-2 {{in instantiation of function template specialization 'test_lambda_errors()::(anonymous class)::operator()' requested here}} +} + +void test_argument_count_errors() { + int h14 = __builtin_bswapg(1, 2); // expected-error {{too many arguments to function call, expected 1, have 2}} +} + +void test_lvalue_reference(int& a) { + auto result = __builtin_bswapg(a); + static_assert(__is_same(int, decltype(result)), "Should decay reference to value type"); +} + +void test_const_lvalue_reference(const int& a) { + auto result = __builtin_bswapg(a); + static_assert(__is_same(int, decltype(result)), "Should decay const reference to value type"); +} + +void test_rvalue_reference(int&& a) { + auto result = __builtin_bswapg(a); + static_assert(__is_same(int, decltype(result)), "Should decay rvalue reference to value type"); +} + +void test_const_rvalue_reference(const int&& a) { + auto result = __builtin_bswapg(a); + static_assert(__is_same(int, decltype(result)), "Should decay const rvalue reference to value type"); +} From ba83b56d21c3f74c0fa6a764b70915f8c0d7904c Mon Sep 17 00:00:00 2001 From: clingfei <1599101385@qq.com> Date: Wed, 15 Oct 2025 14:54:50 +0800 Subject: [PATCH 07/13] add tests for arrays, pointers, enums, class, nullptr_t --- clang/test/Sema/constant-builtins-2.c | 7 ++++ clang/test/SemaCXX/builtin-bswapg.cpp | 58 +++++++++++++++++++++++---- 2 files changed, 57 insertions(+), 8 deletions(-) diff --git a/clang/test/Sema/constant-builtins-2.c b/clang/test/Sema/constant-builtins-2.c index ff15715a0c41c..a7d92fe96bc06 100644 --- a/clang/test/Sema/constant-builtins-2.c +++ b/clang/test/Sema/constant-builtins-2.c @@ -487,6 +487,13 @@ float h10 = __builtin_bswapg(1.0f); // expected-error {{1st argument must be a s double h12 = __builtin_bswapg(1.0L); // expected-error {{1st argument must be a scalar integer type (was 'long double')}} char *h13 = __builtin_bswapg("hello"); // expected-error {{1st argument must be a scalar integer type (was 'char[6]')}} int h14 = __builtin_bswapg(1, 2); // expected-error {{too many arguments to function call, expected 1, have 2}} +int *h15 = __builtin_bswapg(&h9); // expected-error {{1st argument must be a scalar integer type (was 'int *')}} +int arr[4] = {0x12, 0x34, 0x56, 0x78}; +int h16 = __builtin_bswapg(arr); // expected-error {{1st argument must be a scalar integer type (was 'int[4]')}} +enum BasicEnum { + ENUM_VALUE1 = 0x1234, +}; +int h17 = __builtin_bswapg(ENUM_VALUE1) == 0x34120000 ? 1 : f(); extern long int bi0; extern __typeof__(__builtin_expect(0, 0)) bi0; diff --git a/clang/test/SemaCXX/builtin-bswapg.cpp b/clang/test/SemaCXX/builtin-bswapg.cpp index 1e7f2790e60cc..26bc5b54fae78 100644 --- a/clang/test/SemaCXX/builtin-bswapg.cpp +++ b/clang/test/SemaCXX/builtin-bswapg.cpp @@ -140,21 +140,63 @@ void test_argument_count_errors() { } void test_lvalue_reference(int& a) { - auto result = __builtin_bswapg(a); - static_assert(__is_same(int, decltype(result)), "Should decay reference to value type"); + auto result = __builtin_bswapg(a); + static_assert(__is_same(int, decltype(result)), "Should decay reference to value type"); } void test_const_lvalue_reference(const int& a) { - auto result = __builtin_bswapg(a); - static_assert(__is_same(int, decltype(result)), "Should decay const reference to value type"); + auto result = __builtin_bswapg(a); + static_assert(__is_same(int, decltype(result)), "Should decay const reference to value type"); } void test_rvalue_reference(int&& a) { - auto result = __builtin_bswapg(a); - static_assert(__is_same(int, decltype(result)), "Should decay rvalue reference to value type"); + auto result = __builtin_bswapg(a); + static_assert(__is_same(int, decltype(result)), "Should decay rvalue reference to value type"); } void test_const_rvalue_reference(const int&& a) { - auto result = __builtin_bswapg(a); - static_assert(__is_same(int, decltype(result)), "Should decay const rvalue reference to value type"); + auto result = __builtin_bswapg(a); + static_assert(__is_same(int, decltype(result)), "Should decay const rvalue reference to value type"); +} + +void test_array() { + int arr[4] = {0x12, 0x34, 0x56, 0x78}; + __builtin_bswapg(arr); + // expected-error@-1 {{1st argument must be a scalar integer type (was 'int[4]')}} +} + +void test_pointer() { + int x = 0x12345678; + int *ptr = &x; + __builtin_bswapg(ptr); + // expected-error@-1 {{1st argument must be a scalar integer type (was 'int *')}} +} + +enum BasicEnum { + ENUM_VALUE1 = 0x1234, + ENUM_VALUE2 = 0x34120000 +}; + +void test_enum() { + const BasicEnum e = ENUM_VALUE1; + static_assert(__builtin_bswapg(e) == ENUM_VALUE2, ""); +} + +class testClass { +public: + int value; + testClass(int v) : value(v) {} + + int getValue() { return value; } +}; + +void test_class() { + testClass c((int)0x12345678); + __builtin_bswapg(c); + // expected-error@-1 {{1st argument must be a scalar integer type (was 'testClass')}} +} + +void test_nullptr() { + __builtin_bswapg(nullptr); + // expected-error@-1 {{1st argument must be a scalar integer type (was 'std::nullptr_t')}} } From a2a619182ac99f6e986b74d24632f4fc1e09f45e Mon Sep 17 00:00:00 2001 From: clingfei <1599101385@qq.com> Date: Wed, 15 Oct 2025 15:18:29 +0800 Subject: [PATCH 08/13] add release notes --- clang/docs/ReleaseNotes.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 5e9a71e1e74d6..fe158a0a6ff03 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -257,6 +257,9 @@ Non-comprehensive list of changes in this release - Fixed a crash when the second argument to ``__builtin_assume_aligned`` was not constant (#GH161314) +- A new generic byte swap builtin function ``__builtin_bswapg`` that extends the existing + __builtin_bswap{16,32,64} function family to support all standard integer types. + New Compiler Flags ------------------ - New option ``-fno-sanitize-debug-trap-reasons`` added to disable emitting trap reasons into the debug info when compiling with trapping UBSan (e.g. ``-fsanitize-trap=undefined``). From 6afe3340410eb76e1458f106d009e78b531e1f95 Mon Sep 17 00:00:00 2001 From: clingfei <1599101385@qq.com> Date: Sat, 18 Oct 2025 16:31:01 +0800 Subject: [PATCH 09/13] add support and test cases for _BitInt --- .../clang/Basic/DiagnosticSemaKinds.td | 3 ++ clang/lib/CodeGen/CGBuiltin.cpp | 6 ++-- clang/lib/Sema/SemaChecking.cpp | 8 +++++ clang/test/AST/ByteCode/builtin-functions.cpp | 10 ++++++ clang/test/CodeGen/builtins.c | 32 +++++++++++++++++++ clang/test/CodeGenCXX/builtins.cpp | 29 ++++++++++++++--- clang/test/Sema/constant-builtins-2.c | 7 ++++ clang/test/SemaCXX/builtin-bswapg.cpp | 10 ++++++ 8 files changed, 98 insertions(+), 7 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 40bc7b9a4e45e..20d340e8dc159 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -12948,6 +12948,9 @@ def err_builtin_invalid_arg_type: Error< "%plural{0:|: }3" "%plural{[0,3]:type|:types}1 (was %4)">; +def err_bswapg_bitint_not_16bit_aligned : Error< + "_BitInt type %0 (%1 bits) must be a multiple of 16 bits for byte swapping">; + 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/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index cc76024f335db..5f9807d8409a4 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -3626,8 +3626,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, Value *ArgValue = EmitScalarExpr(E->getArg(0)); llvm::IntegerType *IntTy = cast(ArgValue->getType()); assert(IntTy && "LLVM's __builtin_bswapg only supports integer variants"); - assert(((IntTy->getBitWidth() % 16 == 0 && IntTy->getBitWidth() != 0) || IntTy->getBitWidth() == 8) && - "LLVM's __builtin_bswapg only supports integer variants that has a multiple of 16 bits as well as a single byte"); + assert(((IntTy->getBitWidth() % 16 == 0 && IntTy->getBitWidth() != 0) || + IntTy->getBitWidth() == 8) && + "LLVM's __builtin_bswapg only supports integer variants that has a " + "multiple of 16 bits as well as a single byte"); if (IntTy->getBitWidth() == 8) return RValue::get(ArgValue); return RValue::get( diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 6c9ec326f1fde..244640e6a5a99 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -2222,6 +2222,14 @@ static bool BuiltinBswapg(Sema &S, CallExpr *TheCall) { << ArgTy; return true; } + const auto *bitIntType = dyn_cast(ArgTy); + if (bitIntType != nullptr) { + if (bitIntType->getNumBits() % 16 != 0 && bitIntType->getNumBits() != 8) { + S.Diag(Arg->getBeginLoc(), diag::err_bswapg_bitint_not_16bit_aligned) + << ArgTy << bitIntType->getNumBits(); + return true; + } + } TheCall->setType(ArgTy); return false; } diff --git a/clang/test/AST/ByteCode/builtin-functions.cpp b/clang/test/AST/ByteCode/builtin-functions.cpp index 9248f835832f3..4e061afff0941 100644 --- a/clang/test/AST/ByteCode/builtin-functions.cpp +++ b/clang/test/AST/ByteCode/builtin-functions.cpp @@ -828,6 +828,16 @@ namespace bswap { int h7 = __builtin_bswapg(0x1234) == 0x3412 ? 1 : f(); int h8 = __builtin_bswapg(0x00001234) == 0x34120000 ? 1 : f(); int h9 = __builtin_bswapg(0x0000000000001234) == 0x3412000000000000 ? 1 : f(); +#ifndef __AVR__ + int h10 = __builtin_bswapg((_BitInt(8))0x12) == (_BitInt(8))0x12 ? 1 : f(); + int h11 = __builtin_bswapg((_BitInt(16))0x1234) == (_BitInt(16))0x3412 ? 1 : f(); + int h12 = __builtin_bswapg((_BitInt(32))0x00001234) == (_BitInt(32))0x34120000 ? 1 : f(); + int h13 = __builtin_bswapg((_BitInt(64))0x0000000000001234) == (_BitInt(64))0x3412000000000000 ? 1 : f(); + int h14 = __builtin_bswapg(~(_BitInt(128))0) == (~(_BitInt(128))0) ? 1 : f(); + int h15 = __builtin_bswapg((_BitInt(24))0x1234) == (_BitInt(24))0x3412 ? 1 : f(); + // expected-error@-1 {{_BitInt type '_BitInt(24)' (24 bits) must be a multiple of 16 bits for byte swapping}} + // ref-error@-2 {{_BitInt type '_BitInt(24)' (24 bits) must be a multiple of 16 bits for byte swapping}} +#endif constexpr const int const_expr = 0x1234; diff --git a/clang/test/CodeGen/builtins.c b/clang/test/CodeGen/builtins.c index f9bbc26e1473f..e6d636d5f4a95 100644 --- a/clang/test/CodeGen/builtins.c +++ b/clang/test/CodeGen/builtins.c @@ -1280,3 +1280,35 @@ void test_builtin_ctzg(unsigned char uc, unsigned short us, unsigned int ui, } #endif + +// CHECK-LABEL: define{{.*}} void @test_builtin_bswapg +void test_builtin_bswapg(unsigned char uc, unsigned short us, unsigned int ui, + unsigned long ul, unsigned long long ull, + unsigned __int128 ui128, _BitInt(8) bi8, + _BitInt(16) bi16, _BitInt(32) bi32, + _BitInt(64) bi64, _BitInt(128) bi128) { + uc = __builtin_bswapg(uc); + // CHECK: %1 = load i8, ptr %uc.addr + // CHECK: store i8 %1, ptr %uc.addr + us = __builtin_bswapg(us); + // CHECK: call i16 @llvm.bswap.i16 + ui = __builtin_bswapg(ui); + // CHECK: call i32 @llvm.bswap.i32 + ul = __builtin_bswapg(ul); + // CHECK: call i64 @llvm.bswap.i64 + ull = __builtin_bswapg(ull); + // CHECK: call i64 @llvm.bswap.i64 + ui128 = __builtin_bswapg(ui128); + // CHECK: call i128 @llvm.bswap.i128 + bi8 = __builtin_bswapg(bi8); + // CHECK: %17 = load i8, ptr %bi8.addr, align 1 + // CHECK: store i8 %17, ptr %bi8.addr + bi16 = __builtin_bswapg(bi16); + // CHECK: call i16 @llvm.bswap.i16 + bi32 = __builtin_bswapg(bi32); + // CHECK: call i32 @llvm.bswap.i32 + bi64 = __builtin_bswapg(bi64); + // CHECK: call i64 @llvm.bswap.i64 + bi128 = __builtin_bswapg(bi128); + // CHECK: call i128 @llvm.bswap.i128 +} diff --git a/clang/test/CodeGenCXX/builtins.cpp b/clang/test/CodeGenCXX/builtins.cpp index 165f5cdb7cd48..ef30a25a17922 100644 --- a/clang/test/CodeGenCXX/builtins.cpp +++ b/clang/test/CodeGenCXX/builtins.cpp @@ -85,7 +85,7 @@ int structured_binding_size() { } void test_int_reference(int& a) { - __builtin_bswapg(a); + __builtin_bswapg(a); } // CHECK-LABEL: @_Z18test_int_referenceRi // CHECK: store ptr %a, ptr @@ -94,7 +94,7 @@ void test_int_reference(int& a) { // CHECK: call i32 @llvm.bswap.i32 void test_long_reference(long& a) { - __builtin_bswapg(a); + __builtin_bswapg(a); } // CHECK-LABEL: @_Z19test_long_referenceRl // CHECK: store ptr %a, ptr @@ -102,9 +102,8 @@ void test_long_reference(long& a) { // CHECK: load i64, ptr // CHECK: call i64 @llvm.bswap.i64 -// 2. 不同大小的引用测试 void test_short_reference(short& a) { - __builtin_bswapg(a); + __builtin_bswapg(a); } // CHECK-LABEL: @_Z20test_short_referenceRs // CHECK: store ptr %a, ptr @@ -113,10 +112,30 @@ void test_short_reference(short& a) { // CHECK: call i16 @llvm.bswap.i16 void test_char_reference(char& a) { - __builtin_bswapg(a); + __builtin_bswapg(a); } // CHECK-LABEL: @_Z19test_char_referenceRc // CHECK: store ptr %a, ptr // CHECK: load ptr, ptr // CHECK-NOT: call i8 @llvm.bswap.i8 // CHECK: ret void + +void test_bitint() { + _BitInt(8) a = 0x12; + __builtin_bswapg(a); + _BitInt(16) b = 0x1234; + __builtin_bswapg(b); + _BitInt(32) c = 0x00001234; + __builtin_bswapg(c); + _BitInt(64) d = 0x0000000000001234; + __builtin_bswapg(d); + _BitInt(128) e = ~(_BitInt(128))0; + __builtin_bswapg(e); +} +// CHECK-LABEL: @_Z11test_bitintv +// CHECK-NOT: call i8 @llvm.bswap.i8 +// CHECK: call i16 @llvm.bswap.i16 +// CHECK: call i32 @llvm.bswap.i32 +// CHECK: call i64 @llvm.bswap.i64 +// CHECK: call i128 @llvm.bswap.i128 +// CHECK: ret void diff --git a/clang/test/Sema/constant-builtins-2.c b/clang/test/Sema/constant-builtins-2.c index a7d92fe96bc06..9579052b1f76b 100644 --- a/clang/test/Sema/constant-builtins-2.c +++ b/clang/test/Sema/constant-builtins-2.c @@ -494,6 +494,13 @@ enum BasicEnum { ENUM_VALUE1 = 0x1234, }; int h17 = __builtin_bswapg(ENUM_VALUE1) == 0x34120000 ? 1 : f(); +int h18 = __builtin_bswapg((_BitInt(8))0x12) == (_BitInt(8))0x12 ? 1 : f(); +int h19 = __builtin_bswapg((_BitInt(16))0x1234) == (_BitInt(16))0x3412 ? 1 : f(); +int h20 = __builtin_bswapg((_BitInt(32))0x00001234) == (_BitInt(32))0x34120000 ? 1 : f(); +int h21 = __builtin_bswapg((_BitInt(64))0x0000000000001234) == (_BitInt(64))0x3412000000000000 ? 1 : f(); +int h22 = __builtin_bswapg(~(_BitInt(128))0) == (~(_BitInt(128))0) ? 1 : f(); +int h23 = __builtin_bswapg((_BitInt(24))0x1234) == (_BitInt(24))0x3412 ? 1 : f(); +// expected-error@-1 {{_BitInt type '_BitInt(24)' (24 bits) must be a multiple of 16 bits for byte swapping}} extern long int bi0; extern __typeof__(__builtin_expect(0, 0)) bi0; diff --git a/clang/test/SemaCXX/builtin-bswapg.cpp b/clang/test/SemaCXX/builtin-bswapg.cpp index 26bc5b54fae78..7b4d769df9ba7 100644 --- a/clang/test/SemaCXX/builtin-bswapg.cpp +++ b/clang/test/SemaCXX/builtin-bswapg.cpp @@ -200,3 +200,13 @@ void test_nullptr() { __builtin_bswapg(nullptr); // expected-error@-1 {{1st argument must be a scalar integer type (was 'std::nullptr_t')}} } + +void test_bitint() { + static_assert(__builtin_bswapg((_BitInt(8))0x12) == (_BitInt(8))0x12, ""); + static_assert(__builtin_bswapg((_BitInt(16))0x1234) == (_BitInt(16))0x3412, ""); + static_assert(__builtin_bswapg((_BitInt(32))0x00001234) == (_BitInt(32))0x34120000, ""); + static_assert(__builtin_bswapg((_BitInt(64))0x0000000000001234) == (_BitInt(64))0x3412000000000000, ""); + static_assert(__builtin_bswapg(~(_BitInt(128))0) == (~(_BitInt(128))0), ""); + static_assert(__builtin_bswapg((_BitInt(24))0x1234) == (_BitInt(24))0x3412, ""); + // expected-error@-1 {{_BitInt type '_BitInt(24)' (24 bits) must be a multiple of 16 bits for byte swapping}} +} From ed8c33a07dadfd28c0821187661a022d151c7ae9 Mon Sep 17 00:00:00 2001 From: clingfei <1599101385@qq.com> Date: Sat, 18 Oct 2025 16:38:29 +0800 Subject: [PATCH 10/13] remove extra spaces --- clang/test/AST/ByteCode/builtin-functions.cpp | 12 ++--- clang/test/CodeGen/builtins.c | 50 +++++++++---------- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/clang/test/AST/ByteCode/builtin-functions.cpp b/clang/test/AST/ByteCode/builtin-functions.cpp index 4e061afff0941..92bc04be0767d 100644 --- a/clang/test/AST/ByteCode/builtin-functions.cpp +++ b/clang/test/AST/ByteCode/builtin-functions.cpp @@ -831,12 +831,12 @@ namespace bswap { #ifndef __AVR__ int h10 = __builtin_bswapg((_BitInt(8))0x12) == (_BitInt(8))0x12 ? 1 : f(); int h11 = __builtin_bswapg((_BitInt(16))0x1234) == (_BitInt(16))0x3412 ? 1 : f(); - int h12 = __builtin_bswapg((_BitInt(32))0x00001234) == (_BitInt(32))0x34120000 ? 1 : f(); - int h13 = __builtin_bswapg((_BitInt(64))0x0000000000001234) == (_BitInt(64))0x3412000000000000 ? 1 : f(); - int h14 = __builtin_bswapg(~(_BitInt(128))0) == (~(_BitInt(128))0) ? 1 : f(); - int h15 = __builtin_bswapg((_BitInt(24))0x1234) == (_BitInt(24))0x3412 ? 1 : f(); - // expected-error@-1 {{_BitInt type '_BitInt(24)' (24 bits) must be a multiple of 16 bits for byte swapping}} - // ref-error@-2 {{_BitInt type '_BitInt(24)' (24 bits) must be a multiple of 16 bits for byte swapping}} + int h12 = __builtin_bswapg((_BitInt(32))0x00001234) == (_BitInt(32))0x34120000 ? 1 : f(); + int h13 = __builtin_bswapg((_BitInt(64))0x0000000000001234) == (_BitInt(64))0x3412000000000000 ? 1 : f(); + int h14 = __builtin_bswapg(~(_BitInt(128))0) == (~(_BitInt(128))0) ? 1 : f(); + int h15 = __builtin_bswapg((_BitInt(24))0x1234) == (_BitInt(24))0x3412 ? 1 : f(); + // expected-error@-1 {{_BitInt type '_BitInt(24)' (24 bits) must be a multiple of 16 bits for byte swapping}} + // ref-error@-2 {{_BitInt type '_BitInt(24)' (24 bits) must be a multiple of 16 bits for byte swapping}} #endif constexpr const int const_expr = 0x1234; diff --git a/clang/test/CodeGen/builtins.c b/clang/test/CodeGen/builtins.c index e6d636d5f4a95..b3d40992fc975 100644 --- a/clang/test/CodeGen/builtins.c +++ b/clang/test/CodeGen/builtins.c @@ -1285,30 +1285,30 @@ void test_builtin_ctzg(unsigned char uc, unsigned short us, unsigned int ui, void test_builtin_bswapg(unsigned char uc, unsigned short us, unsigned int ui, unsigned long ul, unsigned long long ull, unsigned __int128 ui128, _BitInt(8) bi8, - _BitInt(16) bi16, _BitInt(32) bi32, - _BitInt(64) bi64, _BitInt(128) bi128) { - uc = __builtin_bswapg(uc); - // CHECK: %1 = load i8, ptr %uc.addr - // CHECK: store i8 %1, ptr %uc.addr - us = __builtin_bswapg(us); - // CHECK: call i16 @llvm.bswap.i16 - ui = __builtin_bswapg(ui); - // CHECK: call i32 @llvm.bswap.i32 - ul = __builtin_bswapg(ul); - // CHECK: call i64 @llvm.bswap.i64 - ull = __builtin_bswapg(ull); - // CHECK: call i64 @llvm.bswap.i64 - ui128 = __builtin_bswapg(ui128); - // CHECK: call i128 @llvm.bswap.i128 - bi8 = __builtin_bswapg(bi8); - // CHECK: %17 = load i8, ptr %bi8.addr, align 1 + _BitInt(16) bi16, _BitInt(32) bi32, + _BitInt(64) bi64, _BitInt(128) bi128) { + uc = __builtin_bswapg(uc); + // CHECK: %1 = load i8, ptr %uc.addr + // CHECK: store i8 %1, ptr %uc.addr + us = __builtin_bswapg(us); + // CHECK: call i16 @llvm.bswap.i16 + ui = __builtin_bswapg(ui); + // CHECK: call i32 @llvm.bswap.i32 + ul = __builtin_bswapg(ul); + // CHECK: call i64 @llvm.bswap.i64 + ull = __builtin_bswapg(ull); + // CHECK: call i64 @llvm.bswap.i64 + ui128 = __builtin_bswapg(ui128); + // CHECK: call i128 @llvm.bswap.i128 + bi8 = __builtin_bswapg(bi8); + // CHECK: %17 = load i8, ptr %bi8.addr, align 1 // CHECK: store i8 %17, ptr %bi8.addr - bi16 = __builtin_bswapg(bi16); - // CHECK: call i16 @llvm.bswap.i16 - bi32 = __builtin_bswapg(bi32); - // CHECK: call i32 @llvm.bswap.i32 - bi64 = __builtin_bswapg(bi64); - // CHECK: call i64 @llvm.bswap.i64 - bi128 = __builtin_bswapg(bi128); - // CHECK: call i128 @llvm.bswap.i128 + bi16 = __builtin_bswapg(bi16); + // CHECK: call i16 @llvm.bswap.i16 + bi32 = __builtin_bswapg(bi32); + // CHECK: call i32 @llvm.bswap.i32 + bi64 = __builtin_bswapg(bi64); + // CHECK: call i64 @llvm.bswap.i64 + bi128 = __builtin_bswapg(bi128); + // CHECK: call i128 @llvm.bswap.i128 } From 63336688b08767d44402fca453aba8105bebd343 Mon Sep 17 00:00:00 2001 From: clingfei <1599101385@qq.com> Date: Sun, 19 Oct 2025 14:02:56 +0800 Subject: [PATCH 11/13] add more test cases for _BitInt --- clang/test/SemaCXX/builtin-bswapg.cpp | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/clang/test/SemaCXX/builtin-bswapg.cpp b/clang/test/SemaCXX/builtin-bswapg.cpp index 7b4d769df9ba7..9d8d103e77c51 100644 --- a/clang/test/SemaCXX/builtin-bswapg.cpp +++ b/clang/test/SemaCXX/builtin-bswapg.cpp @@ -10,6 +10,11 @@ void test_basic_type_checks() { static_assert(__is_same(unsigned int, decltype(__builtin_bswapg((unsigned int)0))), ""); static_assert(__is_same(long, decltype(__builtin_bswapg((long)0))), ""); static_assert(__is_same(unsigned long, decltype(__builtin_bswapg((unsigned long)0))), ""); + static_assert(__is_same(_BitInt(8), decltype(__builtin_bswapg((_BitInt(8))0))), ""); + static_assert(__is_same(_BitInt(16), decltype(__builtin_bswapg((_BitInt(16))0))), ""); + static_assert(__is_same(_BitInt(32), decltype(__builtin_bswapg((_BitInt(32))0))), ""); + static_assert(__is_same(_BitInt(64), decltype(__builtin_bswapg((_BitInt(64))0))), ""); + static_assert(__is_same(_BitInt(128), decltype(__builtin_bswapg((_BitInt(128))0))), ""); } template @@ -31,7 +36,11 @@ template void test_template_type_check(); template void test_template_type_check(); template void test_template_type_check(); template void test_template_type_check(); -template void test_template_type_check(); +template void test_template_type_check<_BitInt(8)>(); +template void test_template_type_check<_BitInt(16)>(); +template void test_template_type_check<_BitInt(32)>(); +template void test_template_type_check<_BitInt(64)>(); +template void test_template_type_check<_BitInt(128)>(); void test_lambda_type_checks() { auto lambda = [](auto x) { @@ -135,8 +144,17 @@ void test_lambda_errors() { // expected-note@-2 {{in instantiation of function template specialization 'test_lambda_errors()::(anonymous class)::operator()' requested here}} } -void test_argument_count_errors() { - int h14 = __builtin_bswapg(1, 2); // expected-error {{too many arguments to function call, expected 1, have 2}} +template void test_variadic_template_argument_count(Args... args) { + int result = __builtin_bswapg(args...); // #arg_use +} +void test_variadic_template_args() { + test_variadic_template_argument_count(); + // expected-error@#arg_use {{too few arguments to function call, expected 1, have 0}} + // expected-note@-2 {{in instantiation of function template specialization 'test_variadic_template_argument_count<>' requested here}} + test_variadic_template_argument_count(1); + test_variadic_template_argument_count(1, 2); + // expected-error@#arg_use {{too many arguments to function call, expected 1, have 2}} + // expected-note@-2 {{in instantiation of function template specialization 'test_variadic_template_argument_count' requested here}} } void test_lvalue_reference(int& a) { From 2b4e009d8c29edb871a668800b790e0acfd9bdcb Mon Sep 17 00:00:00 2001 From: clingfei <1599101385@qq.com> Date: Sun, 19 Oct 2025 14:34:11 +0800 Subject: [PATCH 12/13] add CodeGen tests for _BitInt --- clang/lib/Sema/SemaChecking.cpp | 2 +- clang/test/CodeGen/builtins.c | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 244640e6a5a99..5376eb8ac8b33 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -2218,7 +2218,7 @@ static bool BuiltinBswapg(Sema &S, CallExpr *TheCall) { if (!ArgTy->isIntegerType()) { S.Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type) - << 1 << /*scalar=*/ 1 << /*unsigned integer=*/ 1 << /*floating point=*/ 0 + << 1 << /*scalar=*/1 << /*unsigned integer=*/1 << /*floating point=*/0 << ArgTy; return true; } diff --git a/clang/test/CodeGen/builtins.c b/clang/test/CodeGen/builtins.c index b3d40992fc975..79859762b9457 100644 --- a/clang/test/CodeGen/builtins.c +++ b/clang/test/CodeGen/builtins.c @@ -134,6 +134,11 @@ int main(void) { P(bswapg, ((short)N)); P(bswapg, ((int)N)); P(bswapg, ((unsigned long)N)); + P(bswapg, ((_BitInt(8))N)); + P(bswapg, ((_BitInt(16))N)); + P(bswapg, ((_BitInt(32))N)); + P(bswapg, ((_BitInt(64))N)); + P(bswapg, ((_BitInt(128))N)); P(bswap16, (N)); P(bswap32, (N)); P(bswap64, (N)); From 42301e834c89f21a8b9e16871118fe9b627558b9 Mon Sep 17 00:00:00 2001 From: clingfei <1599101385@qq.com> Date: Sun, 19 Oct 2025 14:44:07 +0800 Subject: [PATCH 13/13] remove the assumption 'Val.getActiveBits <= 64' in interp__builtin_bswap to support bswap for values with more bits --- clang/lib/AST/ByteCode/InterpBuiltin.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp index 0bc165f2eeff7..ea254dd3c4dc9 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -969,7 +969,6 @@ static bool interp__builtin_bswap(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const CallExpr *Call) { const APSInt &Val = popToAPSInt(S, Call->getArg(0)); - assert(Val.getActiveBits() <= 64); if (Val.getBitWidth() == 8) pushInteger(S, Val, Call->getType()); else