llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: NagaChaitanya Vellanki (chaitanyav)
<details>
<summary>Changes</summary>
Implement all 32 stdc_load8_* functions from C2y:
stdc_load8_le{u,s}{8,16,32,64}
stdc_load8_be{u,s}{8,16,32,64}
stdc_load8_aligned_le{u,s}{8,16,32,64}
stdc_load8_aligned_be{u,s}{8,16,32,64}
These functions read N bytes from a const unsigned char* and assemble them into
a signed or unsigned integer using little-endian or big-endian byte order.
Constexpr evaluation is supported in both the AST and bytecode interpreters
using the §7.18.21 formula directly. Runtime code generation emits an integer
load followed by llvm.bswap when the requested byte order differs from the
target endianness; 8-bit variants never need a swap.
---
Patch is 30.65 KiB, truncated to 20.00 KiB below, full version:
https://github.com/llvm/llvm-project/pull/203666.diff
8 Files Affected:
- (modified) clang/docs/ReleaseNotes.rst (+7)
- (modified) clang/include/clang/Basic/Builtins.td (+56)
- (modified) clang/lib/AST/ByteCode/InterpBuiltin.cpp (+103)
- (modified) clang/lib/AST/ExprConstant.cpp (+102)
- (modified) clang/lib/CodeGen/CGBuiltin.cpp (+86)
- (added) clang/test/CodeGen/builtin-stdc-load8.c (+97)
- (modified) clang/test/Sema/Inputs/stdbit.h (+40)
- (added) clang/test/Sema/constexpr-builtin-stdc-load8.c (+110)
``````````diff
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index a984982d1bd41..3f2e785009b15 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -238,6 +238,13 @@ C2y Feature Support
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).
+- Implemented the C2y ``<stdbit.h>`` endian-aware 8-bit load functions
+ (``stdc_load8_le``, ``stdc_load8_be``, ``stdc_load8_aligned_le``,
+ ``stdc_load8_aligned_be``, and their signed counterparts) with constexpr
+ evaluation support. These functions read N bytes from a
+ ``const unsigned char *`` and assemble them into an integer using
+ little-endian or big-endian byte order.
+
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 25abd1f36539e..d8ba856cf7296 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -38,6 +38,14 @@ class MemReverse8Template : Template<
["uint8_t", "uint16_t", "uint32_t", "uint64_t"],
["u8", "u16", "u32", "u64"]>;
+class Load8UnsignedTemplate : Template<
+ ["uint8_t", "uint16_t", "uint32_t", "uint64_t"],
+ ["8", "16", "32", "64"]>;
+
+class Load8SignedTemplate : Template<
+ ["int8_t", "int16_t", "int32_t", "int64_t"],
+ ["8", "16", "32", "64"]>;
+
class MSInt8_16_32Template : Template<["char", "short", "msint32_t"],
["8", "16", ""]>;
@@ -1003,6 +1011,54 @@ def StdcMemReverse8Typed : LibBuiltin<"stdbit.h",
"C2Y_LANG">, MemReverse8Templa
let Prototype = "T(T)";
}
+def StdcLoad8LeU : LibBuiltin<"stdbit.h", "C2Y_LANG">, Load8UnsignedTemplate {
+ let Spellings = ["stdc_load8_leu"];
+ let Attributes = [NoThrow, Pure, Constexpr, NonNull<NonOptimizing, [0]>];
+ let Prototype = "T(unsigned char const*)";
+}
+
+def StdcLoad8BeU : LibBuiltin<"stdbit.h", "C2Y_LANG">, Load8UnsignedTemplate {
+ let Spellings = ["stdc_load8_beu"];
+ let Attributes = [NoThrow, Pure, Constexpr, NonNull<NonOptimizing, [0]>];
+ let Prototype = "T(unsigned char const*)";
+}
+
+def StdcLoad8AlignedLeU : LibBuiltin<"stdbit.h", "C2Y_LANG">,
Load8UnsignedTemplate {
+ let Spellings = ["stdc_load8_aligned_leu"];
+ let Attributes = [NoThrow, Pure, Constexpr, NonNull<NonOptimizing, [0]>];
+ let Prototype = "T(unsigned char const*)";
+}
+
+def StdcLoad8AlignedBeU : LibBuiltin<"stdbit.h", "C2Y_LANG">,
Load8UnsignedTemplate {
+ let Spellings = ["stdc_load8_aligned_beu"];
+ let Attributes = [NoThrow, Pure, Constexpr, NonNull<NonOptimizing, [0]>];
+ let Prototype = "T(unsigned char const*)";
+}
+
+def StdcLoad8LeS : LibBuiltin<"stdbit.h", "C2Y_LANG">, Load8SignedTemplate {
+ let Spellings = ["stdc_load8_les"];
+ let Attributes = [NoThrow, Pure, Constexpr, NonNull<NonOptimizing, [0]>];
+ let Prototype = "T(unsigned char const*)";
+}
+
+def StdcLoad8BeS : LibBuiltin<"stdbit.h", "C2Y_LANG">, Load8SignedTemplate {
+ let Spellings = ["stdc_load8_bes"];
+ let Attributes = [NoThrow, Pure, Constexpr, NonNull<NonOptimizing, [0]>];
+ let Prototype = "T(unsigned char const*)";
+}
+
+def StdcLoad8AlignedLeS : LibBuiltin<"stdbit.h", "C2Y_LANG">,
Load8SignedTemplate {
+ let Spellings = ["stdc_load8_aligned_les"];
+ let Attributes = [NoThrow, Pure, Constexpr, NonNull<NonOptimizing, [0]>];
+ let Prototype = "T(unsigned char const*)";
+}
+
+def StdcLoad8AlignedBeS : LibBuiltin<"stdbit.h", "C2Y_LANG">,
Load8SignedTemplate {
+ let Spellings = ["stdc_load8_aligned_bes"];
+ let Attributes = [NoThrow, Pure, Constexpr, NonNull<NonOptimizing, [0]>];
+ let Prototype = "T(unsigned char const*)";
+}
+
// Random GCC builtins
// FIXME: The builtins marked FunctionWithBuiltinPrefix below should be
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index 5f8681ef38492..cdc4e6006e56a 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -2058,6 +2058,73 @@ static bool isOneByteCharacterType(QualType T) {
return T->isCharType() || T->isChar8Type();
}
+static bool interp__builtin_load8(InterpState &S, CodePtr OpPC,
+ const InterpFrame *Frame,
+ const CallExpr *Call, bool IsBigEndian) {
+ Pointer Ptr = S.Stk.pop<Pointer>();
+
+ if (Ptr.isZero()) {
+ S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_null)
+ << AK_Read;
+ return false;
+ }
+
+ if (!isReadable(Ptr) && !Ptr.isOnePastEnd())
+ return false;
+
+ const Descriptor *Desc = Ptr.getFieldDesc();
+ bool IsArray = Desc->isArray();
+ QualType ElemTy = IsArray ? Desc->getElemQualType() : Desc->getType();
+
+ if (!isOneByteCharacterType(ElemTy)) {
+ S.FFDiag(S.Current->getSource(OpPC),
+ diag::note_constexpr_memchr_unsupported)
+ <<
S.getASTContext().BuiltinInfo.getQuotedName(Call->getBuiltinCallee())
+ << ElemTy;
+ return false;
+ }
+
+ if (IsArray)
+ Ptr = Ptr.expand();
+
+ size_t BaseIdx = Ptr.getIndex();
+ size_t ArraySize = Ptr.getNumElems();
+ size_t RemainingElems = ArraySize - BaseIdx;
+
+ unsigned ByteWidth = S.getASTContext().getTypeSize(Call->getType()) / 8;
+ if (ByteWidth > RemainingElems) {
+ if (IsArray)
+ S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
+ << (uint64_t)(BaseIdx + ByteWidth - 1) << /*array*/ 0
+ << (uint64_t)ArraySize;
+ else
+ S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
+ << (uint64_t)(BaseIdx + ByteWidth - 1) << /*non-array*/ 1;
+ return false;
+ }
+
+ PrimType ElemT = *S.getContext().classify(ElemTy);
+ unsigned BitWidth = ByteWidth * 8;
+ APInt Result = APInt::getZero(BitWidth);
+
+ // C2y §7.18.21: result = sum(b_index * 2^(8*index)) for index in [0, N/8)
+ // where b_index = ptr[index] (LE) or ptr[N/8 - index - 1] (BE).
+ for (unsigned I = 0; I < ByteWidth; ++I) {
+ size_t SrcIdx = IsBigEndian ? (ByteWidth - I - 1) : I;
+ Pointer BytePtr = Ptr.atIndex(BaseIdx + SrcIdx);
+ if (!CheckLoad(S, OpPC, BytePtr, AK_Read))
+ return false;
+ uint64_t B;
+ INT_TYPE_SWITCH_NO_BOOL(
+ ElemT, { B = static_cast<uint64_t>(BytePtr.deref<T>().toUnsigned());
});
+ Result |= APInt(BitWidth, B) << (8 * I);
+ }
+
+ bool IsSigned = Call->getType()->isSignedIntegerType();
+ pushInteger(S, APSInt(Result, !IsSigned), Call->getType());
+ return true;
+}
+
static bool interp__builtin_memcmp(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const CallExpr *Call, unsigned ID) {
@@ -4975,6 +5042,42 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC,
const CallExpr *Call,
case Builtin::BIstdc_memreverse8u64:
return interp__builtin_bswap(S, OpPC, Frame, Call);
+ case Builtin::BIstdc_load8_leu8:
+ case Builtin::BIstdc_load8_leu16:
+ case Builtin::BIstdc_load8_leu32:
+ case Builtin::BIstdc_load8_leu64:
+ case Builtin::BIstdc_load8_les8:
+ case Builtin::BIstdc_load8_les16:
+ case Builtin::BIstdc_load8_les32:
+ case Builtin::BIstdc_load8_les64:
+ case Builtin::BIstdc_load8_aligned_leu8:
+ case Builtin::BIstdc_load8_aligned_leu16:
+ case Builtin::BIstdc_load8_aligned_leu32:
+ case Builtin::BIstdc_load8_aligned_leu64:
+ case Builtin::BIstdc_load8_aligned_les8:
+ case Builtin::BIstdc_load8_aligned_les16:
+ case Builtin::BIstdc_load8_aligned_les32:
+ case Builtin::BIstdc_load8_aligned_les64:
+ return interp__builtin_load8(S, OpPC, Frame, Call, /*IsBigEndian=*/false);
+
+ case Builtin::BIstdc_load8_beu8:
+ case Builtin::BIstdc_load8_beu16:
+ case Builtin::BIstdc_load8_beu32:
+ case Builtin::BIstdc_load8_beu64:
+ case Builtin::BIstdc_load8_bes8:
+ case Builtin::BIstdc_load8_bes16:
+ case Builtin::BIstdc_load8_bes32:
+ case Builtin::BIstdc_load8_bes64:
+ case Builtin::BIstdc_load8_aligned_beu8:
+ case Builtin::BIstdc_load8_aligned_beu16:
+ case Builtin::BIstdc_load8_aligned_beu32:
+ case Builtin::BIstdc_load8_aligned_beu64:
+ case Builtin::BIstdc_load8_aligned_bes8:
+ case Builtin::BIstdc_load8_aligned_bes16:
+ case Builtin::BIstdc_load8_aligned_bes32:
+ case Builtin::BIstdc_load8_aligned_bes64:
+ return interp__builtin_load8(S, OpPC, Frame, Call, /*IsBigEndian=*/true);
+
case Builtin::BI__atomic_always_lock_free:
case Builtin::BI__atomic_is_lock_free:
return interp__builtin_atomic_lock_free(S, OpPC, Frame, Call, BuiltinID);
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 1642c41a99a2f..0bf869bc89644 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -16599,6 +16599,108 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const
CallExpr *E,
return Success(Val.byteSwap(), E);
}
+ case Builtin::BIstdc_load8_leu8:
+ case Builtin::BIstdc_load8_leu16:
+ case Builtin::BIstdc_load8_leu32:
+ case Builtin::BIstdc_load8_leu64:
+ case Builtin::BIstdc_load8_les8:
+ case Builtin::BIstdc_load8_les16:
+ case Builtin::BIstdc_load8_les32:
+ case Builtin::BIstdc_load8_les64:
+ case Builtin::BIstdc_load8_aligned_leu8:
+ case Builtin::BIstdc_load8_aligned_leu16:
+ case Builtin::BIstdc_load8_aligned_leu32:
+ case Builtin::BIstdc_load8_aligned_leu64:
+ case Builtin::BIstdc_load8_aligned_les8:
+ case Builtin::BIstdc_load8_aligned_les16:
+ case Builtin::BIstdc_load8_aligned_les32:
+ case Builtin::BIstdc_load8_aligned_les64:
+ case Builtin::BIstdc_load8_beu8:
+ case Builtin::BIstdc_load8_beu16:
+ case Builtin::BIstdc_load8_beu32:
+ case Builtin::BIstdc_load8_beu64:
+ case Builtin::BIstdc_load8_bes8:
+ case Builtin::BIstdc_load8_bes16:
+ case Builtin::BIstdc_load8_bes32:
+ case Builtin::BIstdc_load8_bes64:
+ case Builtin::BIstdc_load8_aligned_beu8:
+ case Builtin::BIstdc_load8_aligned_beu16:
+ case Builtin::BIstdc_load8_aligned_beu32:
+ case Builtin::BIstdc_load8_aligned_beu64:
+ case Builtin::BIstdc_load8_aligned_bes8:
+ case Builtin::BIstdc_load8_aligned_bes16:
+ case Builtin::BIstdc_load8_aligned_bes32:
+ case Builtin::BIstdc_load8_aligned_bes64: {
+ bool IsBE = BuiltinOp == Builtin::BIstdc_load8_beu8 ||
+ BuiltinOp == Builtin::BIstdc_load8_beu16 ||
+ BuiltinOp == Builtin::BIstdc_load8_beu32 ||
+ BuiltinOp == Builtin::BIstdc_load8_beu64 ||
+ BuiltinOp == Builtin::BIstdc_load8_bes8 ||
+ BuiltinOp == Builtin::BIstdc_load8_bes16 ||
+ BuiltinOp == Builtin::BIstdc_load8_bes32 ||
+ BuiltinOp == Builtin::BIstdc_load8_bes64 ||
+ BuiltinOp == Builtin::BIstdc_load8_aligned_beu8 ||
+ BuiltinOp == Builtin::BIstdc_load8_aligned_beu16 ||
+ BuiltinOp == Builtin::BIstdc_load8_aligned_beu32 ||
+ BuiltinOp == Builtin::BIstdc_load8_aligned_beu64 ||
+ BuiltinOp == Builtin::BIstdc_load8_aligned_bes8 ||
+ BuiltinOp == Builtin::BIstdc_load8_aligned_bes16 ||
+ BuiltinOp == Builtin::BIstdc_load8_aligned_bes32 ||
+ BuiltinOp == Builtin::BIstdc_load8_aligned_bes64;
+
+ LValue Ptr;
+ if (!EvaluatePointer(E->getArg(0), Ptr, Info))
+ return false;
+
+ if (!Ptr.checkNullPointerForFoldAccess(Info, E, AK_Read) ||
+ Ptr.Designator.Invalid)
+ return false;
+
+ QualType CharTy = Ptr.Designator.getType(Info.Ctx);
+ if (!isOneByteCharacterType(CharTy)) {
+ Info.FFDiag(E, diag::note_constexpr_memchr_unsupported)
+ << Info.Ctx.BuiltinInfo.getQuotedName(E->getBuiltinCallee())
+ << CharTy;
+ return false;
+ }
+
+ unsigned ByteWidth = Info.Ctx.getTypeSize(E->getType()) / 8;
+ uint64_t RemainingElems = Ptr.Designator.validIndexAdjustments().second;
+ if (ByteWidth > RemainingElems) {
+ uint64_t ArrayIndex =
+ Ptr.Designator.MostDerivedIsArrayElement
+ ? Ptr.Designator.Entries.back().getAsArrayIndex()
+ : (uint64_t)Ptr.Designator.IsOnePastTheEnd;
+ APSInt Index = APSInt::get(ArrayIndex + ByteWidth - 1);
+ Ptr.Designator.diagnosePointerArithmetic(Info, E, Index);
+ return false;
+ }
+
+ // Load bytes sequentially, then assemble per C2y §7.18.21:
+ // result = sum(b_index * 2^(8*index)) where b_index = ptr[index] (LE)
+ // or ptr[N/8 - index - 1] (BE).
+ SmallVector<uint64_t, 8> Bytes(ByteWidth);
+ LValue BytePtr = Ptr;
+ for (unsigned I = 0; I < ByteWidth; ++I) {
+ APValue ByteVal;
+ if (!handleLValueToRValueConversion(Info, E, CharTy, BytePtr, ByteVal))
+ return false;
+ Bytes[I] = ByteVal.getInt().getZExtValue();
+ if (I + 1 < ByteWidth)
+ if (!HandleLValueArrayAdjustment(Info, E, BytePtr, CharTy, 1))
+ return false;
+ }
+
+ APInt Result = APInt::getZero(ByteWidth * 8);
+ for (unsigned I = 0; I < ByteWidth; ++I) {
+ unsigned SrcIdx = IsBE ? (ByteWidth - I - 1) : I;
+ Result |= APInt(ByteWidth * 8, Bytes[SrcIdx]) << (8 * I);
+ }
+
+ bool IsSigned = E->getType()->isSignedIntegerType();
+ return Success(APSInt(Result, !IsSigned), E);
+ }
+
case Builtin::BI__builtin_classify_type:
return Success((int)EvaluateBuiltinClassifyType(E, Info.getLangOpts()), E);
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 682b125890fe1..2357eda318e67 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -4213,6 +4213,92 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl
GD, unsigned BuiltinID,
break;
}
+ // stdc_load8_*: load N bytes from a const unsigned char* and assemble
+ // into an integer using little-endian or big-endian byte order.
+ case Builtin::BIstdc_load8_leu8:
+ case Builtin::BIstdc_load8_les8:
+ case Builtin::BIstdc_load8_beu8:
+ case Builtin::BIstdc_load8_bes8:
+ case Builtin::BIstdc_load8_aligned_leu8:
+ case Builtin::BIstdc_load8_aligned_les8:
+ case Builtin::BIstdc_load8_aligned_beu8:
+ case Builtin::BIstdc_load8_aligned_bes8:
+ case Builtin::BIstdc_load8_leu16:
+ case Builtin::BIstdc_load8_les16:
+ case Builtin::BIstdc_load8_beu16:
+ case Builtin::BIstdc_load8_bes16:
+ case Builtin::BIstdc_load8_aligned_leu16:
+ case Builtin::BIstdc_load8_aligned_les16:
+ case Builtin::BIstdc_load8_aligned_beu16:
+ case Builtin::BIstdc_load8_aligned_bes16:
+ case Builtin::BIstdc_load8_leu32:
+ case Builtin::BIstdc_load8_les32:
+ case Builtin::BIstdc_load8_beu32:
+ case Builtin::BIstdc_load8_bes32:
+ case Builtin::BIstdc_load8_aligned_leu32:
+ case Builtin::BIstdc_load8_aligned_les32:
+ case Builtin::BIstdc_load8_aligned_beu32:
+ case Builtin::BIstdc_load8_aligned_bes32:
+ case Builtin::BIstdc_load8_leu64:
+ case Builtin::BIstdc_load8_les64:
+ case Builtin::BIstdc_load8_beu64:
+ case Builtin::BIstdc_load8_bes64:
+ case Builtin::BIstdc_load8_aligned_leu64:
+ case Builtin::BIstdc_load8_aligned_les64:
+ case Builtin::BIstdc_load8_aligned_beu64:
+ case Builtin::BIstdc_load8_aligned_bes64: {
+ bool IsBE = BuiltinID == Builtin::BIstdc_load8_beu8 ||
+ BuiltinID == Builtin::BIstdc_load8_bes8 ||
+ BuiltinID == Builtin::BIstdc_load8_beu16 ||
+ BuiltinID == Builtin::BIstdc_load8_bes16 ||
+ BuiltinID == Builtin::BIstdc_load8_beu32 ||
+ BuiltinID == Builtin::BIstdc_load8_bes32 ||
+ BuiltinID == Builtin::BIstdc_load8_beu64 ||
+ BuiltinID == Builtin::BIstdc_load8_bes64 ||
+ BuiltinID == Builtin::BIstdc_load8_aligned_beu8 ||
+ BuiltinID == Builtin::BIstdc_load8_aligned_bes8 ||
+ BuiltinID == Builtin::BIstdc_load8_aligned_beu16 ||
+ BuiltinID == Builtin::BIstdc_load8_aligned_bes16 ||
+ BuiltinID == Builtin::BIstdc_load8_aligned_beu32 ||
+ BuiltinID == Builtin::BIstdc_load8_aligned_bes32 ||
+ BuiltinID == Builtin::BIstdc_load8_aligned_beu64 ||
+ BuiltinID == Builtin::BIstdc_load8_aligned_bes64;
+ bool IsAligned = BuiltinID == Builtin::BIstdc_load8_aligned_leu8 ||
+ BuiltinID == Builtin::BIstdc_load8_aligned_les8 ||
+ BuiltinID == Builtin::BIstdc_load8_aligned_beu8 ||
+ BuiltinID == Builtin::BIstdc_load8_aligned_bes8 ||
+ BuiltinID == Builtin::BIstdc_load8_aligned_leu16 ||
+ BuiltinID == Builtin::BIstdc_load8_aligned_les16 ||
+ BuiltinID == Builtin::BIstdc_load8_aligned_beu16 ||
+ BuiltinID == Builtin::BIstdc_load8_aligned_bes16 ||
+ BuiltinID == Builtin::BIstdc_load8_aligned_leu32 ||
+ BuiltinID == Builtin::BIstdc_load8_aligned_les32 ||
+ BuiltinID == Builtin::BIstdc_load8_aligned_beu32 ||
+ BuiltinID == Builtin::BIstdc_load8_aligned_bes32 ||
+ BuiltinID == Builtin::BIstdc_load8_aligned_leu64 ||
+ BuiltinID == Builtin::BIstdc_load8_aligned_les64 ||
+ BuiltinID == Builtin::BIstdc_load8_aligned_beu64 ||
+ BuiltinID == Builtin::BIstdc_load8_aligned_bes64;
+
+ llvm::Type *IntTy = ConvertType(E->getType());
+ unsigned BitWidth = IntTy->getIntegerBitWidth();
+ assert(
+ (BitWidth == 8 || BitWidth == 16 || BitWidth == 32 || BitWidth == 64)
&&
+ "unexpected bit width for stdc_load8_*");
+ CharUnits Alignment = IsAligned
+ ? getContext().getTypeAlignInChars(E->getType())
+ : CharUnits::One();
+ Address Addr =
+ EmitPointerWithAlignment(E->getArg(0)).withAlignment(Alignment);
+ Addr = Addr.withElementType(IntTy);
+ Value *Val = Builder.CreateLoad(Addr);
+ if ((BitWidth == 16 || BitWidth == 32 || BitWidth == 64) &&
+ IsBE != getTarget().isBigEndian())
+ Val = Builder.CreateCall(CGM.getIntrinsic(Intrinsic::bswap, IntTy), Val);
+
+ return RValue::get(Val);
+ }
+
case Builtin::BI__builtin_constant_p: {
llvm::Type *ResultType = ConvertType(E->getType());
diff --git a/clang/test/CodeGen/builtin-stdc-load8.c
b/clang/test/CodeGen/builtin-stdc-load8.c
new file mode 100644
index 0000000000000..88424c7bbda01
--- /dev/null
+++ b/clang/test/CodeGen/builtin-stdc-load8.c
@@ -0,0 +1,97 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -std=c2y -isystem
%S/../Sema/Inputs -emit-llvm -o - %s | FileCheck %s --check-prefix=LE
+// RUN: %clang_cc1 -triple s390x-unknown-unknown -std=c2y -isystem
%S/../Sema/Inputs -emit-llvm -o - %s | FileCheck %s --check-prefix=BE
+
+#include <stdbit.h>
+
+// 8-bit: single byte load, no bswap on either target.
+// LE-LABEL: test_leu8
+// LE: load i8, ptr {{.*}}, align 1
+// LE-NOT: bswap
+// BE-LABEL: test_leu8
+// BE: load i8, ptr {{.*}}, align 1
+// BE-NOT: bswap
+__UINT8_TYPE__ test_leu8(const unsigned char *p) { return stdc_load8_leu8(p); }
+
+// LE load on LE target: no bswap. On BE target: bswap needed.
+// LE-LABEL: test_leu16
+// LE: load i16, ptr {{.*}}, align 1
+// LE-NOT: bswap
+// BE-LABEL: test_leu16
+// BE: load i16, ptr {{.*}}, align 1
+// BE: call i16 @llvm.bswap.i16
+__UINT16_TYPE__ test_leu16(const unsigned char *p) { return
stdc_load8_leu16(p); }
+
+// LE-LABEL: test_leu32
+// LE: load i32, ptr {{.*}}, align 1
+// LE-NOT: bswap
+// BE-LABEL: test_leu32
+// BE: load i32, ptr {{.*}}, align 1
+// BE: call i32 @llvm.bswap.i32
+__UINT32_TYPE__ test_leu32(const unsigned char *p) { return
stdc_load8_leu32(p); }
+
+// LE-LABEL: test_leu64
+// LE: load i64, ptr {{.*}}, align 1
+// LE-NOT: bswap
+// BE-LABEL: test_leu64
+// BE: load i64, ptr {{.*}}, align 1
+// BE: call i64 @llvm.bswap.i64
+__UINT64_TYPE__ test_leu64(const unsigned char *p) { return
stdc_load8_leu64(p); }
+
+// BE load on LE target: bswap needed. On BE target: no bswap.
+// LE-LABEL: test_beu16
+// LE: load i16, ptr {{.*}}, align 1
+// LE: call i16 @llvm.bswap.i16
+// BE-LABEL: test_beu16
+// BE: load i16, ptr {{.*}}, align 1
+// BE-NOT: bswap
+__UINT16_TYPE__ test_beu16(const unsigned char *p) { return stdc_l...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/203666
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits