https://github.com/chaitanyav updated 
https://github.com/llvm/llvm-project/pull/203666

>From 084ebd35986c5cee28c96c4fb0afc4e010269a67 Mon Sep 17 00:00:00 2001
From: NagaChaitanya Vellanki <[email protected]>
Date: Tue, 9 Jun 2026 12:50:57 -0700
Subject: [PATCH 1/2] [clang] Implement C2y stdc_load8_* endian-aware 8-bit
 load functions
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

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.
---
 clang/docs/ReleaseNotes.rst                   |   7 ++
 clang/include/clang/Basic/Builtins.td         |  56 +++++++++
 clang/lib/AST/ByteCode/InterpBuiltin.cpp      | 103 ++++++++++++++++
 clang/lib/AST/ExprConstant.cpp                | 102 ++++++++++++++++
 clang/lib/CodeGen/CGBuiltin.cpp               |  86 ++++++++++++++
 clang/test/CodeGen/builtin-stdc-load8.c       |  97 +++++++++++++++
 clang/test/Sema/Inputs/stdbit.h               |  40 +++++++
 .../test/Sema/constexpr-builtin-stdc-load8.c  | 110 ++++++++++++++++++
 8 files changed, 601 insertions(+)
 create mode 100644 clang/test/CodeGen/builtin-stdc-load8.c
 create mode 100644 clang/test/Sema/constexpr-builtin-stdc-load8.c

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 7828135a6edbc..0c86ff2d6c4ec 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_load8_beu16(p); }
+
+// LE-LABEL: test_beu32
+// LE: load i32, ptr {{.*}}, align 1
+// LE: call i32 @llvm.bswap.i32
+// BE-LABEL: test_beu32
+// BE: load i32, ptr {{.*}}, align 1
+// BE-NOT: bswap
+__UINT32_TYPE__ test_beu32(const unsigned char *p) { return 
stdc_load8_beu32(p); }
+
+// LE-LABEL: test_beu64
+// LE: load i64, ptr {{.*}}, align 1
+// LE: call i64 @llvm.bswap.i64
+// BE-LABEL: test_beu64
+// BE: load i64, ptr {{.*}}, align 1
+// BE-NOT: bswap
+__UINT64_TYPE__ test_beu64(const unsigned char *p) { return 
stdc_load8_beu64(p); }
+
+// Aligned variants use natural alignment instead of align 1.
+// LE-LABEL: test_aligned_leu32
+// LE: load i32, ptr {{.*}}, align 4
+// LE-NOT: bswap
+// BE-LABEL: test_aligned_leu32
+// BE: load i32, ptr {{.*}}, align 4
+// BE: call i32 @llvm.bswap.i32
+__UINT32_TYPE__ test_aligned_leu32(const unsigned char *p) { return 
stdc_load8_aligned_leu32(p); }
+
+// LE-LABEL: test_aligned_beu32
+// LE: load i32, ptr {{.*}}, align 4
+// LE: call i32 @llvm.bswap.i32
+// BE-LABEL: test_aligned_beu32
+// BE: load i32, ptr {{.*}}, align 4
+// BE-NOT: bswap
+__UINT32_TYPE__ test_aligned_beu32(const unsigned char *p) { return 
stdc_load8_aligned_beu32(p); }
+
+// Signed variants: same load+bswap logic, result type is signed.
+// LE-LABEL: test_les32
+// LE: load i32, ptr {{.*}}, align 1
+// LE-NOT: bswap
+// BE-LABEL: test_les32
+// BE: load i32, ptr {{.*}}, align 1
+// BE: call i32 @llvm.bswap.i32
+__INT32_TYPE__ test_les32(const unsigned char *p) { return 
stdc_load8_les32(p); }
+
+// LE-LABEL: test_bes32
+// LE: load i32, ptr {{.*}}, align 1
+// LE: call i32 @llvm.bswap.i32
+// BE-LABEL: test_bes32
+// BE: load i32, ptr {{.*}}, align 1
+// BE-NOT: bswap
+__INT32_TYPE__ test_bes32(const unsigned char *p) { return 
stdc_load8_bes32(p); }
diff --git a/clang/test/Sema/Inputs/stdbit.h b/clang/test/Sema/Inputs/stdbit.h
index 170d3fdb382c3..8200a9e7f3a90 100644
--- a/clang/test/Sema/Inputs/stdbit.h
+++ b/clang/test/Sema/Inputs/stdbit.h
@@ -118,4 +118,44 @@ __UINT16_TYPE__ stdc_memreverse8u16(__UINT16_TYPE__);
 __UINT32_TYPE__ stdc_memreverse8u32(__UINT32_TYPE__);
 __UINT64_TYPE__ stdc_memreverse8u64(__UINT64_TYPE__);
 
+__UINT8_TYPE__ stdc_load8_leu8(const unsigned char *);
+__UINT16_TYPE__ stdc_load8_leu16(const unsigned char *);
+__UINT32_TYPE__ stdc_load8_leu32(const unsigned char *);
+__UINT64_TYPE__ stdc_load8_leu64(const unsigned char *);
+
+__UINT8_TYPE__ stdc_load8_beu8(const unsigned char *);
+__UINT16_TYPE__ stdc_load8_beu16(const unsigned char *);
+__UINT32_TYPE__ stdc_load8_beu32(const unsigned char *);
+__UINT64_TYPE__ stdc_load8_beu64(const unsigned char *);
+
+__UINT8_TYPE__ stdc_load8_aligned_leu8(const unsigned char *);
+__UINT16_TYPE__ stdc_load8_aligned_leu16(const unsigned char *);
+__UINT32_TYPE__ stdc_load8_aligned_leu32(const unsigned char *);
+__UINT64_TYPE__ stdc_load8_aligned_leu64(const unsigned char *);
+
+__UINT8_TYPE__ stdc_load8_aligned_beu8(const unsigned char *);
+__UINT16_TYPE__ stdc_load8_aligned_beu16(const unsigned char *);
+__UINT32_TYPE__ stdc_load8_aligned_beu32(const unsigned char *);
+__UINT64_TYPE__ stdc_load8_aligned_beu64(const unsigned char *);
+
+__INT8_TYPE__ stdc_load8_les8(const unsigned char *);
+__INT16_TYPE__ stdc_load8_les16(const unsigned char *);
+__INT32_TYPE__ stdc_load8_les32(const unsigned char *);
+__INT64_TYPE__ stdc_load8_les64(const unsigned char *);
+
+__INT8_TYPE__ stdc_load8_bes8(const unsigned char *);
+__INT16_TYPE__ stdc_load8_bes16(const unsigned char *);
+__INT32_TYPE__ stdc_load8_bes32(const unsigned char *);
+__INT64_TYPE__ stdc_load8_bes64(const unsigned char *);
+
+__INT8_TYPE__ stdc_load8_aligned_les8(const unsigned char *);
+__INT16_TYPE__ stdc_load8_aligned_les16(const unsigned char *);
+__INT32_TYPE__ stdc_load8_aligned_les32(const unsigned char *);
+__INT64_TYPE__ stdc_load8_aligned_les64(const unsigned char *);
+
+__INT8_TYPE__ stdc_load8_aligned_bes8(const unsigned char *);
+__INT16_TYPE__ stdc_load8_aligned_bes16(const unsigned char *);
+__INT32_TYPE__ stdc_load8_aligned_bes32(const unsigned char *);
+__INT64_TYPE__ stdc_load8_aligned_bes64(const unsigned char *);
+
 #endif
diff --git a/clang/test/Sema/constexpr-builtin-stdc-load8.c 
b/clang/test/Sema/constexpr-builtin-stdc-load8.c
new file mode 100644
index 0000000000000..2661089b8c901
--- /dev/null
+++ b/clang/test/Sema/constexpr-builtin-stdc-load8.c
@@ -0,0 +1,110 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -std=c2y -isystem %S/Inputs 
-fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -std=c2y -isystem %S/Inputs 
-fsyntax-only -verify %s -fexperimental-new-constant-interpreter
+#include <stdbit.h>
+
+// LE unsigned: bytes ordered LSB-first (index 0 = byte 0 of the value)
+static const unsigned char le8_u[]  = {0xAB};
+static const unsigned char le16_u[] = {0x34, 0x12};
+static const unsigned char le32_u[] = {0x78, 0x56, 0x34, 0x12};
+static const unsigned char le64_u[] = {0xF0, 0xDE, 0xBC, 0x9A, 0x78, 0x56, 
0x34, 0x12};
+
+_Static_assert(stdc_load8_leu8(le8_u)   == (__UINT8_TYPE__)0xAB,               
"");
+_Static_assert(stdc_load8_leu16(le16_u) == (__UINT16_TYPE__)0x1234,            
"");
+_Static_assert(stdc_load8_leu32(le32_u) == (__UINT32_TYPE__)0x12345678U,       
"");
+_Static_assert(stdc_load8_leu64(le64_u) == 
(__UINT64_TYPE__)0x123456789ABCDEF0ULL, "");
+
+// BE unsigned: bytes ordered MSB-first (index 0 = highest byte)
+static const unsigned char be8_u[]  = {0xAB};
+static const unsigned char be16_u[] = {0x12, 0x34};
+static const unsigned char be32_u[] = {0x12, 0x34, 0x56, 0x78};
+static const unsigned char be64_u[] = {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 
0xDE, 0xF0};
+
+_Static_assert(stdc_load8_beu8(be8_u)   == (__UINT8_TYPE__)0xAB,               
"");
+_Static_assert(stdc_load8_beu16(be16_u) == (__UINT16_TYPE__)0x1234,            
"");
+_Static_assert(stdc_load8_beu32(be32_u) == (__UINT32_TYPE__)0x12345678U,       
"");
+_Static_assert(stdc_load8_beu64(be64_u) == 
(__UINT64_TYPE__)0x123456789ABCDEF0ULL, "");
+
+// Aligned LE unsigned
+_Static_assert(stdc_load8_aligned_leu8(le8_u)   == (__UINT8_TYPE__)0xAB,       
        "");
+_Static_assert(stdc_load8_aligned_leu16(le16_u) == (__UINT16_TYPE__)0x1234,    
        "");
+_Static_assert(stdc_load8_aligned_leu32(le32_u) == 
(__UINT32_TYPE__)0x12345678U,       "");
+_Static_assert(stdc_load8_aligned_leu64(le64_u) == 
(__UINT64_TYPE__)0x123456789ABCDEF0ULL, "");
+
+// Aligned BE unsigned
+_Static_assert(stdc_load8_aligned_beu8(be8_u)   == (__UINT8_TYPE__)0xAB,       
        "");
+_Static_assert(stdc_load8_aligned_beu16(be16_u) == (__UINT16_TYPE__)0x1234,    
        "");
+_Static_assert(stdc_load8_aligned_beu32(be32_u) == 
(__UINT32_TYPE__)0x12345678U,       "");
+_Static_assert(stdc_load8_aligned_beu64(be64_u) == 
(__UINT64_TYPE__)0x123456789ABCDEF0ULL, "");
+
+// LE signed: 0x80 in u8 = -128 as s8; {0x80, 0xFF} as u16 = -128 as s16
+static const unsigned char le8_s[]  = {0x80};
+static const unsigned char le16_s[] = {0x80, 0xFF};
+static const unsigned char le32_s[] = {0x80, 0xFF, 0xFF, 0xFF};
+static const unsigned char le64_s[] = {0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
0xFF, 0xFF};
+
+_Static_assert(stdc_load8_les8(le8_s)   == (__INT8_TYPE__)-128,  "");
+_Static_assert(stdc_load8_les16(le16_s) == (__INT16_TYPE__)-128, "");
+_Static_assert(stdc_load8_les32(le32_s) == (__INT32_TYPE__)-128, "");
+_Static_assert(stdc_load8_les64(le64_s) == (__INT64_TYPE__)-128, "");
+
+// BE signed
+static const unsigned char be8_s[]  = {0x80};
+static const unsigned char be16_s[] = {0xFF, 0x80};
+static const unsigned char be32_s[] = {0xFF, 0xFF, 0xFF, 0x80};
+static const unsigned char be64_s[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
0xFF, 0x80};
+
+_Static_assert(stdc_load8_bes8(be8_s)   == (__INT8_TYPE__)-128,  "");
+_Static_assert(stdc_load8_bes16(be16_s) == (__INT16_TYPE__)-128, "");
+_Static_assert(stdc_load8_bes32(be32_s) == (__INT32_TYPE__)-128, "");
+_Static_assert(stdc_load8_bes64(be64_s) == (__INT64_TYPE__)-128, "");
+
+// Aligned LE signed
+_Static_assert(stdc_load8_aligned_les8(le8_s)   == (__INT8_TYPE__)-128,  "");
+_Static_assert(stdc_load8_aligned_les16(le16_s) == (__INT16_TYPE__)-128, "");
+_Static_assert(stdc_load8_aligned_les32(le32_s) == (__INT32_TYPE__)-128, "");
+_Static_assert(stdc_load8_aligned_les64(le64_s) == (__INT64_TYPE__)-128, "");
+
+// Aligned BE signed
+_Static_assert(stdc_load8_aligned_bes8(be8_s)   == (__INT8_TYPE__)-128,  "");
+_Static_assert(stdc_load8_aligned_bes16(be16_s) == (__INT16_TYPE__)-128, "");
+_Static_assert(stdc_load8_aligned_bes32(be32_s) == (__INT32_TYPE__)-128, "");
+_Static_assert(stdc_load8_aligned_bes64(be64_s) == (__INT64_TYPE__)-128, "");
+
+// Positive signed round-trip
+static const unsigned char le16_pos[] = {0x01, 0x00};
+static const unsigned char be16_pos[] = {0x00, 0x01};
+_Static_assert(stdc_load8_les16(le16_pos) == 1, "");
+_Static_assert(stdc_load8_bes16(be16_pos) == 1, "");
+
+// constexpr variable declarations require constexpr arrays as the source
+constexpr unsigned char cx_le32[] = {0x78, 0x56, 0x34, 0x12};
+constexpr unsigned char cx_be32[] = {0x12, 0x34, 0x56, 0x78};
+constexpr unsigned char cx_le16_s[] = {0x80, 0xFF};
+constexpr unsigned char cx_be16_s[] = {0xFF, 0x80};
+
+constexpr __UINT32_TYPE__ u32_le = stdc_load8_leu32(cx_le32);
+_Static_assert(u32_le == 0x12345678U, "");
+
+constexpr __UINT32_TYPE__ u32_be = stdc_load8_beu32(cx_be32);
+_Static_assert(u32_be == 0x12345678U, "");
+
+constexpr __INT16_TYPE__ s16_le = stdc_load8_les16(cx_le16_s);
+_Static_assert(s16_le == -128, "");
+
+constexpr __INT16_TYPE__ s16_be = stdc_load8_bes16(cx_be16_s);
+_Static_assert(s16_be == -128, "");
+
+// Null pointer is rejected (NonNull attribute)
+void test_null(void) {
+  __UINT8_TYPE__ x = stdc_load8_leu8(0); // expected-warning{{null passed to a 
callee that requires a non-null argument}}
+}
+
+// Negative: out-of-bounds, scalar, and null.
+constexpr unsigned char small[] = {0x01, 0x02};
+constexpr __UINT32_TYPE__ oob_load = stdc_load8_leu32(small); // 
expected-error{{must be initialized by a constant expression}} 
expected-note{{cannot refer to element 3 of array of 2 elements in a constant 
expression}}
+constexpr __UINT32_TYPE__ oob_mid  = stdc_load8_leu32(small + 1); // 
expected-error{{must be initialized by a constant expression}} 
expected-note{{cannot refer to element 4 of array of 2 elements in a constant 
expression}}
+
+constexpr unsigned char scalar_byte = 0x42;
+constexpr __UINT32_TYPE__ oob_scalar = stdc_load8_leu32(&scalar_byte); // 
expected-error{{must be initialized by a constant expression}} 
expected-note{{cannot refer to element 3 of non-array object in a constant 
expression}}
+
+constexpr __UINT32_TYPE__ null_ce = stdc_load8_leu32((const unsigned char 
*)0); // expected-error{{must be initialized by a constant expression}} 
expected-note{{read of dereferenced null pointer is not allowed in a constant 
expression}}

>From 81eee9e2dad01bc91342c19967fb8b92719c7745 Mon Sep 17 00:00:00 2001
From: NagaChaitanya Vellanki <[email protected]>
Date: Fri, 12 Jun 2026 21:53:28 -0700
Subject: [PATCH 2/2] Add stdc_load8 declarations to CodeGen/Inputs/stdbit.h

---
 clang/test/CodeGen/Inputs/stdbit.h      | 40 +++++++++++++++++++++++++
 clang/test/CodeGen/builtin-stdc-load8.c |  4 +--
 2 files changed, 42 insertions(+), 2 deletions(-)

diff --git a/clang/test/CodeGen/Inputs/stdbit.h 
b/clang/test/CodeGen/Inputs/stdbit.h
index 170d3fdb382c3..8200a9e7f3a90 100644
--- a/clang/test/CodeGen/Inputs/stdbit.h
+++ b/clang/test/CodeGen/Inputs/stdbit.h
@@ -118,4 +118,44 @@ __UINT16_TYPE__ stdc_memreverse8u16(__UINT16_TYPE__);
 __UINT32_TYPE__ stdc_memreverse8u32(__UINT32_TYPE__);
 __UINT64_TYPE__ stdc_memreverse8u64(__UINT64_TYPE__);
 
+__UINT8_TYPE__ stdc_load8_leu8(const unsigned char *);
+__UINT16_TYPE__ stdc_load8_leu16(const unsigned char *);
+__UINT32_TYPE__ stdc_load8_leu32(const unsigned char *);
+__UINT64_TYPE__ stdc_load8_leu64(const unsigned char *);
+
+__UINT8_TYPE__ stdc_load8_beu8(const unsigned char *);
+__UINT16_TYPE__ stdc_load8_beu16(const unsigned char *);
+__UINT32_TYPE__ stdc_load8_beu32(const unsigned char *);
+__UINT64_TYPE__ stdc_load8_beu64(const unsigned char *);
+
+__UINT8_TYPE__ stdc_load8_aligned_leu8(const unsigned char *);
+__UINT16_TYPE__ stdc_load8_aligned_leu16(const unsigned char *);
+__UINT32_TYPE__ stdc_load8_aligned_leu32(const unsigned char *);
+__UINT64_TYPE__ stdc_load8_aligned_leu64(const unsigned char *);
+
+__UINT8_TYPE__ stdc_load8_aligned_beu8(const unsigned char *);
+__UINT16_TYPE__ stdc_load8_aligned_beu16(const unsigned char *);
+__UINT32_TYPE__ stdc_load8_aligned_beu32(const unsigned char *);
+__UINT64_TYPE__ stdc_load8_aligned_beu64(const unsigned char *);
+
+__INT8_TYPE__ stdc_load8_les8(const unsigned char *);
+__INT16_TYPE__ stdc_load8_les16(const unsigned char *);
+__INT32_TYPE__ stdc_load8_les32(const unsigned char *);
+__INT64_TYPE__ stdc_load8_les64(const unsigned char *);
+
+__INT8_TYPE__ stdc_load8_bes8(const unsigned char *);
+__INT16_TYPE__ stdc_load8_bes16(const unsigned char *);
+__INT32_TYPE__ stdc_load8_bes32(const unsigned char *);
+__INT64_TYPE__ stdc_load8_bes64(const unsigned char *);
+
+__INT8_TYPE__ stdc_load8_aligned_les8(const unsigned char *);
+__INT16_TYPE__ stdc_load8_aligned_les16(const unsigned char *);
+__INT32_TYPE__ stdc_load8_aligned_les32(const unsigned char *);
+__INT64_TYPE__ stdc_load8_aligned_les64(const unsigned char *);
+
+__INT8_TYPE__ stdc_load8_aligned_bes8(const unsigned char *);
+__INT16_TYPE__ stdc_load8_aligned_bes16(const unsigned char *);
+__INT32_TYPE__ stdc_load8_aligned_bes32(const unsigned char *);
+__INT64_TYPE__ stdc_load8_aligned_bes64(const unsigned char *);
+
 #endif
diff --git a/clang/test/CodeGen/builtin-stdc-load8.c 
b/clang/test/CodeGen/builtin-stdc-load8.c
index 88424c7bbda01..a9246e0cbc1b0 100644
--- a/clang/test/CodeGen/builtin-stdc-load8.c
+++ b/clang/test/CodeGen/builtin-stdc-load8.c
@@ -1,5 +1,5 @@
-// 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
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -std=c2y -isystem %S/Inputs 
-emit-llvm -o - %s | FileCheck %s --check-prefix=LE
+// RUN: %clang_cc1 -triple s390x-unknown-unknown  -std=c2y -isystem %S/Inputs 
-emit-llvm -o - %s | FileCheck %s --check-prefix=BE
 
 #include <stdbit.h>
 

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to