Add profiling support for APValues.

For C++20 P0732R2; unused so far. Will be used and tested by a follow-on
commit.
This commit is contained in:
Richard Smith 2020-09-02 15:04:41 -07:00
parent 9dcd96f728
commit df2a1f2aab
2 changed files with 163 additions and 0 deletions

View File

@ -19,6 +19,7 @@
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/FoldingSet.h"
namespace clang {
class AddrLabelExpr;
@ -149,6 +150,8 @@ public:
static LValueBase getDynamicAlloc(DynamicAllocLValue LV, QualType Type);
static LValueBase getTypeInfo(TypeInfoLValue LV, QualType TypeInfo);
void profile(llvm::FoldingSetNodeID &ID) const;
template <class T>
bool is() const { return Ptr.is<T>(); }
@ -215,6 +218,8 @@ public:
}
uint64_t getAsArrayIndex() const { return Value; }
void profile(llvm::FoldingSetNodeID &ID) const;
friend bool operator==(LValuePathEntry A, LValuePathEntry B) {
return A.Value == B.Value;
}
@ -357,6 +362,11 @@ public:
/// Swaps the contents of this and the given APValue.
void swap(APValue &RHS);
/// Profile this value. There is no guarantee that values of different
/// types will not produce the same profiled value, so the type should
/// typically also be profiled if it's not implied by the context.
void profile(llvm::FoldingSetNodeID &ID) const;
ValueKind getKind() const { return Kind; }
bool isAbsent() const { return Kind == None; }

View File

@ -77,6 +77,14 @@ QualType APValue::LValueBase::getDynamicAllocType() const {
return QualType::getFromOpaquePtr(DynamicAllocType);
}
void APValue::LValueBase::profile(llvm::FoldingSetNodeID &ID) const {
ID.AddPointer(Ptr.getOpaqueValue());
if (is<TypeInfoLValue>() || is<DynamicAllocLValue>())
return;
ID.AddInteger(Local.CallIndex);
ID.AddInteger(Local.Version);
}
namespace clang {
bool operator==(const APValue::LValueBase &LHS,
const APValue::LValueBase &RHS) {
@ -95,6 +103,10 @@ APValue::LValuePathEntry::LValuePathEntry(BaseOrMemberType BaseOrMember) {
Value = reinterpret_cast<uintptr_t>(BaseOrMember.getOpaqueValue());
}
void APValue::LValuePathEntry::profile(llvm::FoldingSetNodeID &ID) const {
ID.AddInteger(Value);
}
namespace {
struct LVBase {
APValue::LValueBase Base;
@ -402,6 +414,147 @@ void APValue::swap(APValue &RHS) {
std::swap(Data, RHS.Data);
}
void APValue::profile(llvm::FoldingSetNodeID &ID) const {
ID.AddInteger(Kind);
switch (Kind) {
case None:
case Indeterminate:
return;
case AddrLabelDiff:
ID.AddPointer(getAddrLabelDiffLHS()->getLabel()->getCanonicalDecl());
ID.AddPointer(getAddrLabelDiffRHS()->getLabel()->getCanonicalDecl());
return;
case Struct:
ID.AddInteger(getStructNumBases());
for (unsigned I = 0, N = getStructNumBases(); I != N; ++I)
getStructBase(I).profile(ID);
ID.AddInteger(getStructNumFields());
for (unsigned I = 0, N = getStructNumFields(); I != N; ++I)
getStructField(I).profile(ID);
return;
case Union:
if (!getUnionField()) {
ID.AddPointer(nullptr);
return;
}
ID.AddPointer(getUnionField()->getCanonicalDecl());
getUnionValue().profile(ID);
return;
case Array: {
ID.AddInteger(getArraySize());
if (getArraySize() == 0)
return;
// The profile should not depend on whether the array is expanded or
// not, but we don't want to profile the array filler many times for
// a large array. So treat all equal trailing elements as the filler.
// Elements are profiled in reverse order to support this, and the
// first profiled element is followed by a count. For example:
//
// ['a', 'c', 'x', 'x', 'x'] is profiled as
// [5, 'x', 3, 'c', 'a']
llvm::FoldingSetNodeID FillerID;
(hasArrayFiller() ? getArrayFiller() :
getArrayInitializedElt(getArrayInitializedElts() -
1)).profile(FillerID);
ID.AddNodeID(FillerID);
unsigned NumFillers = getArraySize() - getArrayInitializedElts();
unsigned N = getArrayInitializedElts();
// Count the number of elements equal to the last one. This loop ends
// by adding an integer indicating the number of such elements, with
// N set to the number of elements left to profile.
while (true) {
if (N == 0) {
// All elements are fillers.
assert(NumFillers == getArraySize());
ID.AddInteger(NumFillers);
break;
}
// No need to check if the last element is equal to the last
// element.
if (N != getArraySize()) {
llvm::FoldingSetNodeID ElemID;
getArrayInitializedElt(N - 1).profile(ElemID);
if (ElemID != FillerID) {
ID.AddInteger(NumFillers);
ID.AddNodeID(ElemID);
--N;
break;
}
}
// This is a filler.
++NumFillers;
--N;
}
// Emit the remaining elements.
for (; N != 0; --N)
getArrayInitializedElt(N - 1).profile(ID);
return;
}
case Vector:
ID.AddInteger(getVectorLength());
for (unsigned I = 0, N = getVectorLength(); I != N; ++I)
getVectorElt(I).profile(ID);
return;
case Int:
// We don't need to include the sign bit; it's implied by the type.
getInt().APInt::Profile(ID);
return;
case Float:
getFloat().Profile(ID);
return;
case FixedPoint:
// We don't need to include the fixed-point semantics; they're
// implied by the type.
getFixedPoint().getValue().APInt::Profile(ID);
return;
case ComplexFloat:
getComplexFloatReal().Profile(ID);
getComplexFloatImag().Profile(ID);
return;
case ComplexInt:
getComplexIntReal().APInt::Profile(ID);
getComplexIntImag().APInt::Profile(ID);
return;
case LValue:
getLValueBase().profile(ID);
ID.AddInteger(getLValueOffset().getQuantity());
ID.AddInteger(isNullPointer());
ID.AddInteger(isLValueOnePastTheEnd());
// For uniqueness, we only need to profile the entries corresponding
// to union members, but we don't have the type here so we don't know
// how to interpret the entries.
for (LValuePathEntry E : getLValuePath())
E.profile(ID);
return;
case MemberPointer:
ID.AddPointer(getMemberPointerDecl());
ID.AddInteger(isMemberPointerToDerivedMember());
for (const CXXRecordDecl *D : getMemberPointerPath())
ID.AddPointer(D);
return;
}
llvm_unreachable("Unknown APValue kind!");
}
static double GetApproxValue(const llvm::APFloat &F) {
llvm::APFloat V = F;
bool ignored;