1a7dea167SDimitry Andric //===--- Pointer.h - Types for the constexpr VM -----------------*- C++ -*-===// 2a7dea167SDimitry Andric // 3a7dea167SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4a7dea167SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5a7dea167SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6a7dea167SDimitry Andric // 7a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 8a7dea167SDimitry Andric // 9a7dea167SDimitry Andric // Defines the classes responsible for pointer tracking. 10a7dea167SDimitry Andric // 11a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 12a7dea167SDimitry Andric 13a7dea167SDimitry Andric #ifndef LLVM_CLANG_AST_INTERP_POINTER_H 14a7dea167SDimitry Andric #define LLVM_CLANG_AST_INTERP_POINTER_H 15a7dea167SDimitry Andric 16a7dea167SDimitry Andric #include "Descriptor.h" 175ffd83dbSDimitry Andric #include "InterpBlock.h" 185ffd83dbSDimitry Andric #include "clang/AST/ComparisonCategories.h" 19a7dea167SDimitry Andric #include "clang/AST/Decl.h" 20a7dea167SDimitry Andric #include "clang/AST/DeclCXX.h" 21a7dea167SDimitry Andric #include "clang/AST/Expr.h" 22a7dea167SDimitry Andric #include "llvm/Support/raw_ostream.h" 23a7dea167SDimitry Andric 24a7dea167SDimitry Andric namespace clang { 25a7dea167SDimitry Andric namespace interp { 26a7dea167SDimitry Andric class Block; 27a7dea167SDimitry Andric class DeadBlock; 28a7dea167SDimitry Andric class Pointer; 295f757f3fSDimitry Andric class Context; 30*0fca6ea1SDimitry Andric template <unsigned A, bool B> class Integral; 31a7dea167SDimitry Andric enum PrimType : unsigned; 32a7dea167SDimitry Andric 335f757f3fSDimitry Andric class Pointer; 345f757f3fSDimitry Andric inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Pointer &P); 355f757f3fSDimitry Andric 36*0fca6ea1SDimitry Andric struct BlockPointer { 37*0fca6ea1SDimitry Andric /// The block the pointer is pointing to. 38*0fca6ea1SDimitry Andric Block *Pointee; 39*0fca6ea1SDimitry Andric /// Start of the current subfield. 40*0fca6ea1SDimitry Andric unsigned Base; 41*0fca6ea1SDimitry Andric }; 42*0fca6ea1SDimitry Andric 43*0fca6ea1SDimitry Andric struct IntPointer { 44*0fca6ea1SDimitry Andric const Descriptor *Desc; 45*0fca6ea1SDimitry Andric uint64_t Value; 46*0fca6ea1SDimitry Andric }; 47*0fca6ea1SDimitry Andric 48*0fca6ea1SDimitry Andric enum class Storage { Block, Int }; 49*0fca6ea1SDimitry Andric 50a7dea167SDimitry Andric /// A pointer to a memory block, live or dead. 51a7dea167SDimitry Andric /// 52a7dea167SDimitry Andric /// This object can be allocated into interpreter stack frames. If pointing to 53a7dea167SDimitry Andric /// a live block, it is a link in the chain of pointers pointing to the block. 54bdd1243dSDimitry Andric /// 55bdd1243dSDimitry Andric /// In the simplest form, a Pointer has a Block* (the pointee) and both Base 56bdd1243dSDimitry Andric /// and Offset are 0, which means it will point to raw data. 57bdd1243dSDimitry Andric /// 58bdd1243dSDimitry Andric /// The Base field is used to access metadata about the data. For primitive 59bdd1243dSDimitry Andric /// arrays, the Base is followed by an InitMap. In a variety of cases, the 60bdd1243dSDimitry Andric /// Base is preceded by an InlineDescriptor, which is used to track the 61bdd1243dSDimitry Andric /// initialization state, among other things. 62bdd1243dSDimitry Andric /// 63bdd1243dSDimitry Andric /// The Offset field is used to access the actual data. In other words, the 64bdd1243dSDimitry Andric /// data the pointer decribes can be found at 65bdd1243dSDimitry Andric /// Pointee->rawData() + Pointer.Offset. 66bdd1243dSDimitry Andric /// 67bdd1243dSDimitry Andric /// 68bdd1243dSDimitry Andric /// Pointee Offset 69bdd1243dSDimitry Andric /// │ │ 70bdd1243dSDimitry Andric /// │ │ 71bdd1243dSDimitry Andric /// ▼ ▼ 72bdd1243dSDimitry Andric /// ┌───────┬────────────┬─────────┬────────────────────────────┐ 73bdd1243dSDimitry Andric /// │ Block │ InlineDesc │ InitMap │ Actual Data │ 74bdd1243dSDimitry Andric /// └───────┴────────────┴─────────┴────────────────────────────┘ 75bdd1243dSDimitry Andric /// ▲ 76bdd1243dSDimitry Andric /// │ 77bdd1243dSDimitry Andric /// │ 78bdd1243dSDimitry Andric /// Base 79a7dea167SDimitry Andric class Pointer { 80a7dea167SDimitry Andric private: 81bdd1243dSDimitry Andric static constexpr unsigned PastEndMark = ~0u; 82bdd1243dSDimitry Andric static constexpr unsigned RootPtrMark = ~0u; 83a7dea167SDimitry Andric 84a7dea167SDimitry Andric public: 85*0fca6ea1SDimitry Andric Pointer() { 86*0fca6ea1SDimitry Andric StorageKind = Storage::Int; 87*0fca6ea1SDimitry Andric PointeeStorage.Int.Value = 0; 88*0fca6ea1SDimitry Andric PointeeStorage.Int.Desc = nullptr; 89*0fca6ea1SDimitry Andric } 90a7dea167SDimitry Andric Pointer(Block *B); 91*0fca6ea1SDimitry Andric Pointer(Block *B, uint64_t BaseAndOffset); 92a7dea167SDimitry Andric Pointer(const Pointer &P); 93a7dea167SDimitry Andric Pointer(Pointer &&P); 94*0fca6ea1SDimitry Andric Pointer(uint64_t Address, const Descriptor *Desc, uint64_t Offset = 0) 95*0fca6ea1SDimitry Andric : Offset(Offset), StorageKind(Storage::Int) { 96*0fca6ea1SDimitry Andric PointeeStorage.Int.Value = Address; 97*0fca6ea1SDimitry Andric PointeeStorage.Int.Desc = Desc; 98*0fca6ea1SDimitry Andric } 99a7dea167SDimitry Andric ~Pointer(); 100a7dea167SDimitry Andric 101a7dea167SDimitry Andric void operator=(const Pointer &P); 102a7dea167SDimitry Andric void operator=(Pointer &&P); 103a7dea167SDimitry Andric 1045f757f3fSDimitry Andric /// Equality operators are just for tests. 1055f757f3fSDimitry Andric bool operator==(const Pointer &P) const { 106*0fca6ea1SDimitry Andric if (P.StorageKind != StorageKind) 107*0fca6ea1SDimitry Andric return false; 108*0fca6ea1SDimitry Andric if (isIntegralPointer()) 109*0fca6ea1SDimitry Andric return P.asIntPointer().Value == asIntPointer().Value && 110*0fca6ea1SDimitry Andric Offset == P.Offset; 111*0fca6ea1SDimitry Andric 112*0fca6ea1SDimitry Andric assert(isBlockPointer()); 113*0fca6ea1SDimitry Andric return P.asBlockPointer().Pointee == asBlockPointer().Pointee && 114*0fca6ea1SDimitry Andric P.asBlockPointer().Base == asBlockPointer().Base && 115*0fca6ea1SDimitry Andric Offset == P.Offset; 1165f757f3fSDimitry Andric } 1175f757f3fSDimitry Andric 118*0fca6ea1SDimitry Andric bool operator!=(const Pointer &P) const { return !(P == *this); } 1195f757f3fSDimitry Andric 120a7dea167SDimitry Andric /// Converts the pointer to an APValue. 121*0fca6ea1SDimitry Andric APValue toAPValue(const ASTContext &ASTCtx) const; 122a7dea167SDimitry Andric 1235f757f3fSDimitry Andric /// Converts the pointer to a string usable in diagnostics. 1245f757f3fSDimitry Andric std::string toDiagnosticString(const ASTContext &Ctx) const; 1255f757f3fSDimitry Andric 126*0fca6ea1SDimitry Andric uint64_t getIntegerRepresentation() const { 127*0fca6ea1SDimitry Andric if (isIntegralPointer()) 128*0fca6ea1SDimitry Andric return asIntPointer().Value + (Offset * elemSize()); 129*0fca6ea1SDimitry Andric return reinterpret_cast<uint64_t>(asBlockPointer().Pointee) + Offset; 1305f757f3fSDimitry Andric } 1315f757f3fSDimitry Andric 1325f757f3fSDimitry Andric /// Converts the pointer to an APValue that is an rvalue. 133*0fca6ea1SDimitry Andric std::optional<APValue> toRValue(const Context &Ctx, 134*0fca6ea1SDimitry Andric QualType ResultType) const; 1355f757f3fSDimitry Andric 136a7dea167SDimitry Andric /// Offsets a pointer inside an array. 137*0fca6ea1SDimitry Andric [[nodiscard]] Pointer atIndex(uint64_t Idx) const { 138*0fca6ea1SDimitry Andric if (isIntegralPointer()) 139*0fca6ea1SDimitry Andric return Pointer(asIntPointer().Value, asIntPointer().Desc, Idx); 140*0fca6ea1SDimitry Andric 141*0fca6ea1SDimitry Andric if (asBlockPointer().Base == RootPtrMark) 142*0fca6ea1SDimitry Andric return Pointer(asBlockPointer().Pointee, RootPtrMark, 143*0fca6ea1SDimitry Andric getDeclDesc()->getSize()); 144*0fca6ea1SDimitry Andric uint64_t Off = Idx * elemSize(); 145a7dea167SDimitry Andric if (getFieldDesc()->ElemDesc) 146a7dea167SDimitry Andric Off += sizeof(InlineDescriptor); 147a7dea167SDimitry Andric else 1485f757f3fSDimitry Andric Off += sizeof(InitMapPtr); 149*0fca6ea1SDimitry Andric return Pointer(asBlockPointer().Pointee, asBlockPointer().Base, 150*0fca6ea1SDimitry Andric asBlockPointer().Base + Off); 151a7dea167SDimitry Andric } 152a7dea167SDimitry Andric 153a7dea167SDimitry Andric /// Creates a pointer to a field. 1545f757f3fSDimitry Andric [[nodiscard]] Pointer atField(unsigned Off) const { 155a7dea167SDimitry Andric unsigned Field = Offset + Off; 156*0fca6ea1SDimitry Andric if (isIntegralPointer()) 157*0fca6ea1SDimitry Andric return Pointer(asIntPointer().Value + Field, asIntPointer().Desc); 158*0fca6ea1SDimitry Andric return Pointer(asBlockPointer().Pointee, Field, Field); 159a7dea167SDimitry Andric } 160a7dea167SDimitry Andric 1615f757f3fSDimitry Andric /// Subtract the given offset from the current Base and Offset 1625f757f3fSDimitry Andric /// of the pointer. 1635f757f3fSDimitry Andric [[nodiscard]] Pointer atFieldSub(unsigned Off) const { 1645f757f3fSDimitry Andric assert(Offset >= Off); 1655f757f3fSDimitry Andric unsigned O = Offset - Off; 166*0fca6ea1SDimitry Andric return Pointer(asBlockPointer().Pointee, O, O); 1675f757f3fSDimitry Andric } 1685f757f3fSDimitry Andric 169a7dea167SDimitry Andric /// Restricts the scope of an array element pointer. 1705f757f3fSDimitry Andric [[nodiscard]] Pointer narrow() const { 171*0fca6ea1SDimitry Andric if (!isBlockPointer()) 172*0fca6ea1SDimitry Andric return *this; 173*0fca6ea1SDimitry Andric assert(isBlockPointer()); 174a7dea167SDimitry Andric // Null pointers cannot be narrowed. 175a7dea167SDimitry Andric if (isZero() || isUnknownSizeArray()) 176a7dea167SDimitry Andric return *this; 177a7dea167SDimitry Andric 178a7dea167SDimitry Andric // Pointer to an array of base types - enter block. 179*0fca6ea1SDimitry Andric if (asBlockPointer().Base == RootPtrMark) 180*0fca6ea1SDimitry Andric return Pointer(asBlockPointer().Pointee, sizeof(InlineDescriptor), 181*0fca6ea1SDimitry Andric Offset == 0 ? Offset : PastEndMark); 182a7dea167SDimitry Andric 183a7dea167SDimitry Andric // Pointer is one past end - magic offset marks that. 184a7dea167SDimitry Andric if (isOnePastEnd()) 185*0fca6ea1SDimitry Andric return Pointer(asBlockPointer().Pointee, asBlockPointer().Base, 186*0fca6ea1SDimitry Andric PastEndMark); 187a7dea167SDimitry Andric 188a7dea167SDimitry Andric // Primitive arrays are a bit special since they do not have inline 189a7dea167SDimitry Andric // descriptors. If Offset != Base, then the pointer already points to 190a7dea167SDimitry Andric // an element and there is nothing to do. Otherwise, the pointer is 191a7dea167SDimitry Andric // adjusted to the first element of the array. 192a7dea167SDimitry Andric if (inPrimitiveArray()) { 193*0fca6ea1SDimitry Andric if (Offset != asBlockPointer().Base) 194a7dea167SDimitry Andric return *this; 195*0fca6ea1SDimitry Andric return Pointer(asBlockPointer().Pointee, asBlockPointer().Base, 196*0fca6ea1SDimitry Andric Offset + sizeof(InitMapPtr)); 197a7dea167SDimitry Andric } 198a7dea167SDimitry Andric 199a7dea167SDimitry Andric // Pointer is to a field or array element - enter it. 200*0fca6ea1SDimitry Andric if (Offset != asBlockPointer().Base) 201*0fca6ea1SDimitry Andric return Pointer(asBlockPointer().Pointee, Offset, Offset); 202a7dea167SDimitry Andric 203a7dea167SDimitry Andric // Enter the first element of an array. 204a7dea167SDimitry Andric if (!getFieldDesc()->isArray()) 205a7dea167SDimitry Andric return *this; 206a7dea167SDimitry Andric 207*0fca6ea1SDimitry Andric const unsigned NewBase = asBlockPointer().Base + sizeof(InlineDescriptor); 208*0fca6ea1SDimitry Andric return Pointer(asBlockPointer().Pointee, NewBase, NewBase); 209a7dea167SDimitry Andric } 210a7dea167SDimitry Andric 211a7dea167SDimitry Andric /// Expands a pointer to the containing array, undoing narrowing. 2125f757f3fSDimitry Andric [[nodiscard]] Pointer expand() const { 213*0fca6ea1SDimitry Andric assert(isBlockPointer()); 214*0fca6ea1SDimitry Andric Block *Pointee = asBlockPointer().Pointee; 215*0fca6ea1SDimitry Andric 216a7dea167SDimitry Andric if (isElementPastEnd()) { 217a7dea167SDimitry Andric // Revert to an outer one-past-end pointer. 218a7dea167SDimitry Andric unsigned Adjust; 219a7dea167SDimitry Andric if (inPrimitiveArray()) 2205f757f3fSDimitry Andric Adjust = sizeof(InitMapPtr); 221a7dea167SDimitry Andric else 222a7dea167SDimitry Andric Adjust = sizeof(InlineDescriptor); 223*0fca6ea1SDimitry Andric return Pointer(Pointee, asBlockPointer().Base, 224*0fca6ea1SDimitry Andric asBlockPointer().Base + getSize() + Adjust); 225a7dea167SDimitry Andric } 226a7dea167SDimitry Andric 227a7dea167SDimitry Andric // Do not step out of array elements. 228*0fca6ea1SDimitry Andric if (asBlockPointer().Base != Offset) 229a7dea167SDimitry Andric return *this; 230a7dea167SDimitry Andric 231a7dea167SDimitry Andric // If at base, point to an array of base types. 232*0fca6ea1SDimitry Andric if (isRoot()) 233a7dea167SDimitry Andric return Pointer(Pointee, RootPtrMark, 0); 234a7dea167SDimitry Andric 235a7dea167SDimitry Andric // Step into the containing array, if inside one. 236*0fca6ea1SDimitry Andric unsigned Next = asBlockPointer().Base - getInlineDesc()->Offset; 2375f757f3fSDimitry Andric const Descriptor *Desc = 238*0fca6ea1SDimitry Andric (Next == Pointee->getDescriptor()->getMetadataSize()) 239*0fca6ea1SDimitry Andric ? getDeclDesc() 240*0fca6ea1SDimitry Andric : getDescriptor(Next)->Desc; 241a7dea167SDimitry Andric if (!Desc->IsArray) 242a7dea167SDimitry Andric return *this; 243a7dea167SDimitry Andric return Pointer(Pointee, Next, Offset); 244a7dea167SDimitry Andric } 245a7dea167SDimitry Andric 246a7dea167SDimitry Andric /// Checks if the pointer is null. 247*0fca6ea1SDimitry Andric bool isZero() const { 248*0fca6ea1SDimitry Andric if (isBlockPointer()) 249*0fca6ea1SDimitry Andric return asBlockPointer().Pointee == nullptr; 250*0fca6ea1SDimitry Andric assert(isIntegralPointer()); 251*0fca6ea1SDimitry Andric return asIntPointer().Value == 0 && Offset == 0; 252*0fca6ea1SDimitry Andric } 253a7dea167SDimitry Andric /// Checks if the pointer is live. 254*0fca6ea1SDimitry Andric bool isLive() const { 255*0fca6ea1SDimitry Andric if (isIntegralPointer()) 256*0fca6ea1SDimitry Andric return true; 257*0fca6ea1SDimitry Andric return asBlockPointer().Pointee && !asBlockPointer().Pointee->IsDead; 258*0fca6ea1SDimitry Andric } 259a7dea167SDimitry Andric /// Checks if the item is a field in an object. 260*0fca6ea1SDimitry Andric bool isField() const { 261*0fca6ea1SDimitry Andric if (isIntegralPointer()) 262*0fca6ea1SDimitry Andric return false; 263*0fca6ea1SDimitry Andric 264*0fca6ea1SDimitry Andric return !isRoot() && getFieldDesc()->asDecl(); 265*0fca6ea1SDimitry Andric } 266a7dea167SDimitry Andric 267a7dea167SDimitry Andric /// Accessor for information about the declaration site. 2685f757f3fSDimitry Andric const Descriptor *getDeclDesc() const { 269*0fca6ea1SDimitry Andric if (isIntegralPointer()) 270*0fca6ea1SDimitry Andric return asIntPointer().Desc; 271*0fca6ea1SDimitry Andric 272*0fca6ea1SDimitry Andric assert(isBlockPointer()); 273*0fca6ea1SDimitry Andric assert(asBlockPointer().Pointee); 274*0fca6ea1SDimitry Andric return asBlockPointer().Pointee->Desc; 2755f757f3fSDimitry Andric } 276a7dea167SDimitry Andric SourceLocation getDeclLoc() const { return getDeclDesc()->getLocation(); } 277a7dea167SDimitry Andric 278*0fca6ea1SDimitry Andric /// Returns the expression or declaration the pointer has been created for. 279*0fca6ea1SDimitry Andric DeclTy getSource() const { 280*0fca6ea1SDimitry Andric if (isBlockPointer()) 281*0fca6ea1SDimitry Andric return getDeclDesc()->getSource(); 282*0fca6ea1SDimitry Andric 283*0fca6ea1SDimitry Andric assert(isIntegralPointer()); 284*0fca6ea1SDimitry Andric return asIntPointer().Desc ? asIntPointer().Desc->getSource() : DeclTy(); 285*0fca6ea1SDimitry Andric } 286*0fca6ea1SDimitry Andric 287a7dea167SDimitry Andric /// Returns a pointer to the object of which this pointer is a field. 2885f757f3fSDimitry Andric [[nodiscard]] Pointer getBase() const { 289*0fca6ea1SDimitry Andric if (asBlockPointer().Base == RootPtrMark) { 290a7dea167SDimitry Andric assert(Offset == PastEndMark && "cannot get base of a block"); 291*0fca6ea1SDimitry Andric return Pointer(asBlockPointer().Pointee, asBlockPointer().Base, 0); 292a7dea167SDimitry Andric } 293*0fca6ea1SDimitry Andric unsigned NewBase = asBlockPointer().Base - getInlineDesc()->Offset; 294*0fca6ea1SDimitry Andric return Pointer(asBlockPointer().Pointee, NewBase, NewBase); 295a7dea167SDimitry Andric } 296a7dea167SDimitry Andric /// Returns the parent array. 2975f757f3fSDimitry Andric [[nodiscard]] Pointer getArray() const { 298*0fca6ea1SDimitry Andric if (asBlockPointer().Base == RootPtrMark) { 299a7dea167SDimitry Andric assert(Offset != 0 && Offset != PastEndMark && "not an array element"); 300*0fca6ea1SDimitry Andric return Pointer(asBlockPointer().Pointee, asBlockPointer().Base, 0); 301a7dea167SDimitry Andric } 302*0fca6ea1SDimitry Andric assert(Offset != asBlockPointer().Base && "not an array element"); 303*0fca6ea1SDimitry Andric return Pointer(asBlockPointer().Pointee, asBlockPointer().Base, 304*0fca6ea1SDimitry Andric asBlockPointer().Base); 305a7dea167SDimitry Andric } 306a7dea167SDimitry Andric 307a7dea167SDimitry Andric /// Accessors for information about the innermost field. 3085f757f3fSDimitry Andric const Descriptor *getFieldDesc() const { 309*0fca6ea1SDimitry Andric if (isIntegralPointer()) 310*0fca6ea1SDimitry Andric return asIntPointer().Desc; 311*0fca6ea1SDimitry Andric 312*0fca6ea1SDimitry Andric if (isRoot()) 313a7dea167SDimitry Andric return getDeclDesc(); 314a7dea167SDimitry Andric return getInlineDesc()->Desc; 315a7dea167SDimitry Andric } 316a7dea167SDimitry Andric 317a7dea167SDimitry Andric /// Returns the type of the innermost field. 3185f757f3fSDimitry Andric QualType getType() const { 319*0fca6ea1SDimitry Andric if (inPrimitiveArray() && Offset != asBlockPointer().Base) { 320*0fca6ea1SDimitry Andric // Unfortunately, complex and vector types are not array types in clang, 321*0fca6ea1SDimitry Andric // but they are for us. 322*0fca6ea1SDimitry Andric if (const auto *AT = getFieldDesc()->getType()->getAsArrayTypeUnsafe()) 323*0fca6ea1SDimitry Andric return AT->getElementType(); 324*0fca6ea1SDimitry Andric if (const auto *CT = getFieldDesc()->getType()->getAs<ComplexType>()) 325*0fca6ea1SDimitry Andric return CT->getElementType(); 326*0fca6ea1SDimitry Andric if (const auto *CT = getFieldDesc()->getType()->getAs<VectorType>()) 327*0fca6ea1SDimitry Andric return CT->getElementType(); 328*0fca6ea1SDimitry Andric } 3295f757f3fSDimitry Andric return getFieldDesc()->getType(); 3305f757f3fSDimitry Andric } 331a7dea167SDimitry Andric 332*0fca6ea1SDimitry Andric [[nodiscard]] Pointer getDeclPtr() const { 333*0fca6ea1SDimitry Andric return Pointer(asBlockPointer().Pointee); 334*0fca6ea1SDimitry Andric } 33506c3fb27SDimitry Andric 336a7dea167SDimitry Andric /// Returns the element size of the innermost field. 337a7dea167SDimitry Andric size_t elemSize() const { 338*0fca6ea1SDimitry Andric if (isIntegralPointer()) { 339*0fca6ea1SDimitry Andric if (!asIntPointer().Desc) 340*0fca6ea1SDimitry Andric return 1; 341*0fca6ea1SDimitry Andric return asIntPointer().Desc->getElemSize(); 342*0fca6ea1SDimitry Andric } 343*0fca6ea1SDimitry Andric 344*0fca6ea1SDimitry Andric if (asBlockPointer().Base == RootPtrMark) 345a7dea167SDimitry Andric return getDeclDesc()->getSize(); 346a7dea167SDimitry Andric return getFieldDesc()->getElemSize(); 347a7dea167SDimitry Andric } 348a7dea167SDimitry Andric /// Returns the total size of the innermost field. 349*0fca6ea1SDimitry Andric size_t getSize() const { 350*0fca6ea1SDimitry Andric assert(isBlockPointer()); 351*0fca6ea1SDimitry Andric return getFieldDesc()->getSize(); 352*0fca6ea1SDimitry Andric } 353a7dea167SDimitry Andric 354a7dea167SDimitry Andric /// Returns the offset into an array. 355a7dea167SDimitry Andric unsigned getOffset() const { 356a7dea167SDimitry Andric assert(Offset != PastEndMark && "invalid offset"); 357*0fca6ea1SDimitry Andric if (asBlockPointer().Base == RootPtrMark) 358a7dea167SDimitry Andric return Offset; 359a7dea167SDimitry Andric 360a7dea167SDimitry Andric unsigned Adjust = 0; 361*0fca6ea1SDimitry Andric if (Offset != asBlockPointer().Base) { 362a7dea167SDimitry Andric if (getFieldDesc()->ElemDesc) 363a7dea167SDimitry Andric Adjust = sizeof(InlineDescriptor); 364a7dea167SDimitry Andric else 3655f757f3fSDimitry Andric Adjust = sizeof(InitMapPtr); 366a7dea167SDimitry Andric } 367*0fca6ea1SDimitry Andric return Offset - asBlockPointer().Base - Adjust; 368a7dea167SDimitry Andric } 369a7dea167SDimitry Andric 37006c3fb27SDimitry Andric /// Whether this array refers to an array, but not 37106c3fb27SDimitry Andric /// to the first element. 372*0fca6ea1SDimitry Andric bool isArrayRoot() const { 373*0fca6ea1SDimitry Andric return inArray() && Offset == asBlockPointer().Base; 374*0fca6ea1SDimitry Andric } 37506c3fb27SDimitry Andric 376a7dea167SDimitry Andric /// Checks if the innermost field is an array. 377*0fca6ea1SDimitry Andric bool inArray() const { 378*0fca6ea1SDimitry Andric if (isBlockPointer()) 379*0fca6ea1SDimitry Andric return getFieldDesc()->IsArray; 380*0fca6ea1SDimitry Andric return false; 381*0fca6ea1SDimitry Andric } 382a7dea167SDimitry Andric /// Checks if the structure is a primitive array. 383*0fca6ea1SDimitry Andric bool inPrimitiveArray() const { 384*0fca6ea1SDimitry Andric if (isBlockPointer()) 385*0fca6ea1SDimitry Andric return getFieldDesc()->isPrimitiveArray(); 386*0fca6ea1SDimitry Andric return false; 387*0fca6ea1SDimitry Andric } 388a7dea167SDimitry Andric /// Checks if the structure is an array of unknown size. 389a7dea167SDimitry Andric bool isUnknownSizeArray() const { 390*0fca6ea1SDimitry Andric if (!isBlockPointer()) 391*0fca6ea1SDimitry Andric return false; 392a7dea167SDimitry Andric return getFieldDesc()->isUnknownSizeArray(); 393a7dea167SDimitry Andric } 394a7dea167SDimitry Andric /// Checks if the pointer points to an array. 395*0fca6ea1SDimitry Andric bool isArrayElement() const { 396*0fca6ea1SDimitry Andric if (isBlockPointer()) 397*0fca6ea1SDimitry Andric return inArray() && asBlockPointer().Base != Offset; 398*0fca6ea1SDimitry Andric return false; 399*0fca6ea1SDimitry Andric } 400a7dea167SDimitry Andric /// Pointer points directly to a block. 401a7dea167SDimitry Andric bool isRoot() const { 402*0fca6ea1SDimitry Andric if (isZero() || isIntegralPointer()) 403*0fca6ea1SDimitry Andric return true; 404*0fca6ea1SDimitry Andric return (asBlockPointer().Base == 405*0fca6ea1SDimitry Andric asBlockPointer().Pointee->getDescriptor()->getMetadataSize() || 406*0fca6ea1SDimitry Andric asBlockPointer().Base == 0); 407a7dea167SDimitry Andric } 408*0fca6ea1SDimitry Andric /// If this pointer has an InlineDescriptor we can use to initialize. 409*0fca6ea1SDimitry Andric bool canBeInitialized() const { 410*0fca6ea1SDimitry Andric if (!isBlockPointer()) 411*0fca6ea1SDimitry Andric return false; 412*0fca6ea1SDimitry Andric 413*0fca6ea1SDimitry Andric return asBlockPointer().Pointee && asBlockPointer().Base > 0; 414*0fca6ea1SDimitry Andric } 415*0fca6ea1SDimitry Andric 416*0fca6ea1SDimitry Andric [[nodiscard]] const BlockPointer &asBlockPointer() const { 417*0fca6ea1SDimitry Andric assert(isBlockPointer()); 418*0fca6ea1SDimitry Andric return PointeeStorage.BS; 419*0fca6ea1SDimitry Andric } 420*0fca6ea1SDimitry Andric [[nodiscard]] const IntPointer &asIntPointer() const { 421*0fca6ea1SDimitry Andric assert(isIntegralPointer()); 422*0fca6ea1SDimitry Andric return PointeeStorage.Int; 423*0fca6ea1SDimitry Andric } 424*0fca6ea1SDimitry Andric bool isBlockPointer() const { return StorageKind == Storage::Block; } 425*0fca6ea1SDimitry Andric bool isIntegralPointer() const { return StorageKind == Storage::Int; } 426a7dea167SDimitry Andric 427a7dea167SDimitry Andric /// Returns the record descriptor of a class. 42806c3fb27SDimitry Andric const Record *getRecord() const { return getFieldDesc()->ElemRecord; } 42906c3fb27SDimitry Andric /// Returns the element record type, if this is a non-primive array. 43006c3fb27SDimitry Andric const Record *getElemRecord() const { 4315f757f3fSDimitry Andric const Descriptor *ElemDesc = getFieldDesc()->ElemDesc; 4325f757f3fSDimitry Andric return ElemDesc ? ElemDesc->ElemRecord : nullptr; 43306c3fb27SDimitry Andric } 434a7dea167SDimitry Andric /// Returns the field information. 435a7dea167SDimitry Andric const FieldDecl *getField() const { return getFieldDesc()->asFieldDecl(); } 436a7dea167SDimitry Andric 437a7dea167SDimitry Andric /// Checks if the object is a union. 438a7dea167SDimitry Andric bool isUnion() const; 439a7dea167SDimitry Andric 440a7dea167SDimitry Andric /// Checks if the storage is extern. 441*0fca6ea1SDimitry Andric bool isExtern() const { 442*0fca6ea1SDimitry Andric if (isBlockPointer()) 443*0fca6ea1SDimitry Andric return asBlockPointer().Pointee && asBlockPointer().Pointee->isExtern(); 444*0fca6ea1SDimitry Andric return false; 445*0fca6ea1SDimitry Andric } 446a7dea167SDimitry Andric /// Checks if the storage is static. 4475f757f3fSDimitry Andric bool isStatic() const { 448*0fca6ea1SDimitry Andric if (isIntegralPointer()) 449*0fca6ea1SDimitry Andric return true; 450*0fca6ea1SDimitry Andric assert(asBlockPointer().Pointee); 451*0fca6ea1SDimitry Andric return asBlockPointer().Pointee->isStatic(); 4525f757f3fSDimitry Andric } 453a7dea167SDimitry Andric /// Checks if the storage is temporary. 4545f757f3fSDimitry Andric bool isTemporary() const { 455*0fca6ea1SDimitry Andric if (isBlockPointer()) { 456*0fca6ea1SDimitry Andric assert(asBlockPointer().Pointee); 457*0fca6ea1SDimitry Andric return asBlockPointer().Pointee->isTemporary(); 458*0fca6ea1SDimitry Andric } 459*0fca6ea1SDimitry Andric return false; 4605f757f3fSDimitry Andric } 461a7dea167SDimitry Andric /// Checks if the storage is a static temporary. 462a7dea167SDimitry Andric bool isStaticTemporary() const { return isStatic() && isTemporary(); } 463a7dea167SDimitry Andric 464a7dea167SDimitry Andric /// Checks if the field is mutable. 465bdd1243dSDimitry Andric bool isMutable() const { 466*0fca6ea1SDimitry Andric if (!isBlockPointer()) 467*0fca6ea1SDimitry Andric return false; 468*0fca6ea1SDimitry Andric return !isRoot() && getInlineDesc()->IsFieldMutable; 469*0fca6ea1SDimitry Andric } 470*0fca6ea1SDimitry Andric 471*0fca6ea1SDimitry Andric bool isWeak() const { 472*0fca6ea1SDimitry Andric if (isIntegralPointer()) 473*0fca6ea1SDimitry Andric return false; 474*0fca6ea1SDimitry Andric 475*0fca6ea1SDimitry Andric assert(isBlockPointer()); 476*0fca6ea1SDimitry Andric if (const ValueDecl *VD = getDeclDesc()->asValueDecl()) 477*0fca6ea1SDimitry Andric return VD->isWeak(); 478*0fca6ea1SDimitry Andric return false; 479bdd1243dSDimitry Andric } 480a7dea167SDimitry Andric /// Checks if an object was initialized. 481a7dea167SDimitry Andric bool isInitialized() const; 482a7dea167SDimitry Andric /// Checks if the object is active. 483*0fca6ea1SDimitry Andric bool isActive() const { 484*0fca6ea1SDimitry Andric if (!isBlockPointer()) 485*0fca6ea1SDimitry Andric return true; 486*0fca6ea1SDimitry Andric return isRoot() || getInlineDesc()->IsActive; 487*0fca6ea1SDimitry Andric } 488a7dea167SDimitry Andric /// Checks if a structure is a base class. 489a7dea167SDimitry Andric bool isBaseClass() const { return isField() && getInlineDesc()->IsBase; } 490*0fca6ea1SDimitry Andric bool isVirtualBaseClass() const { 491*0fca6ea1SDimitry Andric return isField() && getInlineDesc()->IsVirtualBase; 492*0fca6ea1SDimitry Andric } 493*0fca6ea1SDimitry Andric /// Checks if the pointer points to a dummy value. 494*0fca6ea1SDimitry Andric bool isDummy() const { 495*0fca6ea1SDimitry Andric if (!isBlockPointer()) 496*0fca6ea1SDimitry Andric return false; 497*0fca6ea1SDimitry Andric 498*0fca6ea1SDimitry Andric if (!asBlockPointer().Pointee) 499*0fca6ea1SDimitry Andric return false; 500*0fca6ea1SDimitry Andric 501*0fca6ea1SDimitry Andric return getDeclDesc()->isDummy(); 502*0fca6ea1SDimitry Andric } 503a7dea167SDimitry Andric 504a7dea167SDimitry Andric /// Checks if an object or a subfield is mutable. 505a7dea167SDimitry Andric bool isConst() const { 506*0fca6ea1SDimitry Andric if (isIntegralPointer()) 507*0fca6ea1SDimitry Andric return true; 508*0fca6ea1SDimitry Andric return isRoot() ? getDeclDesc()->IsConst : getInlineDesc()->IsConst; 509a7dea167SDimitry Andric } 510a7dea167SDimitry Andric 511a7dea167SDimitry Andric /// Returns the declaration ID. 5125f757f3fSDimitry Andric std::optional<unsigned> getDeclID() const { 513*0fca6ea1SDimitry Andric if (isBlockPointer()) { 514*0fca6ea1SDimitry Andric assert(asBlockPointer().Pointee); 515*0fca6ea1SDimitry Andric return asBlockPointer().Pointee->getDeclID(); 516*0fca6ea1SDimitry Andric } 517*0fca6ea1SDimitry Andric return std::nullopt; 5185f757f3fSDimitry Andric } 519a7dea167SDimitry Andric 520a7dea167SDimitry Andric /// Returns the byte offset from the start. 521a7dea167SDimitry Andric unsigned getByteOffset() const { 522*0fca6ea1SDimitry Andric if (isIntegralPointer()) 523*0fca6ea1SDimitry Andric return asIntPointer().Value + Offset; 524*0fca6ea1SDimitry Andric if (isOnePastEnd()) 525*0fca6ea1SDimitry Andric return PastEndMark; 526a7dea167SDimitry Andric return Offset; 527a7dea167SDimitry Andric } 528a7dea167SDimitry Andric 529a7dea167SDimitry Andric /// Returns the number of elements. 530*0fca6ea1SDimitry Andric unsigned getNumElems() const { 531*0fca6ea1SDimitry Andric if (isIntegralPointer()) 532*0fca6ea1SDimitry Andric return ~unsigned(0); 533*0fca6ea1SDimitry Andric return getSize() / elemSize(); 534*0fca6ea1SDimitry Andric } 535a7dea167SDimitry Andric 536*0fca6ea1SDimitry Andric const Block *block() const { return asBlockPointer().Pointee; } 53706c3fb27SDimitry Andric 538a7dea167SDimitry Andric /// Returns the index into an array. 539a7dea167SDimitry Andric int64_t getIndex() const { 540*0fca6ea1SDimitry Andric if (!isBlockPointer()) 541*0fca6ea1SDimitry Andric return 0; 542*0fca6ea1SDimitry Andric 543*0fca6ea1SDimitry Andric if (isZero()) 544*0fca6ea1SDimitry Andric return 0; 5455f757f3fSDimitry Andric 5465f757f3fSDimitry Andric // narrow()ed element in a composite array. 547*0fca6ea1SDimitry Andric if (asBlockPointer().Base > sizeof(InlineDescriptor) && 548*0fca6ea1SDimitry Andric asBlockPointer().Base == Offset) 5495f757f3fSDimitry Andric return 0; 5505f757f3fSDimitry Andric 551a7dea167SDimitry Andric if (auto ElemSize = elemSize()) 552a7dea167SDimitry Andric return getOffset() / ElemSize; 553a7dea167SDimitry Andric return 0; 554a7dea167SDimitry Andric } 555a7dea167SDimitry Andric 556a7dea167SDimitry Andric /// Checks if the index is one past end. 557a7dea167SDimitry Andric bool isOnePastEnd() const { 558*0fca6ea1SDimitry Andric if (isIntegralPointer()) 5595f757f3fSDimitry Andric return false; 560*0fca6ea1SDimitry Andric 561*0fca6ea1SDimitry Andric if (!asBlockPointer().Pointee) 562*0fca6ea1SDimitry Andric return false; 563*0fca6ea1SDimitry Andric 564*0fca6ea1SDimitry Andric if (isUnknownSizeArray()) 565*0fca6ea1SDimitry Andric return false; 566*0fca6ea1SDimitry Andric 567*0fca6ea1SDimitry Andric return isElementPastEnd() || isPastEnd() || 568*0fca6ea1SDimitry Andric (getSize() == getOffset() && !isZeroSizeArray()); 569*0fca6ea1SDimitry Andric } 570*0fca6ea1SDimitry Andric 571*0fca6ea1SDimitry Andric /// Checks if the pointer points past the end of the object. 572*0fca6ea1SDimitry Andric bool isPastEnd() const { 573*0fca6ea1SDimitry Andric if (isIntegralPointer()) 574*0fca6ea1SDimitry Andric return false; 575*0fca6ea1SDimitry Andric 576*0fca6ea1SDimitry Andric return !isZero() && Offset > PointeeStorage.BS.Pointee->getSize(); 577a7dea167SDimitry Andric } 578a7dea167SDimitry Andric 579a7dea167SDimitry Andric /// Checks if the pointer is an out-of-bounds element pointer. 580a7dea167SDimitry Andric bool isElementPastEnd() const { return Offset == PastEndMark; } 581a7dea167SDimitry Andric 582*0fca6ea1SDimitry Andric /// Checks if the pointer is pointing to a zero-size array. 583*0fca6ea1SDimitry Andric bool isZeroSizeArray() const { return getFieldDesc()->isZeroSizeArray(); } 584*0fca6ea1SDimitry Andric 585a7dea167SDimitry Andric /// Dereferences the pointer, if it's live. 586a7dea167SDimitry Andric template <typename T> T &deref() const { 587a7dea167SDimitry Andric assert(isLive() && "Invalid pointer"); 588*0fca6ea1SDimitry Andric assert(isBlockPointer()); 589*0fca6ea1SDimitry Andric assert(asBlockPointer().Pointee); 590*0fca6ea1SDimitry Andric assert(isDereferencable()); 591*0fca6ea1SDimitry Andric assert(Offset + sizeof(T) <= 592*0fca6ea1SDimitry Andric asBlockPointer().Pointee->getDescriptor()->getAllocSize()); 59306c3fb27SDimitry Andric 594*0fca6ea1SDimitry Andric if (isArrayRoot()) 595*0fca6ea1SDimitry Andric return *reinterpret_cast<T *>(asBlockPointer().Pointee->rawData() + 596*0fca6ea1SDimitry Andric asBlockPointer().Base + sizeof(InitMapPtr)); 597*0fca6ea1SDimitry Andric 598*0fca6ea1SDimitry Andric return *reinterpret_cast<T *>(asBlockPointer().Pointee->rawData() + Offset); 599a7dea167SDimitry Andric } 600a7dea167SDimitry Andric 601a7dea167SDimitry Andric /// Dereferences a primitive element. 602a7dea167SDimitry Andric template <typename T> T &elem(unsigned I) const { 60306c3fb27SDimitry Andric assert(I < getNumElems()); 604*0fca6ea1SDimitry Andric assert(isBlockPointer()); 605*0fca6ea1SDimitry Andric assert(asBlockPointer().Pointee); 606*0fca6ea1SDimitry Andric return reinterpret_cast<T *>(asBlockPointer().Pointee->data() + 607*0fca6ea1SDimitry Andric sizeof(InitMapPtr))[I]; 608*0fca6ea1SDimitry Andric } 609*0fca6ea1SDimitry Andric 610*0fca6ea1SDimitry Andric /// Whether this block can be read from at all. This is only true for 611*0fca6ea1SDimitry Andric /// block pointers that point to a valid location inside that block. 612*0fca6ea1SDimitry Andric bool isDereferencable() const { 613*0fca6ea1SDimitry Andric if (!isBlockPointer()) 614*0fca6ea1SDimitry Andric return false; 615*0fca6ea1SDimitry Andric if (isPastEnd()) 616*0fca6ea1SDimitry Andric return false; 617*0fca6ea1SDimitry Andric 618*0fca6ea1SDimitry Andric return true; 619a7dea167SDimitry Andric } 620a7dea167SDimitry Andric 621a7dea167SDimitry Andric /// Initializes a field. 622a7dea167SDimitry Andric void initialize() const; 623a7dea167SDimitry Andric /// Activats a field. 624a7dea167SDimitry Andric void activate() const; 625a7dea167SDimitry Andric /// Deactivates an entire strurcutre. 626a7dea167SDimitry Andric void deactivate() const; 627a7dea167SDimitry Andric 6285f757f3fSDimitry Andric /// Compare two pointers. 6295f757f3fSDimitry Andric ComparisonCategoryResult compare(const Pointer &Other) const { 6305f757f3fSDimitry Andric if (!hasSameBase(*this, Other)) 6315f757f3fSDimitry Andric return ComparisonCategoryResult::Unordered; 6325f757f3fSDimitry Andric 6335f757f3fSDimitry Andric if (Offset < Other.Offset) 6345f757f3fSDimitry Andric return ComparisonCategoryResult::Less; 6355f757f3fSDimitry Andric else if (Offset > Other.Offset) 6365f757f3fSDimitry Andric return ComparisonCategoryResult::Greater; 6375f757f3fSDimitry Andric 6385f757f3fSDimitry Andric return ComparisonCategoryResult::Equal; 6395f757f3fSDimitry Andric } 6405f757f3fSDimitry Andric 641a7dea167SDimitry Andric /// Checks if two pointers are comparable. 642a7dea167SDimitry Andric static bool hasSameBase(const Pointer &A, const Pointer &B); 643a7dea167SDimitry Andric /// Checks if two pointers can be subtracted. 644a7dea167SDimitry Andric static bool hasSameArray(const Pointer &A, const Pointer &B); 645a7dea167SDimitry Andric 646a7dea167SDimitry Andric /// Prints the pointer. 647*0fca6ea1SDimitry Andric void print(llvm::raw_ostream &OS) const; 648a7dea167SDimitry Andric 649a7dea167SDimitry Andric private: 650a7dea167SDimitry Andric friend class Block; 651a7dea167SDimitry Andric friend class DeadBlock; 652*0fca6ea1SDimitry Andric friend class MemberPointer; 653*0fca6ea1SDimitry Andric friend class InterpState; 6545f757f3fSDimitry Andric friend struct InitMap; 655*0fca6ea1SDimitry Andric friend class DynamicAllocator; 656a7dea167SDimitry Andric 657*0fca6ea1SDimitry Andric Pointer(Block *Pointee, unsigned Base, uint64_t Offset); 658a7dea167SDimitry Andric 659a7dea167SDimitry Andric /// Returns the embedded descriptor preceding a field. 660*0fca6ea1SDimitry Andric InlineDescriptor *getInlineDesc() const { 661*0fca6ea1SDimitry Andric assert(asBlockPointer().Base != sizeof(GlobalInlineDescriptor)); 662*0fca6ea1SDimitry Andric assert(asBlockPointer().Base <= asBlockPointer().Pointee->getSize()); 663*0fca6ea1SDimitry Andric return getDescriptor(asBlockPointer().Base); 664*0fca6ea1SDimitry Andric } 665a7dea167SDimitry Andric 666a7dea167SDimitry Andric /// Returns a descriptor at a given offset. 667a7dea167SDimitry Andric InlineDescriptor *getDescriptor(unsigned Offset) const { 668a7dea167SDimitry Andric assert(Offset != 0 && "Not a nested pointer"); 669*0fca6ea1SDimitry Andric assert(isBlockPointer()); 670*0fca6ea1SDimitry Andric assert(!isZero()); 671*0fca6ea1SDimitry Andric return reinterpret_cast<InlineDescriptor *>( 672*0fca6ea1SDimitry Andric asBlockPointer().Pointee->rawData() + Offset) - 673bdd1243dSDimitry Andric 1; 674a7dea167SDimitry Andric } 675a7dea167SDimitry Andric 6765f757f3fSDimitry Andric /// Returns a reference to the InitMapPtr which stores the initialization map. 6775f757f3fSDimitry Andric InitMapPtr &getInitMap() const { 678*0fca6ea1SDimitry Andric assert(isBlockPointer()); 679*0fca6ea1SDimitry Andric assert(!isZero()); 680*0fca6ea1SDimitry Andric return *reinterpret_cast<InitMapPtr *>(asBlockPointer().Pointee->rawData() + 681*0fca6ea1SDimitry Andric asBlockPointer().Base); 682a7dea167SDimitry Andric } 683a7dea167SDimitry Andric 684*0fca6ea1SDimitry Andric /// Offset into the storage. 685*0fca6ea1SDimitry Andric uint64_t Offset = 0; 686a7dea167SDimitry Andric 687a7dea167SDimitry Andric /// Previous link in the pointer chain. 688a7dea167SDimitry Andric Pointer *Prev = nullptr; 689a7dea167SDimitry Andric /// Next link in the pointer chain. 690a7dea167SDimitry Andric Pointer *Next = nullptr; 691*0fca6ea1SDimitry Andric 692*0fca6ea1SDimitry Andric union { 693*0fca6ea1SDimitry Andric BlockPointer BS; 694*0fca6ea1SDimitry Andric IntPointer Int; 695*0fca6ea1SDimitry Andric } PointeeStorage; 696*0fca6ea1SDimitry Andric Storage StorageKind = Storage::Int; 697a7dea167SDimitry Andric }; 698a7dea167SDimitry Andric 699a7dea167SDimitry Andric inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Pointer &P) { 700a7dea167SDimitry Andric P.print(OS); 701a7dea167SDimitry Andric return OS; 702a7dea167SDimitry Andric } 703a7dea167SDimitry Andric 704a7dea167SDimitry Andric } // namespace interp 705a7dea167SDimitry Andric } // namespace clang 706a7dea167SDimitry Andric 707a7dea167SDimitry Andric #endif 708