Skip to content

Commit df2a1f2

Browse files
committed
Add profiling support for APValues.
For C++20 P0732R2; unused so far. Will be used and tested by a follow-on commit.
1 parent 9dcd96f commit df2a1f2

File tree

2 files changed

+163
-0
lines changed

2 files changed

+163
-0
lines changed

clang/include/clang/AST/APValue.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "llvm/ADT/APSInt.h"
2020
#include "llvm/ADT/PointerIntPair.h"
2121
#include "llvm/ADT/PointerUnion.h"
22+
#include "llvm/ADT/FoldingSet.h"
2223

2324
namespace clang {
2425
class AddrLabelExpr;
@@ -149,6 +150,8 @@ class APValue {
149150
static LValueBase getDynamicAlloc(DynamicAllocLValue LV, QualType Type);
150151
static LValueBase getTypeInfo(TypeInfoLValue LV, QualType TypeInfo);
151152

153+
void profile(llvm::FoldingSetNodeID &ID) const;
154+
152155
template <class T>
153156
bool is() const { return Ptr.is<T>(); }
154157

@@ -215,6 +218,8 @@ class APValue {
215218
}
216219
uint64_t getAsArrayIndex() const { return Value; }
217220

221+
void profile(llvm::FoldingSetNodeID &ID) const;
222+
218223
friend bool operator==(LValuePathEntry A, LValuePathEntry B) {
219224
return A.Value == B.Value;
220225
}
@@ -357,6 +362,11 @@ class APValue {
357362
/// Swaps the contents of this and the given APValue.
358363
void swap(APValue &RHS);
359364

365+
/// Profile this value. There is no guarantee that values of different
366+
/// types will not produce the same profiled value, so the type should
367+
/// typically also be profiled if it's not implied by the context.
368+
void profile(llvm::FoldingSetNodeID &ID) const;
369+
360370
ValueKind getKind() const { return Kind; }
361371

362372
bool isAbsent() const { return Kind == None; }

clang/lib/AST/APValue.cpp

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,14 @@ QualType APValue::LValueBase::getDynamicAllocType() const {
7777
return QualType::getFromOpaquePtr(DynamicAllocType);
7878
}
7979

80+
void APValue::LValueBase::profile(llvm::FoldingSetNodeID &ID) const {
81+
ID.AddPointer(Ptr.getOpaqueValue());
82+
if (is<TypeInfoLValue>() || is<DynamicAllocLValue>())
83+
return;
84+
ID.AddInteger(Local.CallIndex);
85+
ID.AddInteger(Local.Version);
86+
}
87+
8088
namespace clang {
8189
bool operator==(const APValue::LValueBase &LHS,
8290
const APValue::LValueBase &RHS) {
@@ -95,6 +103,10 @@ APValue::LValuePathEntry::LValuePathEntry(BaseOrMemberType BaseOrMember) {
95103
Value = reinterpret_cast<uintptr_t>(BaseOrMember.getOpaqueValue());
96104
}
97105

106+
void APValue::LValuePathEntry::profile(llvm::FoldingSetNodeID &ID) const {
107+
ID.AddInteger(Value);
108+
}
109+
98110
namespace {
99111
struct LVBase {
100112
APValue::LValueBase Base;
@@ -402,6 +414,147 @@ void APValue::swap(APValue &RHS) {
402414
std::swap(Data, RHS.Data);
403415
}
404416

417+
void APValue::profile(llvm::FoldingSetNodeID &ID) const {
418+
ID.AddInteger(Kind);
419+
420+
switch (Kind) {
421+
case None:
422+
case Indeterminate:
423+
return;
424+
425+
case AddrLabelDiff:
426+
ID.AddPointer(getAddrLabelDiffLHS()->getLabel()->getCanonicalDecl());
427+
ID.AddPointer(getAddrLabelDiffRHS()->getLabel()->getCanonicalDecl());
428+
return;
429+
430+
case Struct:
431+
ID.AddInteger(getStructNumBases());
432+
for (unsigned I = 0, N = getStructNumBases(); I != N; ++I)
433+
getStructBase(I).profile(ID);
434+
ID.AddInteger(getStructNumFields());
435+
for (unsigned I = 0, N = getStructNumFields(); I != N; ++I)
436+
getStructField(I).profile(ID);
437+
return;
438+
439+
case Union:
440+
if (!getUnionField()) {
441+
ID.AddPointer(nullptr);
442+
return;
443+
}
444+
ID.AddPointer(getUnionField()->getCanonicalDecl());
445+
getUnionValue().profile(ID);
446+
return;
447+
448+
case Array: {
449+
ID.AddInteger(getArraySize());
450+
if (getArraySize() == 0)
451+
return;
452+
453+
// The profile should not depend on whether the array is expanded or
454+
// not, but we don't want to profile the array filler many times for
455+
// a large array. So treat all equal trailing elements as the filler.
456+
// Elements are profiled in reverse order to support this, and the
457+
// first profiled element is followed by a count. For example:
458+
//
459+
// ['a', 'c', 'x', 'x', 'x'] is profiled as
460+
// [5, 'x', 3, 'c', 'a']
461+
llvm::FoldingSetNodeID FillerID;
462+
(hasArrayFiller() ? getArrayFiller() :
463+
getArrayInitializedElt(getArrayInitializedElts() -
464+
1)).profile(FillerID);
465+
ID.AddNodeID(FillerID);
466+
unsigned NumFillers = getArraySize() - getArrayInitializedElts();
467+
unsigned N = getArrayInitializedElts();
468+
469+
// Count the number of elements equal to the last one. This loop ends
470+
// by adding an integer indicating the number of such elements, with
471+
// N set to the number of elements left to profile.
472+
while (true) {
473+
if (N == 0) {
474+
// All elements are fillers.
475+
assert(NumFillers == getArraySize());
476+
ID.AddInteger(NumFillers);
477+
break;
478+
}
479+
480+
// No need to check if the last element is equal to the last
481+
// element.
482+
if (N != getArraySize()) {
483+
llvm::FoldingSetNodeID ElemID;
484+
getArrayInitializedElt(N - 1).profile(ElemID);
485+
if (ElemID != FillerID) {
486+
ID.AddInteger(NumFillers);
487+
ID.AddNodeID(ElemID);
488+
--N;
489+
break;
490+
}
491+
}
492+
493+
// This is a filler.
494+
++NumFillers;
495+
--N;
496+
}
497+
498+
// Emit the remaining elements.
499+
for (; N != 0; --N)
500+
getArrayInitializedElt(N - 1).profile(ID);
501+
return;
502+
}
503+
504+
case Vector:
505+
ID.AddInteger(getVectorLength());
506+
for (unsigned I = 0, N = getVectorLength(); I != N; ++I)
507+
getVectorElt(I).profile(ID);
508+
return;
509+
510+
case Int:
511+
// We don't need to include the sign bit; it's implied by the type.
512+
getInt().APInt::Profile(ID);
513+
return;
514+
515+
case Float:
516+
getFloat().Profile(ID);
517+
return;
518+
519+
case FixedPoint:
520+
// We don't need to include the fixed-point semantics; they're
521+
// implied by the type.
522+
getFixedPoint().getValue().APInt::Profile(ID);
523+
return;
524+
525+
case ComplexFloat:
526+
getComplexFloatReal().Profile(ID);
527+
getComplexFloatImag().Profile(ID);
528+
return;
529+
530+
case ComplexInt:
531+
getComplexIntReal().APInt::Profile(ID);
532+
getComplexIntImag().APInt::Profile(ID);
533+
return;
534+
535+
case LValue:
536+
getLValueBase().profile(ID);
537+
ID.AddInteger(getLValueOffset().getQuantity());
538+
ID.AddInteger(isNullPointer());
539+
ID.AddInteger(isLValueOnePastTheEnd());
540+
// For uniqueness, we only need to profile the entries corresponding
541+
// to union members, but we don't have the type here so we don't know
542+
// how to interpret the entries.
543+
for (LValuePathEntry E : getLValuePath())
544+
E.profile(ID);
545+
return;
546+
547+
case MemberPointer:
548+
ID.AddPointer(getMemberPointerDecl());
549+
ID.AddInteger(isMemberPointerToDerivedMember());
550+
for (const CXXRecordDecl *D : getMemberPointerPath())
551+
ID.AddPointer(D);
552+
return;
553+
}
554+
555+
llvm_unreachable("Unknown APValue kind!");
556+
}
557+
405558
static double GetApproxValue(const llvm::APFloat &F) {
406559
llvm::APFloat V = F;
407560
bool ignored;

0 commit comments

Comments
 (0)