llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Timm Baeder (tbaederr)

<details>
<summary>Changes</summary>

This is an alternative approach to 
https://github.com/llvm/llvm-project/pull/169769.

We leave the old `Integral&lt;Bits, Signed&gt;` intact and don't increase its 
size at all, but then introduce a new `IntegralOrPtr&lt;Bits, Signed&gt;`, 
which either holds its value _or_ a pointer and an offset. To support 
address-label-diffs, the offset is always pointer sized as well, making 
everything `&gt;= 32` bits `sizeof(void*) + sizeof(void*) + sizeof(uint8_t)` in 
size.

The old approach did not work out in the end because we need to be able to do 
arithmetic (but essentially just `+` and `-`) on the offsets of such 
integers-that-are-actually-pointers.

c-t-t-:
https://llvm-compile-time-tracker.com/compare.php?from=e7448c3f4088cae61cb1bf8ade1a4a79d7cc4dbb&amp;to=4aa23d5b4d8e6c43b0cf846f18f34ea967895fe5&amp;stat=instructions:u

---

Patch is 60.44 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/185028.diff


33 Files Affected:

- (modified) clang/lib/AST/ByteCode/Boolean.h (+1-2) 
- (modified) clang/lib/AST/ByteCode/Context.cpp (+1-1) 
- (modified) clang/lib/AST/ByteCode/Descriptor.cpp (+7) 
- (modified) clang/lib/AST/ByteCode/Descriptor.h (+5) 
- (modified) clang/lib/AST/ByteCode/Integral.h (+372-10) 
- (modified) clang/lib/AST/ByteCode/IntegralAP.h (+1) 
- (modified) clang/lib/AST/ByteCode/Interp.cpp (+27-13) 
- (modified) clang/lib/AST/ByteCode/Interp.h (+206-9) 
- (modified) clang/lib/AST/ByteCode/InterpBuiltin.cpp (+26-34) 
- (modified) clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp (+10-4) 
- (modified) clang/lib/AST/ByteCode/InterpStack.h (+5-8) 
- (modified) clang/lib/AST/ByteCode/Pointer.cpp (+9) 
- (modified) clang/lib/AST/ByteCode/Pointer.h (+3-1) 
- (modified) clang/lib/AST/ByteCode/PrimType.h (+28-4) 
- (modified) clang/lib/AST/ByteCode/Primitives.h (+8) 
- (added) clang/test/AST/ByteCode/addr-label-diff.c (+19) 
- (added) clang/test/AST/ByteCode/addr-label-diff.cpp (+16) 
- (modified) clang/test/AST/ByteCode/builtin-bit-cast.cpp (+8) 
- (modified) clang/test/AST/ByteCode/const-eval.c (+6-3) 
- (modified) clang/test/AST/ByteCode/cxx11.cpp (+12) 
- (added) clang/test/AST/ByteCode/int-as-ptr-arith.c (+17) 
- (modified) clang/test/CodeGen/const-init.c (+1) 
- (modified) clang/test/CodeGen/const-label-addr.c (+1) 
- (modified) clang/test/CodeGen/statements.c (+1) 
- (modified) clang/test/CodeGen/staticinit.c (+1) 
- (modified) clang/test/CodeGenCXX/2008-05-07-CrazyOffsetOf.cpp (+1) 
- (modified) clang/test/CodeGenCXX/const-init-cxx11.cpp (+3) 
- (modified) clang/test/CodeGenCXX/const-init.cpp (+6) 
- (modified) clang/test/Sema/array-init.c (+2) 
- (modified) clang/test/Sema/compound-literal.c (+1) 
- (modified) clang/test/Sema/const-ptr-int-ptr-cast.c (+1) 
- (modified) clang/test/Sema/init.c (+1) 
- (modified) clang/test/SemaCXX/constexpr-string.cpp (+1) 


``````````diff
diff --git a/clang/lib/AST/ByteCode/Boolean.h b/clang/lib/AST/ByteCode/Boolean.h
index fd8d546656881..09eefee14a854 100644
--- a/clang/lib/AST/ByteCode/Boolean.h
+++ b/clang/lib/AST/ByteCode/Boolean.h
@@ -61,11 +61,10 @@ class Boolean final {
   bool isMin() const { return isZero(); }
 
   constexpr static bool isMinusOne() { return false; }
-
   constexpr static bool isSigned() { return false; }
-
   constexpr static bool isNegative() { return false; }
   constexpr static bool isPositive() { return !isNegative(); }
+  constexpr static bool isNumber() { return true; }
 
   ComparisonCategoryResult compare(const Boolean &RHS) const {
     return Compare(V, RHS.V);
diff --git a/clang/lib/AST/ByteCode/Context.cpp 
b/clang/lib/AST/ByteCode/Context.cpp
index 879d51e6a2c3e..cc391ba3327f8 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()) {
diff --git a/clang/lib/AST/ByteCode/Descriptor.cpp 
b/clang/lib/AST/ByteCode/Descriptor.cpp
index 5ebc726328fb7..6a192cad9bca2 100644
--- a/clang/lib/AST/ByteCode/Descriptor.cpp
+++ b/clang/lib/AST/ByteCode/Descriptor.cpp
@@ -483,3 +483,10 @@ 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;
+}
diff --git a/clang/lib/AST/ByteCode/Descriptor.h 
b/clang/lib/AST/ByteCode/Descriptor.h
index b052971733567..9046801f4ebef 100644
--- a/clang/lib/AST/ByteCode/Descriptor.h
+++ b/clang/lib/AST/ByteCode/Descriptor.h
@@ -246,6 +246,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/Integral.h 
b/clang/lib/AST/ByteCode/Integral.h
index e90f1a9a74e1c..82b62f7969d12 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,7 +71,7 @@ template <unsigned Bits, bool Signed> class Integral final {
 
   // The primitive representing the integral.
   using ReprT = typename Repr<Bits, Signed>::Type;
-  ReprT V;
+  ReprT V = 0;
   static_assert(std::is_trivially_copyable_v<ReprT>);
 
   /// Primitive representing limits.
@@ -83,7 +85,7 @@ template <unsigned Bits, bool Signed> class Integral final {
   using AsUnsigned = Integral<Bits, false>;
 
   /// Zero-initializes an integral.
-  Integral() : V(0) {}
+  Integral() = default;
 
   /// Constructs an integral from another integral.
   template <unsigned SrcBits, bool SrcSign>
@@ -144,15 +146,12 @@ template <unsigned Bits, bool Signed> class Integral 
final {
   }
 
   constexpr static unsigned bitWidth() { return Bits; }
+  constexpr static bool isSigned() { return Signed; }
+  constexpr static bool isNumber() { return true; }
 
   bool isZero() const { return !V; }
-
   bool isMin() const { return *this == min(bitWidth()); }
-
   bool isMinusOne() const { return Signed && V == ReprT(-1); }
-
-  constexpr static bool isSigned() { return Signed; }
-
   bool isNegative() const { return V < ReprT(0); }
   bool isPositive() const { return !isNegative(); }
 
@@ -205,7 +204,8 @@ template <unsigned Bits, bool Signed> class Integral final {
   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,7 +213,8 @@ template <unsigned Bits, bool Signed> class Integral final {
   }
 
   template <unsigned SrcBits, bool SrcSign>
-  static Integral from(Integral<SrcBits, SrcSign> Value) {
+  static std::enable_if_t<SrcBits != 0, Integral>
+  from(Integral<SrcBits, SrcSign> Value) {
     return Integral(Value.V);
   }
 
@@ -287,7 +288,7 @@ template <unsigned Bits, bool Signed> class Integral final {
     *R = Integral::from(A.V >> B.V, OpBits);
   }
 
-private:
+public:
   template <typename T> static bool CheckAddUB(T A, T B, T &R) {
     if constexpr (std::is_signed_v<T>) {
       return llvm::AddOverflow<T>(A, B, R);
@@ -327,6 +328,367 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, 
Integral<Bits, Signed> I) {
   return OS;
 }
 
+template <unsigned Bits, bool Signed> class IntegralOrPtr final {
+  static_assert(Bits >= 32);
+
+public:
+  // The primitive representing the integral.
+  using ReprT = typename Repr<Bits, Signed>::Type;
+
+private:
+  using OffsetT = intptr_t;
+  static_assert(std::is_trivially_copyable_v<ReprT>);
+  template <unsigned OtherBits, bool OtherSigned> friend class IntegralOrPtr;
+
+  IntegralKind Kind = IntegralKind::Number;
+  union {
+    ReprT V;
+    struct {
+      const void *P;
+      OffsetT Offset;
+    } Ptr;
+  };
+
+  static_assert(sizeof(uintptr_t) >= sizeof(ReprT));
+
+  /// Primitive representing limits.
+  static const auto Min = std::numeric_limits<ReprT>::min();
+  static const auto Max = std::numeric_limits<ReprT>::max();
+
+  /// Construct an integral from anything that is convertible to storage.
+  template <typename T> explicit IntegralOrPtr(T V) : V(V) {}
+  template <typename T>
+  explicit IntegralOrPtr(IntegralKind Kind, T V) : Kind(Kind), V(V) {}
+
+public:
+  using AsUnsigned = IntegralOrPtr<Bits, false>;
+
+  /// Zero-initializes an integral.
+  IntegralOrPtr() = default;
+
+  /// Constructs an integral from another integral.
+  template <unsigned SrcBits, bool SrcSign>
+  explicit IntegralOrPtr(Integral<SrcBits, SrcSign> V) : Kind(V.Kind), V(V) {}
+
+  explicit IntegralOrPtr(IntegralKind Kind, const void *P, OffsetT Offset = 0)
+      : Kind(Kind) {
+    Ptr.P = P;
+    Ptr.Offset = Offset;
+  }
+
+  explicit IntegralOrPtr(const void *P1, const void *P2)
+      : Kind(IntegralKind::AddrLabelDiff) {
+    Ptr.P = P1;
+    Ptr.Offset = reinterpret_cast<uintptr_t>(P2);
+  }
+
+  IntegralKind getKind() const { return Kind; }
+  bool isNumber() const { return Kind == IntegralKind::Number; }
+  const void *getPtr() const {
+    assert(!isNumber());
+    return Ptr.P;
+  }
+  ReprT getOffset() const {
+    assert(!isNumber());
+    return Ptr.Offset;
+  }
+
+  /// Construct an integral from a value based on signedness.
+  explicit IntegralOrPtr(const APSInt &V)
+      : V(V.isSigned() ? V.getSExtValue() : V.getZExtValue()) {}
+
+  bool operator<(IntegralOrPtr RHS) const { return V < RHS.V; }
+  bool operator>(IntegralOrPtr RHS) const { return V > RHS.V; }
+  bool operator<=(IntegralOrPtr RHS) const { return V <= RHS.V; }
+  bool operator>=(IntegralOrPtr RHS) const { return V >= RHS.V; }
+  bool operator==(IntegralOrPtr RHS) const { return V == RHS.V; }
+  bool operator!=(IntegralOrPtr RHS) const { return V != RHS.V; }
+  bool operator>=(unsigned RHS) const {
+    return static_cast<unsigned>(V) >= RHS;
+  }
+
+  bool operator>(unsigned RHS) const {
+    return V >= 0 && static_cast<unsigned>(V) > RHS;
+  }
+
+  IntegralOrPtr operator-() const { return IntegralOrPtr(-V); }
+  IntegralOrPtr operator-(const IntegralOrPtr &Other) const {
+    return IntegralOrPtr(V - Other.V);
+  }
+  IntegralOrPtr operator~() const { return IntegralOrPtr(~V); }
+
+  template <unsigned DstBits, bool DstSign>
+  explicit operator IntegralOrPtr<DstBits, DstSign>() const {
+    return IntegralOrPtr<DstBits, DstSign>(Kind, V);
+  }
+
+  template <typename Ty, typename = std::enable_if_t<std::is_integral_v<Ty>>>
+  explicit operator Ty() const {
+    return V;
+  }
+
+  APSInt toAPSInt() const {
+    assert(isNumber());
+    return APSInt(APInt(Bits, static_cast<uint64_t>(V), Signed), !Signed);
+  }
+
+  APSInt toAPSInt(unsigned BitWidth) const {
+    return APSInt(toAPInt(BitWidth), !Signed);
+  }
+
+  APInt toAPInt(unsigned BitWidth) const {
+    assert(isNumber());
+    if constexpr (Signed)
+      return APInt(Bits, static_cast<uint64_t>(V), Signed)
+          .sextOrTrunc(BitWidth);
+    else
+      return APInt(Bits, static_cast<uint64_t>(V), Signed)
+          .zextOrTrunc(BitWidth);
+  }
+
+  APValue toAPValue(const ASTContext &) const {
+    switch (Kind) {
+    case IntegralKind::Address: {
+      return APValue((const ValueDecl *)Ptr.P,
+                     CharUnits::fromQuantity(Ptr.Offset),
+                     APValue::NoLValuePath{});
+    }
+    case IntegralKind::LabelAddress: {
+      return APValue((const Expr *)Ptr.P, CharUnits::Zero(),
+                     APValue::NoLValuePath{});
+    }
+    case IntegralKind::BlockAddress: {
+      const Block *B = reinterpret_cast<const Block *>(Ptr.P);
+      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: {
+      return APValue(
+          (const AddrLabelExpr *)Ptr.P,
+          (const AddrLabelExpr *)reinterpret_cast<const void *>(Ptr.Offset));
+    }
+    case IntegralKind::Number:
+      return APValue(toAPSInt());
+    }
+    llvm_unreachable("Unhandled IntegralKind");
+  }
+
+  IntegralOrPtr<Bits, false> toUnsigned() const {
+    return IntegralOrPtr<Bits, false>(*this);
+  }
+
+  constexpr static unsigned bitWidth() { return Bits; }
+  constexpr static bool isSigned() { return Signed; }
+
+  bool isZero() const { return !V; }
+  bool isMin() const { return *this == min(bitWidth()); }
+  bool isMinusOne() const { return Signed && V == ReprT(-1); }
+  bool isNegative() const { return V < ReprT(0); }
+  bool isPositive() const { return !isNegative(); }
+
+  ComparisonCategoryResult compare(const IntegralOrPtr &RHS) const {
+    return Compare(V, RHS.V);
+  }
+
+  void bitcastToMemory(std::byte *Dest) const {
+    assert(isNumber());
+    std::memcpy(Dest, &V, sizeof(V));
+  }
+
+  static IntegralOrPtr bitcastFromMemory(const std::byte *Src,
+                                         unsigned BitWidth) {
+    assert(BitWidth == sizeof(ReprT) * 8);
+    ReprT V;
+
+    std::memcpy(&V, Src, sizeof(ReprT));
+    return IntegralOrPtr(V);
+  }
+
+  std::string toDiagnosticString(const ASTContext &Ctx) const {
+    std::string NameStr;
+    llvm::raw_string_ostream OS(NameStr);
+    OS << V;
+    return NameStr;
+  }
+
+  unsigned countLeadingZeros() const {
+    assert(isNumber());
+    if constexpr (!Signed)
+      return llvm::countl_zero<ReprT>(V);
+    if (isPositive())
+      return llvm::countl_zero<typename AsUnsigned::ReprT>(
+          static_cast<typename AsUnsigned::ReprT>(V));
+    llvm_unreachable("Don't call countLeadingZeros() on negative values.");
+  }
+
+  IntegralOrPtr truncate(unsigned TruncBits) const {
+    assert(TruncBits >= 1);
+    if (TruncBits >= Bits)
+      return *this;
+    const ReprT BitMask = (ReprT(1) << ReprT(TruncBits)) - 1;
+    const ReprT SignBit = ReprT(1) << (TruncBits - 1);
+    const ReprT ExtMask = ~BitMask;
+    return IntegralOrPtr((V & BitMask) |
+                         (Signed && (V & SignBit) ? ExtMask : 0));
+  }
+
+  void print(llvm::raw_ostream &OS) const {
+    switch (Kind) {
+    case IntegralKind::Number:
+      OS << V;
+      break;
+    case IntegralKind::AddrLabelDiff:
+      OS << Ptr.P << " - " << (const void *)Ptr.Offset << " (AddrLabelDiff)";
+      break;
+    case IntegralKind::Address:
+      OS << Ptr.P << " + " << Ptr.Offset << " (Address)";
+      break;
+    case IntegralKind::BlockAddress:
+      OS << Ptr.P << " + " << Ptr.Offset << " (BlockAddress)";
+      break;
+    case IntegralKind::LabelAddress:
+      OS << Ptr.P << " + " << Ptr.Offset << " (LabelAddress)";
+    }
+  }
+
+  static IntegralOrPtr min(unsigned NumBits) { return IntegralOrPtr(Min); }
+  static IntegralOrPtr max(unsigned NumBits) { return IntegralOrPtr(Max); }
+  static IntegralOrPtr zero(unsigned BitWidth = 0) { return from(0); }
+
+  template <typename ValT>
+  static std::enable_if_t<!std::is_same_v<ValT, IntegralKind>, IntegralOrPtr>
+  from(ValT V, unsigned NumBits = 0) {
+    if constexpr (std::is_integral_v<ValT>)
+      return IntegralOrPtr(V);
+    else
+      return IntegralOrPtr(static_cast<IntegralOrPtr::ReprT>(V));
+  }
+
+  template <unsigned SrcBits, bool SrcSign>
+  static std::enable_if_t<SrcBits != 0, IntegralOrPtr>
+  from(IntegralOrPtr<SrcBits, SrcSign> V) {
+    auto A = IntegralOrPtr(V.Kind, V.V);
+    switch (V.Kind) {
+    case IntegralKind::Number:
+      A.V = V.V;
+      break;
+    case IntegralKind::AddrLabelDiff:
+    case IntegralKind::Address:
+    case IntegralKind::BlockAddress:
+    case IntegralKind::LabelAddress:
+      A.Ptr.P = V.Ptr.P;
+      A.Ptr.Offset = V.Ptr.Offset;
+      break;
+    }
+    return A;
+  }
+
+  template <typename T> static IntegralOrPtr from(IntegralKind Kind, T V) {
+    return IntegralOrPtr(Kind, V);
+  }
+
+  static bool increment(IntegralOrPtr A, IntegralOrPtr *R) {
+    assert(A.isNumber());
+    return add(A, IntegralOrPtr(ReprT(1)), A.bitWidth(), R);
+  }
+
+  static bool decrement(IntegralOrPtr A, IntegralOrPtr *R) {
+    assert(A.isNumber());
+    return sub(A, IntegralOrPtr(ReprT(1)), A.bitWidth(), R);
+  }
+
+  static bool add(IntegralOrPtr A, IntegralOrPtr B, unsigned OpBits,
+                  IntegralOrPtr *R) {
+    assert(A.isNumber() && B.isNumber());
+    return Integral<Bits, Signed>::CheckAddUB(A.V, B.V, R->V);
+  }
+
+  static bool sub(IntegralOrPtr A, IntegralOrPtr B, unsigned OpBits,
+                  IntegralOrPtr *R) {
+    assert(A.isNumber() && B.isNumber());
+    return Integral<Bits, Signed>::CheckSubUB(A.V, B.V, R->V);
+  }
+
+  static bool mul(IntegralOrPtr A, IntegralOrPtr B, unsigned OpBits,
+                  IntegralOrPtr *R) {
+    assert(A.isNumber() && B.isNumber());
+    return Integral<Bits, Signed>::CheckMulUB(A.V, B.V, R->V);
+  }
+
+  static bool rem(IntegralOrPtr A, IntegralOrPtr B, unsigned OpBits,
+                  IntegralOrPtr *R) {
+    assert(A.isNumber() && B.isNumber());
+    *R = IntegralOrPtr(A.V % B.V);
+    return false;
+  }
+
+  static bool div(IntegralOrPtr A, IntegralOrPtr B, unsigned OpBits,
+                  IntegralOrPtr *R) {
+    assert(A.isNumber() && B.isNumber());
+    *R = IntegralOrPtr(A.V / B.V);
+    return false;
+  }
+
+  static bool bitAnd(IntegralOrPtr A, IntegralOrPtr B, unsigned OpBits,
+                     IntegralOrPtr *R) {
+    assert(A.isNumber() && B.isNumber());
+    *R = IntegralOrPtr(A.V & B.V);
+    return false;
+  }
+
+  static bool bitOr(IntegralOrPtr A, IntegralOrPtr B, unsigned OpBits,
+                    IntegralOrPtr *R) {
+    assert(A.isNumber() && B.isNumber());
+    *R = IntegralOrPtr(A.V | B.V);
+    return false;
+  }
+
+  static bool bitXor(IntegralOrPtr A, IntegralOrPtr B, unsigned OpBits,
+                     IntegralOrPtr *R) {
+    assert(A.isNumber() && B.isNumber());
+    *R = IntegralOrPtr(A.V ^ B.V);
+    return false;
+  }
+
+  static bool neg(IntegralOrPtr A, IntegralOrPtr *R) {
+    if (Signed && A.isMin())
+      return true;
+
+    *R = -A;
+    return false;
+  }
+
+  static bool comp(IntegralOrPtr A, IntegralOrPtr *R) {
+    *R = IntegralOrPtr(~A.V);
+    return false;
+  }
+
+  template <unsigned RHSBits, bool RHSSign>
+  static void shiftLeft(const IntegralOrPtr A,
+                        const IntegralOrPtr<RHSBits, RHSSign> B,
+                        unsigned OpBits, IntegralOrPtr *R) {
+    *R = IntegralOrPtr::from(A.V << B.V, OpBits);
+  }
+
+  template <unsigned RHSBits, bool RHSSign>
+  static void shiftRight(const IntegralOrPtr A,
+                         const IntegralOrPtr<RHSBits, RHSSign> B,
+                         unsigned OpBits, IntegralOrPtr *R) {
+    *R = IntegralOrPtr::from(A.V >> B.V, OpBits);
+  }
+};
+
+template <unsigned Bits, bool Signed>
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
+                              IntegralOrPtr<Bits, Signed> I) {
+  I.print(OS);
+  return OS;
+}
+
 } // namespace interp
 } // namespace clang
 
diff --git a/clang/lib/AST/ByteCode/IntegralAP.h 
b/clang/lib/AST/ByteCode/IntegralAP.h
index b11e6eea28e3f..9f53ac7716bba 100644
--- a/clang/lib/AST/ByteCode/IntegralAP.h
+++ b/clang/lib/AST/ByteCode/IntegralAP.h
@@ -139,6 +139,7 @@ template <bool Signed> class IntegralAP final {
   constexpr uint32_t bitWidth() const { return BitWidth; }
   constexpr unsigned numWords() const { return APInt::getNumWords(BitWidth); }
   constexpr bool singleWord() const { return numWords() == 1; }
+  constexpr static bool isNumber() { return true; }
 
   APSInt toAPSInt(unsigned Bits = 0) const {
     if (Bits == 0)
diff --git a/clang/lib/AST/ByteCode/Interp.cpp 
b/clang/lib/AST/ByteCode/Interp.cpp
index ebc7220aa5671..0f571f6789d10 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -88,20 +88,20 @@ static bool BCP(InterpState &S, CodePtr &RealPC, int32_t 
Offset, PrimType PT) {
     if (PT == PT_Ptr) {
       const auto &Ptr = S.Stk.pop<Pointer>();
       assert(S.Stk.size() == StackSizeBefore);
-      S.Stk.push<Integral<32, true>>(
-          Integral<32, true>::from(CheckBCPResult(S, Ptr)));
+      S.Stk.push<IntegralOrPtr<32, true>>(
+          IntegralOrPtr<32, true>::from(CheckBCPResult(S, Ptr)));
     } else {
       // Pop the result from the stack and return success.
       TYPE_SWITCH(PT, S.Stk.pop<T>(););
       assert(S.Stk.size() == StackSizeBefore);
-      S.Stk.push<Integral<32, true>>(Integral<32, true>::from(1));
+      S.Stk.push<IntegralOrPtr<32, true>>(IntegralOrPtr<32, true>::from(1));
     }
   } else {
     if (!S.inConstantContext())
       return Invalid(S, RealPC);
 
     S.Stk.clearTo(StackSizeBefore);
-    S.Stk.push<Integral<32, true>>(Integral<32, true>::from(0));
+    S.Stk.push<IntegralOrPtr<32, true>>(IntegralOrPtr<32, true>::from(0));
   }
 
   // RealPC should not have been modified.
@@ -2187,12 +2187,15 @@ 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 (S.getLangOpts().CPlusPlus && Ptr.isDummy() && !Ptr.pointsToLabel())
     return false;
-  if (Ptr.isFunctionPointer())
+  if (Ptr.isIntegralPointer())
+    return true;
+
+  if (Ptr.isDummy())
     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)
@@ -2201,6 +2204,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>();
 
@@ -2286,13 +2294,19 @@ bool DiagTypeid(InterpState &S, CodePtr OpPC) {
 
 bool arePotentiallyOverlappingStringLiterals(const Pointer &LHS,
                                              const Pointer &RHS) {
+  if (!LHS.pointsToStr...
[truncated]

``````````

</details>


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

Reply via email to