[clang] [clang] Implement C2y stdc_load8_* endian-aware 8-bit load functions (PR #203666)

NagaChaitanya Vellanki via cfe-commits cfe-commits at lists.llvm.org
Tue Jul 14 15:49:03 PDT 2026


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

>From 668d5b20ec5aa083f815234565c7905c63a5f4df Mon Sep 17 00:00:00 2001
From: NagaChaitanya Vellanki <pnagato at protonmail.com>
Date: Tue, 9 Jun 2026 12:50:57 -0700
Subject: [PATCH 01/13] [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.md                    |   6 +
 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, 600 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.md b/clang/docs/ReleaseNotes.md
index 71302bb8da612..179a89dff434b 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -102,6 +102,12 @@ latest release, please see the [Clang Web Site](https://clang.llvm.org) or the
     // ...
   }
 ```
+- 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
 
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 344a712ddc585..ec7bc69877a43 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 70717720c592d..46923d1711b78 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) {
@@ -5216,6 +5283,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 7d9dba8cd33fc..1073beb9b14aa 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -16914,6 +16914,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 37846bbb0b5ec..5f2bf52e0b32e 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -4223,6 +4223,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 47ff76688faabe6fa931086fed473f634958e615 Mon Sep 17 00:00:00 2001
From: NagaChaitanya Vellanki <pnagato at protonmail.com>
Date: Thu, 25 Jun 2026 10:43:58 -0700
Subject: [PATCH 02/13] Use uint_least*_t/int_least*_t for stdc_load8_* return
 types

- C2y standard specifies stdc_load8_* functions to return
{uint,int}_least*_t types instead of {uint,int}_t types
---
 clang/include/clang/Basic/Builtins.td         |   8 +-
 clang/test/CodeGen/builtin-stdc-load8.c       | 130 +++++++++---------
 clang/test/Sema/Inputs/stdbit.h               |  78 +++++------
 .../test/Sema/constexpr-builtin-stdc-load8.c  |  82 +++++------
 clang/utils/TableGen/ClangBuiltinsEmitter.cpp |   8 ++
 5 files changed, 157 insertions(+), 149 deletions(-)

diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index ec7bc69877a43..e27f37a94fa9d 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -39,12 +39,12 @@ class MemReverse8Template : Template<
     ["u8",      "u16",      "u32",      "u64"]>;
 
 class Load8UnsignedTemplate : Template<
-    ["uint8_t", "uint16_t", "uint32_t", "uint64_t"],
-    ["8",       "16",       "32",       "64"]>;
+    ["uint_least8_t", "uint_least16_t", "uint_least32_t", "uint_least64_t"],
+    ["8",             "16",             "32",             "64"]>;
 
 class Load8SignedTemplate : Template<
-    ["int8_t", "int16_t", "int32_t", "int64_t"],
-    ["8",      "16",      "32",      "64"]>;
+    ["int_least8_t", "int_least16_t", "int_least32_t", "int_least64_t"],
+    ["8",            "16",            "32",            "64"]>;
 
 class MSInt8_16_32Template : Template<["char", "short", "msint32_t"],
                                       ["8",    "16",    ""]>;
diff --git a/clang/test/CodeGen/builtin-stdc-load8.c b/clang/test/CodeGen/builtin-stdc-load8.c
index 88424c7bbda01..6fb1dcc8cc771 100644
--- a/clang/test/CodeGen/builtin-stdc-load8.c
+++ b/clang/test/CodeGen/builtin-stdc-load8.c
@@ -4,94 +4,94 @@
 #include <stdbit.h>
 
 // 8-bit: single byte load, no bswap on either target.
-// LE-LABEL: test_leu8
-// LE: load i8, ptr {{.*}}, align 1
+// LE-LABEL: @test_leu8(
+// LE: load i8, ptr {{.+}}, align 1
 // LE-NOT: bswap
-// BE-LABEL: test_leu8
-// BE: load i8, ptr {{.*}}, align 1
+// 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); }
+__UINT_LEAST8_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-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); }
+// BE-LABEL: @test_leu16(
+// BE: load i16, ptr {{.+}}, align 1
+// BE: call i16 @llvm.bswap.i16(
+__UINT_LEAST16_TYPE__ test_leu16(const unsigned char *p) { return stdc_load8_leu16(p); }
 
-// LE-LABEL: test_leu32
-// LE: load i32, ptr {{.*}}, align 1
+// 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); }
+// BE-LABEL: @test_leu32(
+// BE: load i32, ptr {{.+}}, align 1
+// BE: call i32 @llvm.bswap.i32(
+__UINT_LEAST32_TYPE__ test_leu32(const unsigned char *p) { return stdc_load8_leu32(p); }
 
-// LE-LABEL: test_leu64
-// LE: load i64, ptr {{.*}}, align 1
+// 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-LABEL: @test_leu64(
+// BE: load i64, ptr {{.+}}, align 1
+// BE: call i64 @llvm.bswap.i64(
+__UINT_LEAST64_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
+// 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); }
+__UINT_LEAST16_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
+// 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); }
+__UINT_LEAST32_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
+// 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); }
+__UINT_LEAST64_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-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); }
+// BE-LABEL: @test_aligned_leu32(
+// BE: load i32, ptr {{.+}}, align 4
+// BE: call i32 @llvm.bswap.i32(
+__UINT_LEAST32_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
+// 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); }
+__UINT_LEAST32_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-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); }
+// BE-LABEL: @test_les32(
+// BE: load i32, ptr {{.+}}, align 1
+// BE: call i32 @llvm.bswap.i32(
+__INT_LEAST32_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
+// 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); }
+__INT_LEAST32_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 8200a9e7f3a90..9fa5ed7a655c2 100644
--- a/clang/test/Sema/Inputs/stdbit.h
+++ b/clang/test/Sema/Inputs/stdbit.h
@@ -118,44 +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 *);
+__UINT_LEAST8_TYPE__ stdc_load8_leu8(const unsigned char *);
+__UINT_LEAST16_TYPE__ stdc_load8_leu16(const unsigned char *);
+__UINT_LEAST32_TYPE__ stdc_load8_leu32(const unsigned char *);
+__UINT_LEAST64_TYPE__ stdc_load8_leu64(const unsigned char *);
+
+__UINT_LEAST8_TYPE__ stdc_load8_beu8(const unsigned char *);
+__UINT_LEAST16_TYPE__ stdc_load8_beu16(const unsigned char *);
+__UINT_LEAST32_TYPE__ stdc_load8_beu32(const unsigned char *);
+__UINT_LEAST64_TYPE__ stdc_load8_beu64(const unsigned char *);
+
+__UINT_LEAST8_TYPE__ stdc_load8_aligned_leu8(const unsigned char *);
+__UINT_LEAST16_TYPE__ stdc_load8_aligned_leu16(const unsigned char *);
+__UINT_LEAST32_TYPE__ stdc_load8_aligned_leu32(const unsigned char *);
+__UINT_LEAST64_TYPE__ stdc_load8_aligned_leu64(const unsigned char *);
+
+__UINT_LEAST8_TYPE__ stdc_load8_aligned_beu8(const unsigned char *);
+__UINT_LEAST16_TYPE__ stdc_load8_aligned_beu16(const unsigned char *);
+__UINT_LEAST32_TYPE__ stdc_load8_aligned_beu32(const unsigned char *);
+__UINT_LEAST64_TYPE__ stdc_load8_aligned_beu64(const unsigned char *);
+
+__INT_LEAST8_TYPE__ stdc_load8_les8(const unsigned char *);
+__INT_LEAST16_TYPE__ stdc_load8_les16(const unsigned char *);
+__INT_LEAST32_TYPE__ stdc_load8_les32(const unsigned char *);
+__INT_LEAST64_TYPE__ stdc_load8_les64(const unsigned char *);
+
+__INT_LEAST8_TYPE__ stdc_load8_bes8(const unsigned char *);
+__INT_LEAST16_TYPE__ stdc_load8_bes16(const unsigned char *);
+__INT_LEAST32_TYPE__ stdc_load8_bes32(const unsigned char *);
+__INT_LEAST64_TYPE__ stdc_load8_bes64(const unsigned char *);
+
+__INT_LEAST8_TYPE__ stdc_load8_aligned_les8(const unsigned char *);
+__INT_LEAST16_TYPE__ stdc_load8_aligned_les16(const unsigned char *);
+__INT_LEAST32_TYPE__ stdc_load8_aligned_les32(const unsigned char *);
+__INT_LEAST64_TYPE__ stdc_load8_aligned_les64(const unsigned char *);
+
+__INT_LEAST8_TYPE__ stdc_load8_aligned_bes8(const unsigned char *);
+__INT_LEAST16_TYPE__ stdc_load8_aligned_bes16(const unsigned char *);
+__INT_LEAST32_TYPE__ stdc_load8_aligned_bes32(const unsigned char *);
+__INT_LEAST64_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
index 2661089b8c901..beef4f6a31f8e 100644
--- a/clang/test/Sema/constexpr-builtin-stdc-load8.c
+++ b/clang/test/Sema/constexpr-builtin-stdc-load8.c
@@ -8,10 +8,10 @@ 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, "");
+_Static_assert(stdc_load8_leu8(le8_u)   == (__UINT_LEAST8_TYPE__)0xAB,               "");
+_Static_assert(stdc_load8_leu16(le16_u) == (__UINT_LEAST16_TYPE__)0x1234,            "");
+_Static_assert(stdc_load8_leu32(le32_u) == (__UINT_LEAST32_TYPE__)0x12345678U,       "");
+_Static_assert(stdc_load8_leu64(le64_u) == (__UINT_LEAST64_TYPE__)0x123456789ABCDEF0ULL, "");
 
 // BE unsigned: bytes ordered MSB-first (index 0 = highest byte)
 static const unsigned char be8_u[]  = {0xAB};
@@ -19,22 +19,22 @@ 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, "");
+_Static_assert(stdc_load8_beu8(be8_u)   == (__UINT_LEAST8_TYPE__)0xAB,               "");
+_Static_assert(stdc_load8_beu16(be16_u) == (__UINT_LEAST16_TYPE__)0x1234,            "");
+_Static_assert(stdc_load8_beu32(be32_u) == (__UINT_LEAST32_TYPE__)0x12345678U,       "");
+_Static_assert(stdc_load8_beu64(be64_u) == (__UINT_LEAST64_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, "");
+_Static_assert(stdc_load8_aligned_leu8(le8_u)   == (__UINT_LEAST8_TYPE__)0xAB,               "");
+_Static_assert(stdc_load8_aligned_leu16(le16_u) == (__UINT_LEAST16_TYPE__)0x1234,            "");
+_Static_assert(stdc_load8_aligned_leu32(le32_u) == (__UINT_LEAST32_TYPE__)0x12345678U,       "");
+_Static_assert(stdc_load8_aligned_leu64(le64_u) == (__UINT_LEAST64_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, "");
+_Static_assert(stdc_load8_aligned_beu8(be8_u)   == (__UINT_LEAST8_TYPE__)0xAB,               "");
+_Static_assert(stdc_load8_aligned_beu16(be16_u) == (__UINT_LEAST16_TYPE__)0x1234,            "");
+_Static_assert(stdc_load8_aligned_beu32(be32_u) == (__UINT_LEAST32_TYPE__)0x12345678U,       "");
+_Static_assert(stdc_load8_aligned_beu64(be64_u) == (__UINT_LEAST64_TYPE__)0x123456789ABCDEF0ULL, "");
 
 // LE signed: 0x80 in u8 = -128 as s8; {0x80, 0xFF} as u16 = -128 as s16
 static const unsigned char le8_s[]  = {0x80};
@@ -42,10 +42,10 @@ 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, "");
+_Static_assert(stdc_load8_les8(le8_s)   == (__INT_LEAST8_TYPE__)-128,  "");
+_Static_assert(stdc_load8_les16(le16_s) == (__INT_LEAST16_TYPE__)-128, "");
+_Static_assert(stdc_load8_les32(le32_s) == (__INT_LEAST32_TYPE__)-128, "");
+_Static_assert(stdc_load8_les64(le64_s) == (__INT_LEAST64_TYPE__)-128, "");
 
 // BE signed
 static const unsigned char be8_s[]  = {0x80};
@@ -53,22 +53,22 @@ 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, "");
+_Static_assert(stdc_load8_bes8(be8_s)   == (__INT_LEAST8_TYPE__)-128,  "");
+_Static_assert(stdc_load8_bes16(be16_s) == (__INT_LEAST16_TYPE__)-128, "");
+_Static_assert(stdc_load8_bes32(be32_s) == (__INT_LEAST32_TYPE__)-128, "");
+_Static_assert(stdc_load8_bes64(be64_s) == (__INT_LEAST64_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, "");
+_Static_assert(stdc_load8_aligned_les8(le8_s)   == (__INT_LEAST8_TYPE__)-128,  "");
+_Static_assert(stdc_load8_aligned_les16(le16_s) == (__INT_LEAST16_TYPE__)-128, "");
+_Static_assert(stdc_load8_aligned_les32(le32_s) == (__INT_LEAST32_TYPE__)-128, "");
+_Static_assert(stdc_load8_aligned_les64(le64_s) == (__INT_LEAST64_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, "");
+_Static_assert(stdc_load8_aligned_bes8(be8_s)   == (__INT_LEAST8_TYPE__)-128,  "");
+_Static_assert(stdc_load8_aligned_bes16(be16_s) == (__INT_LEAST16_TYPE__)-128, "");
+_Static_assert(stdc_load8_aligned_bes32(be32_s) == (__INT_LEAST32_TYPE__)-128, "");
+_Static_assert(stdc_load8_aligned_bes64(be64_s) == (__INT_LEAST64_TYPE__)-128, "");
 
 // Positive signed round-trip
 static const unsigned char le16_pos[] = {0x01, 0x00};
@@ -82,29 +82,29 @@ 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);
+constexpr __UINT_LEAST32_TYPE__ u32_le = stdc_load8_leu32(cx_le32);
 _Static_assert(u32_le == 0x12345678U, "");
 
-constexpr __UINT32_TYPE__ u32_be = stdc_load8_beu32(cx_be32);
+constexpr __UINT_LEAST32_TYPE__ u32_be = stdc_load8_beu32(cx_be32);
 _Static_assert(u32_be == 0x12345678U, "");
 
-constexpr __INT16_TYPE__ s16_le = stdc_load8_les16(cx_le16_s);
+constexpr __INT_LEAST16_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);
+constexpr __INT_LEAST16_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}}
+  __UINT_LEAST8_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 __UINT_LEAST32_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 __UINT_LEAST32_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 __UINT_LEAST32_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}}
+constexpr __UINT_LEAST32_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}}
diff --git a/clang/utils/TableGen/ClangBuiltinsEmitter.cpp b/clang/utils/TableGen/ClangBuiltinsEmitter.cpp
index 22c81522f9e41..b646db9b95834 100644
--- a/clang/utils/TableGen/ClangBuiltinsEmitter.cpp
+++ b/clang/utils/TableGen/ClangBuiltinsEmitter.cpp
@@ -381,6 +381,14 @@ class PrototypeParser {
                                .Case("uint16_t", "UTi")
                                .Case("uint32_t", "UZi")
                                .Case("uint64_t", "UWi")
+                               .Case("uint_least8_t", "UBi")
+                               .Case("uint_least16_t", "UTi")
+                               .Case("uint_least32_t", "UZi")
+                               .Case("uint_least64_t", "UWi")
+                               .Case("int_least8_t", "Bi")
+                               .Case("int_least16_t", "Ti")
+                               .Case("int_least32_t", "Zi")
+                               .Case("int_least64_t", "Wi")
                                .Case("void", "v")
                                .Case("wchar_t", "w")
                                .Case("...", ".")

>From 0a994849fc5de5040d0ee5163120b0565436832b Mon Sep 17 00:00:00 2001
From: NagaChaitanya Vellanki <pnagato at protonmail.com>
Date: Thu, 25 Jun 2026 17:00:29 -0700
Subject: [PATCH 03/13] Address review feedback for stdc_load8_* implementation

- Fix "signed counterparts" to "unsigned counterparts" in ReleaseNotes
- Remove redundant isOneByteCharacterType check; the declared const
  unsigned char * parameter already enforces this at the call site
- Add assert for CHAR_BIT == 8 in both constexpr evaluators
---
 clang/docs/ReleaseNotes.md                     |  2 +-
 clang/lib/AST/ByteCode/InterpBuiltin.cpp       | 10 ++--------
 clang/lib/AST/ExprConstant.cpp                 |  9 ++-------
 clang/test/Sema/constexpr-builtin-stdc-load8.c |  3 +++
 4 files changed, 8 insertions(+), 16 deletions(-)

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 179a89dff434b..abe9cdaefcfb4 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -104,7 +104,7 @@ latest release, please see the [Clang Web Site](https://clang.llvm.org) or the
 ```
 - 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
+  `stdc_load8_aligned_be`, and their unsigned 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.
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index 46923d1711b78..22bd119e4da97 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -2076,14 +2076,6 @@ static bool interp__builtin_load8(InterpState &S, CodePtr OpPC,
   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();
 
@@ -2091,6 +2083,8 @@ static bool interp__builtin_load8(InterpState &S, CodePtr OpPC,
   size_t ArraySize = Ptr.getNumElems();
   size_t RemainingElems = ArraySize - BaseIdx;
 
+  assert(S.getASTContext().getTargetInfo().getCharWidth() == 8 &&
+         "stdc_load8_* requires CHAR_BIT == 8");
   unsigned ByteWidth = S.getASTContext().getTypeSize(Call->getType()) / 8;
   if (ByteWidth > RemainingElems) {
     if (IsArray)
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 1073beb9b14aa..71d9a4e1805e5 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -16972,13 +16972,8 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
       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;
-    }
-
+    assert(Info.Ctx.getTargetInfo().getCharWidth() == 8 &&
+           "stdc_load8_* requires CHAR_BIT == 8");
     unsigned ByteWidth = Info.Ctx.getTypeSize(E->getType()) / 8;
     uint64_t RemainingElems = Ptr.Designator.validIndexAdjustments().second;
     if (ByteWidth > RemainingElems) {
diff --git a/clang/test/Sema/constexpr-builtin-stdc-load8.c b/clang/test/Sema/constexpr-builtin-stdc-load8.c
index beef4f6a31f8e..45cd1a8ab0595 100644
--- a/clang/test/Sema/constexpr-builtin-stdc-load8.c
+++ b/clang/test/Sema/constexpr-builtin-stdc-load8.c
@@ -108,3 +108,6 @@ constexpr unsigned char scalar_byte = 0x42;
 constexpr __UINT_LEAST32_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 __UINT_LEAST32_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}}
+
+constexpr unsigned char one[] = {0x42};
+constexpr __UINT_LEAST8_TYPE__ oob_past_end = stdc_load8_leu8(one + 1); // expected-error{{must be initialized by a constant expression}} expected-note{{cannot refer to element 1 of array of 1 element in a constant expression}}

>From 47c7afc01ed91bfb238f98123da75adb6f5bc9d4 Mon Sep 17 00:00:00 2001
From: NagaChaitanya Vellanki <pnagato at protonmail.com>
Date: Thu, 25 Jun 2026 19:36:22 -0700
Subject: [PATCH 04/13] Add tests for invalid pointer type argument

---
 clang/test/Sema/constexpr-builtin-stdc-load8.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/clang/test/Sema/constexpr-builtin-stdc-load8.c b/clang/test/Sema/constexpr-builtin-stdc-load8.c
index 45cd1a8ab0595..b4ad6ea1f1d5d 100644
--- a/clang/test/Sema/constexpr-builtin-stdc-load8.c
+++ b/clang/test/Sema/constexpr-builtin-stdc-load8.c
@@ -99,6 +99,17 @@ void test_null(void) {
   __UINT_LEAST8_TYPE__ x = stdc_load8_leu8(0); // expected-warning{{null passed to a callee that requires a non-null argument}}
 }
 
+// Wrong pointer types are rejected by the type system at the call site.
+void test_wrong_types(void) {
+  const int int_arr[] = {0};
+  const unsigned int uint_arr[] = {0};
+  const char char_arr[] = "A";
+
+  (void)stdc_load8_leu32(int_arr);  // expected-error{{incompatible pointer types}} expected-note at Inputs/stdbit.h:*{{passing argument to parameter here}}
+  (void)stdc_load8_leu32(uint_arr); // expected-error{{incompatible pointer types}} expected-note at Inputs/stdbit.h:*{{passing argument to parameter here}}
+  (void)stdc_load8_leu16(char_arr); // expected-warning{{converts between pointers to integer types}} expected-note at Inputs/stdbit.h:*{{passing argument to parameter here}}
+}
+
 // Negative: out-of-bounds, scalar, and null.
 constexpr unsigned char small[] = {0x01, 0x02};
 constexpr __UINT_LEAST32_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}}

>From 5b06b42bd2b52d4b466420f169a2c09127d98b6c Mon Sep 17 00:00:00 2001
From: NagaChaitanya Vellanki <pnagato at protonmail.com>
Date: Thu, 25 Jun 2026 20:19:39 -0700
Subject: [PATCH 05/13] Remove CHAR_BIT == 8 asserts from both interpreters,
 use the existing check in Sema for CHAR_BIT to be 8.

---
 clang/lib/AST/ByteCode/InterpBuiltin.cpp |  2 --
 clang/lib/AST/ExprConstant.cpp           |  2 --
 clang/lib/Sema/SemaChecking.cpp          | 32 ++++++++++++++++++++++++
 3 files changed, 32 insertions(+), 4 deletions(-)

diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index 22bd119e4da97..746614b420375 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -2083,8 +2083,6 @@ static bool interp__builtin_load8(InterpState &S, CodePtr OpPC,
   size_t ArraySize = Ptr.getNumElems();
   size_t RemainingElems = ArraySize - BaseIdx;
 
-  assert(S.getASTContext().getTargetInfo().getCharWidth() == 8 &&
-         "stdc_load8_* requires CHAR_BIT == 8");
   unsigned ByteWidth = S.getASTContext().getTypeSize(Call->getType()) / 8;
   if (ByteWidth > RemainingElems) {
     if (IsArray)
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 71d9a4e1805e5..244ede9502bea 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -16972,8 +16972,6 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
       return false;
 
     QualType CharTy = Ptr.Designator.getType(Info.Ctx);
-    assert(Info.Ctx.getTargetInfo().getCharWidth() == 8 &&
-           "stdc_load8_* requires CHAR_BIT == 8");
     unsigned ByteWidth = Info.Ctx.getTypeSize(E->getType()) / 8;
     uint64_t RemainingElems = Ptr.Designator.validIndexAdjustments().second;
     if (ByteWidth > RemainingElems) {
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 2a8395e26d0bd..9c7e218f008ce 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -4031,6 +4031,38 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
   case Builtin::BIstdc_memreverse8u16:
   case Builtin::BIstdc_memreverse8u32:
   case Builtin::BIstdc_memreverse8u64:
+  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_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_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_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:
     if (Context.getTargetInfo().getCharWidth() != 8) {
       Diag(TheCall->getBeginLoc(), diag::err_builtin_requires_char_bit_8)
           << TheCall->getDirectCallee()->getName();

>From 9d98fc9753ea57adc8ea3195df8500014cd36b97 Mon Sep 17 00:00:00 2001
From: NagaChaitanya Vellanki <pnagato at protonmail.com>
Date: Thu, 25 Jun 2026 20:43:06 -0700
Subject: [PATCH 06/13] Add test for null pointer type

---
 clang/test/Sema/constexpr-builtin-stdc-load8.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/clang/test/Sema/constexpr-builtin-stdc-load8.c b/clang/test/Sema/constexpr-builtin-stdc-load8.c
index b4ad6ea1f1d5d..4df9097b88b88 100644
--- a/clang/test/Sema/constexpr-builtin-stdc-load8.c
+++ b/clang/test/Sema/constexpr-builtin-stdc-load8.c
@@ -96,7 +96,8 @@ _Static_assert(s16_be == -128, "");
 
 // Null pointer is rejected (NonNull attribute)
 void test_null(void) {
-  __UINT_LEAST8_TYPE__ x = stdc_load8_leu8(0); // expected-warning{{null passed to a callee that requires a non-null argument}}
+  __UINT_LEAST8_TYPE__ x = stdc_load8_leu8(0);       // expected-warning{{null passed to a callee that requires a non-null argument}}
+  __UINT_LEAST8_TYPE__ y = stdc_load8_leu8(nullptr);  // expected-warning{{null passed to a callee that requires a non-null argument}}
 }
 
 // Wrong pointer types are rejected by the type system at the call site.
@@ -119,6 +120,7 @@ constexpr unsigned char scalar_byte = 0x42;
 constexpr __UINT_LEAST32_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 __UINT_LEAST32_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}}
+constexpr __UINT_LEAST32_TYPE__ null_ce_nullptr = stdc_load8_leu32(nullptr); // expected-error{{must be initialized by a constant expression}} expected-note{{read of dereferenced null pointer is not allowed in a constant expression}}
 
 constexpr unsigned char one[] = {0x42};
 constexpr __UINT_LEAST8_TYPE__ oob_past_end = stdc_load8_leu8(one + 1); // expected-error{{must be initialized by a constant expression}} expected-note{{cannot refer to element 1 of array of 1 element in a constant expression}}

>From f7ee3a1cba0855061c6d526cc398641bcf1161da Mon Sep 17 00:00:00 2001
From: NagaChaitanya Vellanki <pnagato at protonmail.com>
Date: Fri, 26 Jun 2026 09:16:01 -0700
Subject: [PATCH 07/13] Reject unaligned pointers in stdc_load8_aligned_* at
 constexpr

---
 .../include/clang/Basic/DiagnosticASTKinds.td |   3 +
 clang/lib/AST/ByteCode/InterpBuiltin.cpp      |  42 ++++-
 clang/lib/AST/ExprConstant.cpp                | 152 ++++++++++--------
 .../test/Sema/constexpr-builtin-stdc-load8.c  |  56 +++++--
 4 files changed, 171 insertions(+), 82 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td b/clang/include/clang/Basic/DiagnosticASTKinds.td
index f86f0157b2b1f..c00c3bcc9d3f9 100644
--- a/clang/include/clang/Basic/DiagnosticASTKinds.td
+++ b/clang/include/clang/Basic/DiagnosticASTKinds.td
@@ -274,6 +274,9 @@ def note_constexpr_alignment_compute : Note<
   "cannot constant evaluate whether run-time alignment is at least %0">;
 def note_constexpr_alignment_adjust : Note<
   "cannot constant evaluate the result of adjusting alignment to %0">;
+def note_constexpr_load8_unaligned : Note<
+  "%0 requires a pointer aligned to %1 %plural{1:byte|:bytes}1, but the "
+  "given pointer is only aligned to %2 %plural{1:byte|:bytes}2">;
 def note_constexpr_destroy_out_of_lifetime : Note<
   "destroying object '%0' whose lifetime has already ended">;
 def note_constexpr_unsupported_destruction : Note<
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index 746614b420375..803d918cd819a 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -2060,7 +2060,8 @@ static bool isOneByteCharacterType(QualType T) {
 
 static bool interp__builtin_load8(InterpState &S, CodePtr OpPC,
                                   const InterpFrame *Frame,
-                                  const CallExpr *Call, bool IsBigEndian) {
+                                  const CallExpr *Call, bool IsBigEndian,
+                                  bool IsAligned) {
   Pointer Ptr = S.Stk.pop<Pointer>();
 
   if (Ptr.isZero()) {
@@ -2072,6 +2073,33 @@ static bool interp__builtin_load8(InterpState &S, CodePtr OpPC,
   if (!isReadable(Ptr) && !Ptr.isOnePastEnd())
     return false;
 
+  if (IsAligned) {
+    CharUnits RequiredAlign =
+        S.getASTContext().getTypeAlignInChars(Call->getType());
+    CharUnits BaseAlignment;
+    if (const auto *VD = Ptr.getDeclDesc()->asValueDecl())
+      BaseAlignment = S.getASTContext().getDeclAlign(VD);
+    else if (const auto *E = Ptr.getDeclDesc()->asExpr())
+      BaseAlignment = GetAlignOfExpr(S.getASTContext(), E, UETT_AlignOf);
+    else {
+      S.FFDiag(S.Current->getSource(OpPC),
+               diag::note_constexpr_alignment_compute)
+          << RequiredAlign.getQuantity();
+      return false;
+    }
+    unsigned PtrOffset =
+        Ptr.isElementPastEnd() ? Ptr.getNumElems() : Ptr.getIndex();
+    CharUnits PtrAlign =
+        BaseAlignment.alignmentAtOffset(CharUnits::fromQuantity(PtrOffset));
+    if (PtrAlign < RequiredAlign) {
+      S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_load8_unaligned)
+          << S.getASTContext().BuiltinInfo.getQuotedName(
+                 Call->getBuiltinCallee())
+          << RequiredAlign.getQuantity() << PtrAlign.getQuantity();
+      return false;
+    }
+  }
+
   const Descriptor *Desc = Ptr.getFieldDesc();
   bool IsArray = Desc->isArray();
   QualType ElemTy = IsArray ? Desc->getElemQualType() : Desc->getType();
@@ -5283,6 +5311,9 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
   case Builtin::BIstdc_load8_les16:
   case Builtin::BIstdc_load8_les32:
   case Builtin::BIstdc_load8_les64:
+    return interp__builtin_load8(S, OpPC, Frame, Call, /*IsBigEndian=*/false,
+                                 /*IsAligned=*/false);
+
   case Builtin::BIstdc_load8_aligned_leu8:
   case Builtin::BIstdc_load8_aligned_leu16:
   case Builtin::BIstdc_load8_aligned_leu32:
@@ -5291,7 +5322,8 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
   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);
+    return interp__builtin_load8(S, OpPC, Frame, Call, /*IsBigEndian=*/false,
+                                 /*IsAligned=*/true);
 
   case Builtin::BIstdc_load8_beu8:
   case Builtin::BIstdc_load8_beu16:
@@ -5301,6 +5333,9 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
   case Builtin::BIstdc_load8_bes16:
   case Builtin::BIstdc_load8_bes32:
   case Builtin::BIstdc_load8_bes64:
+    return interp__builtin_load8(S, OpPC, Frame, Call, /*IsBigEndian=*/true,
+                                 /*IsAligned=*/false);
+
   case Builtin::BIstdc_load8_aligned_beu8:
   case Builtin::BIstdc_load8_aligned_beu16:
   case Builtin::BIstdc_load8_aligned_beu32:
@@ -5309,7 +5344,8 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
   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);
+    return interp__builtin_load8(S, OpPC, Frame, Call, /*IsBigEndian=*/true,
+                                 /*IsAligned=*/true);
 
   case Builtin::BI__atomic_always_lock_free:
   case Builtin::BI__atomic_is_lock_free:
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 244ede9502bea..4a16d332206b1 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -16700,6 +16700,70 @@ static bool getBuiltinAlignArguments(const CallExpr *E, EvalInfo &Info,
   return true;
 }
 
+// Implements the C2y §7.18.21 stdc_load8_* family: reads N bytes from
+// E->getArg(0) and assembles them per IsBE into a value of E's type. The
+// aligned_* variants additionally require the pointer to be aligned to the
+// natural alignment of E's type.
+static bool EvaluateStdcLoad8(EvalInfo &Info, const CallExpr *E, bool IsBE,
+                              bool IsAligned, APSInt &Result) {
+  LValue Ptr;
+  if (!EvaluatePointer(E->getArg(0), Ptr, Info))
+    return false;
+
+  if (!Ptr.checkNullPointerForFoldAccess(Info, E, AK_Read) ||
+      Ptr.Designator.Invalid)
+    return false;
+
+  if (IsAligned) {
+    CharUnits RequiredAlign = Info.Ctx.getTypeAlignInChars(E->getType());
+    CharUnits BaseAlignment = getBaseAlignment(Info, Ptr);
+    CharUnits PtrAlign = BaseAlignment.alignmentAtOffset(Ptr.Offset);
+    if (PtrAlign < RequiredAlign) {
+      Info.FFDiag(E, diag::note_constexpr_load8_unaligned)
+          << Info.Ctx.BuiltinInfo.getQuotedName(E->getBuiltinCallee())
+          << RequiredAlign.getQuantity() << PtrAlign.getQuantity();
+      return false;
+    }
+  }
+
+  QualType CharTy = Ptr.Designator.getType(Info.Ctx);
+  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 ResultBits = APInt::getZero(ByteWidth * 8);
+  for (unsigned I = 0; I < ByteWidth; ++I) {
+    unsigned SrcIdx = IsBE ? (ByteWidth - I - 1) : I;
+    ResultBits |= APInt(ByteWidth * 8, Bytes[SrcIdx]) << (8 * I);
+  }
+
+  bool IsSigned = E->getType()->isSignedIntegerType();
+  Result = APSInt(ResultBits, !IsSigned);
+  return true;
+}
+
 bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
                                             unsigned BuiltinOp) {
   auto EvalTestOp = [&](llvm::function_ref<bool(const APInt &, const APInt &)>
@@ -16921,7 +16985,14 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
   case Builtin::BIstdc_load8_les8:
   case Builtin::BIstdc_load8_les16:
   case Builtin::BIstdc_load8_les32:
-  case Builtin::BIstdc_load8_les64:
+  case Builtin::BIstdc_load8_les64: {
+    APSInt Result;
+    if (!EvaluateStdcLoad8(Info, E, /*IsBE=*/false, /*IsAligned=*/false,
+                           Result))
+      return false;
+    return Success(Result, E);
+  }
+
   case Builtin::BIstdc_load8_aligned_leu8:
   case Builtin::BIstdc_load8_aligned_leu16:
   case Builtin::BIstdc_load8_aligned_leu32:
@@ -16929,7 +17000,13 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
   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_aligned_les64: {
+    APSInt Result;
+    if (!EvaluateStdcLoad8(Info, E, /*IsBE=*/false, /*IsAligned=*/true, Result))
+      return false;
+    return Success(Result, E);
+  }
+
   case Builtin::BIstdc_load8_beu8:
   case Builtin::BIstdc_load8_beu16:
   case Builtin::BIstdc_load8_beu32:
@@ -16937,7 +17014,13 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
   case Builtin::BIstdc_load8_bes8:
   case Builtin::BIstdc_load8_bes16:
   case Builtin::BIstdc_load8_bes32:
-  case Builtin::BIstdc_load8_bes64:
+  case Builtin::BIstdc_load8_bes64: {
+    APSInt Result;
+    if (!EvaluateStdcLoad8(Info, E, /*IsBE=*/true, /*IsAligned=*/false, Result))
+      return false;
+    return Success(Result, E);
+  }
+
   case Builtin::BIstdc_load8_aligned_beu8:
   case Builtin::BIstdc_load8_aligned_beu16:
   case Builtin::BIstdc_load8_aligned_beu32:
@@ -16946,67 +17029,10 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
   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);
-    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);
+    APSInt Result;
+    if (!EvaluateStdcLoad8(Info, E, /*IsBE=*/true, /*IsAligned=*/true, Result))
       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);
+    return Success(Result, E);
   }
 
   case Builtin::BI__builtin_classify_type:
diff --git a/clang/test/Sema/constexpr-builtin-stdc-load8.c b/clang/test/Sema/constexpr-builtin-stdc-load8.c
index 4df9097b88b88..d012473d0bc5a 100644
--- a/clang/test/Sema/constexpr-builtin-stdc-load8.c
+++ b/clang/test/Sema/constexpr-builtin-stdc-load8.c
@@ -3,10 +3,11 @@
 #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};
+// alignas(8) so these buffers also satisfy the stdc_load8_aligned_* variants.
+alignas(8) static const unsigned char le8_u[]  = {0xAB};
+alignas(8) static const unsigned char le16_u[] = {0x34, 0x12};
+alignas(8) static const unsigned char le32_u[] = {0x78, 0x56, 0x34, 0x12};
+alignas(8) static const unsigned char le64_u[] = {0xF0, 0xDE, 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12};
 
 _Static_assert(stdc_load8_leu8(le8_u)   == (__UINT_LEAST8_TYPE__)0xAB,               "");
 _Static_assert(stdc_load8_leu16(le16_u) == (__UINT_LEAST16_TYPE__)0x1234,            "");
@@ -14,10 +15,10 @@ _Static_assert(stdc_load8_leu32(le32_u) == (__UINT_LEAST32_TYPE__)0x12345678U,
 _Static_assert(stdc_load8_leu64(le64_u) == (__UINT_LEAST64_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};
+alignas(8) static const unsigned char be8_u[]  = {0xAB};
+alignas(8) static const unsigned char be16_u[] = {0x12, 0x34};
+alignas(8) static const unsigned char be32_u[] = {0x12, 0x34, 0x56, 0x78};
+alignas(8) static const unsigned char be64_u[] = {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0};
 
 _Static_assert(stdc_load8_beu8(be8_u)   == (__UINT_LEAST8_TYPE__)0xAB,               "");
 _Static_assert(stdc_load8_beu16(be16_u) == (__UINT_LEAST16_TYPE__)0x1234,            "");
@@ -37,10 +38,10 @@ _Static_assert(stdc_load8_aligned_beu32(be32_u) == (__UINT_LEAST32_TYPE__)0x1234
 _Static_assert(stdc_load8_aligned_beu64(be64_u) == (__UINT_LEAST64_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};
+alignas(8) static const unsigned char le8_s[]  = {0x80};
+alignas(8) static const unsigned char le16_s[] = {0x80, 0xFF};
+alignas(8) static const unsigned char le32_s[] = {0x80, 0xFF, 0xFF, 0xFF};
+alignas(8) static const unsigned char le64_s[] = {0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
 
 _Static_assert(stdc_load8_les8(le8_s)   == (__INT_LEAST8_TYPE__)-128,  "");
 _Static_assert(stdc_load8_les16(le16_s) == (__INT_LEAST16_TYPE__)-128, "");
@@ -48,10 +49,10 @@ _Static_assert(stdc_load8_les32(le32_s) == (__INT_LEAST32_TYPE__)-128, "");
 _Static_assert(stdc_load8_les64(le64_s) == (__INT_LEAST64_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};
+alignas(8) static const unsigned char be8_s[]  = {0x80};
+alignas(8) static const unsigned char be16_s[] = {0xFF, 0x80};
+alignas(8) static const unsigned char be32_s[] = {0xFF, 0xFF, 0xFF, 0x80};
+alignas(8) static const unsigned char be64_s[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80};
 
 _Static_assert(stdc_load8_bes8(be8_s)   == (__INT_LEAST8_TYPE__)-128,  "");
 _Static_assert(stdc_load8_bes16(be16_s) == (__INT_LEAST16_TYPE__)-128, "");
@@ -76,6 +77,13 @@ static const unsigned char be16_pos[] = {0x00, 0x01};
 _Static_assert(stdc_load8_les16(le16_pos) == 1, "");
 _Static_assert(stdc_load8_bes16(be16_pos) == 1, "");
 
+// N=64 signed boundary: result == 2^63 is not < 2^63, so it wraps to
+// result - 2^64 == INT64_MIN, not a positive value.
+static const unsigned char le64_min[] = {0, 0, 0, 0, 0, 0, 0, 0x80};
+static const unsigned char be64_min[] = {0x80, 0, 0, 0, 0, 0, 0, 0};
+_Static_assert(stdc_load8_les64(le64_min) == (__INT_LEAST64_TYPE__)(-9223372036854775807LL - 1), "");
+_Static_assert(stdc_load8_bes64(be64_min) == (__INT_LEAST64_TYPE__)(-9223372036854775807LL - 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};
@@ -124,3 +132,19 @@ constexpr __UINT_LEAST32_TYPE__ null_ce_nullptr = stdc_load8_leu32(nullptr); //
 
 constexpr unsigned char one[] = {0x42};
 constexpr __UINT_LEAST8_TYPE__ oob_past_end = stdc_load8_leu8(one + 1); // expected-error{{must be initialized by a constant expression}} expected-note{{cannot refer to element 1 of array of 1 element in a constant expression}}
+
+// aligned_* variants require the pointer to be aligned to the result type.
+alignas(8) constexpr unsigned char align_buf[9] = {0, 0x78, 0x56, 0x34, 0x12, 0, 0, 0, 0};
+
+constexpr __UINT_LEAST16_TYPE__ misaligned16 = stdc_load8_aligned_leu16(align_buf + 1); // expected-error{{must be initialized by a constant expression}} expected-note{{'stdc_load8_aligned_leu16' requires a pointer aligned to 2 bytes, but the given pointer is only aligned to 1 byte}}
+constexpr __UINT_LEAST32_TYPE__ misaligned32 = stdc_load8_aligned_leu32(align_buf + 1); // expected-error{{must be initialized by a constant expression}} expected-note{{'stdc_load8_aligned_leu32' requires a pointer aligned to 4 bytes, but the given pointer is only aligned to 1 byte}}
+constexpr __UINT_LEAST64_TYPE__ misaligned64 = stdc_load8_aligned_leu64(align_buf + 1); // expected-error{{must be initialized by a constant expression}} expected-note{{'stdc_load8_aligned_leu64' requires a pointer aligned to 8 bytes, but the given pointer is only aligned to 1 byte}}
+
+// Offset 2 from an 8-byte aligned base is only 2-byte aligned, enough for a
+// 16-bit load but not a 32-bit one.
+constexpr __UINT_LEAST32_TYPE__ misaligned32_half = stdc_load8_aligned_leu32(align_buf + 2); // expected-error{{must be initialized by a constant expression}} expected-note{{'stdc_load8_aligned_leu32' requires a pointer aligned to 4 bytes, but the given pointer is only aligned to 2 bytes}}
+
+// Offset 4 is still 4-byte aligned, enough for a 16-bit (2-byte) load.
+// align_buf[4..5] == {0x12, 0x00}, so LE u16 == 0x0012.
+constexpr __UINT_LEAST16_TYPE__ partially_aligned16 = stdc_load8_aligned_leu16(align_buf + 4);
+static_assert(partially_aligned16 == 0x0012, "");

>From 83d25a2cd3f52b070c9086114c5ff4f0d0f5f81d Mon Sep 17 00:00:00 2001
From: NagaChaitanya Vellanki <pnagato at protonmail.com>
Date: Mon, 13 Jul 2026 09:24:40 -0700
Subject: [PATCH 08/13] Add tests for stdc_load8_aligned_* and widen CodeGen
 coverage across widths/signedness

---
 clang/test/CodeGen/builtin-stdc-load8.c       | 50 +++++++++++++++++++
 .../test/Sema/constexpr-builtin-stdc-load8.c  | 46 +++++++++++++++++
 2 files changed, 96 insertions(+)

diff --git a/clang/test/CodeGen/builtin-stdc-load8.c b/clang/test/CodeGen/builtin-stdc-load8.c
index 6fb1dcc8cc771..c239a4dfa06d6 100644
--- a/clang/test/CodeGen/builtin-stdc-load8.c
+++ b/clang/test/CodeGen/builtin-stdc-load8.c
@@ -95,3 +95,53 @@ __INT_LEAST32_TYPE__ test_les32(const unsigned char *p) { return stdc_load8_les3
 // BE: load i32, ptr {{.+}}, align 1
 // BE-NOT: bswap
 __INT_LEAST32_TYPE__ test_bes32(const unsigned char *p) { return stdc_load8_bes32(p); }
+
+// Aligned load's alignment scales with the result type's width.
+// LE-LABEL: @test_aligned_leu16(
+// LE: load i16, ptr {{.+}}, align 2
+// LE-NOT: bswap
+// BE-LABEL: @test_aligned_leu16(
+// BE: load i16, ptr {{.+}}, align 2
+// BE: call i16 @llvm.bswap.i16(
+__UINT_LEAST16_TYPE__ test_aligned_leu16(const unsigned char *p) { return stdc_load8_aligned_leu16(p); }
+
+// LE-LABEL: @test_aligned_beu16(
+// LE: load i16, ptr {{.+}}, align 2
+// LE: call i16 @llvm.bswap.i16(
+// BE-LABEL: @test_aligned_beu16(
+// BE: load i16, ptr {{.+}}, align 2
+// BE-NOT: bswap
+__UINT_LEAST16_TYPE__ test_aligned_beu16(const unsigned char *p) { return stdc_load8_aligned_beu16(p); }
+
+// LE-LABEL: @test_aligned_leu64(
+// LE: load i64, ptr {{.+}}, align 8
+// LE-NOT: bswap
+// BE-LABEL: @test_aligned_leu64(
+// BE: load i64, ptr {{.+}}, align 8
+// BE: call i64 @llvm.bswap.i64(
+__UINT_LEAST64_TYPE__ test_aligned_leu64(const unsigned char *p) { return stdc_load8_aligned_leu64(p); }
+
+// LE-LABEL: @test_aligned_beu64(
+// LE: load i64, ptr {{.+}}, align 8
+// LE: call i64 @llvm.bswap.i64(
+// BE-LABEL: @test_aligned_beu64(
+// BE: load i64, ptr {{.+}}, align 8
+// BE-NOT: bswap
+__UINT_LEAST64_TYPE__ test_aligned_beu64(const unsigned char *p) { return stdc_load8_aligned_beu64(p); }
+
+// Signed aligned variants use the same alignment lowering as unsigned.
+// LE-LABEL: @test_aligned_les32(
+// LE: load i32, ptr {{.+}}, align 4
+// LE-NOT: bswap
+// BE-LABEL: @test_aligned_les32(
+// BE: load i32, ptr {{.+}}, align 4
+// BE: call i32 @llvm.bswap.i32(
+__INT_LEAST32_TYPE__ test_aligned_les32(const unsigned char *p) { return stdc_load8_aligned_les32(p); }
+
+// LE-LABEL: @test_aligned_bes32(
+// LE: load i32, ptr {{.+}}, align 4
+// LE: call i32 @llvm.bswap.i32(
+// BE-LABEL: @test_aligned_bes32(
+// BE: load i32, ptr {{.+}}, align 4
+// BE-NOT: bswap
+__INT_LEAST32_TYPE__ test_aligned_bes32(const unsigned char *p) { return stdc_load8_aligned_bes32(p); }
diff --git a/clang/test/Sema/constexpr-builtin-stdc-load8.c b/clang/test/Sema/constexpr-builtin-stdc-load8.c
index d012473d0bc5a..28893ebc9d2a7 100644
--- a/clang/test/Sema/constexpr-builtin-stdc-load8.c
+++ b/clang/test/Sema/constexpr-builtin-stdc-load8.c
@@ -148,3 +148,49 @@ constexpr __UINT_LEAST32_TYPE__ misaligned32_half = stdc_load8_aligned_leu32(ali
 // align_buf[4..5] == {0x12, 0x00}, so LE u16 == 0x0012.
 constexpr __UINT_LEAST16_TYPE__ partially_aligned16 = stdc_load8_aligned_leu16(align_buf + 4);
 static_assert(partially_aligned16 == 0x0012, "");
+
+constexpr unsigned char noalign_buf[8] = {0x78, 0x56, 0x34, 0x12, 0, 0, 0, 0};
+constexpr __UINT_LEAST8_TYPE__  noalign_ok   = stdc_load8_aligned_leu8(noalign_buf);
+static_assert(noalign_ok == 0x78, "");
+constexpr __UINT_LEAST16_TYPE__ noalign_fail16 = stdc_load8_aligned_leu16(noalign_buf); // expected-error{{must be initialized by a constant expression}} expected-note{{'stdc_load8_aligned_leu16' requires a pointer aligned to 2 bytes, but the given pointer is only aligned to 1 byte}}
+constexpr __UINT_LEAST32_TYPE__ noalign_fail32 = stdc_load8_aligned_leu32(noalign_buf); // expected-error{{must be initialized by a constant expression}} expected-note{{'stdc_load8_aligned_leu32' requires a pointer aligned to 4 bytes, but the given pointer is only aligned to 1 byte}}
+
+void test_block_scope_vardecl(void) {
+  alignas(8) constexpr unsigned char blk_buf[4] = {0x78, 0x56, 0x34, 0x12};
+  static_assert(stdc_load8_aligned_leu32(blk_buf) == 0x12345678U, "");
+
+  constexpr unsigned char blk_noalign[4] = {0x78, 0x56, 0x34, 0x12};
+  constexpr __UINT_LEAST32_TYPE__ blk_fail = stdc_load8_aligned_leu32(blk_noalign); // expected-error{{must be initialized by a constant expression}} expected-note{{'stdc_load8_aligned_leu32' requires a pointer aligned to 4 bytes, but the given pointer is only aligned to 1 byte}}
+}
+
+constexpr __UINT_LEAST8_TYPE__ strlit_ok = stdc_load8_aligned_leu8((const unsigned char *)u8"\xAB");
+static_assert(strlit_ok == (__UINT_LEAST8_TYPE__)0xAB, "");
+
+constexpr __UINT_LEAST16_TYPE__ strlit_fail = stdc_load8_aligned_leu16((const unsigned char *)u8"\x34\x12"); // expected-error{{must be initialized by a constant expression}} expected-note{{'stdc_load8_aligned_leu16' requires a pointer aligned to 2 bytes, but the given pointer is only aligned to 1 byte}}
+
+constexpr __UINT_LEAST32_TYPE__ complit_fail = stdc_load8_aligned_leu32((unsigned char[4]){0x78, 0x56, 0x34, 0x12}); // expected-error{{must be initialized by a constant expression}} expected-note{{'stdc_load8_aligned_leu32' requires a pointer aligned to 4 bytes, but the given pointer is only aligned to 1 byte}}
+
+typedef unsigned char AlignedBuf8[8] __attribute__((aligned(8)));
+
+constexpr __UINT_LEAST32_TYPE__ complit_offset_fail = stdc_load8_aligned_leu32((AlignedBuf8){0, 0, 0x78, 0x56, 0x34, 0x12} + 2); // expected-error{{must be initialized by a constant expression}} expected-note{{'stdc_load8_aligned_leu32' requires a pointer aligned to 4 bytes, but the given pointer is only aligned to 2 bytes}}
+
+alignas(8) constexpr unsigned char align_buf_be[9] = {0, 0x12, 0x34, 0x56, 0x78, 0, 0, 0, 0};
+
+constexpr __UINT_LEAST16_TYPE__ misaligned16_be = stdc_load8_aligned_beu16(align_buf_be + 1); // expected-error{{must be initialized by a constant expression}} expected-note{{'stdc_load8_aligned_beu16' requires a pointer aligned to 2 bytes, but the given pointer is only aligned to 1 byte}}
+constexpr __UINT_LEAST32_TYPE__ misaligned32_be = stdc_load8_aligned_beu32(align_buf_be + 1); // expected-error{{must be initialized by a constant expression}} expected-note{{'stdc_load8_aligned_beu32' requires a pointer aligned to 4 bytes, but the given pointer is only aligned to 1 byte}}
+constexpr __UINT_LEAST64_TYPE__ misaligned64_be = stdc_load8_aligned_beu64(align_buf_be + 1); // expected-error{{must be initialized by a constant expression}} expected-note{{'stdc_load8_aligned_beu64' requires a pointer aligned to 8 bytes, but the given pointer is only aligned to 1 byte}}
+
+constexpr __UINT_LEAST16_TYPE__ partially_aligned16_be = stdc_load8_aligned_beu16(align_buf_be + 4);
+static_assert(partially_aligned16_be == 0x7800, "");
+
+alignas(8) constexpr unsigned char align_buf_les[9] = {0, 0x80, 0xFF, 0xFF, 0xFF, 0, 0, 0, 0};
+constexpr __INT_LEAST32_TYPE__ misaligned32_les = stdc_load8_aligned_les32(align_buf_les + 1); // expected-error{{must be initialized by a constant expression}} expected-note{{'stdc_load8_aligned_les32' requires a pointer aligned to 4 bytes, but the given pointer is only aligned to 1 byte}}
+
+alignas(8) constexpr unsigned char align_buf_bes[9] = {0, 0xFF, 0xFF, 0xFF, 0x80, 0, 0, 0, 0};
+constexpr __INT_LEAST32_TYPE__ misaligned32_bes = stdc_load8_aligned_bes32(align_buf_bes + 1); // expected-error{{must be initialized by a constant expression}} expected-note{{'stdc_load8_aligned_bes32' requires a pointer aligned to 4 bytes, but the given pointer is only aligned to 1 byte}}
+
+alignas(8) constexpr unsigned char onepastend_buf[4] = {0x78, 0x56, 0x34, 0x12};
+constexpr __UINT_LEAST32_TYPE__ onepastend_aligned = stdc_load8_aligned_leu32(onepastend_buf + 4); // expected-error{{must be initialized by a constant expression}} expected-note{{cannot refer to element 7 of array of 4 elements in a constant expression}}
+
+alignas(8) constexpr unsigned char onepastend_misaligned_buf[5] = {0, 0x78, 0x56, 0x34, 0x12};
+constexpr __UINT_LEAST32_TYPE__ onepastend_misaligned = stdc_load8_aligned_leu32(onepastend_misaligned_buf + 5); // expected-error{{must be initialized by a constant expression}} expected-note{{'stdc_load8_aligned_leu32' requires a pointer aligned to 4 bytes, but the given pointer is only aligned to 1 byte}}

>From ab1ec412df2ac720ba47501a182e3bb1c7017a4a Mon Sep 17 00:00:00 2001
From: NagaChaitanya Vellanki <pnagato at protonmail.com>
Date: Mon, 13 Jul 2026 11:27:24 -0700
Subject: [PATCH 09/13] Fix incorrect offset in stdc_load8_aligned_* alignment
 check for struct fields

---
 clang/lib/AST/ByteCode/InterpBuiltin.cpp       |  6 ++----
 clang/test/Sema/constexpr-builtin-stdc-load8.c | 12 ++++++++++++
 2 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index 803d918cd819a..f7be321eab360 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -2087,10 +2087,8 @@ static bool interp__builtin_load8(InterpState &S, CodePtr OpPC,
           << RequiredAlign.getQuantity();
       return false;
     }
-    unsigned PtrOffset =
-        Ptr.isElementPastEnd() ? Ptr.getNumElems() : Ptr.getIndex();
-    CharUnits PtrAlign =
-        BaseAlignment.alignmentAtOffset(CharUnits::fromQuantity(PtrOffset));
+    CharUnits PtrOffset = Ptr.toAPValue(S.getASTContext()).getLValueOffset();
+    CharUnits PtrAlign = BaseAlignment.alignmentAtOffset(PtrOffset);
     if (PtrAlign < RequiredAlign) {
       S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_load8_unaligned)
           << S.getASTContext().BuiltinInfo.getQuotedName(
diff --git a/clang/test/Sema/constexpr-builtin-stdc-load8.c b/clang/test/Sema/constexpr-builtin-stdc-load8.c
index 28893ebc9d2a7..3396b7cdbea2b 100644
--- a/clang/test/Sema/constexpr-builtin-stdc-load8.c
+++ b/clang/test/Sema/constexpr-builtin-stdc-load8.c
@@ -194,3 +194,15 @@ constexpr __UINT_LEAST32_TYPE__ onepastend_aligned = stdc_load8_aligned_leu32(on
 
 alignas(8) constexpr unsigned char onepastend_misaligned_buf[5] = {0, 0x78, 0x56, 0x34, 0x12};
 constexpr __UINT_LEAST32_TYPE__ onepastend_misaligned = stdc_load8_aligned_leu32(onepastend_misaligned_buf + 5); // expected-error{{must be initialized by a constant expression}} expected-note{{'stdc_load8_aligned_leu32' requires a pointer aligned to 4 bytes, but the given pointer is only aligned to 1 byte}}
+
+struct FieldOffset { unsigned char pad; unsigned char data[8]; };
+alignas(8) constexpr struct FieldOffset field_s = {0, {0x78, 0x56, 0x34, 0x12}};
+constexpr __UINT_LEAST32_TYPE__ field_fail = stdc_load8_aligned_leu32(field_s.data); // expected-error{{must be initialized by a constant expression}} expected-note{{'stdc_load8_aligned_leu32' requires a pointer aligned to 4 bytes, but the given pointer is only aligned to 1 byte}}
+
+alignas(8) constexpr struct FieldOffset field_arr[2] = {{0}, {0, {0x78, 0x56, 0x34, 0x12}}};
+constexpr __UINT_LEAST32_TYPE__ field_arr_fail = stdc_load8_aligned_leu32(field_arr[1].data); // expected-error{{must be initialized by a constant expression}} expected-note{{'stdc_load8_aligned_leu32' requires a pointer aligned to 4 bytes, but the given pointer is only aligned to 2 bytes}}
+
+union FieldUnion { unsigned char c; unsigned char data[8]; };
+alignas(8) constexpr union FieldUnion field_u = {.data = {0x78, 0x56, 0x34, 0x12}};
+constexpr __UINT_LEAST32_TYPE__ union_ok = stdc_load8_aligned_leu32(field_u.data);
+static_assert(union_ok == 0x12345678U, "");

>From 3e122ba7631d648c7322a60e7b1d635f65c0cb2b Mon Sep 17 00:00:00 2001
From: NagaChaitanya Vellanki <pnagato at protonmail.com>
Date: Mon, 13 Jul 2026 12:13:52 -0700
Subject: [PATCH 10/13] Update ReleaseNotes with function suffixes

---
 clang/docs/ReleaseNotes.md | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index abe9cdaefcfb4..a362b98d1495a 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -103,11 +103,11 @@ latest release, please see the [Clang Web Site](https://clang.llvm.org) or the
   }
 ```
 - 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 unsigned 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.
+  `stdc_load8_{le,be}{u,s}{8,16,32,64}` and their aligned counterparts
+  `stdc_load8_aligned_{le,be}{u,s}{8,16,32,64}` 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
 

>From 04f0a6b644b3d5faa320180249b00f6686cad3f9 Mon Sep 17 00:00:00 2001
From: NagaChaitanya Vellanki <pnagato at protonmail.com>
Date: Mon, 13 Jul 2026 12:49:53 -0700
Subject: [PATCH 11/13] Avoid repeating the attributes and prototypes across
 function spellings

---
 clang/include/clang/Basic/Builtins.td | 35 +++++++++------------------
 1 file changed, 12 insertions(+), 23 deletions(-)

diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index e27f37a94fa9d..b48de880bd4a3 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -1011,52 +1011,41 @@ 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"];
+class Load8Common : LibBuiltin<"stdbit.h", "C2Y_LANG"> {
   let Attributes = [NoThrow, Pure, Constexpr, NonNull<NonOptimizing, [0]>];
   let Prototype = "T(unsigned char const*)";
 }
 
-def StdcLoad8BeU : LibBuiltin<"stdbit.h", "C2Y_LANG">, Load8UnsignedTemplate {
+def StdcLoad8LeU : Load8Common, Load8UnsignedTemplate {
+  let Spellings = ["stdc_load8_leu"];
+}
+
+def StdcLoad8BeU : Load8Common, 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 {
+def StdcLoad8AlignedLeU : Load8Common, 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 {
+def StdcLoad8AlignedBeU : Load8Common, 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 {
+def StdcLoad8LeS : Load8Common, 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 {
+def StdcLoad8BeS : Load8Common, 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 {
+def StdcLoad8AlignedLeS : Load8Common, 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 {
+def StdcLoad8AlignedBeS : Load8Common, Load8SignedTemplate {
   let Spellings = ["stdc_load8_aligned_bes"];
-  let Attributes = [NoThrow, Pure, Constexpr, NonNull<NonOptimizing, [0]>];
-  let Prototype = "T(unsigned char const*)";
 }
 
 

>From c91c39cdf2b56c60cd4acecbfb2940e4ce192271 Mon Sep 17 00:00:00 2001
From: NagaChaitanya Vellanki <pnagato at protonmail.com>
Date: Mon, 13 Jul 2026 15:52:35 -0700
Subject: [PATCH 12/13] Avoid indexing into scalar pointer

---
 clang/lib/AST/ByteCode/InterpBuiltin.cpp       |  2 +-
 clang/test/Sema/constexpr-builtin-stdc-load8.c | 12 ++++++++++++
 2 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index f7be321eab360..c93f0acb51bda 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -2129,7 +2129,7 @@ static bool interp__builtin_load8(InterpState &S, CodePtr OpPC,
   // 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);
+    Pointer BytePtr = IsArray ? Ptr.atIndex(BaseIdx + SrcIdx) : Ptr;
     if (!CheckLoad(S, OpPC, BytePtr, AK_Read))
       return false;
     uint64_t B;
diff --git a/clang/test/Sema/constexpr-builtin-stdc-load8.c b/clang/test/Sema/constexpr-builtin-stdc-load8.c
index 3396b7cdbea2b..586afcee5de88 100644
--- a/clang/test/Sema/constexpr-builtin-stdc-load8.c
+++ b/clang/test/Sema/constexpr-builtin-stdc-load8.c
@@ -206,3 +206,15 @@ union FieldUnion { unsigned char c; unsigned char data[8]; };
 alignas(8) constexpr union FieldUnion field_u = {.data = {0x78, 0x56, 0x34, 0x12}};
 constexpr __UINT_LEAST32_TYPE__ union_ok = stdc_load8_aligned_leu32(field_u.data);
 static_assert(union_ok == 0x12345678U, "");
+
+constexpr unsigned char scalar_ok = 0x42;
+constexpr __UINT_LEAST8_TYPE__ scalar_aligned_ok = stdc_load8_aligned_leu8(&scalar_ok);
+static_assert(scalar_aligned_ok == 0x42, "");
+
+alignas(4) constexpr unsigned char scalar_aligned_oob = 0x42;
+constexpr __UINT_LEAST32_TYPE__ oob_scalar_aligned = stdc_load8_aligned_leu32(&scalar_aligned_oob); // expected-error{{must be initialized by a constant expression}} expected-note{{cannot refer to element 3 of non-array object in a constant expression}}
+
+void test_block_scope_scalar(void) {
+  constexpr unsigned char local_scalar = 0x42;
+  static_assert(stdc_load8_aligned_leu8(&local_scalar) == 0x42, "");
+}

>From 769fdd465bfa75a6ba25b231e4f5d29db97d8016 Mon Sep 17 00:00:00 2001
From: NagaChaitanya Vellanki <pnagato at protonmail.com>
Date: Tue, 14 Jul 2026 13:45:01 -0700
Subject: [PATCH 13/13] Extract getBaseAlignment function into ExprConstShared
 for sharing

Instead of duplicating the alignment checks in both interpreters, add
a check for DynamicAllocLValue to getBaseAlignment. Now both
interpreters check for TypeInfoLValue and DynamicAllocLValue.
---
 clang/lib/AST/ByteCode/InterpBuiltin.cpp | 17 ++++-----------
 clang/lib/AST/ExprConstShared.h          |  5 +++++
 clang/lib/AST/ExprConstant.cpp           | 27 +++++++++++++-----------
 3 files changed, 24 insertions(+), 25 deletions(-)

diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index c93f0acb51bda..c4c6dac4594c6 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -2076,19 +2076,10 @@ static bool interp__builtin_load8(InterpState &S, CodePtr OpPC,
   if (IsAligned) {
     CharUnits RequiredAlign =
         S.getASTContext().getTypeAlignInChars(Call->getType());
-    CharUnits BaseAlignment;
-    if (const auto *VD = Ptr.getDeclDesc()->asValueDecl())
-      BaseAlignment = S.getASTContext().getDeclAlign(VD);
-    else if (const auto *E = Ptr.getDeclDesc()->asExpr())
-      BaseAlignment = GetAlignOfExpr(S.getASTContext(), E, UETT_AlignOf);
-    else {
-      S.FFDiag(S.Current->getSource(OpPC),
-               diag::note_constexpr_alignment_compute)
-          << RequiredAlign.getQuantity();
-      return false;
-    }
-    CharUnits PtrOffset = Ptr.toAPValue(S.getASTContext()).getLValueOffset();
-    CharUnits PtrAlign = BaseAlignment.alignmentAtOffset(PtrOffset);
+    APValue AV = Ptr.toAPValue(S.getASTContext());
+    CharUnits BaseAlignment =
+        GetBaseAlignment(S.getASTContext(), AV.getLValueBase());
+    CharUnits PtrAlign = BaseAlignment.alignmentAtOffset(AV.getLValueOffset());
     if (PtrAlign < RequiredAlign) {
       S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_load8_unaligned)
           << S.getASTContext().BuiltinInfo.getQuotedName(
diff --git a/clang/lib/AST/ExprConstShared.h b/clang/lib/AST/ExprConstShared.h
index 7ba3071668bd1..fe00c5de73418 100644
--- a/clang/lib/AST/ExprConstShared.h
+++ b/clang/lib/AST/ExprConstShared.h
@@ -14,6 +14,7 @@
 #ifndef LLVM_CLANG_LIB_AST_EXPRCONSTSHARED_H
 #define LLVM_CLANG_LIB_AST_EXPRCONSTSHARED_H
 
+#include "clang/AST/APValue.h"
 #include "clang/Basic/TypeTraits.h"
 #include <cstdint>
 #include <optional>
@@ -78,6 +79,10 @@ void HandleComplexComplexDiv(llvm::APFloat A, llvm::APFloat B, llvm::APFloat C,
 
 CharUnits GetAlignOfExpr(const ASTContext &Ctx, const Expr *E,
                          UnaryExprOrTypeTrait ExprKind);
+CharUnits GetAlignOfType(const ASTContext &Ctx, QualType T,
+                         UnaryExprOrTypeTrait ExprKind);
+CharUnits GetBaseAlignment(const ASTContext &Ctx,
+                           const APValue::LValueBase &Base);
 
 /// Convert a builtin ID to the canonical x86 builtin ID the constant evaluators
 /// dispatch on in their x86 target-specific cases.
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 4a16d332206b1..997f5df3e9084 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -10298,8 +10298,8 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr *E) {
   return ExprEvaluatorBaseTy::VisitCastExpr(E);
 }
 
-static CharUnits GetAlignOfType(const ASTContext &Ctx, QualType T,
-                                UnaryExprOrTypeTrait ExprKind) {
+CharUnits GetAlignOfType(const ASTContext &Ctx, QualType T,
+                         UnaryExprOrTypeTrait ExprKind) {
   // C++ [expr.alignof]p3:
   //     When alignof is applied to a reference type, the result is the
   //     alignment of the referenced type.
@@ -10394,12 +10394,15 @@ CharUnits GetAlignOfExpr(const ASTContext &Ctx, const Expr *E,
   return GetAlignOfType(Ctx, E->getType(), ExprKind);
 }
 
-static CharUnits getBaseAlignment(EvalInfo &Info, const LValue &Value) {
-  if (const auto *VD = Value.Base.dyn_cast<const ValueDecl *>())
-    return Info.Ctx.getDeclAlign(VD);
-  if (const auto *E = Value.Base.dyn_cast<const Expr *>())
-    return GetAlignOfExpr(Info.Ctx, E, UETT_AlignOf);
-  return GetAlignOfType(Info.Ctx, Value.Base.getTypeInfoType(), UETT_AlignOf);
+CharUnits GetBaseAlignment(const ASTContext &Ctx,
+                           const APValue::LValueBase &Base) {
+  if (const auto *VD = Base.dyn_cast<const ValueDecl *>())
+    return Ctx.getDeclAlign(VD);
+  if (const auto *E = Base.dyn_cast<const Expr *>())
+    return GetAlignOfExpr(Ctx, E, UETT_AlignOf);
+  if (Base.is<TypeInfoLValue>())
+    return GetAlignOfType(Ctx, Base.getTypeInfoType(), UETT_AlignOf);
+  return GetAlignOfType(Ctx, Base.getDynamicAllocType(), UETT_AlignOf);
 }
 
 /// Evaluate the value of the alignment argument to __builtin_align_{up,down},
@@ -10491,7 +10494,7 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
 
     // If there is a base object, then it must have the correct alignment.
     if (OffsetResult.Base) {
-      CharUnits BaseAlignment = getBaseAlignment(Info, OffsetResult);
+      CharUnits BaseAlignment = GetBaseAlignment(Info.Ctx, OffsetResult.Base);
 
       if (BaseAlignment < Align) {
         Result.Designator.setInvalid();
@@ -10525,7 +10528,7 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
     if (!getAlignmentArgument(E->getArg(1), E->getArg(0)->getType(), Info,
                               Alignment))
       return false;
-    CharUnits BaseAlignment = getBaseAlignment(Info, Result);
+    CharUnits BaseAlignment = GetBaseAlignment(Info.Ctx, Result.Base);
     CharUnits PtrAlign = BaseAlignment.alignmentAtOffset(Result.Offset);
     // For align_up/align_down, we can return the same value if the alignment
     // is known to be greater or equal to the requested value.
@@ -16716,7 +16719,7 @@ static bool EvaluateStdcLoad8(EvalInfo &Info, const CallExpr *E, bool IsBE,
 
   if (IsAligned) {
     CharUnits RequiredAlign = Info.Ctx.getTypeAlignInChars(E->getType());
-    CharUnits BaseAlignment = getBaseAlignment(Info, Ptr);
+    CharUnits BaseAlignment = GetBaseAlignment(Info.Ctx, Ptr.Base);
     CharUnits PtrAlign = BaseAlignment.alignmentAtOffset(Ptr.Offset);
     if (PtrAlign < RequiredAlign) {
       Info.FFDiag(E, diag::note_constexpr_load8_unaligned)
@@ -16898,7 +16901,7 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
       // If we evaluated a pointer, check the minimum known alignment.
       LValue Ptr;
       Ptr.setFrom(Info.Ctx, Src);
-      CharUnits BaseAlignment = getBaseAlignment(Info, Ptr);
+      CharUnits BaseAlignment = GetBaseAlignment(Info.Ctx, Ptr.Base);
       CharUnits PtrAlign = BaseAlignment.alignmentAtOffset(Ptr.Offset);
       // We can return true if the known alignment at the computed offset is
       // greater than the requested alignment.



More information about the cfe-commits mailing list