https://github.com/tbaederr updated 
https://github.com/llvm/llvm-project/pull/169769

>From 67b563cd4493db1bc79114fd27199857696d6a53 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <[email protected]>
Date: Mon, 17 Nov 2025 13:58:23 +0100
Subject: [PATCH] [clang][bytecode] Support different integral types (e.g.
 addresses)

---
 clang/lib/AST/ByteCode/Boolean.h              |   8 +-
 clang/lib/AST/ByteCode/Context.cpp            |  11 +-
 clang/lib/AST/ByteCode/Descriptor.cpp         |   7 +
 clang/lib/AST/ByteCode/Descriptor.h           |   5 +
 clang/lib/AST/ByteCode/EvalEmitter.cpp        |  19 +--
 clang/lib/AST/ByteCode/FixedPoint.h           |   9 +-
 clang/lib/AST/ByteCode/Floating.h             |   7 +-
 clang/lib/AST/ByteCode/Integral.h             |  69 ++++++--
 clang/lib/AST/ByteCode/IntegralAP.h           |   8 +-
 clang/lib/AST/ByteCode/Interp.cpp             |  42 +++--
 clang/lib/AST/ByteCode/Interp.h               | 150 +++++++++++++++---
 clang/lib/AST/ByteCode/InterpBuiltin.cpp      |  68 ++++----
 clang/lib/AST/ByteCode/InterpFrame.cpp        |  14 +-
 clang/lib/AST/ByteCode/InterpHelpers.h        |   4 +-
 clang/lib/AST/ByteCode/InterpStack.h          |  24 +--
 clang/lib/AST/ByteCode/MemberPointer.cpp      |   5 +-
 clang/lib/AST/ByteCode/MemberPointer.h        |   7 +-
 clang/lib/AST/ByteCode/Pointer.cpp            |  37 +++--
 clang/lib/AST/ByteCode/Pointer.h              |  11 +-
 clang/lib/AST/ByteCode/PrimType.h             |  16 ++
 clang/lib/AST/ByteCode/Primitives.h           |   8 +
 clang/lib/AST/ByteCode/Program.cpp            |  28 ++--
 clang/lib/AST/ByteCode/Program.h              |  39 +++++
 clang/test/AST/ByteCode/addr-label-diff.c     |  22 +++
 clang/test/AST/ByteCode/const-eval.c          |   3 +
 clang/test/CodeGen/const-label-addr.c         |   1 +
 clang/test/CodeGen/statements.c               |   1 +
 clang/test/CodeGen/staticinit.c               |   1 +
 .../CodeGenCXX/2008-05-07-CrazyOffsetOf.cpp   |   1 +
 clang/test/CodeGenCXX/const-init-cxx11.cpp    |   3 +
 clang/test/Sema/compound-literal.c            |   1 +
 clang/test/SemaCXX/constexpr-string.cpp       |   1 +
 clang/unittests/AST/ByteCode/toAPValue.cpp    |  16 +-
 33 files changed, 475 insertions(+), 171 deletions(-)
 create mode 100644 clang/test/AST/ByteCode/addr-label-diff.c

diff --git a/clang/lib/AST/ByteCode/Boolean.h b/clang/lib/AST/ByteCode/Boolean.h
index fd8d546656881..f04bcd3ba337c 100644
--- a/clang/lib/AST/ByteCode/Boolean.h
+++ b/clang/lib/AST/ByteCode/Boolean.h
@@ -52,10 +52,14 @@ class Boolean final {
   APSInt toAPSInt(unsigned NumBits) const {
     return APSInt(toAPSInt().zextOrTrunc(NumBits), true);
   }
-  APValue toAPValue(const ASTContext &) const { return APValue(toAPSInt()); }
+  APValue toAPValue(const ASTContext &, const Program &) const {
+    return APValue(toAPSInt());
+  }
 
   Boolean toUnsigned() const { return *this; }
 
+  static IntegralKind getKind() { return IntegralKind::Number; }
+
   constexpr static unsigned bitWidth() { return 1; }
   bool isZero() const { return !V; }
   bool isMin() const { return isZero(); }
@@ -84,7 +88,7 @@ class Boolean final {
   void bitcastToMemory(std::byte *Buff) { std::memcpy(Buff, &V, sizeof(V)); }
 
   void print(llvm::raw_ostream &OS) const { OS << (V ? "true" : "false"); }
-  std::string toDiagnosticString(const ASTContext &Ctx) const {
+  std::string toDiagnosticString(const ASTContext &Ctx, const Program &) const 
{
     std::string NameStr;
     llvm::raw_string_ostream OS(NameStr);
     print(OS);
diff --git a/clang/lib/AST/ByteCode/Context.cpp 
b/clang/lib/AST/ByteCode/Context.cpp
index 74ec986e49ca7..6f716b0aee70e 100644
--- a/clang/lib/AST/ByteCode/Context.cpp
+++ b/clang/lib/AST/ByteCode/Context.cpp
@@ -186,7 +186,7 @@ bool Context::evaluateStringRepr(State &Parent, const Expr 
*SizeExpr,
       return false;
 
     // Must be char.
-    if (Ptr.getFieldDesc()->getElemSize() != 1 /*bytes*/)
+    if (Ptr.getFieldDesc()->getElemDataSize() != 1 /*bytes*/)
       return false;
 
     if (Size > Ptr.getNumElems()) {
@@ -199,7 +199,7 @@ bool Context::evaluateStringRepr(State &Parent, const Expr 
*SizeExpr,
       Result = APValue(APValue::UninitArray{}, Size, Size);
       for (uint64_t I = 0; I != Size; ++I) {
         if (std::optional<APValue> ElemVal =
-                Ptr.atIndex(I).toRValue(*this, CharTy))
+                Ptr.atIndex(I).toRValue(*this, CharTy, *P))
           Result.getArrayInitializedElt(I) = *ElemVal;
         else
           return false;
@@ -208,7 +208,12 @@ bool Context::evaluateStringRepr(State &Parent, const Expr 
*SizeExpr,
       assert((std::is_same_v<ResultT, std::string>));
       if (Size < Result.max_size())
         Result.resize(Size);
-      Result.assign(reinterpret_cast<const char *>(Ptr.getRawAddress()), Size);
+      unsigned StartIndex = Ptr.getIndex();
+      for (uint64_t I = 0; I != Size; ++I) {
+        FIXED_SIZE_INT_TYPE_SWITCH(Ptr.getFieldDesc()->getPrimType(), {
+          Result[I] = static_cast<char>(Ptr.elem<T>(StartIndex + I));
+        });
+      }
     }
 
     return true;
diff --git a/clang/lib/AST/ByteCode/Descriptor.cpp 
b/clang/lib/AST/ByteCode/Descriptor.cpp
index 0a819599287ee..59ad3015b9b47 100644
--- a/clang/lib/AST/ByteCode/Descriptor.cpp
+++ b/clang/lib/AST/ByteCode/Descriptor.cpp
@@ -468,6 +468,13 @@ bool Descriptor::hasTrivialDtor() const {
 
 bool Descriptor::isUnion() const { return isRecord() && ElemRecord->isUnion(); 
}
 
+unsigned Descriptor::getElemDataSize() const {
+  if ((isPrimitive() || isPrimitiveArray()) && isIntegralType(getPrimType())) {
+    FIXED_SIZE_INT_TYPE_SWITCH(getPrimType(), { return T::bitWidth() / 8; });
+  }
+  return ElemSize;
+}
+
 InitMap::InitMap(unsigned N)
     : UninitFields(N), Data(std::make_unique<T[]>(numFields(N))) {}
 
diff --git a/clang/lib/AST/ByteCode/Descriptor.h 
b/clang/lib/AST/ByteCode/Descriptor.h
index 90dc2b4aa3111..e4f262d52b858 100644
--- a/clang/lib/AST/ByteCode/Descriptor.h
+++ b/clang/lib/AST/ByteCode/Descriptor.h
@@ -242,6 +242,11 @@ struct Descriptor final {
   unsigned getAllocSize() const { return AllocSize; }
   /// returns the size of an element when the structure is viewed as an array.
   unsigned getElemSize() const { return ElemSize; }
+  /// Returns the element data size, i.e. not what the size of
+  /// our primitive data type is, but what the data size of that is.
+  /// E.g., for PT_SInt32, that's 4 bytes.
+  unsigned getElemDataSize() const;
+
   /// Returns the size of the metadata.
   unsigned getMetadataSize() const { return MDSize; }
 
diff --git a/clang/lib/AST/ByteCode/EvalEmitter.cpp 
b/clang/lib/AST/ByteCode/EvalEmitter.cpp
index a2e01efc8ffd9..9040e4ac5b67c 100644
--- a/clang/lib/AST/ByteCode/EvalEmitter.cpp
+++ b/clang/lib/AST/ByteCode/EvalEmitter.cpp
@@ -182,7 +182,7 @@ template <PrimType OpType> bool 
EvalEmitter::emitRet(SourceInfo Info) {
     return true;
 
   using T = typename PrimConv<OpType>::T;
-  EvalResult.takeValue(S.Stk.pop<T>().toAPValue(Ctx.getASTContext()));
+  EvalResult.takeValue(S.Stk.pop<T>().toAPValue(Ctx.getASTContext(), S.P));
   return true;
 }
 
@@ -193,7 +193,7 @@ template <> bool EvalEmitter::emitRet<PT_Ptr>(SourceInfo 
Info) {
   const Pointer &Ptr = S.Stk.pop<Pointer>();
 
   if (Ptr.isFunctionPointer()) {
-    EvalResult.takeValue(Ptr.toAPValue(Ctx.getASTContext()));
+    EvalResult.takeValue(Ptr.toAPValue(Ctx.getASTContext(), S.P));
     return true;
   }
 
@@ -224,7 +224,7 @@ template <> bool EvalEmitter::emitRet<PT_Ptr>(SourceInfo 
Info) {
       return false;
 
     if (std::optional<APValue> V =
-            Ptr.toRValue(Ctx, EvalResult.getSourceType())) {
+            Ptr.toRValue(Ctx, EvalResult.getSourceType(), P)) {
       EvalResult.takeValue(std::move(*V));
     } else {
       return false;
@@ -234,14 +234,14 @@ template <> bool EvalEmitter::emitRet<PT_Ptr>(SourceInfo 
Info) {
     // the result, even if the pointer is dead.
     // This will later be diagnosed by CheckLValueConstantExpression.
     if (Ptr.isBlockPointer() && !Ptr.block()->isStatic()) {
-      EvalResult.takeValue(Ptr.toAPValue(Ctx.getASTContext()));
+      EvalResult.takeValue(Ptr.toAPValue(Ctx.getASTContext(), S.P));
       return true;
     }
 
     if (!Ptr.isLive() && !Ptr.isTemporary())
       return false;
 
-    EvalResult.takeValue(Ptr.toAPValue(Ctx.getASTContext()));
+    EvalResult.takeValue(Ptr.toAPValue(Ctx.getASTContext(), S.P));
   }
 
   return true;
@@ -261,7 +261,7 @@ bool EvalEmitter::emitRetValue(SourceInfo Info) {
     return false;
 
   if (std::optional<APValue> APV =
-          Ptr.toRValue(S.getASTContext(), EvalResult.getSourceType())) {
+          Ptr.toRValue(S.getASTContext(), EvalResult.getSourceType(), P)) {
     EvalResult.takeValue(std::move(*APV));
     return true;
   }
@@ -361,11 +361,12 @@ void EvalEmitter::updateGlobalTemporaries() {
     const Pointer &Ptr = P.getPtrGlobal(*GlobalIndex);
     APValue *Cached = Temp->getOrCreateValue(true);
     if (OptPrimType T = Ctx.classify(E->getType())) {
-      TYPE_SWITCH(*T,
-                  { *Cached = Ptr.deref<T>().toAPValue(Ctx.getASTContext()); 
});
+      TYPE_SWITCH(*T, {
+        *Cached = Ptr.deref<T>().toAPValue(Ctx.getASTContext(), S.P);
+      });
     } else {
       if (std::optional<APValue> APV =
-              Ptr.toRValue(Ctx, Temp->getTemporaryExpr()->getType()))
+              Ptr.toRValue(Ctx, Temp->getTemporaryExpr()->getType(), P))
         *Cached = *APV;
     }
   }
diff --git a/clang/lib/AST/ByteCode/FixedPoint.h 
b/clang/lib/AST/ByteCode/FixedPoint.h
index fcb3c79cc1097..694b541c14cb5 100644
--- a/clang/lib/AST/ByteCode/FixedPoint.h
+++ b/clang/lib/AST/ByteCode/FixedPoint.h
@@ -13,6 +13,8 @@
 #include "clang/AST/ComparisonCategories.h"
 #include "llvm/ADT/APFixedPoint.h"
 
+#include "Program.h"
+
 namespace clang {
 namespace interp {
 
@@ -49,7 +51,9 @@ class FixedPoint final {
   operator bool() const { return V.getBoolValue(); }
   void print(llvm::raw_ostream &OS) const { OS << V; }
 
-  APValue toAPValue(const ASTContext &) const { return APValue(V); }
+  APValue toAPValue(const ASTContext &, const Program &) const {
+    return APValue(V);
+  }
   APSInt toAPSInt(unsigned BitWidth = 0) const { return V.getValue(); }
 
   unsigned bitWidth() const { return V.getWidth(); }
@@ -78,9 +82,10 @@ class FixedPoint final {
     return V.convertToInt(BitWidth, Signed, Overflow);
   }
 
-  std::string toDiagnosticString(const ASTContext &Ctx) const {
+  std::string toDiagnosticString(const ASTContext &Ctx, const Program &) const 
{
     return V.toString();
   }
+  static IntegralKind getKind() { return IntegralKind::Number; }
 
   ComparisonCategoryResult compare(const FixedPoint &Other) const {
     int c = V.compare(Other.V);
diff --git a/clang/lib/AST/ByteCode/Floating.h 
b/clang/lib/AST/ByteCode/Floating.h
index cc918dc12deb6..149133a535953 100644
--- a/clang/lib/AST/ByteCode/Floating.h
+++ b/clang/lib/AST/ByteCode/Floating.h
@@ -14,6 +14,7 @@
 #define LLVM_CLANG_AST_INTERP_FLOATING_H
 
 #include "Primitives.h"
+#include "Program.h"
 #include "clang/AST/APValue.h"
 #include "llvm/ADT/APFloat.h"
 
@@ -86,14 +87,16 @@ class Floating final {
   APSInt toAPSInt(unsigned NumBits = 0) const {
     return APSInt(getValue().bitcastToAPInt());
   }
-  APValue toAPValue(const ASTContext &) const { return APValue(getValue()); }
+  APValue toAPValue(const ASTContext &, const Program &) const {
+    return APValue(getValue());
+  }
   void print(llvm::raw_ostream &OS) const {
     // Can't use APFloat::print() since it appends a newline.
     SmallVector<char, 16> Buffer;
     getValue().toString(Buffer);
     OS << Buffer;
   }
-  std::string toDiagnosticString(const ASTContext &Ctx) const {
+  std::string toDiagnosticString(const ASTContext &Ctx, const Program &) const 
{
     std::string NameStr;
     llvm::raw_string_ostream OS(NameStr);
     print(OS);
diff --git a/clang/lib/AST/ByteCode/Integral.h 
b/clang/lib/AST/ByteCode/Integral.h
index e90f1a9a74e1c..d86f04c3afa8e 100644
--- a/clang/lib/AST/ByteCode/Integral.h
+++ b/clang/lib/AST/ByteCode/Integral.h
@@ -14,6 +14,7 @@
 #define LLVM_CLANG_AST_INTERP_INTEGRAL_H
 
 #include "clang/AST/APValue.h"
+#include "clang/AST/CharUnits.h"
 #include "clang/AST/ComparisonCategories.h"
 #include "llvm/ADT/APSInt.h"
 #include "llvm/Support/MathExtras.h"
@@ -22,6 +23,7 @@
 #include <cstdint>
 
 #include "Primitives.h"
+#include "Program.h"
 
 namespace clang {
 namespace interp {
@@ -69,8 +71,9 @@ template <unsigned Bits, bool Signed> class Integral final {
 
   // The primitive representing the integral.
   using ReprT = typename Repr<Bits, Signed>::Type;
-  ReprT V;
   static_assert(std::is_trivially_copyable_v<ReprT>);
+  ReprT V;
+  IntegralKind Kind = IntegralKind::Number;
 
   /// Primitive representing limits.
   static const auto Min = std::numeric_limits<ReprT>::min();
@@ -78,6 +81,8 @@ template <unsigned Bits, bool Signed> class Integral final {
 
   /// Construct an integral from anything that is convertible to storage.
   template <typename T> explicit Integral(T V) : V(V) {}
+  template <typename T>
+  explicit Integral(IntegralKind Kind, T V) : V(V), Kind(Kind) {}
 
 public:
   using AsUnsigned = Integral<Bits, false>;
@@ -87,7 +92,9 @@ template <unsigned Bits, bool Signed> class Integral final {
 
   /// Constructs an integral from another integral.
   template <unsigned SrcBits, bool SrcSign>
-  explicit Integral(Integral<SrcBits, SrcSign> V) : V(V.V) {}
+  explicit Integral(Integral<SrcBits, SrcSign> V) : V(V.V), Kind(V.Kind) {}
+
+  IntegralKind getKind() const { return Kind; }
 
   /// Construct an integral from a value based on signedness.
   explicit Integral(const APSInt &V)
@@ -115,7 +122,7 @@ template <unsigned Bits, bool Signed> class Integral final {
 
   template <unsigned DstBits, bool DstSign>
   explicit operator Integral<DstBits, DstSign>() const {
-    return Integral<DstBits, DstSign>(V);
+    return Integral<DstBits, DstSign>(Kind, V);
   }
 
   template <typename Ty, typename = std::enable_if_t<std::is_integral_v<Ty>>>
@@ -137,7 +144,35 @@ template <unsigned Bits, bool Signed> class Integral final 
{
       return APInt(Bits, static_cast<uint64_t>(V), Signed)
           .zextOrTrunc(BitWidth);
   }
-  APValue toAPValue(const ASTContext &) const { return APValue(toAPSInt()); }
+  APValue toAPValue(const ASTContext &, const Program &P) const {
+    switch (Kind) {
+    case IntegralKind::Address: {
+      const ValueDecl *VD =
+          reinterpret_cast<const ValueDecl *>(P.getNativePointer(V));
+      return APValue(VD, CharUnits::Zero(), APValue::NoLValuePath{});
+    }
+    case IntegralKind::LabelAddress: {
+      const Expr *VD = reinterpret_cast<const Expr *>(P.getNativePointer(V));
+      return APValue(VD, CharUnits::Zero(), APValue::NoLValuePath{});
+    }
+    case IntegralKind::BlockAddress: {
+      const Block *B = reinterpret_cast<const Block *>(P.getNativePointer(V));
+      const Descriptor *D = B->getDescriptor();
+      if (const Expr *E = D->asExpr())
+        return APValue(E, CharUnits::Zero(), APValue::NoLValuePath{});
+
+      return APValue(D->asValueDecl(), CharUnits::Zero(),
+                     APValue::NoLValuePath{});
+    }
+    case IntegralKind::AddrLabelDiff: {
+      AddrLabelDiff ALD = P.getLabelDiff(V);
+      return APValue(ALD.LHS, ALD.RHS);
+    }
+    case IntegralKind::Number:
+      return APValue(toAPSInt());
+    }
+    llvm_unreachable("Unhandled IntegralKind");
+  }
 
   Integral<Bits, false> toUnsigned() const {
     return Integral<Bits, false>(*this);
@@ -172,7 +207,7 @@ template <unsigned Bits, bool Signed> class Integral final {
     return Integral(V);
   }
 
-  std::string toDiagnosticString(const ASTContext &Ctx) const {
+  std::string toDiagnosticString(const ASTContext &Ctx, const Program &) const 
{
     std::string NameStr;
     llvm::raw_string_ostream OS(NameStr);
     OS << V;
@@ -198,14 +233,25 @@ template <unsigned Bits, bool Signed> class Integral 
final {
     return Integral((V & BitMask) | (Signed && (V & SignBit) ? ExtMask : 0));
   }
 
-  void print(llvm::raw_ostream &OS) const { OS << V; }
+  void print(llvm::raw_ostream &OS) const {
+    OS << V;
+    if (Kind == IntegralKind::Address)
+      OS << " (Address)";
+    else if (Kind == IntegralKind::BlockAddress)
+      OS << " (BlockAddress)";
+    else if (Kind == IntegralKind::LabelAddress)
+      OS << " (LabelAddress)";
+    else if (Kind == IntegralKind::AddrLabelDiff)
+      OS << " (LabelAddrDiff)";
+  }
 
   static Integral min(unsigned NumBits) { return Integral(Min); }
   static Integral max(unsigned NumBits) { return Integral(Max); }
   static Integral zero(unsigned BitWidth = 0) { return from(0); }
 
   template <typename ValT>
-  static Integral from(ValT Value, unsigned NumBits = 0) {
+  static std::enable_if_t<!std::is_same_v<ValT, IntegralKind>, Integral>
+  from(ValT Value, unsigned NumBits = 0) {
     if constexpr (std::is_integral_v<ValT>)
       return Integral(Value);
     else
@@ -213,8 +259,13 @@ template <unsigned Bits, bool Signed> class Integral final 
{
   }
 
   template <unsigned SrcBits, bool SrcSign>
-  static Integral from(Integral<SrcBits, SrcSign> Value) {
-    return Integral(Value.V);
+  static std::enable_if_t<SrcBits != 0, Integral>
+  from(Integral<SrcBits, SrcSign> Value) {
+    return Integral(Value.Kind, Value.V);
+  }
+
+  template <typename T> static Integral from(IntegralKind Kind, T Value) {
+    return Integral(Kind, Value);
   }
 
   static bool increment(Integral A, Integral *R) {
diff --git a/clang/lib/AST/ByteCode/IntegralAP.h 
b/clang/lib/AST/ByteCode/IntegralAP.h
index b11e6eea28e3f..b14951559fd2a 100644
--- a/clang/lib/AST/ByteCode/IntegralAP.h
+++ b/clang/lib/AST/ByteCode/IntegralAP.h
@@ -22,6 +22,7 @@
 #include <cstdint>
 
 #include "Primitives.h"
+#include "Program.h"
 
 namespace clang {
 namespace interp {
@@ -150,7 +151,9 @@ template <bool Signed> class IntegralAP final {
     else
       return APSInt(getValue().zext(Bits), !Signed);
   }
-  APValue toAPValue(const ASTContext &) const { return APValue(toAPSInt()); }
+  APValue toAPValue(const ASTContext &, const Program &) const {
+    return APValue(toAPSInt());
+  }
 
   bool isZero() const { return getValue().isZero(); }
   bool isPositive() const {
@@ -179,12 +182,13 @@ template <bool Signed> class IntegralAP final {
   unsigned countLeadingZeros() const { return getValue().countl_zero(); }
 
   void print(llvm::raw_ostream &OS) const { getValue().print(OS, Signed); }
-  std::string toDiagnosticString(const ASTContext &Ctx) const {
+  std::string toDiagnosticString(const ASTContext &Ctx, const Program &) const 
{
     std::string NameStr;
     llvm::raw_string_ostream OS(NameStr);
     print(OS);
     return NameStr;
   }
+  static IntegralKind getKind() { return IntegralKind::Number; }
 
   IntegralAP truncate(unsigned BitWidth) const {
     if constexpr (Signed)
diff --git a/clang/lib/AST/ByteCode/Interp.cpp 
b/clang/lib/AST/ByteCode/Interp.cpp
index c3210d7119b40..f35d3789c8798 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -1149,7 +1149,7 @@ bool CheckDeleteSource(InterpState &S, CodePtr OpPC, 
const Expr *Source,
   // Whatever this is, we didn't heap allocate it.
   const SourceInfo &Loc = S.Current->getSource(OpPC);
   S.FFDiag(Loc, diag::note_constexpr_delete_not_heap_alloc)
-      << Ptr.toDiagnosticString(S.getASTContext());
+      << Ptr.toDiagnosticString(S.getASTContext(), S.P);
 
   if (Ptr.isTemporary())
     S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);
@@ -1321,7 +1321,8 @@ bool Free(InterpState &S, CodePtr OpPC, bool 
DeleteIsArrayForm,
         (Ptr.isArrayElement() && Ptr.getIndex() != 0)) {
       const SourceInfo &Loc = S.Current->getSource(OpPC);
       S.FFDiag(Loc, diag::note_constexpr_delete_subobject)
-          << Ptr.toDiagnosticString(S.getASTContext()) << Ptr.isOnePastEnd();
+          << Ptr.toDiagnosticString(S.getASTContext(), S.P)
+          << Ptr.isOnePastEnd();
       return false;
     }
 
@@ -1445,7 +1446,7 @@ static bool getField(InterpState &S, CodePtr OpPC, const 
Pointer &Ptr,
     // `typeid(int).name`, but we currently diagnose `&typeid(int)`.
     S.FFDiag(S.Current->getSource(OpPC),
              diag::note_constexpr_access_unreadable_object)
-        << AK_Read << Ptr.toDiagnosticString(S.getASTContext());
+        << AK_Read << Ptr.toDiagnosticString(S.getASTContext(), S.P);
     return false;
   }
 
@@ -1677,7 +1678,7 @@ static bool GetDynamicDecl(InterpState &S, CodePtr OpPC, 
Pointer TypePtr,
     if (const VarDecl *VD = TypePtr.getDeclDesc()->asVarDecl();
         VD && !VD->isConstexpr()) {
       const Expr *E = S.Current->getExpr(OpPC);
-      APValue V = TypePtr.toAPValue(S.getASTContext());
+      APValue V = TypePtr.toAPValue(S.getASTContext(), S.P);
       QualType TT = S.getASTContext().getLValueReferenceType(DynamicType);
       S.FFDiag(E, diag::note_constexpr_polymorphic_unknown_dynamic_type)
           << AccessKinds::AK_MemberCall << V.getAsString(S.getASTContext(), 
TT);
@@ -2064,10 +2065,10 @@ bool handleFixedPointOverflow(InterpState &S, CodePtr 
OpPC,
   if (S.checkingForUndefinedBehavior()) {
     S.getASTContext().getDiagnostics().Report(
         E->getExprLoc(), diag::warn_fixedpoint_constant_overflow)
-        << FP.toDiagnosticString(S.getASTContext()) << E->getType();
+        << FP.toDiagnosticString(S.getASTContext(), S.P) << E->getType();
   }
   S.CCEDiag(E, diag::note_constexpr_overflow)
-      << FP.toDiagnosticString(S.getASTContext()) << E->getType();
+      << FP.toDiagnosticString(S.getASTContext(), S.P) << E->getType();
   return S.noteUndefinedBehavior();
 }
 
@@ -2085,12 +2086,12 @@ bool CheckPointerToIntegralCast(InterpState &S, CodePtr 
OpPC,
   S.CCEDiag(E, diag::note_constexpr_invalid_cast)
       << 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
 
-  if (Ptr.isDummy())
+  if (Ptr.isDummy() && !Ptr.pointsToLabel())
     return false;
-  if (Ptr.isFunctionPointer())
+  if (Ptr.isIntegralPointer())
     return true;
 
-  if (Ptr.isBlockPointer() && !Ptr.isZero()) {
+  if (!Ptr.isZero()) {
     // Only allow based lvalue casts if they are lossless.
     if (S.getASTContext().getTargetInfo().getPointerWidth(LangAS::Default) !=
         BitWidth)
@@ -2099,6 +2100,11 @@ bool CheckPointerToIntegralCast(InterpState &S, CodePtr 
OpPC,
   return true;
 }
 
+bool CheckIntegralAddressCast(InterpState &S, CodePtr OpPC, unsigned BitWidth) 
{
+  return (S.getASTContext().getTargetInfo().getPointerWidth(LangAS::Default) ==
+          BitWidth);
+}
+
 bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
   const Pointer &Ptr = S.Stk.pop<Pointer>();
 
@@ -2184,13 +2190,19 @@ bool DiagTypeid(InterpState &S, CodePtr OpPC) {
 
 bool arePotentiallyOverlappingStringLiterals(const Pointer &LHS,
                                              const Pointer &RHS) {
+  if (!LHS.pointsToStringLiteral() || !RHS.pointsToStringLiteral())
+    return false;
+
   unsigned LHSOffset = LHS.isOnePastEnd() ? LHS.getNumElems() : LHS.getIndex();
   unsigned RHSOffset = RHS.isOnePastEnd() ? RHS.getNumElems() : RHS.getIndex();
-  unsigned LHSLength = (LHS.getNumElems() - 1) * LHS.elemSize();
-  unsigned RHSLength = (RHS.getNumElems() - 1) * RHS.elemSize();
+  const auto *LHSLit = cast<StringLiteral>(LHS.getDeclDesc()->asExpr());
+  const auto *RHSLit = cast<StringLiteral>(RHS.getDeclDesc()->asExpr());
+
+  StringRef LHSStr(LHSLit->getBytes());
+  unsigned LHSLength = LHSStr.size();
+  StringRef RHSStr(RHSLit->getBytes());
+  unsigned RHSLength = RHSStr.size();
 
-  StringRef LHSStr((const char *)LHS.atIndex(0).getRawAddress(), LHSLength);
-  StringRef RHSStr((const char *)RHS.atIndex(0).getRawAddress(), RHSLength);
   int32_t IndexDiff = RHSOffset - LHSOffset;
   if (IndexDiff < 0) {
     if (static_cast<int32_t>(LHSLength) < -IndexDiff)
@@ -2206,11 +2218,11 @@ bool arePotentiallyOverlappingStringLiterals(const 
Pointer &LHS,
   StringRef Shorter;
   StringRef Longer;
   if (LHSLength < RHSLength) {
-    ShorterCharWidth = LHS.elemSize();
+    ShorterCharWidth = LHS.getFieldDesc()->getElemDataSize();
     Shorter = LHSStr;
     Longer = RHSStr;
   } else {
-    ShorterCharWidth = RHS.elemSize();
+    ShorterCharWidth = RHS.getFieldDesc()->getElemDataSize();
     Shorter = RHSStr;
     Longer = LHSStr;
   }
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index d8b8b209fa927..95caf0131a5c8 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -332,6 +332,33 @@ bool Sub(InterpState &S, CodePtr OpPC) {
   const T &LHS = S.Stk.pop<T>();
   const unsigned Bits = RHS.bitWidth() + 1;
 
+  // Handle (int)&&a - (int)&&b.
+  // Both operands should be integrals that point to labels and the result is a
+  // AddrLabelDiff integral.
+  if (LHS.getKind() == IntegralKind::LabelAddress ||
+      RHS.getKind() == IntegralKind::LabelAddress) {
+    const auto *A = reinterpret_cast<const Expr *>(
+        S.P.getNativePointer(static_cast<uint32_t>(LHS)));
+    const auto *B = reinterpret_cast<const Expr *>(
+        S.P.getNativePointer(static_cast<uint32_t>(RHS)));
+    if (isa<AddrLabelExpr>(A) && isa<AddrLabelExpr>(B)) {
+      const auto *LHSAddrExpr = cast<AddrLabelExpr>(A);
+      const auto *RHSAddrExpr = cast<AddrLabelExpr>(B);
+
+      if (LHSAddrExpr->getLabel()->getDeclContext() !=
+          RHSAddrExpr->getLabel()->getDeclContext())
+        return Invalid(S, OpPC);
+
+      unsigned Index = S.P.getOrCreateAddrLabelDiff(LHSAddrExpr, RHSAddrExpr);
+      if constexpr (std::is_same_v<T, Boolean>) {
+      } else if constexpr (std::is_same_v<T, FixedPoint>) {
+      } else {
+        S.Stk.push<T>(T::from(IntegralKind::AddrLabelDiff, Index));
+      }
+      return true;
+    }
+  }
+
   return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, Bits, LHS, RHS);
 }
 
@@ -1005,16 +1032,16 @@ inline bool CmpHelper<Pointer>(InterpState &S, CodePtr 
OpPC, CompareFn Fn) {
       LHS.isTypeidPointer() || RHS.isTypeidPointer()) {
     const SourceInfo &Loc = S.Current->getSource(OpPC);
     S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
-        << LHS.toDiagnosticString(S.getASTContext())
-        << RHS.toDiagnosticString(S.getASTContext());
+        << LHS.toDiagnosticString(S.getASTContext(), S.P)
+        << RHS.toDiagnosticString(S.getASTContext(), S.P);
     return false;
   }
 
   if (!Pointer::hasSameBase(LHS, RHS)) {
     const SourceInfo &Loc = S.Current->getSource(OpPC);
     S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
-        << LHS.toDiagnosticString(S.getASTContext())
-        << RHS.toDiagnosticString(S.getASTContext());
+        << LHS.toDiagnosticString(S.getASTContext(), S.P)
+        << RHS.toDiagnosticString(S.getASTContext(), S.P);
     return false;
   }
 
@@ -1066,7 +1093,7 @@ inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr 
OpPC, CompareFn Fn) {
     if (P.isWeak()) {
       const SourceInfo &Loc = S.Current->getSource(OpPC);
       S.FFDiag(Loc, diag::note_constexpr_pointer_weak_comparison)
-          << P.toDiagnosticString(S.getASTContext());
+          << P.toDiagnosticString(S.getASTContext(), S.P);
       return false;
     }
   }
@@ -1088,8 +1115,8 @@ inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr 
OpPC, CompareFn Fn) {
     if (arePotentiallyOverlappingStringLiterals(LHS, RHS)) {
       const SourceInfo &Loc = S.Current->getSource(OpPC);
       S.FFDiag(Loc, diag::note_constexpr_literal_comparison)
-          << LHS.toDiagnosticString(S.getASTContext())
-          << RHS.toDiagnosticString(S.getASTContext());
+          << LHS.toDiagnosticString(S.getASTContext(), S.P)
+          << RHS.toDiagnosticString(S.getASTContext(), S.P);
       return false;
     }
   }
@@ -1106,14 +1133,14 @@ inline bool CmpHelperEQ<Pointer>(InterpState &S, 
CodePtr OpPC, CompareFn Fn) {
       RHS.getOffset() == 0) {
     const SourceInfo &Loc = S.Current->getSource(OpPC);
     S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end)
-        << LHS.toDiagnosticString(S.getASTContext());
+        << LHS.toDiagnosticString(S.getASTContext(), S.P);
     return false;
   }
   if (RHS.isOnePastEnd() && !LHS.isOnePastEnd() && !LHS.isZero() &&
       LHS.getOffset() == 0) {
     const SourceInfo &Loc = S.Current->getSource(OpPC);
     S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end)
-        << RHS.toDiagnosticString(S.getASTContext());
+        << RHS.toDiagnosticString(S.getASTContext(), S.P);
     return false;
   }
 
@@ -1133,14 +1160,14 @@ inline bool CmpHelperEQ<Pointer>(InterpState &S, 
CodePtr OpPC, CompareFn Fn) {
           CE && IsOpaqueConstantCall(CE)) {
         const SourceInfo &Loc = S.Current->getSource(OpPC);
         S.FFDiag(Loc, diag::note_constexpr_opaque_call_comparison)
-            << P.toDiagnosticString(S.getASTContext());
+            << P.toDiagnosticString(S.getASTContext(), S.P);
         return false;
       }
     } else if (BothNonNull && P.isIntegralPointer()) {
       const SourceInfo &Loc = S.Current->getSource(OpPC);
       S.FFDiag(Loc, diag::note_constexpr_pointer_constant_comparison)
-          << LHS.toDiagnosticString(S.getASTContext())
-          << RHS.toDiagnosticString(S.getASTContext());
+          << LHS.toDiagnosticString(S.getASTContext(), S.P)
+          << RHS.toDiagnosticString(S.getASTContext(), S.P);
       return false;
     }
   }
@@ -1148,8 +1175,8 @@ inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr 
OpPC, CompareFn Fn) {
   if (LHS.isUnknownSizeArray() && RHS.isUnknownSizeArray()) {
     const SourceInfo &Loc = S.Current->getSource(OpPC);
     S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_zero_sized)
-        << LHS.toDiagnosticString(S.getASTContext())
-        << RHS.toDiagnosticString(S.getASTContext());
+        << LHS.toDiagnosticString(S.getASTContext(), S.P)
+        << RHS.toDiagnosticString(S.getASTContext(), S.P);
     return false;
   }
 
@@ -1217,8 +1244,8 @@ bool CMP3(InterpState &S, CodePtr OpPC, const 
ComparisonCategoryInfo *CmpInfo) {
     if (CmpResult == ComparisonCategoryResult::Unordered) {
       const SourceInfo &Loc = S.Current->getSource(OpPC);
       S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
-          << LHS.toDiagnosticString(S.getASTContext())
-          << RHS.toDiagnosticString(S.getASTContext());
+          << LHS.toDiagnosticString(S.getASTContext(), S.P)
+          << RHS.toDiagnosticString(S.getASTContext(), S.P);
       return false;
     }
   }
@@ -1311,7 +1338,28 @@ bool Const(InterpState &S, CodePtr OpPC, const T &Arg) {
     S.Stk.push<T>(Result);
     return true;
   }
-  S.Stk.push<T>(Arg);
+
+  if constexpr (std::is_same_v<T, uint8_t>) {
+    S.Stk.push<Integral<8, false>>(Integral<8, false>::from(Arg));
+  } else if constexpr (std::is_same_v<T, int8_t>) {
+    S.Stk.push<Integral<8, true>>(Integral<8, true>::from(Arg));
+  } else if constexpr (std::is_same_v<T, uint16_t>) {
+    S.Stk.push<Integral<16, false>>(Integral<16, false>::from(Arg));
+  } else if constexpr (std::is_same_v<T, int16_t>) {
+    S.Stk.push<Integral<16, true>>(Integral<16, true>::from(Arg));
+  } else if constexpr (std::is_same_v<T, uint32_t>) {
+    S.Stk.push<Integral<32, false>>(Integral<32, false>::from(Arg));
+  } else if constexpr (std::is_same_v<T, int32_t>) {
+    S.Stk.push<Integral<32, true>>(Integral<32, true>::from(Arg));
+  } else if constexpr (std::is_same_v<T, uint64_t>) {
+    S.Stk.push<Integral<64, false>>(Integral<64, false>::from(Arg));
+  } else if constexpr (std::is_same_v<T, int64_t>) {
+    S.Stk.push<Integral<64, true>>(Integral<64, true>::from(Arg));
+  } else {
+    // Bool.
+    S.Stk.push<T>(Arg);
+  }
+
   return true;
 }
 
@@ -2392,11 +2440,28 @@ inline bool SubPtr(InterpState &S, CodePtr OpPC, bool 
ElemSizeIsZero) {
   const Pointer &LHS = S.Stk.pop<Pointer>().expand();
   const Pointer &RHS = S.Stk.pop<Pointer>().expand();
 
+  if (LHS.pointsToLabel() || RHS.pointsToLabel()) {
+    const auto *LHSAddrExpr =
+        dyn_cast_if_present<AddrLabelExpr>(LHS.getDeclDesc()->asExpr());
+    const auto *RHSAddrExpr =
+        dyn_cast_if_present<AddrLabelExpr>(RHS.getDeclDesc()->asExpr());
+    if (!LHSAddrExpr || !RHSAddrExpr)
+      return false;
+
+    if (LHSAddrExpr->getLabel()->getDeclContext() !=
+        RHSAddrExpr->getLabel()->getDeclContext())
+      return Invalid(S, OpPC);
+
+    unsigned Index = S.P.getOrCreateAddrLabelDiff(LHSAddrExpr, RHSAddrExpr);
+    S.Stk.push<T>(T::from(IntegralKind::AddrLabelDiff, Index));
+    return true;
+  }
+
   if (!Pointer::hasSameBase(LHS, RHS) && S.getLangOpts().CPlusPlus) {
     S.FFDiag(S.Current->getSource(OpPC),
              diag::note_constexpr_pointer_arith_unspecified)
-        << LHS.toDiagnosticString(S.getASTContext())
-        << RHS.toDiagnosticString(S.getASTContext());
+        << LHS.toDiagnosticString(S.getASTContext(), S.P)
+        << RHS.toDiagnosticString(S.getASTContext(), S.P);
     return false;
   }
 
@@ -2459,7 +2524,7 @@ inline bool Destroy(InterpState &S, CodePtr OpPC, 
uint32_t I) {
       } else {
         S.FFDiag(Ptr.getDeclDesc()->getLocation(),
                  diag::note_constexpr_destroy_out_of_lifetime)
-            << Ptr.toDiagnosticString(S.getASTContext());
+            << Ptr.toDiagnosticString(S.getASTContext(), S.P);
       }
       return false;
     }
@@ -2493,7 +2558,16 @@ inline bool GetLocalEnabled(InterpState &S, CodePtr 
OpPC, uint32_t I) {
 template <PrimType TIn, PrimType TOut> bool Cast(InterpState &S, CodePtr OpPC) 
{
   using T = typename PrimConv<TIn>::T;
   using U = typename PrimConv<TOut>::T;
-  S.Stk.push<U>(U::from(S.Stk.pop<T>()));
+
+  auto In = S.Stk.pop<T>();
+
+  if (In.getKind() != IntegralKind::Number &&
+      In.getKind() != IntegralKind::AddrLabelDiff) {
+    if (!CheckIntegralAddressCast(S, OpPC, In.bitWidth()))
+      return Invalid(S, OpPC);
+  }
+
+  S.Stk.push<U>(U::from(In));
   return true;
 }
 
@@ -2639,6 +2713,7 @@ static inline bool CastFloatingIntegralAPS(InterpState 
&S, CodePtr OpPC,
 
 bool CheckPointerToIntegralCast(InterpState &S, CodePtr OpPC,
                                 const Pointer &Ptr, unsigned BitWidth);
+bool CheckIntegralAddressCast(InterpState &S, CodePtr OpPC, unsigned BitWidth);
 bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth);
 bool CastPointerIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth);
 
@@ -2649,7 +2724,33 @@ bool CastPointerIntegral(InterpState &S, CodePtr OpPC) {
   if (!CheckPointerToIntegralCast(S, OpPC, Ptr, T::bitWidth()))
     return Invalid(S, OpPC);
 
-  S.Stk.push<T>(T::from(Ptr.getIntegerRepresentation()));
+  if constexpr (std::is_same_v<T, Boolean>) {
+
+    S.Stk.push<T>(T::from(Ptr.getIntegerRepresentation()));
+  } else {
+    if (Ptr.isBlockPointer()) {
+      uintptr_t IntVal;
+      IntegralKind Kind = IntegralKind::Address;
+      if (Ptr.isDummy()) {
+        if (const Expr *E = Ptr.getDeclDesc()->asExpr()) {
+          IntVal = S.P.getOrCreateNativePointer(E);
+          if (isa<AddrLabelExpr>(E))
+            Kind = IntegralKind::LabelAddress;
+        } else
+          IntVal = S.P.getOrCreateNativePointer(Ptr.getDeclDesc()->asDecl());
+      } else {
+        Kind = IntegralKind::BlockAddress;
+        IntVal = S.P.getOrCreateNativePointer(Ptr.block());
+      }
+      S.Stk.push<T>(T::from(Kind, IntVal));
+    } else if (Ptr.isFunctionPointer()) {
+      uintptr_t IntVal = S.P.getOrCreateNativePointer(
+          Ptr.asFunctionPointer().getFunction()->getDecl());
+      S.Stk.push<T>(T::from(IntegralKind::Address, IntVal));
+    } else {
+      S.Stk.push<T>(T::from(Ptr.getIntegerRepresentation()));
+    }
+  }
   return true;
 }
 
@@ -3436,7 +3537,8 @@ template <PrimType Name, class T = typename 
PrimConv<Name>::T>
 inline bool OffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E) {
   llvm::SmallVector<int64_t> ArrayIndices;
   for (size_t I = 0; I != E->getNumExpressions(); ++I)
-    ArrayIndices.emplace_back(S.Stk.pop<int64_t>());
+    ArrayIndices.emplace_back(
+        static_cast<int64_t>(S.Stk.pop<Integral<64, true>>()));
 
   int64_t Result;
   if (!InterpretOffsetOf(S, OpPC, E, ArrayIndices, Result))
@@ -3551,7 +3653,7 @@ inline bool AllocN(InterpState &S, CodePtr OpPC, PrimType 
T, const Expr *Source,
   if (NumElements.isNegative()) {
     if (!IsNoThrow) {
       S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_new_negative)
-          << NumElements.toDiagnosticString(S.getASTContext());
+          << NumElements.toDiagnosticString(S.getASTContext(), S.P);
       return false;
     }
     S.Stk.push<Pointer>(0, nullptr);
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp 
b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index 659b6985d3157..37aff11e9208d 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -314,11 +314,12 @@ static bool interp__builtin_strlen(InterpState &S, 
CodePtr OpPC,
     return false;
 
   assert(StrPtr.getFieldDesc()->isPrimitiveArray());
-  unsigned ElemSize = StrPtr.getFieldDesc()->getElemSize();
+  PrimType ElemT = StrPtr.getFieldDesc()->getPrimType();
 
   if (ID == Builtin::BI__builtin_wcslen || ID == Builtin::BIwcslen) {
-    [[maybe_unused]] const ASTContext &AC = S.getASTContext();
-    assert(ElemSize == AC.getTypeSizeInChars(AC.getWCharType()).getQuantity());
+    [[maybe_unused]] const ASTContext &ASTCtx = S.getASTContext();
+    assert(StrPtr.getFieldDesc()->getElemDataSize() ==
+           ASTCtx.getTypeSizeInChars(ASTCtx.getWCharType()).getQuantity());
   }
 
   size_t Len = 0;
@@ -329,19 +330,8 @@ static bool interp__builtin_strlen(InterpState &S, CodePtr 
OpPC,
       return false;
 
     uint32_t Val;
-    switch (ElemSize) {
-    case 1:
-      Val = ElemPtr.deref<uint8_t>();
-      break;
-    case 2:
-      Val = ElemPtr.deref<uint16_t>();
-      break;
-    case 4:
-      Val = ElemPtr.deref<uint32_t>();
-      break;
-    default:
-      llvm_unreachable("Unsupported char size");
-    }
+    FIXED_SIZE_INT_TYPE_SWITCH(
+        ElemT, { Val = static_cast<uint32_t>(ElemPtr.deref<T>()); });
     if (Val == 0)
       break;
   }
@@ -1225,7 +1215,7 @@ static bool interp__builtin_assume_aligned(InterpState 
&S, CodePtr OpPC,
     }
   }
 
-  APValue AV = Ptr.toAPValue(S.getASTContext());
+  APValue AV = Ptr.toAPValue(S.getASTContext(), S.P);
   CharUnits AVOffset = AV.getLValueOffset();
   if (ExtraOffset)
     AVOffset -= CharUnits::fromQuantity(ExtraOffset->getZExtValue());
@@ -1301,11 +1291,11 @@ 
interp__builtin_ptrauth_string_discriminator(InterpState &S, CodePtr OpPC,
   const auto &Ptr = S.Stk.pop<Pointer>();
   assert(Ptr.getFieldDesc()->isPrimitiveArray());
 
-  // This should be created for a StringLiteral, so should alway shold at least
+  // This should be created for a StringLiteral, so always holds at least
   // one array element.
   assert(Ptr.getFieldDesc()->getNumElems() >= 1);
-  StringRef R(&Ptr.deref<char>(), Ptr.getFieldDesc()->getNumElems() - 1);
-  uint64_t Result = getPointerAuthStableSipHash(R);
+  uint64_t Result = getPointerAuthStableSipHash(
+      cast<StringLiteral>(Ptr.getFieldDesc()->asExpr())->getString());
   pushInteger(S, Result, Call->getType());
   return true;
 }
@@ -1489,7 +1479,7 @@ static bool interp__builtin_operator_delete(InterpState 
&S, CodePtr OpPC,
 
     if (!BlockToDelete->isDynamic()) {
       S.FFDiag(Call, diag::note_constexpr_delete_not_heap_alloc)
-          << Ptr.toDiagnosticString(S.getASTContext());
+          << Ptr.toDiagnosticString(S.getASTContext(), S.P);
       if (const auto *D = Ptr.getFieldDesc()->asDecl())
         S.Note(D->getLocation(), diag::note_declared_at);
     }
@@ -1790,7 +1780,7 @@ static bool interp__builtin_memcpy(InterpState &S, 
CodePtr OpPC,
     Pointer DiagPtr = (SrcPtr.isZero() ? SrcPtr : DestPtr);
     S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_memcpy_null)
         << /*IsMove=*/Move << /*IsWchar=*/WChar << !SrcPtr.isZero()
-        << DiagPtr.toDiagnosticString(ASTCtx);
+        << DiagPtr.toDiagnosticString(ASTCtx, S.P);
     return false;
   }
 
@@ -1900,8 +1890,8 @@ static bool interp__builtin_memcpy(InterpState &S, 
CodePtr OpPC,
     while (DestP.isBaseClass())
       DestP = DestP.getBase();
 
-    unsigned SrcIndex = SrcP.expand().getIndex() * SrcP.elemSize();
-    unsigned DstIndex = DestP.expand().getIndex() * DestP.elemSize();
+    unsigned SrcIndex = SrcP.expand().getIndex() * SrcElemSize;
+    unsigned DstIndex = DestP.expand().getIndex() * DestElemSize;
     unsigned N = Size.getZExtValue();
 
     if ((SrcIndex <= DstIndex && (SrcIndex + N) > DstIndex) ||
@@ -1970,6 +1960,7 @@ static bool interp__builtin_memcmp(InterpState &S, 
CodePtr OpPC,
   BitcastBuffer BufferA(
       Bits(ASTCtx.getTypeSize(ElemTypeA) * PtrA.getNumElems()));
   readPointerToBuffer(S.getContext(), PtrA, BufferA, false);
+
   // FIXME: The swapping here is UNDOING something we do when reading the
   // data into the buffer.
   if (ASTCtx.getTargetInfo().isBigEndian())
@@ -1996,21 +1987,22 @@ static bool interp__builtin_memcmp(InterpState &S, 
CodePtr OpPC,
 
   for (size_t I = 0; I != CmpSize; I += ElemSize) {
     if (IsWide) {
-      INT_TYPE_SWITCH(*S.getContext().classify(ASTCtx.getWCharType()), {
-        T A = *reinterpret_cast<T *>(BufferA.atByte(I));
-        T B = *reinterpret_cast<T *>(BufferB.atByte(I));
-        if (A < B) {
-          pushInteger(S, -1, Call->getType());
-          return true;
-        }
-        if (A > B) {
-          pushInteger(S, 1, Call->getType());
-          return true;
-        }
-      });
+      FIXED_SIZE_INT_TYPE_SWITCH(
+          *S.getContext().classify(ASTCtx.getWCharType()), {
+            T A = T::bitcastFromMemory(BufferA.atByte(I), T::bitWidth());
+            T B = T::bitcastFromMemory(BufferB.atByte(I), T::bitWidth());
+            if (A < B) {
+              pushInteger(S, -1, Call->getType());
+              return true;
+            }
+            if (A > B) {
+              pushInteger(S, 1, Call->getType());
+              return true;
+            }
+          });
     } else {
-      std::byte A = BufferA.deref<std::byte>(Bytes(I));
-      std::byte B = BufferB.deref<std::byte>(Bytes(I));
+      auto A = BufferA.deref<std::byte>(Bytes(I));
+      auto B = BufferB.deref<std::byte>(Bytes(I));
 
       if (A < B) {
         pushInteger(S, -1, Call->getType());
diff --git a/clang/lib/AST/ByteCode/InterpFrame.cpp 
b/clang/lib/AST/ByteCode/InterpFrame.cpp
index 3b883761ad001..02ef50b379bdc 100644
--- a/clang/lib/AST/ByteCode/InterpFrame.cpp
+++ b/clang/lib/AST/ByteCode/InterpFrame.cpp
@@ -114,18 +114,18 @@ void InterpFrame::destroy(unsigned Idx) {
 
 template <typename T>
 static void print(llvm::raw_ostream &OS, const T &V, ASTContext &ASTCtx,
-                  QualType Ty) {
+                  QualType Ty, const Program &P) {
   if constexpr (std::is_same_v<Pointer, T>) {
     if (Ty->isPointerOrReferenceType())
-      V.toAPValue(ASTCtx).printPretty(OS, ASTCtx, Ty);
+      V.toAPValue(ASTCtx, P).printPretty(OS, ASTCtx, Ty);
     else {
-      if (std::optional<APValue> RValue = V.toRValue(ASTCtx, Ty))
+      if (std::optional<APValue> RValue = V.toRValue(ASTCtx, Ty, P))
         RValue->printPretty(OS, ASTCtx, Ty);
       else
         OS << "...";
     }
   } else {
-    V.toAPValue(ASTCtx).printPretty(OS, ASTCtx, Ty);
+    V.toAPValue(ASTCtx, P).printPretty(OS, ASTCtx, Ty);
   }
 }
 
@@ -178,7 +178,8 @@ void InterpFrame::describe(llvm::raw_ostream &OS) const {
     } else if (const auto *M = dyn_cast<CXXMethodDecl>(F)) {
       print(OS, getThis(), S.getASTContext(),
             S.getASTContext().getLValueReferenceType(
-                S.getASTContext().getCanonicalTagType(M->getParent())));
+                S.getASTContext().getCanonicalTagType(M->getParent())),
+            S.P);
       OS << ".";
     }
   }
@@ -196,7 +197,8 @@ void InterpFrame::describe(llvm::raw_ostream &OS) const {
 
     PrimType PrimTy = S.Ctx.classify(Ty).value_or(PT_Ptr);
 
-    TYPE_SWITCH(PrimTy, print(OS, stackRef<T>(Off), S.getASTContext(), Ty));
+    TYPE_SWITCH(PrimTy,
+                print(OS, stackRef<T>(Off), S.getASTContext(), Ty, S.P));
     Off += align(primSize(PrimTy));
     if (I + 1 != N)
       OS << ", ";
diff --git a/clang/lib/AST/ByteCode/InterpHelpers.h 
b/clang/lib/AST/ByteCode/InterpHelpers.h
index 6bf89d318378c..edc6f83dd59be 100644
--- a/clang/lib/AST/ByteCode/InterpHelpers.h
+++ b/clang/lib/AST/ByteCode/InterpHelpers.h
@@ -124,10 +124,10 @@ bool CheckArraySize(InterpState &S, CodePtr OpPC, SizeT 
*NumElements,
 
       if (NumElements->isSigned() && NumElements->isNegative()) {
         S.FFDiag(Loc, diag::note_constexpr_new_negative)
-            << NumElements->toDiagnosticString(S.getASTContext());
+            << NumElements->toDiagnosticString(S.getASTContext(), S.P);
       } else {
         S.FFDiag(Loc, diag::note_constexpr_new_too_large)
-            << NumElements->toDiagnosticString(S.getASTContext());
+            << NumElements->toDiagnosticString(S.getASTContext(), S.P);
       }
     }
     return false;
diff --git a/clang/lib/AST/ByteCode/InterpStack.h 
b/clang/lib/AST/ByteCode/InterpStack.h
index c647dfa6d85ea..b50e6b78d7bf6 100644
--- a/clang/lib/AST/ByteCode/InterpStack.h
+++ b/clang/lib/AST/ByteCode/InterpStack.h
@@ -173,29 +173,21 @@ class InterpStack final {
       return PT_Ptr;
     else if constexpr (std::is_same_v<T, bool> || std::is_same_v<T, Boolean>)
       return PT_Bool;
-    else if constexpr (std::is_same_v<T, int8_t> ||
-                       std::is_same_v<T, Integral<8, true>>)
+    else if constexpr (std::is_same_v<T, Integral<8, true>>)
       return PT_Sint8;
-    else if constexpr (std::is_same_v<T, uint8_t> ||
-                       std::is_same_v<T, Integral<8, false>>)
+    else if constexpr (std::is_same_v<T, Integral<8, false>>)
       return PT_Uint8;
-    else if constexpr (std::is_same_v<T, int16_t> ||
-                       std::is_same_v<T, Integral<16, true>>)
+    else if constexpr (std::is_same_v<T, Integral<16, true>>)
       return PT_Sint16;
-    else if constexpr (std::is_same_v<T, uint16_t> ||
-                       std::is_same_v<T, Integral<16, false>>)
+    else if constexpr (std::is_same_v<T, Integral<16, false>>)
       return PT_Uint16;
-    else if constexpr (std::is_same_v<T, int32_t> ||
-                       std::is_same_v<T, Integral<32, true>>)
+    else if constexpr (std::is_same_v<T, Integral<32, true>>)
       return PT_Sint32;
-    else if constexpr (std::is_same_v<T, uint32_t> ||
-                       std::is_same_v<T, Integral<32, false>>)
+    else if constexpr (std::is_same_v<T, Integral<32, false>>)
       return PT_Uint32;
-    else if constexpr (std::is_same_v<T, int64_t> ||
-                       std::is_same_v<T, Integral<64, true>>)
+    else if constexpr (std::is_same_v<T, Integral<64, true>>)
       return PT_Sint64;
-    else if constexpr (std::is_same_v<T, uint64_t> ||
-                       std::is_same_v<T, Integral<64, false>>)
+    else if constexpr (std::is_same_v<T, Integral<64, false>>)
       return PT_Uint64;
     else if constexpr (std::is_same_v<T, Floating>)
       return PT_Float;
diff --git a/clang/lib/AST/ByteCode/MemberPointer.cpp 
b/clang/lib/AST/ByteCode/MemberPointer.cpp
index 8b1b0187818e9..812bb92d2fb3d 100644
--- a/clang/lib/AST/ByteCode/MemberPointer.cpp
+++ b/clang/lib/AST/ByteCode/MemberPointer.cpp
@@ -80,13 +80,14 @@ FunctionPointer MemberPointer::toFunctionPointer(const 
Context &Ctx) const {
   return 
FunctionPointer(Ctx.getProgram().getFunction(cast<FunctionDecl>(Dcl)));
 }
 
-APValue MemberPointer::toAPValue(const ASTContext &ASTCtx) const {
+APValue MemberPointer::toAPValue(const ASTContext &ASTCtx,
+                                 const Program &P) const {
   if (isZero())
     return APValue(static_cast<ValueDecl *>(nullptr), 
/*IsDerivedMember=*/false,
                    /*Path=*/{});
 
   if (hasBase())
-    return Base.toAPValue(ASTCtx);
+    return Base.toAPValue(ASTCtx, P);
 
   return APValue(getDecl(), /*IsDerivedMember=*/false,
                  /*Path=*/{});
diff --git a/clang/lib/AST/ByteCode/MemberPointer.h 
b/clang/lib/AST/ByteCode/MemberPointer.h
index 8dd75cad092c0..a51e00e3c064c 100644
--- a/clang/lib/AST/ByteCode/MemberPointer.h
+++ b/clang/lib/AST/ByteCode/MemberPointer.h
@@ -86,7 +86,7 @@ class MemberPointer final {
     return MemberPointer(Instance, this->Dcl, this->PtrOffset);
   }
 
-  APValue toAPValue(const ASTContext &) const;
+  APValue toAPValue(const ASTContext &, const Program &) const;
 
   bool isZero() const { return Base.isZero() && !Dcl; }
   bool hasBase() const { return !Base.isZero(); }
@@ -101,8 +101,9 @@ class MemberPointer final {
        << ")";
   }
 
-  std::string toDiagnosticString(const ASTContext &Ctx) const {
-    return toAPValue(Ctx).getAsString(Ctx, Dcl->getType());
+  std::string toDiagnosticString(const ASTContext &Ctx,
+                                 const Program &P) const {
+    return toAPValue(Ctx, P).getAsString(Ctx, Dcl->getType());
   }
 
   ComparisonCategoryResult compare(const MemberPointer &RHS) const {
diff --git a/clang/lib/AST/ByteCode/Pointer.cpp 
b/clang/lib/AST/ByteCode/Pointer.cpp
index 25719bd6f0f91..f4292202b9265 100644
--- a/clang/lib/AST/ByteCode/Pointer.cpp
+++ b/clang/lib/AST/ByteCode/Pointer.cpp
@@ -169,7 +169,7 @@ Pointer &Pointer::operator=(Pointer &&P) {
   return *this;
 }
 
-APValue Pointer::toAPValue(const ASTContext &ASTCtx) const {
+APValue Pointer::toAPValue(const ASTContext &ASTCtx, const Program &) const {
   llvm::SmallVector<APValue::LValuePathEntry, 5> Path;
 
   if (isZero())
@@ -425,7 +425,8 @@ size_t Pointer::computeOffsetForComparison() const {
   return Result;
 }
 
-std::string Pointer::toDiagnosticString(const ASTContext &Ctx) const {
+std::string Pointer::toDiagnosticString(const ASTContext &Ctx,
+                                        const Program &P) const {
   if (isZero())
     return "nullptr";
 
@@ -435,7 +436,7 @@ std::string Pointer::toDiagnosticString(const ASTContext 
&Ctx) const {
   if (isFunctionPointer())
     return asFunctionPointer().toDiagnosticString(Ctx);
 
-  return toAPValue(Ctx).getAsString(Ctx, getType());
+  return toAPValue(Ctx, P).getAsString(Ctx, getType());
 }
 
 bool Pointer::isInitialized() const {
@@ -683,6 +684,15 @@ bool Pointer::pointsToStringLiteral() const {
   return isa_and_nonnull<StringLiteral>(E);
 }
 
+bool Pointer::pointsToLabel() const {
+  if (isZero() || !isBlockPointer())
+    return false;
+
+  if (const Expr *E = BS.Pointee->getDescriptor()->asExpr())
+    return isa<AddrLabelExpr>(E);
+  return false;
+}
+
 std::optional<std::pair<Pointer, Pointer>>
 Pointer::computeSplitPoint(const Pointer &A, const Pointer &B) {
   if (!A.isBlockPointer() || !B.isBlockPointer())
@@ -726,13 +736,14 @@ Pointer::computeSplitPoint(const Pointer &A, const 
Pointer &B) {
 }
 
 std::optional<APValue> Pointer::toRValue(const Context &Ctx,
-                                         QualType ResultType) const {
+                                         QualType ResultType,
+                                         const Program &P) const {
   const ASTContext &ASTCtx = Ctx.getASTContext();
   assert(!ResultType.isNull());
   // Method to recursively traverse composites.
   std::function<bool(QualType, const Pointer &, APValue &)> Composite;
-  Composite = [&Composite, &Ctx, &ASTCtx](QualType Ty, const Pointer &Ptr,
-                                          APValue &R) {
+  Composite = [&Composite, &Ctx, &ASTCtx, &P](QualType Ty, const Pointer &Ptr,
+                                              APValue &R) {
     if (const auto *AT = Ty->getAs<AtomicType>())
       Ty = AT->getValueType();
 
@@ -743,7 +754,7 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx,
 
     // Primitive values.
     if (OptPrimType T = Ctx.classify(Ty)) {
-      TYPE_SWITCH(*T, R = Ptr.deref<T>().toAPValue(ASTCtx));
+      TYPE_SWITCH(*T, R = Ptr.deref<T>().toAPValue(ASTCtx, P));
       return true;
     }
 
@@ -760,7 +771,7 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx,
           QualType FieldTy = F.Decl->getType();
           if (FP.isActive()) {
             if (OptPrimType T = Ctx.classify(FieldTy)) {
-              TYPE_SWITCH(*T, Value = FP.deref<T>().toAPValue(ASTCtx));
+              TYPE_SWITCH(*T, Value = FP.deref<T>().toAPValue(ASTCtx, P));
             } else {
               Ok &= Composite(FieldTy, FP, Value);
             }
@@ -783,7 +794,7 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx,
           APValue &Value = R.getStructField(I);
 
           if (OptPrimType T = Ctx.classify(FieldTy)) {
-            TYPE_SWITCH(*T, Value = FP.deref<T>().toAPValue(ASTCtx));
+            TYPE_SWITCH(*T, Value = FP.deref<T>().toAPValue(ASTCtx, P));
           } else {
             Ok &= Composite(FieldTy, FP, Value);
           }
@@ -822,7 +833,7 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx,
       for (unsigned I = 0; I != NumElems; ++I) {
         APValue &Slot = R.getArrayInitializedElt(I);
         if (ElemT) {
-          TYPE_SWITCH(*ElemT, Slot = Ptr.elem<T>(I).toAPValue(ASTCtx));
+          TYPE_SWITCH(*ElemT, Slot = Ptr.elem<T>(I).toAPValue(ASTCtx, P));
         } else {
           Ok &= Composite(ElemTy, Ptr.atIndex(I).narrow(), Slot);
         }
@@ -864,7 +875,7 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx,
       Values.reserve(VT->getNumElements());
       for (unsigned I = 0; I != VT->getNumElements(); ++I) {
         TYPE_SWITCH(ElemT,
-                    { Values.push_back(Ptr.elem<T>(I).toAPValue(ASTCtx)); });
+                    { Values.push_back(Ptr.elem<T>(I).toAPValue(ASTCtx, P)); 
});
       }
 
       assert(Values.size() == VT->getNumElements());
@@ -881,11 +892,11 @@ std::optional<APValue> Pointer::toRValue(const Context 
&Ctx,
 
   // We can return these as rvalues, but we can't deref() them.
   if (isZero() || isIntegralPointer())
-    return toAPValue(ASTCtx);
+    return toAPValue(ASTCtx, P);
 
   // Just load primitive types.
   if (OptPrimType T = Ctx.classify(ResultType)) {
-    TYPE_SWITCH(*T, return this->deref<T>().toAPValue(ASTCtx));
+    TYPE_SWITCH(*T, return this->deref<T>().toAPValue(ASTCtx, P));
   }
 
   // Return the composite type.
diff --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h
index 57c8e45609027..762051d2ec1e0 100644
--- a/clang/lib/AST/ByteCode/Pointer.h
+++ b/clang/lib/AST/ByteCode/Pointer.h
@@ -135,10 +135,10 @@ class Pointer {
   bool operator!=(const Pointer &P) const { return !(P == *this); }
 
   /// Converts the pointer to an APValue.
-  APValue toAPValue(const ASTContext &ASTCtx) const;
+  APValue toAPValue(const ASTContext &ASTCtx, const Program &) const;
 
   /// Converts the pointer to a string usable in diagnostics.
-  std::string toDiagnosticString(const ASTContext &Ctx) const;
+  std::string toDiagnosticString(const ASTContext &Ctx, const Program &) const;
 
   uint64_t getIntegerRepresentation() const {
     if (isIntegralPointer())
@@ -149,8 +149,8 @@ class Pointer {
   }
 
   /// Converts the pointer to an APValue that is an rvalue.
-  std::optional<APValue> toRValue(const Context &Ctx,
-                                  QualType ResultType) const;
+  std::optional<APValue> toRValue(const Context &Ctx, QualType ResultType,
+                                  const Program &) const;
 
   /// Offsets a pointer inside an array.
   [[nodiscard]] Pointer atIndex(uint64_t Idx) const {
@@ -363,7 +363,7 @@ class Pointer {
     if (isIntegralPointer()) {
       if (!Int.Desc)
         return 1;
-      return Int.Desc->getElemSize();
+      return Int.Desc->getElemDataSize();
     }
 
     if (BS.Base == RootPtrMark)
@@ -776,6 +776,7 @@ class Pointer {
   /// i.e. a non-MaterializeTemporaryExpr Expr.
   bool pointsToLiteral() const;
   bool pointsToStringLiteral() const;
+  bool pointsToLabel() const;
 
   /// Prints the pointer.
   void print(llvm::raw_ostream &OS) const;
diff --git a/clang/lib/AST/ByteCode/PrimType.h 
b/clang/lib/AST/ByteCode/PrimType.h
index f0454b484ff98..9a83cd036b180 100644
--- a/clang/lib/AST/ByteCode/PrimType.h
+++ b/clang/lib/AST/ByteCode/PrimType.h
@@ -248,6 +248,22 @@ static inline bool aligned(const void *P) {
     }                                                                          
\
   } while (0)
 
+#define FIXED_SIZE_INT_TYPE_SWITCH(Expr, B)                                    
\
+  do {                                                                         
\
+    switch (Expr) {                                                            
\
+      TYPE_SWITCH_CASE(PT_Sint8, B)                                            
\
+      TYPE_SWITCH_CASE(PT_Uint8, B)                                            
\
+      TYPE_SWITCH_CASE(PT_Sint16, B)                                           
\
+      TYPE_SWITCH_CASE(PT_Uint16, B)                                           
\
+      TYPE_SWITCH_CASE(PT_Sint32, B)                                           
\
+      TYPE_SWITCH_CASE(PT_Uint32, B)                                           
\
+      TYPE_SWITCH_CASE(PT_Sint64, B)                                           
\
+      TYPE_SWITCH_CASE(PT_Uint64, B)                                           
\
+    default:                                                                   
\
+      llvm_unreachable("Not an integer value");                                
\
+    }                                                                          
\
+  } while (0)
+
 #define INT_TYPE_SWITCH_NO_BOOL(Expr, B)                                       
\
   do {                                                                         
\
     switch (Expr) {                                                            
\
diff --git a/clang/lib/AST/ByteCode/Primitives.h 
b/clang/lib/AST/ByteCode/Primitives.h
index e935dbfd3691c..2784d5302c743 100644
--- a/clang/lib/AST/ByteCode/Primitives.h
+++ b/clang/lib/AST/ByteCode/Primitives.h
@@ -21,6 +21,14 @@
 namespace clang {
 namespace interp {
 
+enum class IntegralKind {
+  Number = 0,
+  Address,
+  BlockAddress,
+  LabelAddress,
+  AddrLabelDiff
+};
+
 /// Helper to compare two comparable types.
 template <typename T> ComparisonCategoryResult Compare(const T &X, const T &Y) 
{
   if (X < Y)
diff --git a/clang/lib/AST/ByteCode/Program.cpp 
b/clang/lib/AST/ByteCode/Program.cpp
index d96934071cb60..1409fb2f15a7b 100644
--- a/clang/lib/AST/ByteCode/Program.cpp
+++ b/clang/lib/AST/ByteCode/Program.cpp
@@ -31,6 +31,20 @@ const void *Program::getNativePointer(unsigned Idx) const {
   return NativePointers[Idx];
 }
 
+unsigned Program::getOrCreateAddrLabelDiff(const AddrLabelExpr *LHS,
+                                           const AddrLabelExpr *RHS) {
+  auto [It, Inserted] = AddrLabelDiffIndices.try_emplace(
+      AddrLabelDiff{LHS, RHS}, AddrLabelDiffs.size());
+  if (Inserted)
+    AddrLabelDiffs.push_back(AddrLabelDiff{LHS, RHS});
+
+  return It->second;
+}
+
+AddrLabelDiff Program::getLabelDiff(unsigned Index) const {
+  return AddrLabelDiffs[Index];
+}
+
 unsigned Program::createGlobalString(const StringLiteral *S, const Expr *Base) 
{
   const size_t CharWidth = S->getCharByteWidth();
   const size_t BitWidth = CharWidth * Ctx.getCharBit();
@@ -49,7 +63,6 @@ unsigned Program::createGlobalString(const StringLiteral *S, 
const Expr *Base) {
                                         /*isConst=*/true,
                                         /*isTemporary=*/false,
                                         /*isMutable=*/false);
-
   // Allocate storage for the string.
   // The byte length does not include the null terminator.
   unsigned GlobalIndex = Globals.size();
@@ -63,15 +76,10 @@ unsigned Program::createGlobalString(const StringLiteral 
*S, const Expr *Base) {
   Globals.push_back(G);
 
   const Pointer Ptr(G->block());
-  if (CharWidth == 1) {
-    std::memcpy(&Ptr.elem<char>(0), S->getString().data(), StringLength);
-  } else {
-    // Construct the string in storage.
-    for (unsigned I = 0; I <= StringLength; ++I) {
-      uint32_t CodePoint = I == StringLength ? 0 : S->getCodeUnit(I);
-      INT_TYPE_SWITCH_NO_BOOL(*CharType,
-                              Ptr.elem<T>(I) = T::from(CodePoint, BitWidth););
-    }
+  for (unsigned I = 0; I <= StringLength; ++I) {
+    uint32_t CodePoint = I == StringLength ? 0 : S->getCodeUnit(I);
+    INT_TYPE_SWITCH_NO_BOOL(*CharType,
+                            Ptr.elem<T>(I) = T::from(CodePoint, BitWidth););
   }
   Ptr.initializeAllElements();
 
diff --git a/clang/lib/AST/ByteCode/Program.h b/clang/lib/AST/ByteCode/Program.h
index c8795504391fa..e947aaf87e373 100644
--- a/clang/lib/AST/ByteCode/Program.h
+++ b/clang/lib/AST/ByteCode/Program.h
@@ -32,6 +32,14 @@ class VarDecl;
 namespace interp {
 class Context;
 
+struct AddrLabelDiff {
+  const AddrLabelExpr *LHS;
+  const AddrLabelExpr *RHS;
+  bool operator==(const AddrLabelDiff &Other) const {
+    return LHS == Other.LHS && RHS == Other.RHS;
+  }
+};
+
 /// The program contains and links the bytecode for all functions.
 class Program final {
 public:
@@ -59,6 +67,9 @@ class Program final {
 
   /// Returns the value of a marshalled native pointer.
   const void *getNativePointer(unsigned Idx) const;
+  unsigned getOrCreateAddrLabelDiff(const AddrLabelExpr *LHS,
+                                    const AddrLabelExpr *RHS);
+  AddrLabelDiff getLabelDiff(unsigned Index) const;
 
   /// Emits a string literal among global data.
   unsigned createGlobalString(const StringLiteral *S,
@@ -181,6 +192,10 @@ class Program final {
   /// Cached native pointer indices.
   llvm::DenseMap<const void *, unsigned> NativePointerIndices;
 
+  std::vector<AddrLabelDiff> AddrLabelDiffs;
+  /// Cached native pointer indices.
+  llvm::DenseMap<AddrLabelDiff, unsigned> AddrLabelDiffIndices;
+
   /// Custom allocator for global storage.
   using PoolAllocTy = llvm::BumpPtrAllocator;
 
@@ -257,4 +272,28 @@ inline void *operator new[](size_t Bytes, const 
clang::interp::Program &C,
   return C.Allocate(Bytes, Alignment);
 }
 
+namespace llvm {
+template <> struct DenseMapInfo<clang::interp::AddrLabelDiff> {
+  static clang::interp::AddrLabelDiff getEmptyKey() {
+    return clang::interp::AddrLabelDiff{};
+  }
+
+  static clang::interp::AddrLabelDiff getTombstoneKey() {
+    return clang::interp::AddrLabelDiff{
+        DenseMapInfo<const clang::AddrLabelExpr *>::getTombstoneKey(),
+        DenseMapInfo<const clang::AddrLabelExpr *>::getTombstoneKey()};
+  }
+
+  static unsigned getHashValue(const clang::interp::AddrLabelDiff &D) {
+    return DenseMapInfo<const clang::Expr *>::getHashValue(D.LHS) +
+           DenseMapInfo<const clang::Expr *>::getHashValue(D.RHS);
+  }
+
+  static bool isEqual(const clang::interp::AddrLabelDiff &LHS,
+                      const clang::interp::AddrLabelDiff &RHS) {
+    return LHS == RHS;
+  }
+};
+} // namespace llvm
+
 #endif
diff --git a/clang/test/AST/ByteCode/addr-label-diff.c 
b/clang/test/AST/ByteCode/addr-label-diff.c
new file mode 100644
index 0000000000000..a87be4a75a784
--- /dev/null
+++ b/clang/test/AST/ByteCode/addr-label-diff.c
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -triple x86_64 -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64 -emit-llvm %s -o - 
-fexperimental-new-constant-interpreter | FileCheck %s
+
+typedef __typeof((int*) 0 - (int*) 0) intptr_t;
+
+// CHECK: @f1.l0 = internal global i64 ptrtoint (ptr @f1 to i64)
+void f1(void) { static intptr_t l0 = (intptr_t) f1; }
+
+
+// CHECK: @FoldableAddrLabelDiff.x = internal global i64 sub (i64 ptrtoint 
(ptr blockaddress(@FoldableAddrLabelDiff, %a) to i64), i64 ptrtoint (ptr 
blockaddress(@FoldableAddrLabelDiff, %b) to i64)), align 8
+void FoldableAddrLabelDiff() { static long x = (long)&&a-(long)&&b; 
a:b:return;}
+
+// CHECK: @c.ar = internal global {{.*}} sub (i{{..}} ptrtoint (ptr 
blockaddress(@c, %l2) to i{{..}}), i{{..}} ptrtoint (ptr blockaddress(@c, %l1) 
to i{{..}}))
+int c(void) {
+  static int ar = &&l2 - &&l1;
+l1:
+  return 10;
+l2:
+  return 11;
+}
+
+
diff --git a/clang/test/AST/ByteCode/const-eval.c 
b/clang/test/AST/ByteCode/const-eval.c
index d6cf600b378a8..15dd5933deea7 100644
--- a/clang/test/AST/ByteCode/const-eval.c
+++ b/clang/test/AST/ByteCode/const-eval.c
@@ -173,6 +173,9 @@ _Static_assert(A > B, "");
 int * GH149500_p = &(*(int *)0x400);
 static const void *GH149500_q = &(*(const struct sysrq_key_op *)0);
 
+
+void f0(void) { static intptr_t l0 = (unsigned)(intptr_t) f0;} // both-error 
{{initializer element is not a compile-time constant}}
+
 #else
 #error :(
 #endif
diff --git a/clang/test/CodeGen/const-label-addr.c 
b/clang/test/CodeGen/const-label-addr.c
index 8030f96cb8aed..086971045d2ca 100644
--- a/clang/test/CodeGen/const-label-addr.c
+++ b/clang/test/CodeGen/const-label-addr.c
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -emit-llvm -o - -fexperimental-new-constant-interpreter 
| FileCheck %s
 // REQUIRES: asserts
 
 // CHECK: @a.a = internal global ptr blockaddress(@a, %A)
diff --git a/clang/test/CodeGen/statements.c b/clang/test/CodeGen/statements.c
index 07ae075d6d807..bdfb5fc718755 100644
--- a/clang/test/CodeGen/statements.c
+++ b/clang/test/CodeGen/statements.c
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -Wno-error=return-type -Wno-error=int-conversion %s 
-emit-llvm-only
+// RUN: %clang_cc1 -Wno-error=return-type -Wno-error=int-conversion %s 
-emit-llvm-only -fexperimental-new-constant-interpreter
 // REQUIRES: LP64
 
 // Mismatched type between return and function result.
diff --git a/clang/test/CodeGen/staticinit.c b/clang/test/CodeGen/staticinit.c
index ec9b5b34d3ade..7ada59e220776 100644
--- a/clang/test/CodeGen/staticinit.c
+++ b/clang/test/CodeGen/staticinit.c
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -triple i386-pc-linux-gnu -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple i386-pc-linux-gnu -emit-llvm -o - %s 
-fexperimental-new-constant-interpreter | FileCheck %s
 
 struct AStruct { 
   int i;
diff --git a/clang/test/CodeGenCXX/2008-05-07-CrazyOffsetOf.cpp 
b/clang/test/CodeGenCXX/2008-05-07-CrazyOffsetOf.cpp
index cb31a04c69fea..3be58ea1b7cae 100644
--- a/clang/test/CodeGenCXX/2008-05-07-CrazyOffsetOf.cpp
+++ b/clang/test/CodeGenCXX/2008-05-07-CrazyOffsetOf.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -triple=x86_64-unknown-linux -emit-llvm %s -o - | FileCheck 
%s
+// RUN: %clang_cc1 -triple=x86_64-unknown-linux -emit-llvm %s -o - 
-fexperimental-new-constant-interpreter | FileCheck %s
 
 struct bork {
   struct bork *next_local;
diff --git a/clang/test/CodeGenCXX/const-init-cxx11.cpp 
b/clang/test/CodeGenCXX/const-init-cxx11.cpp
index 0795fb534af4b..125bf8c383a81 100644
--- a/clang/test/CodeGenCXX/const-init-cxx11.cpp
+++ b/clang/test/CodeGenCXX/const-init-cxx11.cpp
@@ -1,6 +1,9 @@
 // RUN: %clang_cc1 -w -fmerge-all-constants -triple x86_64-elf-gnu -emit-llvm 
-o - %s -std=c++11 | FileCheck %s
 // RUN: %clang_cc1 -w -fmerge-all-constants -triple x86_64-elf-gnu -emit-llvm 
-o - %s -std=c++20 | FileCheck -check-prefix=CHECK20 %s
 
+// RUN: %clang_cc1 -w -fmerge-all-constants -triple x86_64-elf-gnu -emit-llvm 
-o - %s -std=c++11 -fexperimental-new-constant-interpreter | FileCheck %s
+// RUN: %clang_cc1 -w -fmerge-all-constants -triple x86_64-elf-gnu -emit-llvm 
-o - %s -std=c++20 -fexperimental-new-constant-interpreter | FileCheck 
-check-prefix=CHECK20 %s
+
 // FIXME: The padding in all these objects should be zero-initialized.
 namespace StructUnion {
   struct A {
diff --git a/clang/test/Sema/compound-literal.c 
b/clang/test/Sema/compound-literal.c
index 3ed53d670d38f..1026e5ece11b4 100644
--- a/clang/test/Sema/compound-literal.c
+++ b/clang/test/Sema/compound-literal.c
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -fblocks -pedantic %s
+// RUN: %clang_cc1 -fsyntax-only -verify -fblocks -pedantic %s 
-fexperimental-new-constant-interpreter
 // REQUIRES: LP64
 
 struct foo { int a, b; };
diff --git a/clang/test/SemaCXX/constexpr-string.cpp 
b/clang/test/SemaCXX/constexpr-string.cpp
index 93e234685d284..b49979bbc8ca0 100644
--- a/clang/test/SemaCXX/constexpr-string.cpp
+++ b/clang/test/SemaCXX/constexpr-string.cpp
@@ -8,6 +8,7 @@
 // RUN: %clang_cc1 %s -triple armebv7-unknown-linux -std=c++2a -fsyntax-only 
-verify -pedantic -Wno-vla-extension -fno-wchar -DNO_PREDEFINED_WCHAR_T
 
 // RUN: %clang_cc1 %s -triple armebv7-unknown-linux -std=c++2a -fsyntax-only 
-verify -pedantic -Wno-vla-extension -fno-signed-char 
-fexperimental-new-constant-interpreter
+// RUN: %clang_cc1 %s -triple armebv7-unknown-linux -std=c++2a -fsyntax-only 
-verify -pedantic -Wno-vla-extension -fno-wchar -DNO_PREDEFINED_WCHAR_T 
-fexperimental-new-constant-interpreter
 
 # 9 "/usr/include/string.h" 1 3 4  // expected-warning {{this style of line 
directive is a GNU extension}}
 extern "C" {
diff --git a/clang/unittests/AST/ByteCode/toAPValue.cpp 
b/clang/unittests/AST/ByteCode/toAPValue.cpp
index 939d08601bb7d..9dbb47e3c3c3c 100644
--- a/clang/unittests/AST/ByteCode/toAPValue.cpp
+++ b/clang/unittests/AST/ByteCode/toAPValue.cpp
@@ -50,7 +50,7 @@ TEST(ToAPValue, Pointers) {
     const Pointer &GP = getGlobalPtr("b");
     const Pointer &P = GP.deref<Pointer>();
     ASSERT_TRUE(P.isLive());
-    APValue A = P.toAPValue(ASTCtx);
+    APValue A = P.toAPValue(ASTCtx, Prog);
     ASSERT_TRUE(A.isLValue());
     ASSERT_TRUE(A.hasLValuePath());
     const auto &Path = A.getLValuePath();
@@ -65,7 +65,7 @@ TEST(ToAPValue, Pointers) {
     const Pointer &GP = getGlobalPtr("p");
     const Pointer &P = GP.deref<Pointer>();
     ASSERT_TRUE(P.isIntegralPointer());
-    APValue A = P.toAPValue(ASTCtx);
+    APValue A = P.toAPValue(ASTCtx, Prog);
     ASSERT_TRUE(A.isLValue());
     ASSERT_TRUE(A.getLValueBase().isNull());
     APSInt I;
@@ -80,7 +80,7 @@ TEST(ToAPValue, Pointers) {
     const Pointer &GP = getGlobalPtr("nullp");
     const Pointer &P = GP.deref<Pointer>();
     ASSERT_TRUE(P.isIntegralPointer());
-    APValue A = P.toAPValue(ASTCtx);
+    APValue A = P.toAPValue(ASTCtx, Prog);
     ASSERT_TRUE(A.isLValue());
     ASSERT_TRUE(A.getLValueBase().isNull());
     ASSERT_TRUE(A.isNullPointer());
@@ -95,7 +95,7 @@ TEST(ToAPValue, Pointers) {
     const ValueDecl *D = getDecl("arrp");
     ASSERT_NE(D, nullptr);
     const Pointer &GP = getGlobalPtr("arrp").deref<Pointer>();
-    APValue A = GP.toAPValue(ASTCtx);
+    APValue A = GP.toAPValue(ASTCtx, Prog);
     ASSERT_TRUE(A.isLValue());
     ASSERT_TRUE(A.hasLValuePath());
     ASSERT_EQ(A.getLValuePath().size(), 2u);
@@ -137,7 +137,7 @@ TEST(ToAPValue, FunctionPointers) {
     const Pointer &GP = getGlobalPtr("func");
     const Pointer &FP = GP.deref<Pointer>();
     ASSERT_FALSE(FP.isZero());
-    APValue A = FP.toAPValue(ASTCtx);
+    APValue A = FP.toAPValue(ASTCtx, Prog);
     ASSERT_TRUE(A.hasValue());
     ASSERT_TRUE(A.isLValue());
     ASSERT_TRUE(A.hasLValuePath());
@@ -195,7 +195,7 @@ TEST(ToAPValue, FunctionPointersC) {
     ASSERT_TRUE(GP.isLive());
     const Pointer &FP = GP.deref<Pointer>();
     ASSERT_FALSE(FP.isZero());
-    APValue A = FP.toAPValue(ASTCtx);
+    APValue A = FP.toAPValue(ASTCtx, Prog);
     ASSERT_TRUE(A.hasValue());
     ASSERT_TRUE(A.isLValue());
     const auto &Path = A.getLValuePath();
@@ -240,7 +240,7 @@ TEST(ToAPValue, MemberPointers) {
     const Pointer &GP = getGlobalPtr("pm");
     ASSERT_TRUE(GP.isLive());
     const MemberPointer &FP = GP.deref<MemberPointer>();
-    APValue A = FP.toAPValue(ASTCtx);
+    APValue A = FP.toAPValue(ASTCtx, Prog);
     ASSERT_EQ(A.getMemberPointerDecl(), getDecl("m"));
     ASSERT_EQ(A.getKind(), APValue::MemberPointer);
   }
@@ -250,7 +250,7 @@ TEST(ToAPValue, MemberPointers) {
     ASSERT_TRUE(GP.isLive());
     const MemberPointer &NP = GP.deref<MemberPointer>();
     ASSERT_TRUE(NP.isZero());
-    APValue A = NP.toAPValue(ASTCtx);
+    APValue A = NP.toAPValue(ASTCtx, Prog);
     ASSERT_EQ(A.getKind(), APValue::MemberPointer);
   }
 }

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

Reply via email to