[clang] 3f5c25f - [clang] Implement C2y stdc_memreverse8 and stdc_memreverse8u{8,16,32,64} builtins (#197358)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Jun 8 06:30:04 PDT 2026
Author: NagaChaitanya Vellanki
Date: 2026-06-08T09:29:58-04:00
New Revision: 3f5c25fbe2d87e197b137bd8287715f120f11275
URL: https://github.com/llvm/llvm-project/commit/3f5c25fbe2d87e197b137bd8287715f120f11275
DIFF: https://github.com/llvm/llvm-project/commit/3f5c25fbe2d87e197b137bd8287715f120f11275.diff
LOG: [clang] Implement C2y stdc_memreverse8 and stdc_memreverse8u{8,16,32,64} builtins (#197358)
Implements the C2y <stdbit.h> memory reversal functions stdc_memreverse8
and stdc_memreverse8u{8,16,32,64}. The typed variants lower to
llvm.bswap and support constexpr evaluation.
Added:
clang/test/CodeGen/builtin-stdc-memreverse8.c
clang/test/Sema/builtin-stdc-memreverse8.c
Modified:
clang/docs/ReleaseNotes.rst
clang/include/clang/Basic/Builtins.def
clang/include/clang/Basic/Builtins.td
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/lib/AST/ASTContext.cpp
clang/lib/AST/ByteCode/InterpBuiltin.cpp
clang/lib/AST/ExprConstant.cpp
clang/lib/CodeGen/CGBuiltin.cpp
clang/lib/Sema/SemaChecking.cpp
clang/test/CodeGen/Inputs/stdbit.h
clang/test/Sema/Inputs/stdbit.h
clang/test/TableGen/target-builtins-prototype-parser.td
clang/utils/TableGen/ClangBuiltinsEmitter.cpp
Removed:
################################################################################
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index f8bb0b48e2512..aebd60e1646d6 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -232,6 +232,11 @@ C2y Feature Support
``stdc_rotate_left_{uc,us,ui,ul,ull}`` and
``stdc_rotate_right_{uc,us,ui,ul,ull}``.
+- Implemented C2y ``<stdbit.h>`` memory reversal functions:
+ ``__builtin_stdc_memreverse8`` / ``stdc_memreverse8`` (in-place byte
+ reversal of a byte array) and ``stdc_memreverse8u{8,16,32,64}`` (byte-swap
+ of an exact-width unsigned integer value, usable in constant expressions).
+
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.def b/clang/include/clang/Basic/Builtins.def
index 0e94b0bba4e32..77fca0a7ad8c1 100644
--- a/clang/include/clang/Basic/Builtins.def
+++ b/clang/include/clang/Basic/Builtins.def
@@ -50,6 +50,8 @@
// L -> long (e.g. Li for 'long int', Ld for 'long double')
// LL -> long long (e.g. LLi for 'long long int', LLd for __float128)
// LLL -> __int128_t (e.g. LLLi)
+// B -> int8_t (byte-width integer, e.g. Bi for 'int8_t', UBi for 'uint8_t')
+// T -> int16_t (short-width integer, e.g. Ti for 'int16_t', UTi for 'uint16_t')
// Z -> int32_t (require a native 32-bit integer type on the target)
// W -> int64_t (require a native 64-bit integer type on the target)
// N -> 'int' size if target is LP64, 'L' otherwise.
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 8d2a824ef5610..e7fb43be8794e 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -34,6 +34,10 @@ class IntBitUtilTemplate : Template<
"unsigned long int", "unsigned long long int"],
["_uc", "_us", "_ui", "_ul", "_ull"]>;
+class MemReverse8Template : Template<
+ ["uint8_t", "uint16_t", "uint32_t", "uint64_t"],
+ ["u8", "u16", "u32", "u64"]>;
+
class MSInt8_16_32Template : Template<["char", "short", "msint32_t"],
["8", "16", ""]>;
@@ -986,6 +990,19 @@ def StdcRotateRightTyped : LibBuiltin<"stdbit.h", "C2Y_LANG">, IntBitUtilTemplat
let Prototype = "T(T, unsigned int)";
}
+def StdcMemReverse8: LibBuiltin<"stdbit.h", "C2Y_LANG"> {
+ let Spellings = ["stdc_memreverse8"];
+ let Attributes = [NoThrow, NonNull<NonOptimizing, [1]>];
+ let Prototype = "void(size_t, unsigned char*)";
+ let AddBuiltinPrefixedAlias = 1;
+}
+
+def StdcMemReverse8Typed : LibBuiltin<"stdbit.h", "C2Y_LANG">, MemReverse8Template {
+ let Spellings = ["stdc_memreverse8"];
+ let Attributes = [NoThrow, Pure, Const, Constexpr];
+ let Prototype = "T(T)";
+}
+
// Random GCC builtins
// FIXME: The builtins marked FunctionWithBuiltinPrefix below should be
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 4e3585b7b8191..423482fd08b27 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -11530,6 +11530,8 @@ def err_builtin_setjmp_unsupported : Error<
def err_builtin_longjmp_invalid_val : Error<
"argument to __builtin_longjmp must be a constant 1">;
def err_builtin_requires_language : Error<"'%0' is only available in %1">;
+def err_builtin_requires_char_bit_8 : Error<
+ "'%0' is only available on targets where 'CHAR_BIT == 8'">;
def err_constant_integer_arg_type : Error<
"argument to %0 must be a constant integer">;
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 96fa5c4551c47..4ac41985b50c5 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -12583,6 +12583,7 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context,
// Modifiers.
int HowLong = 0;
bool Signed = false, Unsigned = false;
+ bool IsChar = false, IsShort = false;
RequiresICE = false;
// Read the prefixed modifiers first.
@@ -12606,8 +12607,29 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context,
assert(!Unsigned && "Can't use 'U' modifier multiple times!");
Unsigned = true;
break;
+ case 'B':
+ // This modifier represents int8 type (byte-width).
+ assert(!IsSpecial &&
+ "Can't use two 'N', 'W', 'Z', 'O', 'B', or 'T' modifiers!");
+ assert(HowLong == 0 && "Can't use both 'L' and 'B' modifiers!");
+#ifndef NDEBUG
+ IsSpecial = true;
+#endif
+ IsChar = true;
+ break;
+ case 'T':
+ // This modifier represents int16 type (short-width).
+ assert(!IsSpecial &&
+ "Can't use two 'N', 'W', 'Z', 'O', 'B', or 'T' modifiers!");
+ assert(HowLong == 0 && "Can't use both 'L' and 'T' modifiers!");
+#ifndef NDEBUG
+ IsSpecial = true;
+#endif
+ IsShort = true;
+ break;
case 'L':
- assert(!IsSpecial && "Can't use 'L' with 'W', 'N', 'Z' or 'O' modifiers");
+ assert(!IsSpecial &&
+ "Can't use 'L' with 'W', 'N', 'Z', 'O', 'B', or 'T' modifiers");
assert(HowLong <= 2 && "Can't have LLLL modifier");
++HowLong;
break;
@@ -12723,7 +12745,11 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context,
Type = Context.ShortTy;
break;
case 'i':
- if (HowLong == 3)
+ if (IsChar)
+ Type = Unsigned ? Context.UnsignedCharTy : Context.SignedCharTy;
+ else if (IsShort)
+ Type = Unsigned ? Context.UnsignedShortTy : Context.ShortTy;
+ else if (HowLong == 3)
Type = Unsigned ? Context.UnsignedInt128Ty : Context.Int128Ty;
else if (HowLong == 2)
Type = Unsigned ? Context.UnsignedLongLongTy : Context.LongLongTy;
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index 501c7f76a0376..9b76cdb75ef70 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -4957,6 +4957,10 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
case Builtin::BI__builtin_bswap16:
case Builtin::BI__builtin_bswap32:
case Builtin::BI__builtin_bswap64:
+ case Builtin::BIstdc_memreverse8u8:
+ case Builtin::BIstdc_memreverse8u16:
+ case Builtin::BIstdc_memreverse8u32:
+ case Builtin::BIstdc_memreverse8u64:
return interp__builtin_bswap(S, OpPC, Frame, Call);
case Builtin::BI__atomic_always_lock_free:
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 33df4cab06e7c..f574443dad8c3 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -16562,7 +16562,11 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
case Builtin::BI__builtin_bswapg:
case Builtin::BI__builtin_bswap16:
case Builtin::BI__builtin_bswap32:
- case Builtin::BI__builtin_bswap64: {
+ case Builtin::BI__builtin_bswap64:
+ case Builtin::BIstdc_memreverse8u8:
+ case Builtin::BIstdc_memreverse8u16:
+ case Builtin::BIstdc_memreverse8u32:
+ case Builtin::BIstdc_memreverse8u64: {
APSInt Val;
if (!EvaluateInteger(E->getArg(0), Val, Info))
return false;
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 0cb5f95049789..d77b94af9221b 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -4230,6 +4230,41 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
return RValue::get(Phi);
}
+ // stdc_memreverse8u8 is a no-op (single byte, nothing to swap).
+ case Builtin::BIstdc_memreverse8u8:
+ return RValue::get(EmitScalarExpr(E->getArg(0)));
+
+ case Builtin::BIstdc_memreverse8u16:
+ case Builtin::BIstdc_memreverse8u32:
+ case Builtin::BIstdc_memreverse8u64:
+ return RValue::get(
+ emitBuiltinWithOneOverloadedType<1>(*this, E, Intrinsic::bswap));
+
+ case Builtin::BIstdc_memreverse8:
+ case Builtin::BI__builtin_stdc_memreverse8: {
+ Expr::EvalResult R;
+ if (E->getArg(0)->EvaluateAsInt(R, getContext())) {
+ uint64_t Size = R.Val.getInt().getZExtValue();
+ if (Size <= 1) {
+ EmitIgnoredExpr(E->getArg(1));
+ return RValue::get(nullptr);
+ }
+ if (Size == 2 || Size == 4 || Size == 8) {
+ llvm::Type *IntTy = Builder.getIntNTy(Size * 8);
+ Address PtrAddr = EmitPointerWithAlignment(E->getArg(1));
+ Address Addr = PtrAddr.withElementType(IntTy);
+ Value *Val = Builder.CreateLoad(Addr);
+ Function *F = CGM.getIntrinsic(Intrinsic::bswap, IntTy);
+ Value *Swapped = Builder.CreateCall(F, Val);
+ Builder.CreateStore(Swapped, Addr);
+ return RValue::get(nullptr);
+ }
+ }
+
+ // General case: fall back to the library function stdc_memreverse8.
+ break;
+ }
+
case Builtin::BI__builtin_constant_p: {
llvm::Type *ResultType = ConvertType(E->getType());
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 324cd46556767..1e513ff875aec 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -3933,6 +3933,19 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
return ExprError();
break;
+ case Builtin::BI__builtin_stdc_memreverse8:
+ case Builtin::BIstdc_memreverse8:
+ case Builtin::BIstdc_memreverse8u8:
+ case Builtin::BIstdc_memreverse8u16:
+ case Builtin::BIstdc_memreverse8u32:
+ case Builtin::BIstdc_memreverse8u64:
+ if (Context.getTargetInfo().getCharWidth() != 8) {
+ Diag(TheCall->getBeginLoc(), diag::err_builtin_requires_char_bit_8)
+ << TheCall->getDirectCallee()->getName();
+ return ExprError();
+ }
+ break;
+
case Builtin::BI__builtin_stdc_bit_floor:
case Builtin::BI__builtin_stdc_bit_ceil:
if (BuiltinStdCBuiltin(*this, TheCall, QualType()))
diff --git a/clang/test/CodeGen/Inputs/stdbit.h b/clang/test/CodeGen/Inputs/stdbit.h
index bdabb9ec8ee7d..170d3fdb382c3 100644
--- a/clang/test/CodeGen/Inputs/stdbit.h
+++ b/clang/test/CodeGen/Inputs/stdbit.h
@@ -112,4 +112,10 @@ 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);
+void stdc_memreverse8(__SIZE_TYPE__, unsigned char *);
+__UINT8_TYPE__ stdc_memreverse8u8(__UINT8_TYPE__);
+__UINT16_TYPE__ stdc_memreverse8u16(__UINT16_TYPE__);
+__UINT32_TYPE__ stdc_memreverse8u32(__UINT32_TYPE__);
+__UINT64_TYPE__ stdc_memreverse8u64(__UINT64_TYPE__);
+
#endif
diff --git a/clang/test/CodeGen/builtin-stdc-memreverse8.c b/clang/test/CodeGen/builtin-stdc-memreverse8.c
new file mode 100644
index 0000000000000..b49dd3ac6ed49
--- /dev/null
+++ b/clang/test/CodeGen/builtin-stdc-memreverse8.c
@@ -0,0 +1,107 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -std=c2y -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -std=c2y -isystem %S/Inputs -DTEST_C2Y_LIB_SPELLINGS %s -emit-llvm -o - | FileCheck %s --check-prefix=C2Y
+
+#ifndef TEST_C2Y_LIB_SPELLINGS
+
+// N=0 and N=1: no-op, no library call or bswap emitted.
+// CHECK-LABEL: test_memreverse8_const0
+// CHECK-NOT: call void @stdc_memreverse8
+void test_memreverse8_const0(unsigned char *p) {
+ __builtin_stdc_memreverse8(0, p);
+}
+
+// CHECK-LABEL: test_memreverse8_const1
+// CHECK-NOT: call void @stdc_memreverse8
+void test_memreverse8_const1(unsigned char *p) {
+ __builtin_stdc_memreverse8(1, p);
+}
+
+// N=0 and N=1 with side effects: pointer argument is evaluated but no reversal.
+// CHECK-LABEL: test_memreverse8_sideeffect_n0
+// CHECK: getelementptr
+// CHECK: store ptr
+// CHECK-NOT: call void @stdc_memreverse8
+unsigned char *gp;
+void test_memreverse8_sideeffect_n0(void) {
+ __builtin_stdc_memreverse8(0, gp++);
+}
+
+// CHECK-LABEL: test_memreverse8_sideeffect_n1
+// CHECK: getelementptr
+// CHECK: store ptr
+// CHECK-NOT: call void @stdc_memreverse8
+void test_memreverse8_sideeffect_n1(void) {
+ __builtin_stdc_memreverse8(1, gp++);
+}
+
+// N=2, 4, 8: lowered to a single bswap with unaligned load/store.
+// CHECK-LABEL: test_memreverse8_const2
+// CHECK: load i16, ptr {{.*}}, align 1
+// CHECK: call i16 @llvm.bswap.i16
+// CHECK: store i16 {{.*}}, ptr {{.*}}, align 1
+void test_memreverse8_const2(unsigned char *p) {
+ __builtin_stdc_memreverse8(2, p);
+}
+
+// CHECK-LABEL: test_memreverse8_const4
+// CHECK: load i32, ptr {{.*}}, align 1
+// CHECK: call i32 @llvm.bswap.i32
+// CHECK: store i32 {{.*}}, ptr {{.*}}, align 1
+void test_memreverse8_const4(unsigned char *p) {
+ __builtin_stdc_memreverse8(4, p);
+}
+
+// CHECK-LABEL: test_memreverse8_const8
+// CHECK: load i64, ptr {{.*}}, align 1
+// CHECK: call i64 @llvm.bswap.i64
+// CHECK: store i64 {{.*}}, ptr {{.*}}, align 1
+void test_memreverse8_const8(unsigned char *p) {
+ __builtin_stdc_memreverse8(8, p);
+}
+
+// Constant N=3: not bswap-optimized, falls back to library call.
+// CHECK-LABEL: test_memreverse8_const3
+// CHECK: call void @stdc_memreverse8(
+// CHECK-NOT: @llvm.bswap
+void test_memreverse8_const3(unsigned char *p) {
+ __builtin_stdc_memreverse8(3, p);
+}
+
+// Runtime N: falls back to library call.
+// CHECK-LABEL: test_memreverse8_runtime
+// CHECK: call void @stdc_memreverse8(
+void test_memreverse8_runtime(__SIZE_TYPE__ n, unsigned char *p) {
+ __builtin_stdc_memreverse8(n, p);
+}
+
+#endif // !TEST_C2Y_LIB_SPELLINGS
+
+#ifdef TEST_C2Y_LIB_SPELLINGS
+#include <stdbit.h>
+
+// u8 is a no-op: single byte, nothing to swap.
+// C2Y-LABEL: test_typed_memreverse8u8
+// C2Y-NOT: @llvm.bswap
+unsigned char test_typed_memreverse8u8(unsigned char x) {
+ return stdc_memreverse8u8(x);
+}
+
+// C2Y-LABEL: test_typed_memreverse8u16
+// C2Y: call i16 @llvm.bswap.i16
+unsigned short test_typed_memreverse8u16(unsigned short x) {
+ return stdc_memreverse8u16(x);
+}
+
+// C2Y-LABEL: test_typed_memreverse8u32
+// C2Y: call i32 @llvm.bswap.i32
+unsigned int test_typed_memreverse8u32(unsigned int x) {
+ return stdc_memreverse8u32(x);
+}
+
+// C2Y-LABEL: test_typed_memreverse8u64
+// C2Y: call i64 @llvm.bswap.i64
+__UINT64_TYPE__ test_typed_memreverse8u64(__UINT64_TYPE__ x) {
+ return stdc_memreverse8u64(x);
+}
+
+#endif // TEST_C2Y_LIB_SPELLINGS
diff --git a/clang/test/Sema/Inputs/stdbit.h b/clang/test/Sema/Inputs/stdbit.h
index bdabb9ec8ee7d..170d3fdb382c3 100644
--- a/clang/test/Sema/Inputs/stdbit.h
+++ b/clang/test/Sema/Inputs/stdbit.h
@@ -112,4 +112,10 @@ 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);
+void stdc_memreverse8(__SIZE_TYPE__, unsigned char *);
+__UINT8_TYPE__ stdc_memreverse8u8(__UINT8_TYPE__);
+__UINT16_TYPE__ stdc_memreverse8u16(__UINT16_TYPE__);
+__UINT32_TYPE__ stdc_memreverse8u32(__UINT32_TYPE__);
+__UINT64_TYPE__ stdc_memreverse8u64(__UINT64_TYPE__);
+
#endif
diff --git a/clang/test/Sema/builtin-stdc-memreverse8.c b/clang/test/Sema/builtin-stdc-memreverse8.c
new file mode 100644
index 0000000000000..6b0017ab7540c
--- /dev/null
+++ b/clang/test/Sema/builtin-stdc-memreverse8.c
@@ -0,0 +1,84 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -std=c2y -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -std=c2y -isystem %S/Inputs -fsyntax-only -verify %s
+
+void test_errors(void) {
+ unsigned char buf[4];
+
+ __builtin_stdc_memreverse8(4); // expected-error {{too few arguments to function call}}
+ __builtin_stdc_memreverse8(4, buf, buf); // expected-error {{too many arguments to function call}}
+}
+
+void test_null_pointer(void) {
+ __builtin_stdc_memreverse8(4, 0); // expected-warning {{null passed to a callee that requires a non-null argument}}
+ __builtin_stdc_memreverse8(4, (unsigned char *)0); // expected-warning {{null passed to a callee that requires a non-null argument}}
+}
+
+void test_uintN_pointer_types(void) {
+ __UINT8_TYPE__ *p8 = 0;
+ __UINT16_TYPE__ *p16 = 0;
+ __UINT32_TYPE__ *p32 = 0;
+ __UINT64_TYPE__ *p64 = 0;
+
+ __builtin_stdc_memreverse8(4, p8); // uint8_t* == unsigned char*, no diagnostic
+ __builtin_stdc_memreverse8(4, p16); // expected-error {{incompatible pointer types}}
+ __builtin_stdc_memreverse8(4, p32); // expected-error {{incompatible pointer types}}
+ __builtin_stdc_memreverse8(4, p64); // expected-error {{incompatible pointer types}}
+}
+
+void test_pointer_types(void) {
+ char *cp = 0;
+ int *ip = 0;
+ void *vp = 0;
+ const unsigned char *ccp = 0;
+ signed char *scp = 0;
+ unsigned char **ucpp = 0;
+
+ __builtin_stdc_memreverse8(4, cp); // expected-warning {{converts between pointers to integer types}}
+ __builtin_stdc_memreverse8(4, ip); // expected-error {{incompatible pointer types}}
+ __builtin_stdc_memreverse8(4, vp); // void* implicitly converts, no diagnostic
+ __builtin_stdc_memreverse8(4, ccp); // expected-warning {{discards qualifiers}}
+ __builtin_stdc_memreverse8(4, scp); // expected-warning {{converts between pointers to integer types}}
+ __builtin_stdc_memreverse8(4, ucpp); // expected-error {{incompatible pointer types}}
+}
+
+#ifdef __has_include
+#if __has_include(<stdbit.h>)
+#include <stdbit.h>
+
+_Static_assert(stdc_memreverse8u8(0xAB) == 0xAB, "");
+_Static_assert(stdc_memreverse8u16(0x1234) == 0x3412, "");
+_Static_assert(stdc_memreverse8u32(0x12345678U) == 0x78563412U, "");
+_Static_assert(stdc_memreverse8u64(0x123456789ABCDEF0ULL) == 0xF0DEBC9A78563412ULL, "");
+
+_Static_assert(stdc_memreverse8u16(0) == 0, "");
+_Static_assert(stdc_memreverse8u32(0) == 0, "");
+_Static_assert(stdc_memreverse8u64(0) == 0, "");
+_Static_assert(stdc_memreverse8u16(0xFFFF) == 0xFFFF, "");
+_Static_assert(stdc_memreverse8u32(0xFFFFFFFFU) == 0xFFFFFFFFU, "");
+_Static_assert(stdc_memreverse8u64(0xFFFFFFFFFFFFFFFFULL) == 0xFFFFFFFFFFFFFFFFULL, "");
+
+_Static_assert(stdc_memreverse8u16(stdc_memreverse8u16(0x1234)) == 0x1234, "");
+_Static_assert(stdc_memreverse8u32(stdc_memreverse8u32(0x12345678U)) == 0x12345678U, "");
+_Static_assert(stdc_memreverse8u64(stdc_memreverse8u64(0x123456789ABCDEF0ULL)) == 0x123456789ABCDEF0ULL, "");
+_Static_assert(stdc_memreverse8u8(0xAB) == 0xAB, "");
+_Static_assert(stdc_memreverse8u16(0xDEAD) == 0xADDE, "");
+_Static_assert(stdc_memreverse8u32(0xDEADBEEFU) == 0xEFBEADDEU, "");
+_Static_assert(stdc_memreverse8u64(0x0102030405060708ULL) == 0x0807060504030201ULL, "");
+
+_Static_assert(stdc_memreverse8u8(0xAA) == 0xAA, "");
+_Static_assert(stdc_memreverse8u16(0xABAB) == 0xABAB, "");
+_Static_assert(stdc_memreverse8u32(0xABCDCDABU) == 0xABCDCDABU, "");
+_Static_assert(stdc_memreverse8u64(0x0102030404030201ULL) == 0x0102030404030201ULL, "");
+
+void test_typed_variant_errors(void) {
+ stdc_memreverse8u8(); // expected-error {{too few arguments to function call}}
+ stdc_memreverse8u8(1, 2); // expected-error {{too many arguments to function call}}
+ stdc_memreverse8u16(); // expected-error {{too few arguments to function call}}
+ stdc_memreverse8u16(1, 2); // expected-error {{too many arguments to function call}}
+ stdc_memreverse8u32(); // expected-error {{too few arguments to function call}}
+ stdc_memreverse8u32(1, 2); // expected-error {{too many arguments to function call}}
+ stdc_memreverse8u64(); // expected-error {{too few arguments to function call}}
+ stdc_memreverse8u64(1, 2); // expected-error {{too many arguments to function call}}
+}
+#endif
+#endif
diff --git a/clang/test/TableGen/target-builtins-prototype-parser.td b/clang/test/TableGen/target-builtins-prototype-parser.td
index ea22b8ed626eb..0fa1246a01008 100644
--- a/clang/test/TableGen/target-builtins-prototype-parser.td
+++ b/clang/test/TableGen/target-builtins-prototype-parser.td
@@ -75,6 +75,18 @@ def : Builtin {
let Spellings = ["__builtin_11"];
}
+def : Builtin {
+// CHECK: Builtin::Info{{.*}} __builtin_12 {{.*}} /* UBiUTiUZiUWi */
+ let Prototype = "uint8_t(uint16_t, uint32_t, uint64_t)";
+ let Spellings = ["__builtin_12"];
+}
+
+def : Builtin {
+// CHECK: Builtin::Info{{.*}} __builtin_13 {{.*}} /* BiTiZiWi */
+ let Prototype = "int8_t(int16_t, int32_t, int64_t)";
+ let Spellings = ["__builtin_13"];
+}
+
#ifdef ERROR_EXPECTED_LANES
def : Builtin {
// ERROR_EXPECTED_LANES: :[[# @LINE + 1]]:7: error: Expected number of lanes after '_ExtVector<'
diff --git a/clang/utils/TableGen/ClangBuiltinsEmitter.cpp b/clang/utils/TableGen/ClangBuiltinsEmitter.cpp
index c2e38c0d6aeb8..4f7f437bcf73c 100644
--- a/clang/utils/TableGen/ClangBuiltinsEmitter.cpp
+++ b/clang/utils/TableGen/ClangBuiltinsEmitter.cpp
@@ -359,6 +359,8 @@ class PrototypeParser {
.Case("float", "f")
.Case("id", "G")
.Case("int", "i")
+ .Case("int8_t", "Bi")
+ .Case("int16_t", "Ti")
.Case("int32_t", "Zi")
.Case("int64_t", "Wi")
.Case("jmp_buf", "J")
@@ -372,6 +374,8 @@ class PrototypeParser {
.Case("sigjmp_buf", "SJ")
.Case("size_t", "z")
.Case("ucontext_t", "K")
+ .Case("uint8_t", "UBi")
+ .Case("uint16_t", "UTi")
.Case("uint32_t", "UZi")
.Case("uint64_t", "UWi")
.Case("void", "v")
More information about the cfe-commits
mailing list