diff --git a/clang/include/clang/AST/APValue.h b/clang/include/clang/AST/APValue.h index 6307f8a92e5a..ac8ed0818af0 100644 --- a/clang/include/clang/AST/APValue.h +++ b/clang/include/clang/AST/APValue.h @@ -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 bool is() const { return Ptr.is(); } @@ -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; } diff --git a/clang/lib/AST/APValue.cpp b/clang/lib/AST/APValue.cpp index 32d3ff7ce1d0..7efd0caf3f1d 100644 --- a/clang/lib/AST/APValue.cpp +++ b/clang/lib/AST/APValue.cpp @@ -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() || is()) + 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(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;