2222#include < map>
2323
2424namespace llvm {
25+ class PGOContextualProfile ;
26+ class PGOCtxProfContext ;
27+
28+ namespace internal {
29+ // When we traverse the contextual profile, we typically want to visit contexts
30+ // pertaining to a specific function. To avoid traversing the whole tree, we
31+ // want to keep a per-function list - which will be in preorder - of that
32+ // function's contexts. This happens in PGOContextualProfile. For memory use
33+ // efficiency, we want to make PGOCtxProfContext an intrusive double-linked list
34+ // node. We need to handle the cases where PGOCtxProfContext nodes are moved and
35+ // deleted: in both cases, we need to update the index (==list). We can do that
36+ // directly from the node in the list, without knowing who the "parent" of the
37+ // list is. That makes the ADT ilist overkill here. Finally, IndexNode is meant
38+ // to be an implementation detail of PGOCtxProfContext, and the only reason it's
39+ // factored out is to avoid implementing move semantics for all its members.
40+ template <class T > class IndexNode {
41+ // This class' members are intentionally private - it's a convenience
42+ // implementation detail.
43+ friend class ::llvm::PGOCtxProfContext;
44+ friend class ::llvm::PGOContextualProfile;
45+
46+ T *Previous = nullptr ;
47+ T *Next = nullptr ;
48+
49+ ~IndexNode () {
50+ if (Next)
51+ Next->Previous = Previous;
52+ if (Previous)
53+ Previous->Next = Next;
54+ }
55+
56+ T *self () { return reinterpret_cast <T *>(this ); }
57+
58+ IndexNode (const IndexNode &Other) = delete ;
59+
60+ IndexNode (IndexNode &&Other) {
61+ // Copy the neighbor info
62+ Next = Other.Next ;
63+ Previous = Other.Previous ;
64+
65+ // Update the neighbors to point to this object
66+ if (Other.Next )
67+ Other.Next ->Previous = self ();
68+ if (Other.Previous )
69+ Other.Previous ->Next = self ();
70+
71+ // Make sure the dtor is a noop
72+ Other.Next = nullptr ;
73+ Other.Previous = nullptr ;
74+ }
75+ IndexNode () = default ;
76+ };
77+ } // namespace internal
78+
2579// / A node (context) in the loaded contextual profile, suitable for mutation
2680// / during IPO passes. We generally expect a fraction of counters and
2781// / callsites to be populated. We continue to model counters as vectors, but
2882// / callsites are modeled as a map of a map. The expectation is that, typically,
2983// / there is a small number of indirect targets (usually, 1 for direct calls);
3084// / but potentially a large number of callsites, and, as inlining progresses,
3185// / the callsite count of a caller will grow.
32- class PGOCtxProfContext final {
86+ class PGOCtxProfContext final : public internal::IndexNode<PGOCtxProfContext> {
3387public:
3488 using CallTargetMapTy = std::map<GlobalValue::GUID, PGOCtxProfContext>;
3589 using CallsiteMapTy = std::map<uint32_t , CallTargetMapTy>;
3690
3791private:
3892 friend class PGOCtxProfileReader ;
93+ friend class PGOContextualProfile ;
94+
3995 GlobalValue::GUID GUID = 0 ;
4096 SmallVector<uint64_t , 16 > Counters;
4197 CallsiteMapTy Callsites;
@@ -47,11 +103,15 @@ class PGOCtxProfContext final {
47103 getOrEmplace (uint32_t Index, GlobalValue::GUID G,
48104 SmallVectorImpl<uint64_t > &&Counters);
49105
106+ // Create a bogus context object, used for anchoring the index double linked
107+ // list - see IndexNode
108+ PGOCtxProfContext () = default ;
109+
50110public:
51111 PGOCtxProfContext (const PGOCtxProfContext &) = delete ;
52112 PGOCtxProfContext &operator =(const PGOCtxProfContext &) = delete ;
53113 PGOCtxProfContext (PGOCtxProfContext &&) = default ;
54- PGOCtxProfContext &operator =(PGOCtxProfContext &&) = default ;
114+ PGOCtxProfContext &operator =(PGOCtxProfContext &&) = delete ;
55115
56116 GlobalValue::GUID guid () const { return GUID; }
57117 const SmallVectorImpl<uint64_t > &counters () const { return Counters; }
0 commit comments