[clang] [clang][bytecode] Add `PtrView` for non-tracking pointers (PR #184129)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Mar 2 06:10:22 PST 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Timm Baeder (tbaederr)
<details>
<summary>Changes</summary>
Currently, when creating a `Pointer` (of block type, which I will assume here), the pointer will add itself (via its address) to its block's pointer list. This way, a block always knows what pointers point to it. That's important so we can handle the case when a block (which was e.g. created for a local variable) is destroyed and we now need to update its pointers.
However, since always do this for all `Pointer` instances, it creates a weird performance problem where we do this dance all the time for no reason, e.g. consider `Pointer::stripBaseCasts()`:
https://github.com/llvm/llvm-project/blob/88693c49d9ac58a33af5978d31f6c70fe1d5b45b/clang/lib/AST/ByteCode/Pointer.h#L778-L783
This will add and remove the newly created pointer from the block's pointer list every iteration. Other offenders are `Pointer::toRValue()`, `EvaluationResult::checkFullyInitialized()` or `Pointer::computeOffsetForComparison()`.
This commit introduces a `PtrView` struct, which is like a `BlockPointer`, but without the prev/next next links to other `Pointer`s in the block's pointer list. It also moves a lot of the accessors from `Pointer` to `PtrView` (e.g. `isRoot()` or `getFieldDesc()`, etc.).
This PR is mostly a draft but I'm looking for opinions on the approach. The downside of this is that all the accessors in `PtrView` are also duplicated in `Pointer`, since the two aren't related. I was also trying to keep both as simple as possible, i.e. without introducing any base classes or using CRTP.
compile-time-tracker: https://llvm-compile-time-tracker.com/compare.php?from=4716dc8c51719cbcc82928cd00e41a29e5b9adff&to=28d69d4ec16e77370938675826b07752e108eede&stat=instructions:u
---
Patch is 33.01 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/184129.diff
4 Files Affected:
- (modified) clang/lib/AST/ByteCode/EvaluationResult.cpp (+20-20)
- (modified) clang/lib/AST/ByteCode/Interp.h (+1-1)
- (modified) clang/lib/AST/ByteCode/Pointer.cpp (+48-38)
- (modified) clang/lib/AST/ByteCode/Pointer.h (+276-108)
``````````diff
diff --git a/clang/lib/AST/ByteCode/EvaluationResult.cpp b/clang/lib/AST/ByteCode/EvaluationResult.cpp
index 039848f00764e..d548d3e613912 100644
--- a/clang/lib/AST/ByteCode/EvaluationResult.cpp
+++ b/clang/lib/AST/ByteCode/EvaluationResult.cpp
@@ -27,10 +27,10 @@ static void DiagnoseUninitializedSubobject(InterpState &S, SourceLocation Loc,
}
static bool CheckFieldsInitialized(InterpState &S, SourceLocation Loc,
- const Pointer &BasePtr, const Record *R);
+ PtrView BasePtr, const Record *R);
static bool CheckArrayInitialized(InterpState &S, SourceLocation Loc,
- const Pointer &BasePtr,
+ PtrView BasePtr,
const ConstantArrayType *CAT) {
size_t NumElems = CAT->getZExtSize();
@@ -43,12 +43,12 @@ static bool CheckArrayInitialized(InterpState &S, SourceLocation Loc,
if (ElemType->isRecordType()) {
const Record *R = BasePtr.getElemRecord();
for (size_t I = 0; I != NumElems; ++I) {
- Pointer ElemPtr = BasePtr.atIndex(I).narrow();
+ PtrView ElemPtr = BasePtr.atIndex(I);
Result &= CheckFieldsInitialized(S, Loc, ElemPtr, R);
}
} else if (const auto *ElemCAT = dyn_cast<ConstantArrayType>(ElemType)) {
for (size_t I = 0; I != NumElems; ++I) {
- Pointer ElemPtr = BasePtr.atIndex(I).narrow();
+ PtrView ElemPtr = BasePtr.atIndex(I);
Result &= CheckArrayInitialized(S, Loc, ElemPtr, ElemCAT);
}
} else {
@@ -74,12 +74,12 @@ static bool CheckArrayInitialized(InterpState &S, SourceLocation Loc,
}
static bool CheckFieldsInitialized(InterpState &S, SourceLocation Loc,
- const Pointer &BasePtr, const Record *R) {
+ PtrView BasePtr, const Record *R) {
assert(R);
bool Result = true;
// Check all fields of this record are initialized.
for (const Record::Field &F : R->fields()) {
- Pointer FieldPtr = BasePtr.atField(F.Offset);
+ PtrView FieldPtr = BasePtr.atField(F.Offset);
QualType FieldType = F.Decl->getType();
// Don't check inactive union members.
@@ -104,7 +104,7 @@ static bool CheckFieldsInitialized(InterpState &S, SourceLocation Loc,
// Check Fields in all bases
for (auto [I, B] : llvm::enumerate(R->bases())) {
- Pointer P = BasePtr.atField(B.Offset);
+ PtrView P = BasePtr.atField(B.Offset);
if (!P.isInitialized()) {
const Descriptor *Desc = BasePtr.getDeclDesc();
if (const auto *CD = dyn_cast_if_present<CXXRecordDecl>(R->getDecl())) {
@@ -122,7 +122,6 @@ static bool CheckFieldsInitialized(InterpState &S, SourceLocation Loc,
}
// TODO: Virtual bases
-
return Result;
}
@@ -148,11 +147,11 @@ bool EvaluationResult::checkFullyInitialized(InterpState &S,
InitLoc = E->getExprLoc();
if (const Record *R = Ptr.getRecord())
- return CheckFieldsInitialized(S, InitLoc, Ptr, R);
+ return CheckFieldsInitialized(S, InitLoc, Ptr.view(), R);
if (const auto *CAT = dyn_cast_if_present<ConstantArrayType>(
Ptr.getType()->getAsArrayTypeUnsafe()))
- return CheckArrayInitialized(S, InitLoc, Ptr, CAT);
+ return CheckArrayInitialized(S, InitLoc, Ptr.view(), CAT);
return true;
}
@@ -166,17 +165,16 @@ static bool isOrHasPtr(const Descriptor *D) {
return false;
}
-static void collectBlocks(const Pointer &Ptr,
- llvm::SetVector<const Block *> &Blocks) {
+static void collectBlocks(PtrView Ptr, llvm::SetVector<const Block *> &Blocks) {
auto isUsefulPtr = [](const Pointer &P) -> bool {
return P.isLive() && P.isBlockPointer() && !P.isZero() && !P.isDummy() &&
P.isDereferencable() && !P.isUnknownSizeArray() && !P.isOnePastEnd();
};
- if (!isUsefulPtr(Ptr))
+ if (!isUsefulPtr(Pointer(Ptr)))
return;
- Blocks.insert(Ptr.block());
+ Blocks.insert(Ptr.Pointee);
const Descriptor *Desc = Ptr.getFieldDesc();
if (!Desc)
@@ -187,24 +185,24 @@ static void collectBlocks(const Pointer &Ptr,
for (const Record::Field &F : R->fields()) {
if (!isOrHasPtr(F.Desc))
continue;
- Pointer FieldPtr = Ptr.atField(F.Offset);
- assert(FieldPtr.block() == Ptr.block());
+ PtrView FieldPtr = Ptr.atField(F.Offset);
+ // assert(FieldPtr.block() == Ptr.block());
collectBlocks(FieldPtr, Blocks);
}
} else if (Desc->isPrimitive() && Desc->getPrimType() == PT_Ptr) {
Pointer Pointee = Ptr.deref<Pointer>();
if (isUsefulPtr(Pointee) && !Blocks.contains(Pointee.block()))
- collectBlocks(Pointee, Blocks);
+ collectBlocks(Pointee.view(), Blocks);
} else if (Desc->isPrimitiveArray() && Desc->getPrimType() == PT_Ptr) {
for (unsigned I = 0; I != Desc->getNumElems(); ++I) {
Pointer ElemPointee = Ptr.elem<Pointer>(I);
if (isUsefulPtr(ElemPointee) && !Blocks.contains(ElemPointee.block()))
- collectBlocks(ElemPointee, Blocks);
+ collectBlocks(ElemPointee.view(), Blocks);
}
} else if (Desc->isCompositeArray() && isOrHasPtr(Desc->ElemDesc)) {
for (unsigned I = 0; I != Desc->getNumElems(); ++I) {
- Pointer ElemPtr = Ptr.atIndex(I).narrow();
+ PtrView ElemPtr = Ptr.atIndex(I);
collectBlocks(ElemPtr, Blocks);
}
}
@@ -213,11 +211,13 @@ static void collectBlocks(const Pointer &Ptr,
bool EvaluationResult::checkReturnValue(InterpState &S, const Context &Ctx,
const Pointer &Ptr,
const SourceInfo &Info) {
+ if (!Ptr.isBlockPointer())
+ return true;
// Collect all blocks that this pointer (transitively) points to and
// return false if any of them is a dynamic block.
llvm::SetVector<const Block *> Blocks;
- collectBlocks(Ptr, Blocks);
+ collectBlocks(Ptr.view(), Blocks);
for (const Block *B : Blocks) {
if (B->isDynamic()) {
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index 7f30def20cc36..f3187ba29b08b 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -1083,7 +1083,7 @@ inline bool CmpHelper<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
}
// Diagnose comparisons between fields with different access specifiers.
- if (std::optional<std::pair<Pointer, Pointer>> Split =
+ if (std::optional<std::pair<PtrView, PtrView>> Split =
Pointer::computeSplitPoint(LHS, RHS)) {
const FieldDecl *LF = Split->first.getField();
const FieldDecl *RF = Split->second.getField();
diff --git a/clang/lib/AST/ByteCode/Pointer.cpp b/clang/lib/AST/ByteCode/Pointer.cpp
index e237013f4199c..a3a754dc2a5d0 100644
--- a/clang/lib/AST/ByteCode/Pointer.cpp
+++ b/clang/lib/AST/ByteCode/Pointer.cpp
@@ -237,7 +237,8 @@ APValue Pointer::toAPValue(const ASTContext &ASTCtx) const {
// Build the path into the object.
bool OnePastEnd = isOnePastEnd() && !isZeroSizeArray();
- Pointer Ptr = *this;
+ // Pointer Ptr = *this;
+ PtrView Ptr = view();
while (Ptr.isField() || Ptr.isArrayElement()) {
if (Ptr.isArrayRoot()) {
@@ -382,7 +383,7 @@ size_t Pointer::computeOffsetForComparison(const ASTContext &ASTCtx) const {
}
size_t Result = 0;
- Pointer P = *this;
+ PtrView P = view();
while (true) {
if (P.isVirtualBaseClass()) {
Result += getInlineDesc()->Offset;
@@ -470,15 +471,18 @@ bool Pointer::isElementInitialized(unsigned Index) const {
if (!isBlockPointer())
return true;
+ return view().isElementInitialized(Index);
+}
+
+bool PtrView::isElementInitialized(unsigned Index) const {
const Descriptor *Desc = getFieldDesc();
assert(Desc);
- if (isStatic() && BS.Base == 0)
+ if (Pointee->isStatic() && Base == 0)
return true;
- if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) &&
- Offset == BS.Base) {
- const auto &GD = block()->getBlockDesc<GlobalInlineDescriptor>();
+ if (isRoot() && Base == sizeof(GlobalInlineDescriptor) && Offset == Base) {
+ const auto &GD = Pointee->getBlockDesc<GlobalInlineDescriptor>();
return GD.InitState == GlobalInitState::Initialized;
}
@@ -602,16 +606,15 @@ void Pointer::initializeAllElements() const {
getInitMap().noteAllInitialized();
}
-bool Pointer::allElementsInitialized() const {
+bool PtrView::allElementsInitialized() const {
assert(getFieldDesc()->isPrimitiveArray());
- assert(isArrayRoot());
+ // assert(isArrayRoot());
- if (isStatic() && BS.Base == 0)
+ if (Pointee->isStatic() && Base == 0)
return true;
- if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) &&
- Offset == BS.Base) {
- const auto &GD = block()->getBlockDesc<GlobalInlineDescriptor>();
+ if (isRoot() && Base == sizeof(GlobalInlineDescriptor) && Offset == Base) {
+ const auto &GD = Pointee->getBlockDesc<GlobalInlineDescriptor>();
return GD.InitState == GlobalInitState::Initialized;
}
@@ -619,6 +622,13 @@ bool Pointer::allElementsInitialized() const {
return IM.allInitialized();
}
+bool Pointer::allElementsInitialized() const {
+ assert(getFieldDesc()->isPrimitiveArray());
+ assert(isArrayRoot());
+
+ return view().allElementsInitialized();
+}
+
bool Pointer::allElementsAlive() const {
assert(getFieldDesc()->isPrimitiveArray());
assert(isArrayRoot());
@@ -645,12 +655,12 @@ void Pointer::activate() const {
if (!getInlineDesc()->InUnion)
return;
- std::function<void(Pointer &)> activate;
- activate = [&activate](Pointer &P) -> void {
+ std::function<void(PtrView P)> activate;
+ activate = [&activate](PtrView P) -> void {
P.getInlineDesc()->IsActive = true;
if (const Record *R = P.getRecord(); R && !R->isUnion()) {
for (const Record::Field &F : R->fields()) {
- Pointer FieldPtr = P.atField(F.Offset);
+ PtrView FieldPtr = P.atField(F.Offset);
if (!FieldPtr.getInlineDesc()->IsActive)
activate(FieldPtr);
}
@@ -658,13 +668,13 @@ void Pointer::activate() const {
}
};
- std::function<void(Pointer &)> deactivate;
- deactivate = [&deactivate](Pointer &P) -> void {
+ std::function<void(PtrView &)> deactivate;
+ deactivate = [&deactivate](PtrView &P) -> void {
P.getInlineDesc()->IsActive = false;
if (const Record *R = P.getRecord()) {
for (const Record::Field &F : R->fields()) {
- Pointer FieldPtr = P.atField(F.Offset);
+ PtrView FieldPtr = P.atField(F.Offset);
if (FieldPtr.getInlineDesc()->IsActive)
deactivate(FieldPtr);
}
@@ -672,17 +682,17 @@ void Pointer::activate() const {
}
};
- Pointer B = *this;
+ PtrView B = view(); //*this;
while (!B.isRoot() && B.inUnion()) {
activate(B);
// When walking up the pointer chain, deactivate
// all union child pointers that aren't on our path.
- Pointer Cur = B;
+ PtrView Cur = B;
B = B.getBase();
if (const Record *BR = B.getRecord(); BR && BR->isUnion()) {
for (const Record::Field &F : BR->fields()) {
- Pointer FieldPtr = B.atField(F.Offset);
+ PtrView FieldPtr = B.atField(F.Offset);
if (FieldPtr != Cur)
deactivate(FieldPtr);
}
@@ -745,7 +755,7 @@ bool Pointer::pointsToStringLiteral() const {
return isa_and_nonnull<StringLiteral>(E);
}
-std::optional<std::pair<Pointer, Pointer>>
+std::optional<std::pair<PtrView, PtrView>>
Pointer::computeSplitPoint(const Pointer &A, const Pointer &B) {
if (!A.isBlockPointer() || !B.isBlockPointer())
return std::nullopt;
@@ -756,20 +766,20 @@ Pointer::computeSplitPoint(const Pointer &A, const Pointer &B) {
return std::nullopt;
if (A == B)
- return std::make_pair(A, B);
+ return std::make_pair(A.view(), B.view());
- auto getBase = [](const Pointer &P) -> Pointer {
+ auto getBase = [](PtrView P) -> PtrView {
if (P.isArrayElement())
return P.expand().getArray();
return P.getBase();
};
- Pointer IterA = A;
- Pointer IterB = B;
- Pointer CurA = IterA;
- Pointer CurB = IterB;
+ PtrView IterA = A.view();
+ PtrView IterB = B.view();
+ PtrView CurA = IterA;
+ PtrView CurB = IterB;
for (;;) {
- if (IterA.asBlockPointer().Base > IterB.asBlockPointer().Base) {
+ if (IterA.Base > IterB.Base) {
CurA = IterA;
IterA = getBase(IterA);
} else {
@@ -792,14 +802,14 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx,
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,
+ std::function<bool(QualType, PtrView, APValue &)> Composite;
+ Composite = [&Composite, &Ctx, &ASTCtx](QualType Ty, PtrView Ptr,
APValue &R) {
if (const auto *AT = Ty->getAs<AtomicType>())
Ty = AT->getValueType();
// Invalid pointers.
- if (Ptr.isDummy() || !Ptr.isLive() || !Ptr.isBlockPointer() ||
+ if (Ptr.isDummy() || !Ptr.isLive() || //! Ptr.isBlockPointer() ||
Ptr.isPastEnd())
return false;
@@ -818,7 +828,7 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx,
const FieldDecl *ActiveField = nullptr;
APValue Value;
for (const auto &F : Record->fields()) {
- const Pointer &FP = Ptr.atField(F.Offset);
+ PtrView FP = Ptr.atField(F.Offset);
QualType FieldTy = F.Decl->getType();
if (FP.isActive()) {
if (OptPrimType T = Ctx.classify(FieldTy)) {
@@ -841,7 +851,7 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx,
for (unsigned I = 0; I < NF; ++I) {
const Record::Field *FD = Record->getField(I);
QualType FieldTy = FD->Decl->getType();
- const Pointer &FP = Ptr.atField(FD->Offset);
+ PtrView FP = Ptr.atField(FD->Offset);
APValue &Value = R.getStructField(I);
if (OptPrimType T = Ctx.classify(FieldTy)) {
@@ -854,7 +864,7 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx,
for (unsigned I = 0; I < NB; ++I) {
const Record::Base *BD = Record->getBase(I);
QualType BaseTy = Ctx.getASTContext().getCanonicalTagType(BD->Decl);
- const Pointer &BP = Ptr.atField(BD->Offset);
+ PtrView BP = Ptr.atField(BD->Offset);
Ok &= Composite(BaseTy, BP, R.getStructBase(I));
}
@@ -862,7 +872,7 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx,
const Record::Base *VD = Record->getVirtualBase(I);
QualType VirtBaseTy =
Ctx.getASTContext().getCanonicalTagType(VD->Decl);
- const Pointer &VP = Ptr.atField(VD->Offset);
+ PtrView VP = Ptr.atField(VD->Offset);
Ok &= Composite(VirtBaseTy, VP, R.getStructBase(NB + I));
}
}
@@ -886,7 +896,7 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx,
if (ElemT) {
TYPE_SWITCH(*ElemT, Slot = Ptr.elem<T>(I).toAPValue(ASTCtx));
} else {
- Ok &= Composite(ElemTy, Ptr.atIndex(I).narrow(), Slot);
+ Ok &= Composite(ElemTy, Ptr.atIndex(I), Slot);
}
}
return Ok;
@@ -958,7 +968,7 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx,
// Return the composite type.
APValue Result;
- if (!Composite(ResultType, *this, Result))
+ if (!Composite(ResultType, view(), Result))
return std::nullopt;
return Result;
}
diff --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h
index 010e917de81b2..2235c0c0594b1 100644
--- a/clang/lib/AST/ByteCode/Pointer.h
+++ b/clang/lib/AST/ByteCode/Pointer.h
@@ -33,6 +33,244 @@ class Context;
class Pointer;
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Pointer &P);
+struct PtrView {
+ Block *Pointee; // XXX const?
+ unsigned Base;
+ uint64_t Offset;
+
+ bool isRoot() const {
+ return Base == Pointee->getDescriptor()->getMetadataSize();
+ }
+
+ InlineDescriptor *getInlineDesc() const {
+ assert(Base != sizeof(GlobalInlineDescriptor));
+ assert(Base <= Pointee->getSize());
+ assert(Base >= sizeof(InlineDescriptor));
+ return getDescriptor(Base);
+ }
+
+ InlineDescriptor *getDescriptor(unsigned Offset) const {
+ assert(Offset != 0 && "Not a nested pointer");
+ return reinterpret_cast<InlineDescriptor *>(Pointee->rawData() + Offset) -
+ 1;
+ }
+
+ const Descriptor *getFieldDesc() const {
+ if (isRoot())
+ return Pointee->getDescriptor();
+ return getInlineDesc()->Desc;
+ }
+ const Descriptor *getDeclDesc() const { return Pointee->getDescriptor(); }
+
+ size_t elemSize() const { return getFieldDesc()->getElemSize(); }
+
+ bool isArrayRoot() const { return inArray() && Offset == Base; }
+
+ [[nodiscard]] PtrView expand() const {
+#if 0
+ if (isElementPastEnd()) {
+ // Revert to an outer one-past-end pointer.
+ unsigned Adjust;
+ if (inPrimitiveArray())
+ Adjust = sizeof(InitMapPtr);
+ else
+ Adjust = sizeof(InlineDescriptor);
+ return Pointer(Pointee, BS.Base, BS.Base + getSize() + Adjust);
+ }
+#endif
+
+ // Do not step out of array elements.
+ if (Base != Offset)
+ return *this;
+
+ if (isRoot())
+ return PtrView{Pointee, Base, Base};
+
+ // Step into the containing array, if inside one.
+ unsigned Next = Base - getInlineDesc()->Offset;
+ const Descriptor *Desc =
+ (Next == Pointee->getDescriptor()->getMetadataSize())
+ ? getDeclDesc()
+ : getDescriptor(Next)->Desc;
+ if (!Desc->IsArray)
+ return *this;
+ return PtrView{Pointee, Next, Offset};
+ }
+
+ [[nodiscard]] PtrView getArray() const {
+ // if (BS.Base == RootPtrMark) {
+ // assert(Offset != 0 && Offset != PastEndMark && "not an array element");
+ // return Pointer(BS.Pointee, BS.Base, 0);
+ // }
+ assert(Offset != Base && "not an array element");
+ return PtrView{Pointee, Base, Base};
+ }
+
+ const Record *getRecord() const { return getFieldDesc()->ElemRecord; }
+ const Record *getElemRecord() const {
+ const Descriptor *ElemDesc = getFieldDesc()->ElemDesc;
+ return ElemDesc ? ElemDesc->ElemRecord : nullptr;
+ }
+ const FieldDecl *getField() const { return getFieldDesc()->asFieldDecl(); }
+
+ bool isZero() const { return !Pointee; }
+
+ bool isField() const {
+ return !isZero() && !isRoot() && getFieldDesc()->asDecl();
+ }
+
+ bool isBaseClass() const { return isField() && getInlineDesc()->IsBase; }
+ bool isVirtualBaseClass() const {
+ return isField() && getInlineDesc()->IsVirtualBase;
+ }
+ bool isUnknownSizeArray() const {
+ return getFieldDesc()->isUnknownSizeArray();
+ }
+
+ bool isPastEnd() const { return Offset > Pointee->getSize(); }
+
+ unsigned getOffset() const {
+ // assert(Offset != PastEndMark && "invalid offset");
+ // assert(isBlockPointer());
+ // if (BS.Base == RootPtrMark)
+ // return Offset;
+
+ unsigned Adjust = 0;
+ if (Offset != Base) {
+ if (getFieldDesc()->ElemDesc)
+ Adjust = sizeof(InlineDescriptor);
+ else
+ Adjust = sizeof(InitMapPtr);
+ }
+ return Offset - Base - Adjust;
+ }
+ size_t getSize() const { return getFieldDesc()->getSize(); }
+
+ bool isOnePastEnd() const {
+ if (!Pointee)
+ return false;
+
+ if (isUnknownSizeArray())
+ return false;
+ return isPastEnd() || (getSize() == getOffset());
+ }
+
+ bool inUnion() const { return getInlineDesc()->InUnion; };
+
+ PtrView atIndex(unsigned Idx) const {
+ unsigned Off = Idx * elemSize();
+ if (getFieldDesc()->ElemDesc)
+ Off += sizeof(InlineDescriptor);
+ else
+ Off += sizeof(InitMapPtr);
+ return PtrView{Pointee, Base + Off, Base + Off};
+ }
+
+ int64_t getIndex() const {
+ // narrow()ed element in a composite array.
+ // if (BS.Base > sizeof(InlineDescriptor) && BS.Base == Offset)
+ // return 0;
+
+ if (auto ElemSize = elemSize())
+ return getOffset() / ElemSize;
+ return 0;
+ }
+
+ unsigned getNumElems() const { return getSize() / elemSize(); }
+
+ bool inArray() const { return getFieldDesc()->IsArray; }
+
+ bool isArrayElement() const {
+ if (inArray() && Base != Offset)
+ ...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/184129
More information about the cfe-commits
mailing list