https://github.com/chaitanyav updated https://github.com/llvm/llvm-project/pull/160259
>From 01dfdddf03cf0b7c2d63ffd3e89dce814ecfd630 Mon Sep 17 00:00:00 2001 From: NagaChaitanya Vellanki <pnag...@protonmail.com> Date: Tue, 23 Sep 2025 02:17:49 -0700 Subject: [PATCH] [clang] Implement __builtin_stdc_rotate_{left,right} Resolves #122819 --- clang/include/clang/Basic/Builtins.td | 12 +++++ clang/lib/AST/ExprConstant.cpp | 2 + clang/lib/CodeGen/CGBuiltin.cpp | 2 + clang/lib/Sema/SemaChecking.cpp | 48 ++++++++++++++++++ clang/test/CodeGen/builtin-rotate.c | 73 +++++++++++++++++++++++++++ 5 files changed, 137 insertions(+) diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 35d2c3e19fdf9..49987df6a380b 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -767,12 +767,24 @@ def RotateLeft : BitInt8_16_32_64BuiltinsTemplate, Builtin { let Prototype = "T(T, T)"; } +def StdcRotateLeft : Builtin { + let Spellings = ["__builtin_stdc_rotate_left"]; + let Attributes = [NoThrow, Const, Constexpr, CustomTypeChecking]; + let Prototype = "void(...)"; +} + def RotateRight : BitInt8_16_32_64BuiltinsTemplate, Builtin { let Spellings = ["__builtin_rotateright"]; let Attributes = [NoThrow, Const, Constexpr]; let Prototype = "T(T, T)"; } +def StdcRotateRight : Builtin { + let Spellings = ["__builtin_stdc_rotate_right"]; + 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/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index d10e2afeb2341..4780f1b73232d 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -14077,6 +14077,7 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, case Builtin::BI__builtin_rotateleft16: case Builtin::BI__builtin_rotateleft32: case Builtin::BI__builtin_rotateleft64: + case Builtin::BI__builtin_stdc_rotate_left: case Builtin::BI_rotl8: // Microsoft variants of rotate right case Builtin::BI_rotl16: case Builtin::BI_rotl: @@ -14094,6 +14095,7 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, case Builtin::BI__builtin_rotateright16: case Builtin::BI__builtin_rotateright32: case Builtin::BI__builtin_rotateright64: + case Builtin::BI__builtin_stdc_rotate_right: case Builtin::BI_rotr8: // Microsoft variants of rotate right case Builtin::BI_rotr16: case Builtin::BI_rotr: diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index f7c3dea257d50..9f96b6f940b5c 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -3642,6 +3642,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_rotateleft16: case Builtin::BI__builtin_rotateleft32: case Builtin::BI__builtin_rotateleft64: + case Builtin::BI__builtin_stdc_rotate_left: case Builtin::BI_rotl8: // Microsoft variants of rotate left case Builtin::BI_rotl16: case Builtin::BI_rotl: @@ -3653,6 +3654,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_rotateright16: case Builtin::BI__builtin_rotateright32: case Builtin::BI__builtin_rotateright64: + case Builtin::BI__builtin_stdc_rotate_right: case Builtin::BI_rotr8: // Microsoft variants of rotate right case Builtin::BI_rotr16: case Builtin::BI_rotr: diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index b3b67230f7687..3e9b7645b8182 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -2267,6 +2267,48 @@ static bool BuiltinCountZeroBitsGeneric(Sema &S, CallExpr *TheCall) { return false; } +/// Checks that __builtin_stdc_rotate_{left,right} was called with two +/// arguments, that the first argument is an unsigned integer type, and that +/// the second argument is an integer type. +static bool BuiltinRotateGeneric(Sema &S, CallExpr *TheCall) { + if (S.checkArgCount(TheCall, 2)) + return true; + + ExprResult Arg0Res = S.DefaultLvalueConversion(TheCall->getArg(0)); + if (Arg0Res.isInvalid()) + return true; + + Expr *Arg0 = Arg0Res.get(); + TheCall->setArg(0, Arg0); + + QualType Arg0Ty = Arg0->getType(); + + if (!Arg0Ty->isUnsignedIntegerType()) { + S.Diag(Arg0->getBeginLoc(), diag::err_builtin_invalid_arg_type) + << 1 << /* scalar */ 1 << /* unsigned integer ty */ 3 << /* no fp */ 0 + << Arg0Ty; + return true; + } + + ExprResult Arg1Res = S.DefaultLvalueConversion(TheCall->getArg(1)); + if (Arg1Res.isInvalid()) + return true; + + Expr *Arg1 = Arg1Res.get(); + TheCall->setArg(1, Arg1); + + QualType Arg1Ty = Arg1->getType(); + + if (!Arg1Ty->isIntegerType()) { + S.Diag(Arg1->getBeginLoc(), diag::err_builtin_invalid_arg_type) + << 2 << /* scalar */ 1 << /* integer ty */ 2 << /* no fp */ 0 << Arg1Ty; + return true; + } + + TheCall->setType(Arg0Ty); + return false; +} + static bool CheckMaskedBuiltinArgs(Sema &S, Expr *MaskArg, Expr *PtrArg, unsigned Pos, bool Vector = true) { QualType MaskTy = MaskArg->getType(); @@ -3416,6 +3458,12 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, return ExprError(); break; + case Builtin::BI__builtin_stdc_rotate_left: + case Builtin::BI__builtin_stdc_rotate_right: + if (BuiltinRotateGeneric(*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-rotate.c b/clang/test/CodeGen/builtin-rotate.c index 8fc1701c6c9bb..5a3e5501e9c45 100644 --- a/clang/test/CodeGen/builtin-rotate.c +++ b/clang/test/CodeGen/builtin-rotate.c @@ -32,6 +32,43 @@ unsigned long long rotl64(unsigned long long x, long long y) { return __builtin_rotateleft64(x, y); } +// CHECK-LABEL: test_builtin_stdc_rotate_left +void test_builtin_stdc_rotate_left(unsigned char uc, unsigned short us, + unsigned int ui, unsigned long ul, + unsigned long long ull, unsigned __int128 ui128, + unsigned _BitInt(128) ubi128) { + +volatile unsigned char result_uc; +volatile unsigned int result_ui; +volatile unsigned short result_us; +volatile unsigned long result_ul; +volatile unsigned long long result_ull; +volatile unsigned __int128 result_ui128; +volatile unsigned _BitInt(128) result_ubi128; + + // CHECK: call i8 @llvm.fshl.i8(i8 %{{.*}}, i8 %{{.*}}, i8 3) + result_uc = __builtin_stdc_rotate_left(uc, 3); + + // CHECK: call i16 @llvm.fshl.i16(i16 %{{.*}}, i16 %{{.*}}, i16 5) + result_us = __builtin_stdc_rotate_left(us, 5); + + // CHECK: call i32 @llvm.fshl.i32(i32 %{{.*}}, i32 %{{.*}}, i32 8) + result_ui = __builtin_stdc_rotate_left(ui, 8); + + // CHECK: call i{{32|64}} @llvm.fshl.i{{32|64}}(i{{32|64}} %{{.*}}, i{{32|64}} %{{.*}}, i{{32|64}} 8) + result_ul = __builtin_stdc_rotate_left(ul, 8); + + // CHECK: call i64 @llvm.fshl.i64(i64 %{{.*}}, i64 %{{.*}}, i64 16) + result_ull = __builtin_stdc_rotate_left(ull, 16); + + // CHECK: call i128 @llvm.fshl.i128(i128 %{{.*}}, i128 %{{.*}}, i128 32) + result_ui128 = __builtin_stdc_rotate_left(ui128, 32); + + // CHECK: call i128 @llvm.fshl.i128(i128 %{{.*}}, i128 %{{.*}}, i128 64) + result_ubi128 = __builtin_stdc_rotate_left(ubi128, 64); + +} + char rotr8(char x, char y) { // CHECK-LABEL: rotr8 // CHECK: [[F:%.*]] = call i8 @llvm.fshr.i8(i8 [[X:%.*]], i8 [[X]], i8 [[Y:%.*]]) @@ -64,3 +101,39 @@ long long rotr64(long long x, unsigned long long y) { return __builtin_rotateright64(x, y); } +// CHECK-LABEL: test_builtin_stdc_rotate_right +void test_builtin_stdc_rotate_right(unsigned char uc, unsigned short us, + unsigned int ui, unsigned long ul, + unsigned long long ull, unsigned __int128 ui128, + unsigned _BitInt(128) ubi128) { + + volatile unsigned char result_uc; + volatile unsigned int result_ui; + volatile unsigned short result_us; + volatile unsigned long result_ul; + volatile unsigned long long result_ull; + volatile unsigned __int128 result_ui128; + volatile unsigned _BitInt(128) result_ubi128; + + // CHECK: call i8 @llvm.fshr.i8(i8 %{{.*}}, i8 %{{.*}}, i8 3) + result_uc = __builtin_stdc_rotate_right(uc, 3); + + // CHECK: call i16 @llvm.fshr.i16(i16 %{{.*}}, i16 %{{.*}}, i16 5) + result_us = __builtin_stdc_rotate_right(us, 5); + + // CHECK: call i32 @llvm.fshr.i32(i32 %{{.*}}, i32 %{{.*}}, i32 8) + result_ui = __builtin_stdc_rotate_right(ui, 8); + + // CHECK: call i{{32|64}} @llvm.fshr.i{{32|64}}(i{{32|64}} %{{.*}}, i{{32|64}} %{{.*}}, i{{32|64}} 8) + result_ul = __builtin_stdc_rotate_right(ul, 8); + + // CHECK: call i64 @llvm.fshr.i64(i64 %{{.*}}, i64 %{{.*}}, i64 16) + result_ull = __builtin_stdc_rotate_right(ull, 16); + + // CHECK: call i128 @llvm.fshr.i128(i128 %{{.*}}, i128 %{{.*}}, i128 32) + result_ui128 = __builtin_stdc_rotate_right(ui128, 32); + + // CHECK: call i128 @llvm.fshr.i128(i128 %{{.*}}, i128 %{{.*}}, i128 64) + result_ubi128 = __builtin_stdc_rotate_right(ubi128, 64); + +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits