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+ 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+ IndexNode *Previous = nullptr ;
47+ IndexNode *Next = nullptr ;
48+
49+ ~IndexNode () {
50+ if (Next)
51+ Next->Previous = Previous;
52+ if (Previous)
53+ Previous->Next = Next;
54+ }
55+
56+ IndexNode (const IndexNode &Other) = delete ;
57+
58+ IndexNode (IndexNode &&Other) {
59+ // Copy the neighbor info
60+ Next = Other.Next ;
61+ Previous = Other.Previous ;
62+
63+ // Update the neighbors to point to this object
64+ if (Other.Next )
65+ Other.Next ->Previous = this ;
66+ if (Other.Previous )
67+ Other.Previous ->Next = this ;
68+
69+ // Make sure the dtor is a noop
70+ Other.Next = nullptr ;
71+ Other.Previous = nullptr ;
72+ }
73+ IndexNode () = default ;
74+ };
75+ } // namespace internal
76+
2577// / A node (context) in the loaded contextual profile, suitable for mutation
2678// / during IPO passes. We generally expect a fraction of counters and
2779// / callsites to be populated. We continue to model counters as vectors, but
2880// / callsites are modeled as a map of a map. The expectation is that, typically,
2981// / there is a small number of indirect targets (usually, 1 for direct calls);
3082// / but potentially a large number of callsites, and, as inlining progresses,
3183// / the callsite count of a caller will grow.
32- class PGOCtxProfContext final {
84+ class PGOCtxProfContext final : public internal::IndexNode {
3385public:
3486 using CallTargetMapTy = std::map<GlobalValue::GUID, PGOCtxProfContext>;
3587 using CallsiteMapTy = std::map<uint32_t , CallTargetMapTy>;
3688
3789private:
3890 friend class PGOCtxProfileReader ;
91+ friend class PGOContextualProfile ;
92+
3993 GlobalValue::GUID GUID = 0 ;
4094 SmallVector<uint64_t , 16 > Counters;
4195 CallsiteMapTy Callsites;
@@ -47,11 +101,15 @@ class PGOCtxProfContext final {
47101 getOrEmplace (uint32_t Index, GlobalValue::GUID G,
48102 SmallVectorImpl<uint64_t > &&Counters);
49103
104+ // Create a bogus context object, used for anchoring the index double linked
105+ // list - see IndexNode
106+ PGOCtxProfContext () = default ;
107+
50108public:
51109 PGOCtxProfContext (const PGOCtxProfContext &) = delete ;
52110 PGOCtxProfContext &operator =(const PGOCtxProfContext &) = delete ;
53111 PGOCtxProfContext (PGOCtxProfContext &&) = default ;
54- PGOCtxProfContext &operator =(PGOCtxProfContext &&) = default ;
112+ PGOCtxProfContext &operator =(PGOCtxProfContext &&) = delete ;
55113
56114 GlobalValue::GUID guid () const { return GUID; }
57115 const SmallVectorImpl<uint64_t > &counters () const { return Counters; }
0 commit comments