[clang] [clang] Add typed variants for C2y stdbit.h rotate builtins (PR #195299)
NagaChaitanya Vellanki via cfe-commits
cfe-commits at lists.llvm.org
Fri May 1 10:14:39 PDT 2026
https://github.com/chaitanyav created https://github.com/llvm/llvm-project/pull/195299
stdc_rotate_left_{uc,us,ui,ul,ull}
stdc_rotate_right_{uc,us,ui,ul,ull}
Lower type-specific <stdbit.h> rotate functions to LLVM intrinsics (fshl/fshr). Includes constant expression support and tests for Sema, CodeGen, and constant evaluation.
Followup: #160259
>From ab38e1557e9ac633937e8121fb0485e50f4db969 Mon Sep 17 00:00:00 2001
From: NagaChaitanya Vellanki <pnagato at protonmail.com>
Date: Thu, 30 Apr 2026 21:38:03 -0700
Subject: [PATCH] [clang] Add typed variants for C2y stdbit.h rotate builtins
stdc_rotate_left_{uc,us,ui,ul,ull}
stdc_rotate_right_{uc,us,ui,ul,ull}
Lower type-specific <stdbit.h> rotate functions to LLVM intrinsics (fshl/fshr). Includes constant expression support and tests for Sema, CodeGen, and constant evaluation.
Followup: #160259
---
clang/docs/ReleaseNotes.rst | 5 +
clang/include/clang/Basic/Builtins.h | 1 +
clang/include/clang/Basic/Builtins.td | 23 +++
clang/lib/AST/ByteCode/InterpBuiltin.cpp | 18 +++
clang/lib/AST/ExprConstant.cpp | 18 +++
clang/lib/Basic/Builtins.cpp | 3 +
clang/lib/CodeGen/CGBuiltin.cpp | 12 ++
clang/lib/Sema/SemaChecking.cpp | 2 +
clang/test/CodeGen/Inputs/stdbit.h | 12 ++
clang/test/CodeGen/builtin-rotate.c | 196 +++++++++++++++++++++++
clang/test/Sema/Inputs/stdbit.h | 12 ++
clang/test/Sema/builtin-stdc-rotate.c | 77 +++++++++
12 files changed, 379 insertions(+)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index c408196c3816b..4a6728aaaa5b2 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -164,6 +164,11 @@ C Language Changes
C2y Feature Support
^^^^^^^^^^^^^^^^^^^
+- Implemented the type-specific C2y ``<stdbit.h>`` rotate functions with constexpr
+ evaluation support:
+ ``stdc_rotate_left_{uc,us,ui,ul,ull}`` and
+ ``stdc_rotate_right_{uc,us,ui,ul,ull}``.
+
C23 Feature Support
^^^^^^^^^^^^^^^^^^^
- Clang now allows C23 ``constexpr`` struct member access through the dot operator in constant expressions. (#GH178349)
diff --git a/clang/include/clang/Basic/Builtins.h b/clang/include/clang/Basic/Builtins.h
index 51f0745d47015..9054f9415ce67 100644
--- a/clang/include/clang/Basic/Builtins.h
+++ b/clang/include/clang/Basic/Builtins.h
@@ -46,6 +46,7 @@ enum LanguageID : uint16_t {
ALL_OCL_LANGUAGES = 0x800, // builtin for OCL languages.
HLSL_LANG = 0x1000, // builtin requires HLSL.
C23_LANG = 0x2000, // builtin requires C23 or later.
+ C2Y_LANG = 0x4000, // builtin requires C2y or later.
ALL_LANGUAGES = C_LANG | CXX_LANG | OBJC_LANG, // builtin for all languages.
ALL_GNU_LANGUAGES = ALL_LANGUAGES | GNU_LANG, // builtin requires GNU mode.
ALL_MS_LANGUAGES = ALL_LANGUAGES | MS_LANG // builtin requires MS mode.
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 4a7eaeb3d353e..5565d3c6ae3d5 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -970,6 +970,18 @@ def StdcBitCeilLib: LibBuiltin<"stdbit.h", "C23_LANG"> {
let Prototype = "void(...)";
}
+def StdcRotateLeftLib: LibBuiltin<"stdbit.h", "C2Y_LANG"> {
+ let Spellings = ["stdc_rotate_left"];
+ let Attributes = [NoThrow, Const, CustomTypeChecking];
+ let Prototype = "void(...)";
+}
+
+def StdcRotateRightLib: LibBuiltin<"stdbit.h", "C2Y_LANG"> {
+ let Spellings = ["stdc_rotate_right"];
+ let Attributes = [NoThrow, Const, CustomTypeChecking];
+ let Prototype = "void(...)";
+}
+
// Typed variants of the C23 stdbit.h builtins (e.g. stdc_leading_zeros_uc).
// IntBitUtilTemplate generates the _uc/_us/_ui/_ul/_ull spellings with
// concrete prototypes so the compiler can match the <stdbit.h> declarations.
@@ -1058,6 +1070,17 @@ def StdcBitCeilTyped : LibBuiltin<"stdbit.h", "C23_LANG">, IntBitUtilTemplate {
let Prototype = "T(T)";
}
+def StdcRotateLeftTyped : LibBuiltin<"stdbit.h", "C2Y_LANG">, IntBitUtilTemplate {
+ let Spellings = ["stdc_rotate_left"];
+ let Attributes = [NoThrow, Const, Constexpr];
+ let Prototype = "T(T, unsigned int)";
+}
+
+def StdcRotateRightTyped : LibBuiltin<"stdbit.h", "C2Y_LANG">, IntBitUtilTemplate {
+ let Spellings = ["stdc_rotate_right"];
+ let Attributes = [NoThrow, Const, Constexpr];
+ let Prototype = "T(T, unsigned int)";
+}
// Random GCC builtins
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index 77ea83605cc16..82b7b3d6c8d31 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -4609,6 +4609,12 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
case Builtin::BI__builtin_rotateleft32:
case Builtin::BI__builtin_rotateleft64:
case Builtin::BI__builtin_stdc_rotate_left:
+ case Builtin::BIstdc_rotate_left:
+ case Builtin::BIstdc_rotate_left_uc:
+ case Builtin::BIstdc_rotate_left_us:
+ case Builtin::BIstdc_rotate_left_ui:
+ case Builtin::BIstdc_rotate_left_ul:
+ case Builtin::BIstdc_rotate_left_ull:
case Builtin::BI_rotl8: // Microsoft variants of rotate left
case Builtin::BI_rotl16:
case Builtin::BI_rotl:
@@ -4619,6 +4625,12 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
case Builtin::BI__builtin_rotateright32:
case Builtin::BI__builtin_rotateright64:
case Builtin::BI__builtin_stdc_rotate_right:
+ case Builtin::BIstdc_rotate_right:
+ case Builtin::BIstdc_rotate_right_uc:
+ case Builtin::BIstdc_rotate_right_us:
+ case Builtin::BIstdc_rotate_right_ui:
+ case Builtin::BIstdc_rotate_right_ul:
+ case Builtin::BIstdc_rotate_right_ull:
case Builtin::BI_rotr8: // Microsoft variants of rotate right
case Builtin::BI_rotr16:
case Builtin::BI_rotr:
@@ -4632,6 +4644,12 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
case Builtin::BI__builtin_rotateright32:
case Builtin::BI__builtin_rotateright64:
case Builtin::BI__builtin_stdc_rotate_right:
+ case Builtin::BIstdc_rotate_right:
+ case Builtin::BIstdc_rotate_right_uc:
+ case Builtin::BIstdc_rotate_right_us:
+ case Builtin::BIstdc_rotate_right_ui:
+ case Builtin::BIstdc_rotate_right_ul:
+ case Builtin::BIstdc_rotate_right_ull:
case Builtin::BI_rotr8:
case Builtin::BI_rotr16:
case Builtin::BI_rotr:
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 1a4c962801077..6dfcc9bf4c486 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -16870,6 +16870,18 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
case Builtin::BI__builtin_rotateright64:
case Builtin::BI__builtin_stdc_rotate_left:
case Builtin::BI__builtin_stdc_rotate_right:
+ case Builtin::BIstdc_rotate_left:
+ case Builtin::BIstdc_rotate_left_uc:
+ case Builtin::BIstdc_rotate_left_us:
+ case Builtin::BIstdc_rotate_left_ui:
+ case Builtin::BIstdc_rotate_left_ul:
+ case Builtin::BIstdc_rotate_left_ull:
+ case Builtin::BIstdc_rotate_right:
+ case Builtin::BIstdc_rotate_right_uc:
+ case Builtin::BIstdc_rotate_right_us:
+ case Builtin::BIstdc_rotate_right_ui:
+ case Builtin::BIstdc_rotate_right_ul:
+ case Builtin::BIstdc_rotate_right_ull:
case Builtin::BI_rotl8: // Microsoft variants of rotate left
case Builtin::BI_rotl16:
case Builtin::BI_rotl:
@@ -16893,6 +16905,12 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
case Builtin::BI__builtin_rotateright32:
case Builtin::BI__builtin_rotateright64:
case Builtin::BI__builtin_stdc_rotate_right:
+ case Builtin::BIstdc_rotate_right:
+ case Builtin::BIstdc_rotate_right_uc:
+ case Builtin::BIstdc_rotate_right_us:
+ case Builtin::BIstdc_rotate_right_ui:
+ case Builtin::BIstdc_rotate_right_ul:
+ case Builtin::BIstdc_rotate_right_ull:
case Builtin::BI_rotr8:
case Builtin::BI_rotr16:
case Builtin::BI_rotr:
diff --git a/clang/lib/Basic/Builtins.cpp b/clang/lib/Basic/Builtins.cpp
index 72735b04a16ba..49517fc748112 100644
--- a/clang/lib/Basic/Builtins.cpp
+++ b/clang/lib/Basic/Builtins.cpp
@@ -194,6 +194,9 @@ static bool builtinIsSupported(const llvm::StringTable &Strings,
/* C23 unsupported */
if (!LangOpts.C23 && BuiltinInfo.Langs == C23_LANG)
return false;
+ /* C2y unsupported */
+ if (!LangOpts.C2y && BuiltinInfo.Langs == C2Y_LANG)
+ return false;
return true;
}
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 67de2a34f44ea..264a2d12488c2 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3770,6 +3770,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_rotateleft32:
case Builtin::BI__builtin_rotateleft64:
case Builtin::BI__builtin_stdc_rotate_left:
+ case Builtin::BIstdc_rotate_left:
+ case Builtin::BIstdc_rotate_left_uc:
+ case Builtin::BIstdc_rotate_left_us:
+ case Builtin::BIstdc_rotate_left_ui:
+ case Builtin::BIstdc_rotate_left_ul:
+ case Builtin::BIstdc_rotate_left_ull:
case Builtin::BI_rotl8: // Microsoft variants of rotate left
case Builtin::BI_rotl16:
case Builtin::BI_rotl:
@@ -3782,6 +3788,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_rotateright32:
case Builtin::BI__builtin_rotateright64:
case Builtin::BI__builtin_stdc_rotate_right:
+ case Builtin::BIstdc_rotate_right:
+ case Builtin::BIstdc_rotate_right_uc:
+ case Builtin::BIstdc_rotate_right_us:
+ case Builtin::BIstdc_rotate_right_ui:
+ case Builtin::BIstdc_rotate_right_ul:
+ case Builtin::BIstdc_rotate_right_ull:
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 eb957df6f1e97..e27274a5e2c2b 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -3858,6 +3858,8 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
case Builtin::BI__builtin_stdc_rotate_left:
case Builtin::BI__builtin_stdc_rotate_right:
+ case Builtin::BIstdc_rotate_left:
+ case Builtin::BIstdc_rotate_right:
if (BuiltinRotateGeneric(*this, TheCall))
return ExprError();
break;
diff --git a/clang/test/CodeGen/Inputs/stdbit.h b/clang/test/CodeGen/Inputs/stdbit.h
index 529f456151007..bdabb9ec8ee7d 100644
--- a/clang/test/CodeGen/Inputs/stdbit.h
+++ b/clang/test/CodeGen/Inputs/stdbit.h
@@ -100,4 +100,16 @@ unsigned int stdc_bit_ceil_ui(unsigned int);
unsigned long stdc_bit_ceil_ul(unsigned long);
unsigned long long stdc_bit_ceil_ull(unsigned long long);
+unsigned char stdc_rotate_left_uc(unsigned char, unsigned int);
+unsigned short stdc_rotate_left_us(unsigned short, unsigned int);
+unsigned int stdc_rotate_left_ui(unsigned int, unsigned int);
+unsigned long stdc_rotate_left_ul(unsigned long, unsigned int);
+unsigned long long stdc_rotate_left_ull(unsigned long long, unsigned int);
+
+unsigned char stdc_rotate_right_uc(unsigned char, unsigned int);
+unsigned short stdc_rotate_right_us(unsigned short, unsigned int);
+unsigned int stdc_rotate_right_ui(unsigned int, unsigned int);
+unsigned long stdc_rotate_right_ul(unsigned long, unsigned int);
+unsigned long long stdc_rotate_right_ull(unsigned long long, unsigned int);
+
#endif
diff --git a/clang/test/CodeGen/builtin-rotate.c b/clang/test/CodeGen/builtin-rotate.c
index 6e2d3f3dd31b6..691aff56509b8 100644
--- a/clang/test/CodeGen/builtin-rotate.c
+++ b/clang/test/CodeGen/builtin-rotate.c
@@ -1,6 +1,8 @@
// RUN: %clang_cc1 -ffreestanding %s -emit-llvm -o - | FileCheck %s
// RUN: %if clang-target-64-bits %{ %clang_cc1 -ffreestanding %s -emit-llvm -o - | FileCheck %s --check-prefix=INT128 %}
+// RUN: %clang_cc1 -std=c2y -isystem %S/Inputs -DTEST_C2Y_LIB_SPELLINGS %s -emit-llvm -o - | FileCheck %s --check-prefix=C2Y
+#ifndef TEST_C2Y_LIB_SPELLINGS
#include<stdint.h>
unsigned char rotl8(unsigned char x, unsigned char y) {
@@ -313,3 +315,197 @@ void test_int128_rotate(unsigned __int128 u128) {
result_u128 = __builtin_stdc_rotate_right(u128, 32);
}
#endif
+
+#endif // !TEST_C2Y_LIB_SPELLINGS
+
+#ifdef TEST_C2Y_LIB_SPELLINGS
+#include <stdbit.h>
+
+// C2Y-LABEL: define dso_local zeroext i8 @test_typed_rotate_left_uc(
+// C2Y-SAME: i8 noundef zeroext [[X:%.*]], i32 noundef [[CNT:%.*]]) #[[ATTR0:[0-9]+]] {
+// C2Y-NEXT: [[ENTRY:.*:]]
+// C2Y-NEXT: [[X_ADDR:%.*]] = alloca i8, align 1
+// C2Y-NEXT: [[CNT_ADDR:%.*]] = alloca i32, align 4
+// C2Y-NEXT: store i8 [[X]], ptr [[X_ADDR]], align 1
+// C2Y-NEXT: store i32 [[CNT]], ptr [[CNT_ADDR]], align 4
+// C2Y-NEXT: [[TMP0:%.*]] = load i8, ptr [[X_ADDR]], align 1
+// C2Y-NEXT: [[TMP1:%.*]] = load i32, ptr [[CNT_ADDR]], align 4
+// C2Y-NEXT: [[TMP2:%.*]] = urem i32 [[TMP1]], 8
+// C2Y-NEXT: [[TMP3:%.*]] = trunc i32 [[TMP2]] to i8
+// C2Y-NEXT: [[TMP4:%.*]] = call i8 @llvm.fshl.i8(i8 [[TMP0]], i8 [[TMP0]], i8 [[TMP3]])
+// C2Y-NEXT: ret i8 [[TMP4]]
+//
+unsigned char test_typed_rotate_left_uc(unsigned char x, unsigned int cnt) {
+ return stdc_rotate_left_uc(x, cnt);
+}
+
+// C2Y-LABEL: define dso_local zeroext i16 @test_typed_rotate_left_us(
+// C2Y-SAME: i16 noundef zeroext [[X:%.*]], i32 noundef [[CNT:%.*]]) #[[ATTR0]] {
+// C2Y-NEXT: [[ENTRY:.*:]]
+// C2Y-NEXT: [[X_ADDR:%.*]] = alloca i16, align 2
+// C2Y-NEXT: [[CNT_ADDR:%.*]] = alloca i32, align 4
+// C2Y-NEXT: store i16 [[X]], ptr [[X_ADDR]], align 2
+// C2Y-NEXT: store i32 [[CNT]], ptr [[CNT_ADDR]], align 4
+// C2Y-NEXT: [[TMP0:%.*]] = load i16, ptr [[X_ADDR]], align 2
+// C2Y-NEXT: [[TMP1:%.*]] = load i32, ptr [[CNT_ADDR]], align 4
+// C2Y-NEXT: [[TMP2:%.*]] = urem i32 [[TMP1]], 16
+// C2Y-NEXT: [[TMP3:%.*]] = trunc i32 [[TMP2]] to i16
+// C2Y-NEXT: [[TMP4:%.*]] = call i16 @llvm.fshl.i16(i16 [[TMP0]], i16 [[TMP0]], i16 [[TMP3]])
+// C2Y-NEXT: ret i16 [[TMP4]]
+//
+unsigned short test_typed_rotate_left_us(unsigned short x, unsigned int cnt) {
+ return stdc_rotate_left_us(x, cnt);
+}
+
+// C2Y-LABEL: define dso_local i32 @test_typed_rotate_left_ui(
+// C2Y-SAME: i32 noundef [[X:%.*]], i32 noundef [[CNT:%.*]]) #[[ATTR0]] {
+// C2Y-NEXT: [[ENTRY:.*:]]
+// C2Y-NEXT: [[X_ADDR:%.*]] = alloca i32, align 4
+// C2Y-NEXT: [[CNT_ADDR:%.*]] = alloca i32, align 4
+// C2Y-NEXT: store i32 [[X]], ptr [[X_ADDR]], align 4
+// C2Y-NEXT: store i32 [[CNT]], ptr [[CNT_ADDR]], align 4
+// C2Y-NEXT: [[TMP0:%.*]] = load i32, ptr [[X_ADDR]], align 4
+// C2Y-NEXT: [[TMP1:%.*]] = load i32, ptr [[CNT_ADDR]], align 4
+// C2Y-NEXT: [[TMP2:%.*]] = urem i32 [[TMP1]], 32
+// C2Y-NEXT: [[TMP3:%.*]] = call i32 @llvm.fshl.i32(i32 [[TMP0]], i32 [[TMP0]], i32 [[TMP2]])
+// C2Y-NEXT: ret i32 [[TMP3]]
+//
+unsigned int test_typed_rotate_left_ui(unsigned int x, unsigned int cnt) {
+ return stdc_rotate_left_ui(x, cnt);
+}
+
+// C2Y-LABEL: define dso_local i64 @test_typed_rotate_left_ull(
+// C2Y-SAME: i64 noundef [[X:%.*]], i32 noundef [[CNT:%.*]]) #[[ATTR0]] {
+// C2Y-NEXT: [[ENTRY:.*:]]
+// C2Y-NEXT: [[X_ADDR:%.*]] = alloca i64, align 8
+// C2Y-NEXT: [[CNT_ADDR:%.*]] = alloca i32, align 4
+// C2Y-NEXT: store i64 [[X]], ptr [[X_ADDR]], align 8
+// C2Y-NEXT: store i32 [[CNT]], ptr [[CNT_ADDR]], align 4
+// C2Y-NEXT: [[TMP0:%.*]] = load i64, ptr [[X_ADDR]], align 8
+// C2Y-NEXT: [[TMP1:%.*]] = load i32, ptr [[CNT_ADDR]], align 4
+// C2Y-NEXT: [[TMP2:%.*]] = zext i32 [[TMP1]] to i64
+// C2Y-NEXT: [[TMP3:%.*]] = urem i64 [[TMP2]], 64
+// C2Y-NEXT: [[TMP4:%.*]] = call i64 @llvm.fshl.i64(i64 [[TMP0]], i64 [[TMP0]], i64 [[TMP3]])
+// C2Y-NEXT: ret i64 [[TMP4]]
+//
+unsigned long long test_typed_rotate_left_ull(unsigned long long x, unsigned int cnt) {
+ return stdc_rotate_left_ull(x, cnt);
+}
+
+// C2Y-LABEL: define dso_local zeroext i8 @test_typed_rotate_right_uc(
+// C2Y-SAME: i8 noundef zeroext [[X:%.*]], i32 noundef [[CNT:%.*]]) #[[ATTR0]] {
+// C2Y-NEXT: [[ENTRY:.*:]]
+// C2Y-NEXT: [[X_ADDR:%.*]] = alloca i8, align 1
+// C2Y-NEXT: [[CNT_ADDR:%.*]] = alloca i32, align 4
+// C2Y-NEXT: store i8 [[X]], ptr [[X_ADDR]], align 1
+// C2Y-NEXT: store i32 [[CNT]], ptr [[CNT_ADDR]], align 4
+// C2Y-NEXT: [[TMP0:%.*]] = load i8, ptr [[X_ADDR]], align 1
+// C2Y-NEXT: [[TMP1:%.*]] = load i32, ptr [[CNT_ADDR]], align 4
+// C2Y-NEXT: [[TMP2:%.*]] = urem i32 [[TMP1]], 8
+// C2Y-NEXT: [[TMP3:%.*]] = trunc i32 [[TMP2]] to i8
+// C2Y-NEXT: [[TMP4:%.*]] = call i8 @llvm.fshr.i8(i8 [[TMP0]], i8 [[TMP0]], i8 [[TMP3]])
+// C2Y-NEXT: ret i8 [[TMP4]]
+//
+unsigned char test_typed_rotate_right_uc(unsigned char x, unsigned int cnt) {
+ return stdc_rotate_right_uc(x, cnt);
+}
+
+// C2Y-LABEL: define dso_local zeroext i16 @test_typed_rotate_right_us(
+// C2Y-SAME: i16 noundef zeroext [[X:%.*]], i32 noundef [[CNT:%.*]]) #[[ATTR0]] {
+// C2Y-NEXT: [[ENTRY:.*:]]
+// C2Y-NEXT: [[X_ADDR:%.*]] = alloca i16, align 2
+// C2Y-NEXT: [[CNT_ADDR:%.*]] = alloca i32, align 4
+// C2Y-NEXT: store i16 [[X]], ptr [[X_ADDR]], align 2
+// C2Y-NEXT: store i32 [[CNT]], ptr [[CNT_ADDR]], align 4
+// C2Y-NEXT: [[TMP0:%.*]] = load i16, ptr [[X_ADDR]], align 2
+// C2Y-NEXT: [[TMP1:%.*]] = load i32, ptr [[CNT_ADDR]], align 4
+// C2Y-NEXT: [[TMP2:%.*]] = urem i32 [[TMP1]], 16
+// C2Y-NEXT: [[TMP3:%.*]] = trunc i32 [[TMP2]] to i16
+// C2Y-NEXT: [[TMP4:%.*]] = call i16 @llvm.fshr.i16(i16 [[TMP0]], i16 [[TMP0]], i16 [[TMP3]])
+// C2Y-NEXT: ret i16 [[TMP4]]
+//
+unsigned short test_typed_rotate_right_us(unsigned short x, unsigned int cnt) {
+ return stdc_rotate_right_us(x, cnt);
+}
+
+// C2Y-LABEL: define dso_local i32 @test_typed_rotate_right_ui(
+// C2Y-SAME: i32 noundef [[X:%.*]], i32 noundef [[CNT:%.*]]) #[[ATTR0]] {
+// C2Y-NEXT: [[ENTRY:.*:]]
+// C2Y-NEXT: [[X_ADDR:%.*]] = alloca i32, align 4
+// C2Y-NEXT: [[CNT_ADDR:%.*]] = alloca i32, align 4
+// C2Y-NEXT: store i32 [[X]], ptr [[X_ADDR]], align 4
+// C2Y-NEXT: store i32 [[CNT]], ptr [[CNT_ADDR]], align 4
+// C2Y-NEXT: [[TMP0:%.*]] = load i32, ptr [[X_ADDR]], align 4
+// C2Y-NEXT: [[TMP1:%.*]] = load i32, ptr [[CNT_ADDR]], align 4
+// C2Y-NEXT: [[TMP2:%.*]] = urem i32 [[TMP1]], 32
+// C2Y-NEXT: [[TMP3:%.*]] = call i32 @llvm.fshr.i32(i32 [[TMP0]], i32 [[TMP0]], i32 [[TMP2]])
+// C2Y-NEXT: ret i32 [[TMP3]]
+//
+unsigned int test_typed_rotate_right_ui(unsigned int x, unsigned int cnt) {
+ return stdc_rotate_right_ui(x, cnt);
+}
+
+// C2Y-LABEL: define dso_local i64 @test_typed_rotate_right_ull(
+// C2Y-SAME: i64 noundef [[X:%.*]], i32 noundef [[CNT:%.*]]) #[[ATTR0]] {
+// C2Y-NEXT: [[ENTRY:.*:]]
+// C2Y-NEXT: [[X_ADDR:%.*]] = alloca i64, align 8
+// C2Y-NEXT: [[CNT_ADDR:%.*]] = alloca i32, align 4
+// C2Y-NEXT: store i64 [[X]], ptr [[X_ADDR]], align 8
+// C2Y-NEXT: store i32 [[CNT]], ptr [[CNT_ADDR]], align 4
+// C2Y-NEXT: [[TMP0:%.*]] = load i64, ptr [[X_ADDR]], align 8
+// C2Y-NEXT: [[TMP1:%.*]] = load i32, ptr [[CNT_ADDR]], align 4
+// C2Y-NEXT: [[TMP2:%.*]] = zext i32 [[TMP1]] to i64
+// C2Y-NEXT: [[TMP3:%.*]] = urem i64 [[TMP2]], 64
+// C2Y-NEXT: [[TMP4:%.*]] = call i64 @llvm.fshr.i64(i64 [[TMP0]], i64 [[TMP0]], i64 [[TMP3]])
+// C2Y-NEXT: ret i64 [[TMP4]]
+//
+unsigned long long test_typed_rotate_right_ull(unsigned long long x, unsigned int cnt) {
+ return stdc_rotate_right_ull(x, cnt);
+}
+
+// C2Y-LABEL: define dso_local void @test_typed_rotate_constant_count(
+// C2Y-SAME: i8 noundef zeroext [[UC:%.*]], i16 noundef zeroext [[US:%.*]], i32 noundef [[UI:%.*]], i64 noundef [[ULL:%.*]]) #[[ATTR0]] {
+// C2Y-NEXT: [[ENTRY:.*:]]
+// C2Y-NEXT: [[UC_ADDR:%.*]] = alloca i8, align 1
+// C2Y-NEXT: [[US_ADDR:%.*]] = alloca i16, align 2
+// C2Y-NEXT: [[UI_ADDR:%.*]] = alloca i32, align 4
+// C2Y-NEXT: [[ULL_ADDR:%.*]] = alloca i64, align 8
+// C2Y-NEXT: [[R_UC:%.*]] = alloca i8, align 1
+// C2Y-NEXT: [[R_US:%.*]] = alloca i16, align 2
+// C2Y-NEXT: [[R_UI:%.*]] = alloca i32, align 4
+// C2Y-NEXT: [[R_ULL:%.*]] = alloca i64, align 8
+// C2Y-NEXT: store i8 [[UC]], ptr [[UC_ADDR]], align 1
+// C2Y-NEXT: store i16 [[US]], ptr [[US_ADDR]], align 2
+// C2Y-NEXT: store i32 [[UI]], ptr [[UI_ADDR]], align 4
+// C2Y-NEXT: store i64 [[ULL]], ptr [[ULL_ADDR]], align 8
+// C2Y-NEXT: [[TMP0:%.*]] = load i8, ptr [[UC_ADDR]], align 1
+// C2Y-NEXT: [[TMP1:%.*]] = call i8 @llvm.fshl.i8(i8 [[TMP0]], i8 [[TMP0]], i8 3)
+// C2Y-NEXT: store volatile i8 [[TMP1]], ptr [[R_UC]], align 1
+// C2Y-NEXT: [[TMP2:%.*]] = load i8, ptr [[UC_ADDR]], align 1
+// C2Y-NEXT: [[TMP3:%.*]] = call i8 @llvm.fshr.i8(i8 [[TMP2]], i8 [[TMP2]], i8 3)
+// C2Y-NEXT: store volatile i8 [[TMP3]], ptr [[R_UC]], align 1
+// C2Y-NEXT: [[TMP4:%.*]] = load i16, ptr [[US_ADDR]], align 2
+// C2Y-NEXT: [[TMP5:%.*]] = call i16 @llvm.fshl.i16(i16 [[TMP4]], i16 [[TMP4]], i16 5)
+// C2Y-NEXT: store volatile i16 [[TMP5]], ptr [[R_US]], align 2
+// C2Y-NEXT: [[TMP6:%.*]] = load i32, ptr [[UI_ADDR]], align 4
+// C2Y-NEXT: [[TMP7:%.*]] = call i32 @llvm.fshl.i32(i32 [[TMP6]], i32 [[TMP6]], i32 8)
+// C2Y-NEXT: store volatile i32 [[TMP7]], ptr [[R_UI]], align 4
+// C2Y-NEXT: [[TMP8:%.*]] = load i64, ptr [[ULL_ADDR]], align 8
+// C2Y-NEXT: [[TMP9:%.*]] = call i64 @llvm.fshr.i64(i64 [[TMP8]], i64 [[TMP8]], i64 16)
+// C2Y-NEXT: store volatile i64 [[TMP9]], ptr [[R_ULL]], align 8
+// C2Y-NEXT: ret void
+//
+void test_typed_rotate_constant_count(unsigned char uc, unsigned short us,
+ unsigned int ui, unsigned long long ull) {
+ volatile unsigned char r_uc;
+ volatile unsigned short r_us;
+ volatile unsigned int r_ui;
+ volatile unsigned long long r_ull;
+ r_uc = stdc_rotate_left_uc(uc, 3);
+ r_uc = stdc_rotate_right_uc(uc, 3);
+ r_us = stdc_rotate_left_us(us, 5);
+ r_ui = stdc_rotate_left_ui(ui, 8);
+ r_ull = stdc_rotate_right_ull(ull, 16);
+}
+
+#endif // TEST_C2Y_LIB_SPELLINGS
diff --git a/clang/test/Sema/Inputs/stdbit.h b/clang/test/Sema/Inputs/stdbit.h
index 529f456151007..bdabb9ec8ee7d 100644
--- a/clang/test/Sema/Inputs/stdbit.h
+++ b/clang/test/Sema/Inputs/stdbit.h
@@ -100,4 +100,16 @@ unsigned int stdc_bit_ceil_ui(unsigned int);
unsigned long stdc_bit_ceil_ul(unsigned long);
unsigned long long stdc_bit_ceil_ull(unsigned long long);
+unsigned char stdc_rotate_left_uc(unsigned char, unsigned int);
+unsigned short stdc_rotate_left_us(unsigned short, unsigned int);
+unsigned int stdc_rotate_left_ui(unsigned int, unsigned int);
+unsigned long stdc_rotate_left_ul(unsigned long, unsigned int);
+unsigned long long stdc_rotate_left_ull(unsigned long long, unsigned int);
+
+unsigned char stdc_rotate_right_uc(unsigned char, unsigned int);
+unsigned short stdc_rotate_right_us(unsigned short, unsigned int);
+unsigned int stdc_rotate_right_ui(unsigned int, unsigned int);
+unsigned long stdc_rotate_right_ul(unsigned long, unsigned int);
+unsigned long long stdc_rotate_right_ull(unsigned long long, unsigned int);
+
#endif
diff --git a/clang/test/Sema/builtin-stdc-rotate.c b/clang/test/Sema/builtin-stdc-rotate.c
index d8b506dbd6e46..b7ce7ff5adf25 100644
--- a/clang/test/Sema/builtin-stdc-rotate.c
+++ b/clang/test/Sema/builtin-stdc-rotate.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -std=c2y -isystem %S/Inputs -fsyntax-only -verify %s
_Static_assert(__builtin_stdc_rotate_left((unsigned char)0xB1, 3) == 0x8D, "");
_Static_assert(__builtin_stdc_rotate_right((unsigned char)0xB1, 3) == 0x36, "");
@@ -130,3 +131,79 @@ void test_invalid_types(float f, int si) {
(void)__builtin_stdc_rotate_left(-5, 1); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
(void)__builtin_stdc_rotate_right(3.0, 1); // expected-error {{1st argument must be a scalar unsigned integer type (was 'double')}}
}
+
+#ifdef __has_include
+#if __has_include(<stdbit.h>)
+#include <stdbit.h>
+
+_Static_assert(stdc_rotate_left_uc(0xB1, 3) == 0x8D, "");
+_Static_assert(stdc_rotate_right_uc(0xB1, 3) == 0x36, "");
+_Static_assert(stdc_rotate_left_us(0x1234, 4) == 0x2341, "");
+_Static_assert(stdc_rotate_right_us(0x1234, 4) == 0x4123, "");
+_Static_assert(stdc_rotate_left_ui(0x12345678U, 8) == 0x34567812U, "");
+_Static_assert(stdc_rotate_right_ui(0x12345678U, 8) == 0x78123456U, "");
+_Static_assert(stdc_rotate_left_ull(0x123456789ABCDEF0ULL, 16) == 0x56789ABCDEF01234ULL, "");
+_Static_assert(stdc_rotate_right_ull(0x123456789ABCDEF0ULL, 16) == 0xDEF0123456789ABCULL, "");
+
+_Static_assert(stdc_rotate_left_uc(0xAB, 0) == 0xAB, "");
+_Static_assert(stdc_rotate_right_uc(0xAB, 0) == 0xAB, "");
+_Static_assert(stdc_rotate_left_us(0x1234, 0) == 0x1234, "");
+_Static_assert(stdc_rotate_right_us(0x1234, 0) == 0x1234, "");
+_Static_assert(stdc_rotate_left_ui(0x12345678U, 0) == 0x12345678U, "");
+_Static_assert(stdc_rotate_right_ui(0x12345678U, 0) == 0x12345678U, "");
+_Static_assert(stdc_rotate_left_ull(0x123456789ABCDEF0ULL, 0) == 0x123456789ABCDEF0ULL, "");
+_Static_assert(stdc_rotate_right_ull(0x123456789ABCDEF0ULL, 0) == 0x123456789ABCDEF0ULL, "");
+
+_Static_assert(stdc_rotate_left_uc(0xAB, 8) == 0xAB, "");
+_Static_assert(stdc_rotate_right_uc(0xAB, 8) == 0xAB, "");
+_Static_assert(stdc_rotate_left_us(0x1234, 16) == 0x1234, "");
+_Static_assert(stdc_rotate_right_us(0x1234, 16) == 0x1234, "");
+_Static_assert(stdc_rotate_left_ui(0x12345678U, 32) == 0x12345678U, "");
+_Static_assert(stdc_rotate_right_ui(0x12345678U, 32) == 0x12345678U, "");
+_Static_assert(stdc_rotate_left_ull(0x123456789ABCDEF0ULL, 64) == 0x123456789ABCDEF0ULL, "");
+_Static_assert(stdc_rotate_right_ull(0x123456789ABCDEF0ULL, 64) == 0x123456789ABCDEF0ULL, "");
+
+_Static_assert(stdc_rotate_left_uc(0xB1, 11) == stdc_rotate_left_uc(0xB1, 3), "");
+_Static_assert(stdc_rotate_right_uc(0xB1, 11) == stdc_rotate_right_uc(0xB1, 3), "");
+_Static_assert(stdc_rotate_left_us(0x1234, 20) == stdc_rotate_left_us(0x1234, 4), "");
+_Static_assert(stdc_rotate_right_us(0x1234, 20) == stdc_rotate_right_us(0x1234, 4), "");
+_Static_assert(stdc_rotate_left_ui(0x12345678U, 40) == stdc_rotate_left_ui(0x12345678U, 8), "");
+_Static_assert(stdc_rotate_right_ui(0x12345678U, 40) == stdc_rotate_right_ui(0x12345678U, 8), "");
+_Static_assert(stdc_rotate_left_ull(0x123456789ABCDEF0ULL, 80) == stdc_rotate_left_ull(0x123456789ABCDEF0ULL, 16), "");
+_Static_assert(stdc_rotate_right_ull(0x123456789ABCDEF0ULL, 80) == stdc_rotate_right_ull(0x123456789ABCDEF0ULL, 16), "");
+
+_Static_assert(stdc_rotate_left_uc(0, 3) == 0, "");
+_Static_assert(stdc_rotate_right_ui(0U, 7) == 0U, "");
+
+_Static_assert(stdc_rotate_left_uc(0xFF, 3) == 0xFF, "");
+_Static_assert(stdc_rotate_right_ull(0xFFFFFFFFFFFFFFFFULL, 7) == 0xFFFFFFFFFFFFFFFFULL, "");
+
+_Static_assert(stdc_rotate_left_uc(0x80, 1) == 0x01, "");
+_Static_assert(stdc_rotate_right_uc(0x01, 1) == 0x80, "");
+_Static_assert(stdc_rotate_left_us(0x8000, 1) == 0x0001, "");
+_Static_assert(stdc_rotate_right_us(0x0001, 1) == 0x8000, "");
+_Static_assert(stdc_rotate_left_ui(0x80000000U, 1) == 0x00000001U, "");
+_Static_assert(stdc_rotate_right_ui(0x00000001U, 1) == 0x80000000U, "");
+_Static_assert(stdc_rotate_left_ull(0x8000000000000000ULL, 1) == 0x0000000000000001ULL, "");
+_Static_assert(stdc_rotate_right_ull(0x0000000000000001ULL, 1) == 0x8000000000000000ULL, "");
+
+enum { ULONG_WIDTH = __SIZEOF_LONG__ * 8 };
+_Static_assert(stdc_rotate_left_ul(0UL, 3) == 0UL, "");
+_Static_assert(stdc_rotate_right_ul(0UL, 3) == 0UL, "");
+_Static_assert(stdc_rotate_left_ul(~0UL, 5) == ~0UL, "");
+_Static_assert(stdc_rotate_right_ul(~0UL, 5) == ~0UL, "");
+_Static_assert(stdc_rotate_left_ul(1UL, ULONG_WIDTH - 1) == (1UL << (ULONG_WIDTH - 1)), "");
+_Static_assert(stdc_rotate_right_ul(1UL << (ULONG_WIDTH - 1), ULONG_WIDTH - 1) == 1UL, "");
+_Static_assert(stdc_rotate_left_ul(1UL, ULONG_WIDTH) == 1UL, "");
+_Static_assert(stdc_rotate_right_ul(1UL, ULONG_WIDTH) == 1UL, "");
+
+void test_typed_variant_errors(void) {
+ stdc_rotate_left_uc(0xAB); // expected-error {{too few arguments to function call}}
+ stdc_rotate_left_uc(0xAB, 1, 2); // expected-error {{too many arguments to function call}}
+ stdc_rotate_right_ui(0x12345678U); // expected-error {{too few arguments to function call}}
+ stdc_rotate_right_ui(0x12345678U, 1, 2); // expected-error {{too many arguments to function call}}
+ stdc_rotate_left_ull(0xFFULL); // expected-error {{too few arguments to function call}}
+ stdc_rotate_right_ull(0xFFULL, 1, 2); // expected-error {{too many arguments to function call}}
+}
+#endif
+#endif
More information about the cfe-commits
mailing list