[clang] [clang] Implement __builtin_rotate{left,right}g (PR #160259)
NagaChaitanya Vellanki via cfe-commits
cfe-commits at lists.llvm.org
Tue Sep 23 08:29:26 PDT 2025
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 <pnagato at 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);
+
+}
More information about the cfe-commits
mailing list