Author: Timm Baeder
Date: 2026-06-10T10:10:57+02:00
New Revision: be1f53f568394ee7c1976a9a5785c8127dbcdf39

URL: 
https://github.com/llvm/llvm-project/commit/be1f53f568394ee7c1976a9a5785c8127dbcdf39
DIFF: 
https://github.com/llvm/llvm-project/commit/be1f53f568394ee7c1976a9a5785c8127dbcdf39.diff

LOG: [clang][bytecode] Save a `Type*` in integral pointers instead of a 
descriptor (#202835)

This way we don't need to allocate a descriptor via the `Program`, which
is for global data.

Added: 
    

Modified: 
    clang/lib/AST/ByteCode/Compiler.cpp
    clang/lib/AST/ByteCode/Interp.cpp
    clang/lib/AST/ByteCode/Interp.h
    clang/lib/AST/ByteCode/MemberPointer.h
    clang/lib/AST/ByteCode/Opcodes.td
    clang/lib/AST/ByteCode/Pointer.cpp
    clang/lib/AST/ByteCode/Pointer.h

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/ByteCode/Compiler.cpp 
b/clang/lib/AST/ByteCode/Compiler.cpp
index b89849b6983d8..8ea42fea03bee 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -434,18 +434,9 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *E) {
   case CK_NullToMemberPointer: {
     if (!this->discard(SubExpr))
       return false;
-    const Descriptor *Desc = nullptr;
-    const QualType PointeeType = E->getType()->getPointeeType();
-    if (!PointeeType.isNull()) {
-      if (OptPrimType T = classify(PointeeType))
-        Desc = P.createDescriptor(SubExpr, *T);
-      else
-        Desc = P.createDescriptor(SubExpr, PointeeType.getTypePtr(),
-                                  std::nullopt, /*IsConst=*/true);
-    }
-
     uint64_t Val = Ctx.getASTContext().getTargetNullPointerValue(E->getType());
-    return this->emitNull(classifyPrim(E->getType()), Val, Desc, E);
+    return this->emitNull(classifyPrim(E->getType()), Val,
+                          E->getType().getTypePtr(), E);
   }
 
   case CK_PointerToIntegral: {
@@ -481,19 +472,10 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *E) {
     // FIXME: I think the discard is wrong since the int->ptr cast might cause 
a
     // diagnostic.
     PrimType T = classifyPrim(IntType);
-    QualType PtrType = E->getType();
-    const Descriptor *Desc;
-    if (OptPrimType T = classify(PtrType->getPointeeType()))
-      Desc = P.createDescriptor(SubExpr, *T);
-    else if (PtrType->getPointeeType()->isVoidType())
-      Desc = nullptr;
-    else
-      Desc = P.createDescriptor(E, PtrType->getPointeeType().getTypePtr(),
-                                Descriptor::InlineDescMD, /*IsConst=*/true);
-
-    if (!this->emitGetIntPtr(T, Desc, E))
+    if (!this->emitGetIntPtr(T, E->getType().getTypePtr(), E))
       return false;
 
+    QualType PtrType = E->getType();
     PrimType DestPtrT = classifyPrim(PtrType);
     if (DestPtrT == PT_Ptr)
       return true;

diff  --git a/clang/lib/AST/ByteCode/Interp.cpp 
b/clang/lib/AST/ByteCode/Interp.cpp
index f6cac7aeb9fb5..f21dbb3d5246c 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -1489,7 +1489,7 @@ static bool getField(InterpState &S, CodePtr OpPC, const 
Pointer &Ptr,
 
   if (Ptr.isIntegralPointer()) {
     if (std::optional<IntPointer> IntPtr =
-            Ptr.asIntPointer().atOffset(S.getASTContext(), Off)) {
+            Ptr.asIntPointer().atOffset(S.Ctx, Off)) {
       S.Stk.push<Pointer>(std::move(*IntPtr));
       return true;
     }
@@ -1535,7 +1535,7 @@ static bool getBase(InterpState &S, CodePtr OpPC, const 
Pointer &Ptr,
   if (!Ptr.isBlockPointer()) {
     if (!Ptr.isIntegralPointer())
       return false;
-    S.Stk.push<Pointer>(Ptr.asIntPointer().baseCast(S.getASTContext(), Off));
+    S.Stk.push<Pointer>(Ptr.asIntPointer().baseCast(S.Ctx, Off));
     return true;
   }
 
@@ -1895,7 +1895,7 @@ static bool getDynamicDecl(InterpState &S, CodePtr OpPC, 
Pointer TypePtr,
 
   QualType DynamicType = TypePtr.getType();
   if (TypePtr.isStatic() || TypePtr.isConst()) {
-    if (const VarDecl *VD = TypePtr.getDeclDesc()->asVarDecl();
+    if (const VarDecl *VD = TypePtr.getRootVarDecl();
         VD && !VD->isConstexpr()) {
       const Expr *E = S.Current->getExpr(OpPC);
       APValue V = TypePtr.toAPValue(S.getASTContext());

diff  --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index 4c0a7040f46aa..9d3d3b449bea3 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -2503,11 +2503,16 @@ std::optional<Pointer> OffsetHelper(InterpState &S, 
CodePtr OpPC,
   // This is much simpler for integral pointers, so handle them first.
   if (Ptr.isIntegralPointer()) {
     uint64_t V = Ptr.getIntegerRepresentation();
-    uint64_t O = static_cast<uint64_t>(Offset) * Ptr.elemSize();
-    if constexpr (Op == ArithOp::Add)
-      return Pointer(V + O, Ptr.asIntPointer().Desc);
-    else
-      return Pointer(V - O, Ptr.asIntPointer().Desc);
+    QualType ElemType = Ptr.asIntPointer().getPointeeType();
+    uint64_t ElemSize =
+        (ElemType.isNull() || ElemType->isVoidType())
+            ? 1u
+            : S.getASTContext().getTypeSizeInChars(ElemType).getQuantity();
+    uint64_t O = static_cast<uint64_t>(Offset) * ElemSize;
+    if constexpr (Op == ArithOp::Add) {
+      return Pointer(V + O, Ptr.asIntPointer().Ty);
+    } else
+      return Pointer(V - O, Ptr.asIntPointer().Ty);
   } else if (Ptr.isFunctionPointer()) {
     uint64_t O = static_cast<uint64_t>(Offset);
     uint64_t N;
@@ -3119,11 +3124,10 @@ static inline bool ZeroIntAPS(InterpState &S, CodePtr 
OpPC, uint32_t BitWidth) {
 }
 
 template <PrimType Name, class T = typename PrimConv<Name>::T>
-inline bool Null(InterpState &S, CodePtr OpPC, uint64_t Value,
-                 const Descriptor *Desc) {
+inline bool Null(InterpState &S, CodePtr OpPC, uint64_t Value, const Type *Ty) 
{
   // FIXME(perf): This is a somewhat often-used function and the value of a
   // null pointer is almost always 0.
-  S.Stk.push<T>(Value, Desc);
+  S.Stk.push<T>(Value, Ty);
   return true;
 }
 
@@ -3563,7 +3567,7 @@ inline bool GetFnPtr(InterpState &S, CodePtr OpPC, const 
Function *Func) {
 }
 
 template <PrimType Name, class T = typename PrimConv<Name>::T>
-inline bool GetIntPtr(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
+inline bool GetIntPtr(InterpState &S, CodePtr OpPC, const Type *Ty) {
   const T &IntVal = S.Stk.pop<T>();
 
   S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_invalid_cast)
@@ -3588,10 +3592,10 @@ inline bool GetIntPtr(InterpState &S, CodePtr OpPC, 
const Descriptor *Desc) {
           S.P.getFunction((const FunctionDecl *)IntVal.getPtr());
       S.Stk.push<Pointer>(F, IntVal.getOffset());
     } else {
-      S.Stk.push<Pointer>(static_cast<uint64_t>(IntVal), Desc);
+      S.Stk.push<Pointer>(static_cast<uint64_t>(IntVal), Ty);
     }
   } else {
-    S.Stk.push<Pointer>(static_cast<uint64_t>(IntVal), Desc);
+    S.Stk.push<Pointer>(static_cast<uint64_t>(IntVal), Ty);
   }
 
   return true;
@@ -3872,7 +3876,7 @@ inline bool AllocN(InterpState &S, CodePtr OpPC, PrimType 
T, const Expr *Source,
       return false;
 
     // If this failed and is nothrow, just return a null ptr.
-    S.Stk.push<Pointer>(0, nullptr);
+    S.Stk.push<Pointer>();
     return true;
   }
   if (NumElements.isNegative()) {
@@ -3881,7 +3885,7 @@ inline bool AllocN(InterpState &S, CodePtr OpPC, PrimType 
T, const Expr *Source,
           << NumElements.toDiagnosticString(S.getASTContext());
       return false;
     }
-    S.Stk.push<Pointer>(0, nullptr);
+    S.Stk.push<Pointer>();
     return true;
   }
 
@@ -3915,7 +3919,7 @@ inline bool AllocCN(InterpState &S, CodePtr OpPC, const 
Descriptor *ElementDesc,
       return false;
 
     // If this failed and is nothrow, just return a null ptr.
-    S.Stk.push<Pointer>(0, ElementDesc);
+    S.Stk.push<Pointer>(0, ElementDesc->getType().getTypePtr());
     return true;
   }
   if (NumElements.isNegative()) {
@@ -3924,7 +3928,7 @@ inline bool AllocCN(InterpState &S, CodePtr OpPC, const 
Descriptor *ElementDesc,
           << NumElements.toDiagnosticString(S.getASTContext());
       return false;
     }
-    S.Stk.push<Pointer>(0, nullptr);
+    S.Stk.push<Pointer>();
     return true;
   }
 

diff  --git a/clang/lib/AST/ByteCode/MemberPointer.h 
b/clang/lib/AST/ByteCode/MemberPointer.h
index dbbf1fe85bada..b23acf7befc67 100644
--- a/clang/lib/AST/ByteCode/MemberPointer.h
+++ b/clang/lib/AST/ByteCode/MemberPointer.h
@@ -44,7 +44,7 @@ class MemberPointer final {
   MemberPointer() = default;
   MemberPointer(Pointer Base, const ValueDecl *Dcl)
       : Base(Base), DeclAndIsDerivedMember(Dcl) {}
-  MemberPointer(uint32_t Address, const Descriptor *D) {
+  MemberPointer(uint32_t Address, const Type *) {
     // We only reach this for Address == 0, when creating a null member 
pointer.
     assert(Address == 0);
   }

diff  --git a/clang/lib/AST/ByteCode/Opcodes.td 
b/clang/lib/AST/ByteCode/Opcodes.td
index 4bd61cdce658d..09c616aa2ff1d 100644
--- a/clang/lib/AST/ByteCode/Opcodes.td
+++ b/clang/lib/AST/ByteCode/Opcodes.td
@@ -311,7 +311,7 @@ def ZeroIntAPS : Opcode {
 // [] -> [Pointer]
 def Null : Opcode {
   let Types = [PtrTypeClass];
-  let Args = [ArgUint64, ArgDesc];
+  let Args = [ArgUint64, ArgTypePtr];
   let HasGroup = 1;
 }
 
@@ -596,7 +596,7 @@ def GetFnPtr : Opcode {
 
 def GetIntPtr : Opcode {
   let Types = [AluTypeClass];
-  let Args = [ArgDesc];
+  let Args = [ArgTypePtr];
   let HasGroup = 1;
 }
 

diff  --git a/clang/lib/AST/ByteCode/Pointer.cpp 
b/clang/lib/AST/ByteCode/Pointer.cpp
index 96409faeb6929..1b15c59c9fbff 100644
--- a/clang/lib/AST/ByteCode/Pointer.cpp
+++ b/clang/lib/AST/ByteCode/Pointer.cpp
@@ -337,9 +337,7 @@ void Pointer::print(llvm::raw_ostream &OS) const {
     OS << "}";
   } break;
   case Storage::Int:
-    OS << "(Int) {";
-    OS << Int.Value << " + " << Offset << ", " << Int.Desc;
-    OS << "}";
+    OS << "(Int) {" << Int.Value << " + " << Offset << ", " << Int.Ty << "}";
     break;
   case Storage::Fn:
     OS << "(Fn) { " << Fn.Func << " + " << Offset << " }";
@@ -994,11 +992,19 @@ std::optional<APValue> Pointer::toRValue(const Context 
&Ctx,
   return Result;
 }
 
-std::optional<IntPointer> IntPointer::atOffset(const ASTContext &ASTCtx,
+const VarDecl *Pointer::getRootVarDecl() const {
+  if (isBlockPointer())
+    return getDeclDesc()->asVarDecl();
+  return nullptr;
+}
+
+std::optional<IntPointer> IntPointer::atOffset(const interp::Context &Ctx,
                                                unsigned Offset) const {
-  if (!this->Desc)
-    return *this;
-  const Record *R = this->Desc->ElemRecord;
+  QualType CurType = getPointeeType();
+  if (CurType.isNull() || !CurType->isRecordType())
+    return std::nullopt;
+
+  const Record *R = Ctx.getRecord(CurType->getAsRecordDecl());
   if (!R)
     return *this;
 
@@ -1016,21 +1022,26 @@ std::optional<IntPointer> IntPointer::atOffset(const 
ASTContext &ASTCtx,
   if (FD->getParent()->isInvalidDecl())
     return std::nullopt;
 
+  const ASTContext &ASTCtx = Ctx.getASTContext();
   const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(FD->getParent());
   unsigned FieldIndex = FD->getFieldIndex();
   uint64_t FieldOffset =
       ASTCtx.toCharUnitsFromBits(Layout.getFieldOffset(FieldIndex))
           .getQuantity();
-  return IntPointer{F->Desc, this->Value + FieldOffset};
+
+  return IntPointer{FD->getType().getTypePtr(), this->Value + FieldOffset};
 }
 
-IntPointer IntPointer::baseCast(const ASTContext &ASTCtx,
+IntPointer IntPointer::baseCast(const interp::Context &Ctx,
                                 unsigned BaseOffset) const {
-  if (!Desc) {
-    assert(Value == 0);
+  if (!Ty)
     return *this;
-  }
-  const Record *R = Desc->ElemRecord;
+
+  QualType CurType = getPointeeType();
+  if (CurType.isNull() || !CurType->isRecordType())
+    return *this;
+
+  const Record *R = Ctx.getRecord(CurType->getAsRecordDecl());
   const Descriptor *BaseDesc = nullptr;
 
   // This iterates over bases and checks for the proper offset. That's
@@ -1044,9 +1055,13 @@ IntPointer IntPointer::baseCast(const ASTContext &ASTCtx,
   assert(BaseDesc);
 
   // Adjust the offset value based on the information from the record layout.
+  const ASTContext &ASTCtx = Ctx.getASTContext();
   const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(R->getDecl());
   CharUnits BaseLayoutOffset =
       Layout.getBaseClassOffset(cast<CXXRecordDecl>(BaseDesc->asDecl()));
 
-  return {BaseDesc, Value + BaseLayoutOffset.getQuantity()};
+  const RecordDecl *RD = BaseDesc->ElemRecord->getDecl();
+  QualType T = RD->getASTContext().getTagType(ElaboratedTypeKeyword::None,
+                                              std::nullopt, RD, false);
+  return {T.getTypePtr(), Value + BaseLayoutOffset.getQuantity()};
 }

diff  --git a/clang/lib/AST/ByteCode/Pointer.h 
b/clang/lib/AST/ByteCode/Pointer.h
index a77918f667fd3..2b455ebc5efb5 100644
--- a/clang/lib/AST/ByteCode/Pointer.h
+++ b/clang/lib/AST/ByteCode/Pointer.h
@@ -45,12 +45,24 @@ struct BlockPointer {
 };
 
 struct IntPointer {
-  const Descriptor *Desc;
+  const Type *Ty;
   uint64_t Value;
 
-  std::optional<IntPointer> atOffset(const ASTContext &ASTCtx,
-                                     unsigned Offset) const;
-  IntPointer baseCast(const ASTContext &ASTCtx, unsigned BaseOffset) const;
+  std::optional<IntPointer> atOffset(const Context &Ctx, unsigned Offset) 
const;
+  IntPointer baseCast(const Context &Ctx, unsigned BaseOffset) const;
+
+  QualType getPointeeType() const {
+    if (!Ty)
+      return QualType();
+
+    QualType QT(Ty, 0);
+    if (QT->isPointerOrReferenceType())
+      QT = QT->getPointeeType();
+    else if (QT->isArrayType())
+      QT = QT->getAsArrayTypeUnsafe()->getElementType();
+
+    return QT.IgnoreParens();
+  }
 };
 
 struct FunctionPointer {
@@ -107,8 +119,8 @@ class Pointer {
   Pointer(Block *B, uint64_t BaseAndOffset);
   Pointer(const Pointer &P);
   Pointer(Pointer &&P);
-  Pointer(uint64_t Address, const Descriptor *Desc, uint64_t Offset = 0)
-      : Offset(Offset), StorageKind(Storage::Int), Int{Desc, Address} {}
+  Pointer(uint64_t Address, const Type *Ty, uint64_t Offset = 0)
+      : Offset(Offset), StorageKind(Storage::Int), Int{Ty, Address} {}
   Pointer(const Function *F, uint64_t Offset = 0)
       : Offset(Offset), StorageKind(Storage::Fn), Fn{F} {}
   Pointer(const Type *TypePtr, const Type *TypeInfoType, uint64_t Offset = 0)
@@ -127,7 +139,7 @@ class Pointer {
     if (P.StorageKind != StorageKind)
       return false;
     if (isIntegralPointer())
-      return P.Int.Value == Int.Value && P.Int.Desc == Int.Desc &&
+      return P.Int.Value == Int.Value && P.Int.Ty == Int.Ty &&
              P.Offset == Offset;
 
     if (isFunctionPointer())
@@ -161,7 +173,7 @@ class Pointer {
   /// Offsets a pointer inside an array.
   [[nodiscard]] Pointer atIndex(uint64_t Idx) const {
     if (isIntegralPointer())
-      return Pointer(Int.Value, Int.Desc, Idx);
+      return Pointer(Int.Value, Int.Ty, Idx);
     if (isFunctionPointer())
       return Pointer(Fn.Func, Idx);
 
@@ -290,9 +302,7 @@ class Pointer {
 
   /// Accessor for information about the declaration site.
   const Descriptor *getDeclDesc() const {
-    if (isIntegralPointer())
-      return Int.Desc;
-    if (isFunctionPointer() || isTypeidPointer())
+    if (!isBlockPointer())
       return nullptr;
 
     assert(isBlockPointer());
@@ -309,8 +319,8 @@ class Pointer {
       const Function *F = Fn.Func;
       return F ? F->getDecl() : DeclTy();
     }
-    assert(isIntegralPointer());
-    return Int.Desc ? Int.Desc->getSource() : DeclTy();
+    llvm_unreachable("Unsupported pointer type in getSource()");
+    return DeclTy();
   }
 
   /// Returns a pointer to the object of which this pointer is a field.
@@ -335,7 +345,7 @@ class Pointer {
   /// Accessors for information about the innermost field.
   const Descriptor *getFieldDesc() const {
     if (isIntegralPointer())
-      return Int.Desc;
+      return nullptr;
 
     if (isRoot())
       return getDeclDesc();
@@ -348,6 +358,8 @@ class Pointer {
       return QualType(Typeid.TypeInfoType, 0);
     if (isFunctionPointer())
       return Fn.Func->getDecl()->getType();
+    if (isIntegralPointer())
+      return Int.getPointeeType();
 
     if (isRoot() && BS.Base == Offset) {
       // If this pointer points to the root of a declaration, try to consult
@@ -372,14 +384,15 @@ class Pointer {
     return getFieldDesc()->getType();
   }
 
+  const VarDecl *getRootVarDecl() const;
+
   [[nodiscard]] Pointer getDeclPtr() const { return Pointer(BS.Pointee); }
 
   /// Returns the element size of the innermost field.
   size_t elemSize() const {
     if (isIntegralPointer()) {
-      if (!Int.Desc)
-        return 1;
-      return Int.Desc->getElemDataSize();
+      // FIXME: Remove this and handle int ptrs specially?
+      return 1;
     }
 
     if (BS.Base == RootPtrMark)


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

Reply via email to