[clang] Implement C2y stdc_memreverse8 and stdc_memreverse8u{8,16,32,64} builtins#197358
[clang] Implement C2y stdc_memreverse8 and stdc_memreverse8u{8,16,32,64} builtins#197358chaitanyav wants to merge 3 commits into
Conversation
|
@llvm/pr-subscribers-clang-codegen @llvm/pr-subscribers-clang Author: NagaChaitanya Vellanki (chaitanyav) ChangesImplements 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. Full diff: https://github.com/llvm/llvm-project/pull/197358.diff 11 Files Affected:
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 4b0eb5b9d8505..85d21e549cd65 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -182,6 +182,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.td b/clang/include/clang/Basic/Builtins.td
index 40ec94ab75046..1a9c5facfd43e 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<
+ ["unsigned char", "unsigned short", "uint32_t", "uint64_t"],
+ ["u8", "u16", "u32", "u64"]>;
+
class MSInt8_16_32Template : Template<["char", "short", "msint32_t"],
["8", "16", ""]>;
@@ -986,6 +990,18 @@ def StdcRotateRightTyped : LibBuiltin<"stdbit.h", "C2Y_LANG">, IntBitUtilTemplat
let Prototype = "T(T, unsigned int)";
}
+def StdcMemReverse8: Builtin {
+ let Spellings = ["__builtin_stdc_memreverse8"];
+ let Attributes = [NoThrow, NonNull<NonOptimizing, [1]>];
+ let Prototype = "void(size_t, unsigned char*)";
+}
+
+def StdcMemReverse8Typed : LibBuiltin<"stdbit.h", "C2Y_LANG">, MemReverse8Template {
+ let Spellings = ["stdc_memreverse8"];
+ let Attributes = [NoThrow, 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 5c225dc56ddd8..0647036d8c1df 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -11512,6 +11512,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/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index e05c9aed39b14..f19d2aca4e70c 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -4953,6 +4953,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 5f09c9ea4a7b8..9da83fb0b3016 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -16483,7 +16483,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 1f97c67f26c8e..16f99975be64a 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3949,6 +3949,64 @@ 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::BI__builtin_stdc_memreverse8: {
+ Value *N = EmitScalarExpr(E->getArg(0));
+ Value *Ptr = EmitScalarExpr(E->getArg(1));
+
+ if (auto *CI = dyn_cast<ConstantInt>(N)) {
+ uint64_t Size = CI->getZExtValue();
+ if (Size == 2 || Size == 4 || Size == 8) {
+ llvm::Type *IntTy = Builder.getIntNTy(Size * 8);
+ CharUnits Align = CharUnits::One();
+ Address Addr(Ptr, IntTy, Align);
+ 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: emit a loop swapping ptr[i] and ptr[n-i-1].
+ BasicBlock *EntryBB = Builder.GetInsertBlock();
+ BasicBlock *LoopBB = createBasicBlock("memreverse8.loop", CurFn);
+ BasicBlock *AfterBB = createBasicBlock("memreverse8.after", CurFn);
+ Value *Half = Builder.CreateLShr(N, ConstantInt::get(N->getType(), 1));
+ Value *IsEmpty =
+ Builder.CreateICmpEQ(Half, ConstantInt::get(Half->getType(), 0));
+ Builder.CreateCondBr(IsEmpty, AfterBB, LoopBB);
+
+ Builder.SetInsertPoint(LoopBB);
+ PHINode *Idx = Builder.CreatePHI(Half->getType(), 2, "i");
+ Idx->addIncoming(ConstantInt::get(Half->getType(), 0), EntryBB);
+ Value *J = Builder.CreateSub(Builder.CreateSub(N, Idx),
+ ConstantInt::get(N->getType(), 1));
+ Address AddrI(Builder.CreateGEP(Int8Ty, Ptr, Idx), Int8Ty,
+ CharUnits::One());
+ Address AddrJ(Builder.CreateGEP(Int8Ty, Ptr, J), Int8Ty, CharUnits::One());
+ Value *XI = Builder.CreateLoad(AddrI);
+ Value *XJ = Builder.CreateLoad(AddrJ);
+ Builder.CreateStore(XJ, AddrI);
+ Builder.CreateStore(XI, AddrJ);
+ Value *Next = Builder.CreateAdd(Idx, ConstantInt::get(Half->getType(), 1));
+ Idx->addIncoming(Next, LoopBB);
+ Value *Done = Builder.CreateICmpEQ(Next, Half);
+ Builder.CreateCondBr(Done, AfterBB, LoopBB);
+
+ Builder.SetInsertPoint(AfterBB);
+ return RValue::get(nullptr);
+ }
+
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 530587208cce8..685298d33ddb8 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -3863,6 +3863,18 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
return ExprError();
break;
+ case Builtin::BI__builtin_stdc_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..ca8b87deb67e3 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 *);
+unsigned char stdc_memreverse8u8(unsigned char);
+unsigned short stdc_memreverse8u16(unsigned short);
+__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..730f29bb9664a
--- /dev/null
+++ b/clang/test/CodeGen/builtin-stdc-memreverse8.c
@@ -0,0 +1,96 @@
+// 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: IsEmpty folds to true, branch to after without entering loop.
+// CHECK-LABEL: test_memreverse8_const0
+// CHECK: br i1 true,
+void test_memreverse8_const0(unsigned char *p) {
+ __builtin_stdc_memreverse8(0, p);
+}
+
+// CHECK-LABEL: test_memreverse8_const1
+// CHECK: br i1 true,
+void test_memreverse8_const1(unsigned char *p) {
+ __builtin_stdc_memreverse8(1, p);
+}
+
+// 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 the loop.
+// CHECK-LABEL: test_memreverse8_const3
+// CHECK: br i1 false,
+// CHECK-NOT: @llvm.bswap
+void test_memreverse8_const3(unsigned char *p) {
+ __builtin_stdc_memreverse8(3, p);
+}
+
+// CHECK-LABEL: test_memreverse8_runtime
+// CHECK: lshr
+// CHECK: memreverse8.loop:
+// CHECK: getelementptr
+// CHECK: getelementptr
+// CHECK: load i8
+// CHECK: load i8
+// CHECK: store i8
+// CHECK: store i8
+// CHECK: memreverse8.after:
+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..ca8b87deb67e3 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 *);
+unsigned char stdc_memreverse8u8(unsigned char);
+unsigned short stdc_memreverse8u16(unsigned short);
+__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
|
| ["_uc", "_us", "_ui", "_ul", "_ull"]>; | ||
|
|
||
| class MemReverse8Template : Template< | ||
| ["unsigned char", "unsigned short", "uint32_t", "uint64_t"], |
There was a problem hiding this comment.
It's a bit interesting to see uint32_t but unsigned char instead of uint8_t, do we not support the smaller bit widths here?
There was a problem hiding this comment.
i am seeing this build error when using uint8_t
/home/naga/llvm-project/clang/include/clang/Basic/Builtins.td:1002:7: error: Unknown Type: uint8_t
let Prototype = "T(T)";There was a problem hiding this comment.
That's because we haven't added support for them yet, but I think we should if we intend to use them:
WDYT @efriedma-quic ?
There was a problem hiding this comment.
It doesn't have much practical impact, but it's probably worth trying to be consistent with the C standard definitions, sure.
| def StdcMemReverse8: Builtin { | ||
| let Spellings = ["__builtin_stdc_memreverse8"]; | ||
| let Attributes = [NoThrow, NonNull<NonOptimizing, [1]>]; | ||
| let Prototype = "void(size_t, unsigned char*)"; |
There was a problem hiding this comment.
I think this prototype is reasonable as-is, but the official prototype is:
void stdc_memreverse8(size_t n, unsigned char ptr[static n]);
and that actually associates some good bounds information that could be used by other analyses, at least in C. Nothing to change, but it might be nice if we had a way to use the correct signature for C and fall back to the decayed signature for C++.
|
|
||
| def StdcMemReverse8: Builtin { | ||
| let Spellings = ["__builtin_stdc_memreverse8"]; | ||
| let Attributes = [NoThrow, NonNull<NonOptimizing, [1]>]; |
There was a problem hiding this comment.
Should this one also be pure?
There was a problem hiding this comment.
the function is modifying the buffer pointed to by the ptr and the return type is void
There was a problem hiding this comment.
Added Pure to the typed variants
| "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">; |
There was a problem hiding this comment.
| "'%0' is only available on targets where CHAR_BIT == 8">; | |
| "'%0' is only available on targets where 'CHAR_BIT == 8'">; |
| case Builtin::BIstdc_memreverse8u32: | ||
| case Builtin::BIstdc_memreverse8u64: | ||
| if (Context.getTargetInfo().getCharWidth() != 8) { | ||
| Diag(TheCall->getBeginLoc(), diag::err_builtin_requires_char_bit_8) |
There was a problem hiding this comment.
I agree with the code but I also don't think we have a way to test it either; we don't have options to let you control CHAR_BIT and we don't have targets that aren't 8-bit currently.
f047b1a to
5383211
Compare
🐧 Linux x64 Test Results
Failed Tests(click on a test name to see its output) lldb-apilldb-api.python_api/run_locker/TestRunLocker.pyIf these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the |
…64} builtins
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.
5383211 to
c1b9306
Compare
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.