xref: /freebsd-src/contrib/llvm-project/llvm/lib/Transforms/IPO/SampleContextTracker.cpp (revision 81ad626541db97eb356e2c1d4a20eb2a26a766ab)
1e8d8bef9SDimitry Andric //===- SampleContextTracker.cpp - Context-sensitive Profile Tracker -------===//
2e8d8bef9SDimitry Andric //
3e8d8bef9SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e8d8bef9SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e8d8bef9SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e8d8bef9SDimitry Andric //
7e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===//
8e8d8bef9SDimitry Andric //
9e8d8bef9SDimitry Andric // This file implements the SampleContextTracker used by CSSPGO.
10e8d8bef9SDimitry Andric //
11e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===//
12e8d8bef9SDimitry Andric 
13e8d8bef9SDimitry Andric #include "llvm/Transforms/IPO/SampleContextTracker.h"
14e8d8bef9SDimitry Andric #include "llvm/ADT/StringMap.h"
15e8d8bef9SDimitry Andric #include "llvm/ADT/StringRef.h"
16e8d8bef9SDimitry Andric #include "llvm/IR/DebugInfoMetadata.h"
17*81ad6265SDimitry Andric #include "llvm/IR/InstrTypes.h"
18*81ad6265SDimitry Andric #include "llvm/IR/Instruction.h"
19e8d8bef9SDimitry Andric #include "llvm/ProfileData/SampleProf.h"
20e8d8bef9SDimitry Andric #include <map>
21e8d8bef9SDimitry Andric #include <queue>
22e8d8bef9SDimitry Andric #include <vector>
23e8d8bef9SDimitry Andric 
24e8d8bef9SDimitry Andric using namespace llvm;
25e8d8bef9SDimitry Andric using namespace sampleprof;
26e8d8bef9SDimitry Andric 
27e8d8bef9SDimitry Andric #define DEBUG_TYPE "sample-context-tracker"
28e8d8bef9SDimitry Andric 
29e8d8bef9SDimitry Andric namespace llvm {
30e8d8bef9SDimitry Andric 
31e8d8bef9SDimitry Andric ContextTrieNode *ContextTrieNode::getChildContext(const LineLocation &CallSite,
32e8d8bef9SDimitry Andric                                                   StringRef CalleeName) {
33e8d8bef9SDimitry Andric   if (CalleeName.empty())
34d409305fSDimitry Andric     return getHottestChildContext(CallSite);
35e8d8bef9SDimitry Andric 
360eae32dcSDimitry Andric   uint64_t Hash = FunctionSamples::getCallSiteHash(CalleeName, CallSite);
37e8d8bef9SDimitry Andric   auto It = AllChildContext.find(Hash);
38e8d8bef9SDimitry Andric   if (It != AllChildContext.end())
39e8d8bef9SDimitry Andric     return &It->second;
40e8d8bef9SDimitry Andric   return nullptr;
41e8d8bef9SDimitry Andric }
42e8d8bef9SDimitry Andric 
43e8d8bef9SDimitry Andric ContextTrieNode *
44d409305fSDimitry Andric ContextTrieNode::getHottestChildContext(const LineLocation &CallSite) {
45e8d8bef9SDimitry Andric   // CSFDO-TODO: This could be slow, change AllChildContext so we can
46e8d8bef9SDimitry Andric   // do point look up for child node by call site alone.
47d409305fSDimitry Andric   // Retrieve the child node with max count for indirect call
48e8d8bef9SDimitry Andric   ContextTrieNode *ChildNodeRet = nullptr;
49d409305fSDimitry Andric   uint64_t MaxCalleeSamples = 0;
50e8d8bef9SDimitry Andric   for (auto &It : AllChildContext) {
51e8d8bef9SDimitry Andric     ContextTrieNode &ChildNode = It.second;
52d409305fSDimitry Andric     if (ChildNode.CallSiteLoc != CallSite)
53d409305fSDimitry Andric       continue;
54d409305fSDimitry Andric     FunctionSamples *Samples = ChildNode.getFunctionSamples();
55d409305fSDimitry Andric     if (!Samples)
56d409305fSDimitry Andric       continue;
57d409305fSDimitry Andric     if (Samples->getTotalSamples() > MaxCalleeSamples) {
58e8d8bef9SDimitry Andric       ChildNodeRet = &ChildNode;
59d409305fSDimitry Andric       MaxCalleeSamples = Samples->getTotalSamples();
60e8d8bef9SDimitry Andric     }
61e8d8bef9SDimitry Andric   }
62e8d8bef9SDimitry Andric 
63e8d8bef9SDimitry Andric   return ChildNodeRet;
64e8d8bef9SDimitry Andric }
65e8d8bef9SDimitry Andric 
66*81ad6265SDimitry Andric ContextTrieNode &
67*81ad6265SDimitry Andric SampleContextTracker::moveContextSamples(ContextTrieNode &ToNodeParent,
68*81ad6265SDimitry Andric                                          const LineLocation &CallSite,
69*81ad6265SDimitry Andric                                          ContextTrieNode &&NodeToMove) {
700eae32dcSDimitry Andric   uint64_t Hash =
710eae32dcSDimitry Andric       FunctionSamples::getCallSiteHash(NodeToMove.getFuncName(), CallSite);
72*81ad6265SDimitry Andric   std::map<uint64_t, ContextTrieNode> &AllChildContext =
73*81ad6265SDimitry Andric       ToNodeParent.getAllChildContext();
74e8d8bef9SDimitry Andric   assert(!AllChildContext.count(Hash) && "Node to remove must exist");
75e8d8bef9SDimitry Andric   AllChildContext[Hash] = NodeToMove;
76e8d8bef9SDimitry Andric   ContextTrieNode &NewNode = AllChildContext[Hash];
77*81ad6265SDimitry Andric   NewNode.setCallSiteLoc(CallSite);
78e8d8bef9SDimitry Andric 
79e8d8bef9SDimitry Andric   // Walk through nodes in the moved the subtree, and update
80e8d8bef9SDimitry Andric   // FunctionSamples' context as for the context promotion.
81e8d8bef9SDimitry Andric   // We also need to set new parant link for all children.
82e8d8bef9SDimitry Andric   std::queue<ContextTrieNode *> NodeToUpdate;
83*81ad6265SDimitry Andric   NewNode.setParentContext(&ToNodeParent);
84e8d8bef9SDimitry Andric   NodeToUpdate.push(&NewNode);
85e8d8bef9SDimitry Andric 
86e8d8bef9SDimitry Andric   while (!NodeToUpdate.empty()) {
87e8d8bef9SDimitry Andric     ContextTrieNode *Node = NodeToUpdate.front();
88e8d8bef9SDimitry Andric     NodeToUpdate.pop();
89e8d8bef9SDimitry Andric     FunctionSamples *FSamples = Node->getFunctionSamples();
90e8d8bef9SDimitry Andric 
91e8d8bef9SDimitry Andric     if (FSamples) {
92*81ad6265SDimitry Andric       setContextNode(FSamples, Node);
93e8d8bef9SDimitry Andric       FSamples->getContext().setState(SyntheticContext);
94e8d8bef9SDimitry Andric     }
95e8d8bef9SDimitry Andric 
96e8d8bef9SDimitry Andric     for (auto &It : Node->getAllChildContext()) {
97e8d8bef9SDimitry Andric       ContextTrieNode *ChildNode = &It.second;
98e8d8bef9SDimitry Andric       ChildNode->setParentContext(Node);
99e8d8bef9SDimitry Andric       NodeToUpdate.push(ChildNode);
100e8d8bef9SDimitry Andric     }
101e8d8bef9SDimitry Andric   }
102e8d8bef9SDimitry Andric 
103e8d8bef9SDimitry Andric   return NewNode;
104e8d8bef9SDimitry Andric }
105e8d8bef9SDimitry Andric 
106e8d8bef9SDimitry Andric void ContextTrieNode::removeChildContext(const LineLocation &CallSite,
107e8d8bef9SDimitry Andric                                          StringRef CalleeName) {
1080eae32dcSDimitry Andric   uint64_t Hash = FunctionSamples::getCallSiteHash(CalleeName, CallSite);
109e8d8bef9SDimitry Andric   // Note this essentially calls dtor and destroys that child context
110e8d8bef9SDimitry Andric   AllChildContext.erase(Hash);
111e8d8bef9SDimitry Andric }
112e8d8bef9SDimitry Andric 
113349cc55cSDimitry Andric std::map<uint64_t, ContextTrieNode> &ContextTrieNode::getAllChildContext() {
114e8d8bef9SDimitry Andric   return AllChildContext;
115e8d8bef9SDimitry Andric }
116e8d8bef9SDimitry Andric 
117fe6060f1SDimitry Andric StringRef ContextTrieNode::getFuncName() const { return FuncName; }
118e8d8bef9SDimitry Andric 
119e8d8bef9SDimitry Andric FunctionSamples *ContextTrieNode::getFunctionSamples() const {
120e8d8bef9SDimitry Andric   return FuncSamples;
121e8d8bef9SDimitry Andric }
122e8d8bef9SDimitry Andric 
123e8d8bef9SDimitry Andric void ContextTrieNode::setFunctionSamples(FunctionSamples *FSamples) {
124e8d8bef9SDimitry Andric   FuncSamples = FSamples;
125e8d8bef9SDimitry Andric }
126e8d8bef9SDimitry Andric 
127349cc55cSDimitry Andric Optional<uint32_t> ContextTrieNode::getFunctionSize() const { return FuncSize; }
128349cc55cSDimitry Andric 
129349cc55cSDimitry Andric void ContextTrieNode::addFunctionSize(uint32_t FSize) {
130*81ad6265SDimitry Andric   if (!FuncSize)
131349cc55cSDimitry Andric     FuncSize = 0;
132349cc55cSDimitry Andric 
133349cc55cSDimitry Andric   FuncSize = FuncSize.getValue() + FSize;
134349cc55cSDimitry Andric }
135349cc55cSDimitry Andric 
136e8d8bef9SDimitry Andric LineLocation ContextTrieNode::getCallSiteLoc() const { return CallSiteLoc; }
137e8d8bef9SDimitry Andric 
138e8d8bef9SDimitry Andric ContextTrieNode *ContextTrieNode::getParentContext() const {
139e8d8bef9SDimitry Andric   return ParentContext;
140e8d8bef9SDimitry Andric }
141e8d8bef9SDimitry Andric 
142e8d8bef9SDimitry Andric void ContextTrieNode::setParentContext(ContextTrieNode *Parent) {
143e8d8bef9SDimitry Andric   ParentContext = Parent;
144e8d8bef9SDimitry Andric }
145e8d8bef9SDimitry Andric 
146*81ad6265SDimitry Andric void ContextTrieNode::setCallSiteLoc(const LineLocation &Loc) {
147*81ad6265SDimitry Andric   CallSiteLoc = Loc;
148*81ad6265SDimitry Andric }
149*81ad6265SDimitry Andric 
150349cc55cSDimitry Andric void ContextTrieNode::dumpNode() {
151e8d8bef9SDimitry Andric   dbgs() << "Node: " << FuncName << "\n"
152e8d8bef9SDimitry Andric          << "  Callsite: " << CallSiteLoc << "\n"
153349cc55cSDimitry Andric          << "  Size: " << FuncSize << "\n"
154e8d8bef9SDimitry Andric          << "  Children:\n";
155e8d8bef9SDimitry Andric 
156e8d8bef9SDimitry Andric   for (auto &It : AllChildContext) {
157e8d8bef9SDimitry Andric     dbgs() << "    Node: " << It.second.getFuncName() << "\n";
158e8d8bef9SDimitry Andric   }
159e8d8bef9SDimitry Andric }
160e8d8bef9SDimitry Andric 
161349cc55cSDimitry Andric void ContextTrieNode::dumpTree() {
162349cc55cSDimitry Andric   dbgs() << "Context Profile Tree:\n";
163349cc55cSDimitry Andric   std::queue<ContextTrieNode *> NodeQueue;
164349cc55cSDimitry Andric   NodeQueue.push(this);
165349cc55cSDimitry Andric 
166349cc55cSDimitry Andric   while (!NodeQueue.empty()) {
167349cc55cSDimitry Andric     ContextTrieNode *Node = NodeQueue.front();
168349cc55cSDimitry Andric     NodeQueue.pop();
169349cc55cSDimitry Andric     Node->dumpNode();
170349cc55cSDimitry Andric 
171349cc55cSDimitry Andric     for (auto &It : Node->getAllChildContext()) {
172349cc55cSDimitry Andric       ContextTrieNode *ChildNode = &It.second;
173349cc55cSDimitry Andric       NodeQueue.push(ChildNode);
174349cc55cSDimitry Andric     }
175349cc55cSDimitry Andric   }
176349cc55cSDimitry Andric }
177349cc55cSDimitry Andric 
178e8d8bef9SDimitry Andric ContextTrieNode *ContextTrieNode::getOrCreateChildContext(
179e8d8bef9SDimitry Andric     const LineLocation &CallSite, StringRef CalleeName, bool AllowCreate) {
1800eae32dcSDimitry Andric   uint64_t Hash = FunctionSamples::getCallSiteHash(CalleeName, CallSite);
181e8d8bef9SDimitry Andric   auto It = AllChildContext.find(Hash);
182e8d8bef9SDimitry Andric   if (It != AllChildContext.end()) {
183e8d8bef9SDimitry Andric     assert(It->second.getFuncName() == CalleeName &&
184e8d8bef9SDimitry Andric            "Hash collision for child context node");
185e8d8bef9SDimitry Andric     return &It->second;
186e8d8bef9SDimitry Andric   }
187e8d8bef9SDimitry Andric 
188e8d8bef9SDimitry Andric   if (!AllowCreate)
189e8d8bef9SDimitry Andric     return nullptr;
190e8d8bef9SDimitry Andric 
191e8d8bef9SDimitry Andric   AllChildContext[Hash] = ContextTrieNode(this, CalleeName, nullptr, CallSite);
192e8d8bef9SDimitry Andric   return &AllChildContext[Hash];
193e8d8bef9SDimitry Andric }
194e8d8bef9SDimitry Andric 
195e8d8bef9SDimitry Andric // Profiler tracker than manages profiles and its associated context
196e8d8bef9SDimitry Andric SampleContextTracker::SampleContextTracker(
197349cc55cSDimitry Andric     SampleProfileMap &Profiles,
198349cc55cSDimitry Andric     const DenseMap<uint64_t, StringRef> *GUIDToFuncNameMap)
199349cc55cSDimitry Andric     : GUIDToFuncNameMap(GUIDToFuncNameMap) {
200e8d8bef9SDimitry Andric   for (auto &FuncSample : Profiles) {
201e8d8bef9SDimitry Andric     FunctionSamples *FSamples = &FuncSample.second;
202349cc55cSDimitry Andric     SampleContext Context = FuncSample.first;
203349cc55cSDimitry Andric     LLVM_DEBUG(dbgs() << "Tracking Context for function: " << Context.toString()
204349cc55cSDimitry Andric                       << "\n");
205e8d8bef9SDimitry Andric     ContextTrieNode *NewNode = getOrCreateContextPath(Context, true);
206e8d8bef9SDimitry Andric     assert(!NewNode->getFunctionSamples() &&
207e8d8bef9SDimitry Andric            "New node can't have sample profile");
208e8d8bef9SDimitry Andric     NewNode->setFunctionSamples(FSamples);
209e8d8bef9SDimitry Andric   }
210*81ad6265SDimitry Andric   populateFuncToCtxtMap();
211*81ad6265SDimitry Andric }
212*81ad6265SDimitry Andric 
213*81ad6265SDimitry Andric void SampleContextTracker::populateFuncToCtxtMap() {
214*81ad6265SDimitry Andric   for (auto *Node : *this) {
215*81ad6265SDimitry Andric     FunctionSamples *FSamples = Node->getFunctionSamples();
216*81ad6265SDimitry Andric     if (FSamples) {
217*81ad6265SDimitry Andric       FSamples->getContext().setState(RawContext);
218*81ad6265SDimitry Andric       setContextNode(FSamples, Node);
219*81ad6265SDimitry Andric       FuncToCtxtProfiles[Node->getFuncName()].push_back(FSamples);
220*81ad6265SDimitry Andric     }
221*81ad6265SDimitry Andric   }
222e8d8bef9SDimitry Andric }
223e8d8bef9SDimitry Andric 
224e8d8bef9SDimitry Andric FunctionSamples *
225e8d8bef9SDimitry Andric SampleContextTracker::getCalleeContextSamplesFor(const CallBase &Inst,
226e8d8bef9SDimitry Andric                                                  StringRef CalleeName) {
227e8d8bef9SDimitry Andric   LLVM_DEBUG(dbgs() << "Getting callee context for instr: " << Inst << "\n");
228e8d8bef9SDimitry Andric   DILocation *DIL = Inst.getDebugLoc();
229e8d8bef9SDimitry Andric   if (!DIL)
230e8d8bef9SDimitry Andric     return nullptr;
231e8d8bef9SDimitry Andric 
232fe6060f1SDimitry Andric   CalleeName = FunctionSamples::getCanonicalFnName(CalleeName);
233349cc55cSDimitry Andric   // Convert real function names to MD5 names, if the input profile is
234349cc55cSDimitry Andric   // MD5-based.
235349cc55cSDimitry Andric   std::string FGUID;
236349cc55cSDimitry Andric   CalleeName = getRepInFormat(CalleeName, FunctionSamples::UseMD5, FGUID);
237fe6060f1SDimitry Andric 
238d409305fSDimitry Andric   // For indirect call, CalleeName will be empty, in which case the context
239d409305fSDimitry Andric   // profile for callee with largest total samples will be returned.
240e8d8bef9SDimitry Andric   ContextTrieNode *CalleeContext = getCalleeContextFor(DIL, CalleeName);
241e8d8bef9SDimitry Andric   if (CalleeContext) {
242e8d8bef9SDimitry Andric     FunctionSamples *FSamples = CalleeContext->getFunctionSamples();
243e8d8bef9SDimitry Andric     LLVM_DEBUG(if (FSamples) {
244*81ad6265SDimitry Andric       dbgs() << "  Callee context found: " << getContextString(CalleeContext)
245349cc55cSDimitry Andric              << "\n";
246e8d8bef9SDimitry Andric     });
247e8d8bef9SDimitry Andric     return FSamples;
248e8d8bef9SDimitry Andric   }
249e8d8bef9SDimitry Andric 
250e8d8bef9SDimitry Andric   return nullptr;
251e8d8bef9SDimitry Andric }
252e8d8bef9SDimitry Andric 
253d409305fSDimitry Andric std::vector<const FunctionSamples *>
254d409305fSDimitry Andric SampleContextTracker::getIndirectCalleeContextSamplesFor(
255d409305fSDimitry Andric     const DILocation *DIL) {
256d409305fSDimitry Andric   std::vector<const FunctionSamples *> R;
257d409305fSDimitry Andric   if (!DIL)
258d409305fSDimitry Andric     return R;
259d409305fSDimitry Andric 
260d409305fSDimitry Andric   ContextTrieNode *CallerNode = getContextFor(DIL);
261d409305fSDimitry Andric   LineLocation CallSite = FunctionSamples::getCallSiteIdentifier(DIL);
262d409305fSDimitry Andric   for (auto &It : CallerNode->getAllChildContext()) {
263d409305fSDimitry Andric     ContextTrieNode &ChildNode = It.second;
264d409305fSDimitry Andric     if (ChildNode.getCallSiteLoc() != CallSite)
265d409305fSDimitry Andric       continue;
266d409305fSDimitry Andric     if (FunctionSamples *CalleeSamples = ChildNode.getFunctionSamples())
267d409305fSDimitry Andric       R.push_back(CalleeSamples);
268d409305fSDimitry Andric   }
269d409305fSDimitry Andric 
270d409305fSDimitry Andric   return R;
271d409305fSDimitry Andric }
272d409305fSDimitry Andric 
273e8d8bef9SDimitry Andric FunctionSamples *
274e8d8bef9SDimitry Andric SampleContextTracker::getContextSamplesFor(const DILocation *DIL) {
275e8d8bef9SDimitry Andric   assert(DIL && "Expect non-null location");
276e8d8bef9SDimitry Andric 
277e8d8bef9SDimitry Andric   ContextTrieNode *ContextNode = getContextFor(DIL);
278e8d8bef9SDimitry Andric   if (!ContextNode)
279e8d8bef9SDimitry Andric     return nullptr;
280e8d8bef9SDimitry Andric 
281e8d8bef9SDimitry Andric   // We may have inlined callees during pre-LTO compilation, in which case
282e8d8bef9SDimitry Andric   // we need to rely on the inline stack from !dbg to mark context profile
283e8d8bef9SDimitry Andric   // as inlined, instead of `MarkContextSamplesInlined` during inlining.
284e8d8bef9SDimitry Andric   // Sample profile loader walks through all instructions to get profile,
285e8d8bef9SDimitry Andric   // which calls this function. So once that is done, all previously inlined
286e8d8bef9SDimitry Andric   // context profile should be marked properly.
287e8d8bef9SDimitry Andric   FunctionSamples *Samples = ContextNode->getFunctionSamples();
288e8d8bef9SDimitry Andric   if (Samples && ContextNode->getParentContext() != &RootContext)
289e8d8bef9SDimitry Andric     Samples->getContext().setState(InlinedContext);
290e8d8bef9SDimitry Andric 
291e8d8bef9SDimitry Andric   return Samples;
292e8d8bef9SDimitry Andric }
293e8d8bef9SDimitry Andric 
294e8d8bef9SDimitry Andric FunctionSamples *
295e8d8bef9SDimitry Andric SampleContextTracker::getContextSamplesFor(const SampleContext &Context) {
296e8d8bef9SDimitry Andric   ContextTrieNode *Node = getContextFor(Context);
297e8d8bef9SDimitry Andric   if (!Node)
298e8d8bef9SDimitry Andric     return nullptr;
299e8d8bef9SDimitry Andric 
300e8d8bef9SDimitry Andric   return Node->getFunctionSamples();
301e8d8bef9SDimitry Andric }
302e8d8bef9SDimitry Andric 
303d409305fSDimitry Andric SampleContextTracker::ContextSamplesTy &
304d409305fSDimitry Andric SampleContextTracker::getAllContextSamplesFor(const Function &Func) {
305d409305fSDimitry Andric   StringRef CanonName = FunctionSamples::getCanonicalFnName(Func);
306fe6060f1SDimitry Andric   return FuncToCtxtProfiles[CanonName];
307d409305fSDimitry Andric }
308d409305fSDimitry Andric 
309d409305fSDimitry Andric SampleContextTracker::ContextSamplesTy &
310d409305fSDimitry Andric SampleContextTracker::getAllContextSamplesFor(StringRef Name) {
311fe6060f1SDimitry Andric   return FuncToCtxtProfiles[Name];
312d409305fSDimitry Andric }
313d409305fSDimitry Andric 
314e8d8bef9SDimitry Andric FunctionSamples *SampleContextTracker::getBaseSamplesFor(const Function &Func,
315e8d8bef9SDimitry Andric                                                          bool MergeContext) {
316e8d8bef9SDimitry Andric   StringRef CanonName = FunctionSamples::getCanonicalFnName(Func);
317e8d8bef9SDimitry Andric   return getBaseSamplesFor(CanonName, MergeContext);
318e8d8bef9SDimitry Andric }
319e8d8bef9SDimitry Andric 
320e8d8bef9SDimitry Andric FunctionSamples *SampleContextTracker::getBaseSamplesFor(StringRef Name,
321e8d8bef9SDimitry Andric                                                          bool MergeContext) {
322e8d8bef9SDimitry Andric   LLVM_DEBUG(dbgs() << "Getting base profile for function: " << Name << "\n");
323349cc55cSDimitry Andric   // Convert real function names to MD5 names, if the input profile is
324349cc55cSDimitry Andric   // MD5-based.
325349cc55cSDimitry Andric   std::string FGUID;
326349cc55cSDimitry Andric   Name = getRepInFormat(Name, FunctionSamples::UseMD5, FGUID);
327349cc55cSDimitry Andric 
328e8d8bef9SDimitry Andric   // Base profile is top-level node (child of root node), so try to retrieve
329e8d8bef9SDimitry Andric   // existing top-level node for given function first. If it exists, it could be
330e8d8bef9SDimitry Andric   // that we've merged base profile before, or there's actually context-less
331e8d8bef9SDimitry Andric   // profile from the input (e.g. due to unreliable stack walking).
332e8d8bef9SDimitry Andric   ContextTrieNode *Node = getTopLevelContextNode(Name);
333e8d8bef9SDimitry Andric   if (MergeContext) {
334e8d8bef9SDimitry Andric     LLVM_DEBUG(dbgs() << "  Merging context profile into base profile: " << Name
335e8d8bef9SDimitry Andric                       << "\n");
336e8d8bef9SDimitry Andric 
337e8d8bef9SDimitry Andric     // We have profile for function under different contexts,
338e8d8bef9SDimitry Andric     // create synthetic base profile and merge context profiles
339e8d8bef9SDimitry Andric     // into base profile.
340fe6060f1SDimitry Andric     for (auto *CSamples : FuncToCtxtProfiles[Name]) {
341e8d8bef9SDimitry Andric       SampleContext &Context = CSamples->getContext();
342e8d8bef9SDimitry Andric       // Skip inlined context profile and also don't re-merge any context
343e8d8bef9SDimitry Andric       if (Context.hasState(InlinedContext) || Context.hasState(MergedContext))
344e8d8bef9SDimitry Andric         continue;
345e8d8bef9SDimitry Andric 
346*81ad6265SDimitry Andric       ContextTrieNode *FromNode = getContextNodeForProfile(CSamples);
347349cc55cSDimitry Andric       if (FromNode == Node)
348349cc55cSDimitry Andric         continue;
349349cc55cSDimitry Andric 
350e8d8bef9SDimitry Andric       ContextTrieNode &ToNode = promoteMergeContextSamplesTree(*FromNode);
351e8d8bef9SDimitry Andric       assert((!Node || Node == &ToNode) && "Expect only one base profile");
352e8d8bef9SDimitry Andric       Node = &ToNode;
353e8d8bef9SDimitry Andric     }
354e8d8bef9SDimitry Andric   }
355e8d8bef9SDimitry Andric 
356e8d8bef9SDimitry Andric   // Still no profile even after merge/promotion (if allowed)
357e8d8bef9SDimitry Andric   if (!Node)
358e8d8bef9SDimitry Andric     return nullptr;
359e8d8bef9SDimitry Andric 
360e8d8bef9SDimitry Andric   return Node->getFunctionSamples();
361e8d8bef9SDimitry Andric }
362e8d8bef9SDimitry Andric 
363e8d8bef9SDimitry Andric void SampleContextTracker::markContextSamplesInlined(
364e8d8bef9SDimitry Andric     const FunctionSamples *InlinedSamples) {
365e8d8bef9SDimitry Andric   assert(InlinedSamples && "Expect non-null inlined samples");
366e8d8bef9SDimitry Andric   LLVM_DEBUG(dbgs() << "Marking context profile as inlined: "
367*81ad6265SDimitry Andric                     << getContextString(*InlinedSamples) << "\n");
368e8d8bef9SDimitry Andric   InlinedSamples->getContext().setState(InlinedContext);
369e8d8bef9SDimitry Andric }
370e8d8bef9SDimitry Andric 
371fe6060f1SDimitry Andric ContextTrieNode &SampleContextTracker::getRootContext() { return RootContext; }
372fe6060f1SDimitry Andric 
373e8d8bef9SDimitry Andric void SampleContextTracker::promoteMergeContextSamplesTree(
374e8d8bef9SDimitry Andric     const Instruction &Inst, StringRef CalleeName) {
375e8d8bef9SDimitry Andric   LLVM_DEBUG(dbgs() << "Promoting and merging context tree for instr: \n"
376e8d8bef9SDimitry Andric                     << Inst << "\n");
377e8d8bef9SDimitry Andric   // Get the caller context for the call instruction, we don't use callee
378e8d8bef9SDimitry Andric   // name from call because there can be context from indirect calls too.
379e8d8bef9SDimitry Andric   DILocation *DIL = Inst.getDebugLoc();
380e8d8bef9SDimitry Andric   ContextTrieNode *CallerNode = getContextFor(DIL);
381e8d8bef9SDimitry Andric   if (!CallerNode)
382e8d8bef9SDimitry Andric     return;
383e8d8bef9SDimitry Andric 
384e8d8bef9SDimitry Andric   // Get the context that needs to be promoted
385d409305fSDimitry Andric   LineLocation CallSite = FunctionSamples::getCallSiteIdentifier(DIL);
386d409305fSDimitry Andric   // For indirect call, CalleeName will be empty, in which case we need to
387d409305fSDimitry Andric   // promote all non-inlined child context profiles.
388d409305fSDimitry Andric   if (CalleeName.empty()) {
389d409305fSDimitry Andric     for (auto &It : CallerNode->getAllChildContext()) {
390d409305fSDimitry Andric       ContextTrieNode *NodeToPromo = &It.second;
391d409305fSDimitry Andric       if (CallSite != NodeToPromo->getCallSiteLoc())
392d409305fSDimitry Andric         continue;
393d409305fSDimitry Andric       FunctionSamples *FromSamples = NodeToPromo->getFunctionSamples();
394d409305fSDimitry Andric       if (FromSamples && FromSamples->getContext().hasState(InlinedContext))
395d409305fSDimitry Andric         continue;
396d409305fSDimitry Andric       promoteMergeContextSamplesTree(*NodeToPromo);
397d409305fSDimitry Andric     }
398d409305fSDimitry Andric     return;
399d409305fSDimitry Andric   }
400d409305fSDimitry Andric 
401d409305fSDimitry Andric   // Get the context for the given callee that needs to be promoted
402e8d8bef9SDimitry Andric   ContextTrieNode *NodeToPromo =
403e8d8bef9SDimitry Andric       CallerNode->getChildContext(CallSite, CalleeName);
404e8d8bef9SDimitry Andric   if (!NodeToPromo)
405e8d8bef9SDimitry Andric     return;
406e8d8bef9SDimitry Andric 
407e8d8bef9SDimitry Andric   promoteMergeContextSamplesTree(*NodeToPromo);
408e8d8bef9SDimitry Andric }
409e8d8bef9SDimitry Andric 
410e8d8bef9SDimitry Andric ContextTrieNode &SampleContextTracker::promoteMergeContextSamplesTree(
411e8d8bef9SDimitry Andric     ContextTrieNode &NodeToPromo) {
412e8d8bef9SDimitry Andric   // Promote the input node to be directly under root. This can happen
413e8d8bef9SDimitry Andric   // when we decided to not inline a function under context represented
414e8d8bef9SDimitry Andric   // by the input node. The promote and merge is then needed to reflect
415e8d8bef9SDimitry Andric   // the context profile in the base (context-less) profile.
416e8d8bef9SDimitry Andric   FunctionSamples *FromSamples = NodeToPromo.getFunctionSamples();
417e8d8bef9SDimitry Andric   assert(FromSamples && "Shouldn't promote a context without profile");
418*81ad6265SDimitry Andric   (void)FromSamples;  // Unused in release build.
419*81ad6265SDimitry Andric 
420e8d8bef9SDimitry Andric   LLVM_DEBUG(dbgs() << "  Found context tree root to promote: "
421*81ad6265SDimitry Andric                     << getContextString(&NodeToPromo) << "\n");
422e8d8bef9SDimitry Andric 
423d409305fSDimitry Andric   assert(!FromSamples->getContext().hasState(InlinedContext) &&
424d409305fSDimitry Andric          "Shouldn't promote inlined context profile");
425*81ad6265SDimitry Andric   return promoteMergeContextSamplesTree(NodeToPromo, RootContext);
426e8d8bef9SDimitry Andric }
427e8d8bef9SDimitry Andric 
428*81ad6265SDimitry Andric #ifndef NDEBUG
429*81ad6265SDimitry Andric std::string
430*81ad6265SDimitry Andric SampleContextTracker::getContextString(const FunctionSamples &FSamples) const {
431*81ad6265SDimitry Andric   return getContextString(getContextNodeForProfile(&FSamples));
432*81ad6265SDimitry Andric }
433*81ad6265SDimitry Andric 
434*81ad6265SDimitry Andric std::string
435*81ad6265SDimitry Andric SampleContextTracker::getContextString(ContextTrieNode *Node) const {
436*81ad6265SDimitry Andric   SampleContextFrameVector Res;
437*81ad6265SDimitry Andric   if (Node == &RootContext)
438*81ad6265SDimitry Andric     return std::string();
439*81ad6265SDimitry Andric   Res.emplace_back(Node->getFuncName(), LineLocation(0, 0));
440*81ad6265SDimitry Andric 
441*81ad6265SDimitry Andric   ContextTrieNode *PreNode = Node;
442*81ad6265SDimitry Andric   Node = Node->getParentContext();
443*81ad6265SDimitry Andric   while (Node && Node != &RootContext) {
444*81ad6265SDimitry Andric     Res.emplace_back(Node->getFuncName(), PreNode->getCallSiteLoc());
445*81ad6265SDimitry Andric     PreNode = Node;
446*81ad6265SDimitry Andric     Node = Node->getParentContext();
447*81ad6265SDimitry Andric   }
448*81ad6265SDimitry Andric 
449*81ad6265SDimitry Andric   std::reverse(Res.begin(), Res.end());
450*81ad6265SDimitry Andric 
451*81ad6265SDimitry Andric   return SampleContext::getContextString(Res);
452*81ad6265SDimitry Andric }
453*81ad6265SDimitry Andric #endif
454*81ad6265SDimitry Andric 
455349cc55cSDimitry Andric void SampleContextTracker::dump() { RootContext.dumpTree(); }
456e8d8bef9SDimitry Andric 
457349cc55cSDimitry Andric StringRef SampleContextTracker::getFuncNameFor(ContextTrieNode *Node) const {
458349cc55cSDimitry Andric   if (!FunctionSamples::UseMD5)
459349cc55cSDimitry Andric     return Node->getFuncName();
460349cc55cSDimitry Andric   assert(GUIDToFuncNameMap && "GUIDToFuncNameMap needs to be populated first");
461349cc55cSDimitry Andric   return GUIDToFuncNameMap->lookup(std::stoull(Node->getFuncName().data()));
462e8d8bef9SDimitry Andric }
463e8d8bef9SDimitry Andric 
464e8d8bef9SDimitry Andric ContextTrieNode *
465e8d8bef9SDimitry Andric SampleContextTracker::getContextFor(const SampleContext &Context) {
466e8d8bef9SDimitry Andric   return getOrCreateContextPath(Context, false);
467e8d8bef9SDimitry Andric }
468e8d8bef9SDimitry Andric 
469e8d8bef9SDimitry Andric ContextTrieNode *
470e8d8bef9SDimitry Andric SampleContextTracker::getCalleeContextFor(const DILocation *DIL,
471e8d8bef9SDimitry Andric                                           StringRef CalleeName) {
472e8d8bef9SDimitry Andric   assert(DIL && "Expect non-null location");
473e8d8bef9SDimitry Andric 
474e8d8bef9SDimitry Andric   ContextTrieNode *CallContext = getContextFor(DIL);
475e8d8bef9SDimitry Andric   if (!CallContext)
476e8d8bef9SDimitry Andric     return nullptr;
477e8d8bef9SDimitry Andric 
478d409305fSDimitry Andric   // When CalleeName is empty, the child context profile with max
479d409305fSDimitry Andric   // total samples will be returned.
480e8d8bef9SDimitry Andric   return CallContext->getChildContext(
481d409305fSDimitry Andric       FunctionSamples::getCallSiteIdentifier(DIL), CalleeName);
482e8d8bef9SDimitry Andric }
483e8d8bef9SDimitry Andric 
484e8d8bef9SDimitry Andric ContextTrieNode *SampleContextTracker::getContextFor(const DILocation *DIL) {
485e8d8bef9SDimitry Andric   assert(DIL && "Expect non-null location");
486e8d8bef9SDimitry Andric   SmallVector<std::pair<LineLocation, StringRef>, 10> S;
487e8d8bef9SDimitry Andric 
488e8d8bef9SDimitry Andric   // Use C++ linkage name if possible.
489e8d8bef9SDimitry Andric   const DILocation *PrevDIL = DIL;
490e8d8bef9SDimitry Andric   for (DIL = DIL->getInlinedAt(); DIL; DIL = DIL->getInlinedAt()) {
491e8d8bef9SDimitry Andric     StringRef Name = PrevDIL->getScope()->getSubprogram()->getLinkageName();
492e8d8bef9SDimitry Andric     if (Name.empty())
493e8d8bef9SDimitry Andric       Name = PrevDIL->getScope()->getSubprogram()->getName();
494e8d8bef9SDimitry Andric     S.push_back(
495fe6060f1SDimitry Andric         std::make_pair(FunctionSamples::getCallSiteIdentifier(DIL), Name));
496e8d8bef9SDimitry Andric     PrevDIL = DIL;
497e8d8bef9SDimitry Andric   }
498e8d8bef9SDimitry Andric 
499e8d8bef9SDimitry Andric   // Push root node, note that root node like main may only
500e8d8bef9SDimitry Andric   // a name, but not linkage name.
501e8d8bef9SDimitry Andric   StringRef RootName = PrevDIL->getScope()->getSubprogram()->getLinkageName();
502e8d8bef9SDimitry Andric   if (RootName.empty())
503e8d8bef9SDimitry Andric     RootName = PrevDIL->getScope()->getSubprogram()->getName();
504e8d8bef9SDimitry Andric   S.push_back(std::make_pair(LineLocation(0, 0), RootName));
505e8d8bef9SDimitry Andric 
506349cc55cSDimitry Andric   // Convert real function names to MD5 names, if the input profile is
507349cc55cSDimitry Andric   // MD5-based.
508349cc55cSDimitry Andric   std::list<std::string> MD5Names;
509349cc55cSDimitry Andric   if (FunctionSamples::UseMD5) {
510349cc55cSDimitry Andric     for (auto &Location : S) {
511349cc55cSDimitry Andric       MD5Names.emplace_back();
512349cc55cSDimitry Andric       getRepInFormat(Location.second, FunctionSamples::UseMD5, MD5Names.back());
513349cc55cSDimitry Andric       Location.second = MD5Names.back();
514349cc55cSDimitry Andric     }
515349cc55cSDimitry Andric   }
516349cc55cSDimitry Andric 
517e8d8bef9SDimitry Andric   ContextTrieNode *ContextNode = &RootContext;
518e8d8bef9SDimitry Andric   int I = S.size();
519e8d8bef9SDimitry Andric   while (--I >= 0 && ContextNode) {
520e8d8bef9SDimitry Andric     LineLocation &CallSite = S[I].first;
521349cc55cSDimitry Andric     StringRef CalleeName = S[I].second;
522e8d8bef9SDimitry Andric     ContextNode = ContextNode->getChildContext(CallSite, CalleeName);
523e8d8bef9SDimitry Andric   }
524e8d8bef9SDimitry Andric 
525e8d8bef9SDimitry Andric   if (I < 0)
526e8d8bef9SDimitry Andric     return ContextNode;
527e8d8bef9SDimitry Andric 
528e8d8bef9SDimitry Andric   return nullptr;
529e8d8bef9SDimitry Andric }
530e8d8bef9SDimitry Andric 
531e8d8bef9SDimitry Andric ContextTrieNode *
532e8d8bef9SDimitry Andric SampleContextTracker::getOrCreateContextPath(const SampleContext &Context,
533e8d8bef9SDimitry Andric                                              bool AllowCreate) {
534e8d8bef9SDimitry Andric   ContextTrieNode *ContextNode = &RootContext;
535e8d8bef9SDimitry Andric   LineLocation CallSiteLoc(0, 0);
536e8d8bef9SDimitry Andric 
537349cc55cSDimitry Andric   for (auto &Callsite : Context.getContextFrames()) {
538e8d8bef9SDimitry Andric     // Create child node at parent line/disc location
539e8d8bef9SDimitry Andric     if (AllowCreate) {
540e8d8bef9SDimitry Andric       ContextNode =
541349cc55cSDimitry Andric           ContextNode->getOrCreateChildContext(CallSiteLoc, Callsite.FuncName);
542e8d8bef9SDimitry Andric     } else {
543349cc55cSDimitry Andric       ContextNode =
544349cc55cSDimitry Andric           ContextNode->getChildContext(CallSiteLoc, Callsite.FuncName);
545e8d8bef9SDimitry Andric     }
546349cc55cSDimitry Andric     CallSiteLoc = Callsite.Location;
547e8d8bef9SDimitry Andric   }
548e8d8bef9SDimitry Andric 
549e8d8bef9SDimitry Andric   assert((!AllowCreate || ContextNode) &&
550e8d8bef9SDimitry Andric          "Node must exist if creation is allowed");
551e8d8bef9SDimitry Andric   return ContextNode;
552e8d8bef9SDimitry Andric }
553e8d8bef9SDimitry Andric 
554e8d8bef9SDimitry Andric ContextTrieNode *SampleContextTracker::getTopLevelContextNode(StringRef FName) {
555fe6060f1SDimitry Andric   assert(!FName.empty() && "Top level node query must provide valid name");
556e8d8bef9SDimitry Andric   return RootContext.getChildContext(LineLocation(0, 0), FName);
557e8d8bef9SDimitry Andric }
558e8d8bef9SDimitry Andric 
559e8d8bef9SDimitry Andric ContextTrieNode &SampleContextTracker::addTopLevelContextNode(StringRef FName) {
560e8d8bef9SDimitry Andric   assert(!getTopLevelContextNode(FName) && "Node to add must not exist");
561e8d8bef9SDimitry Andric   return *RootContext.getOrCreateChildContext(LineLocation(0, 0), FName);
562e8d8bef9SDimitry Andric }
563e8d8bef9SDimitry Andric 
564e8d8bef9SDimitry Andric void SampleContextTracker::mergeContextNode(ContextTrieNode &FromNode,
565*81ad6265SDimitry Andric                                             ContextTrieNode &ToNode) {
566e8d8bef9SDimitry Andric   FunctionSamples *FromSamples = FromNode.getFunctionSamples();
567e8d8bef9SDimitry Andric   FunctionSamples *ToSamples = ToNode.getFunctionSamples();
568e8d8bef9SDimitry Andric   if (FromSamples && ToSamples) {
569e8d8bef9SDimitry Andric     // Merge/duplicate FromSamples into ToSamples
570e8d8bef9SDimitry Andric     ToSamples->merge(*FromSamples);
571e8d8bef9SDimitry Andric     ToSamples->getContext().setState(SyntheticContext);
572e8d8bef9SDimitry Andric     FromSamples->getContext().setState(MergedContext);
573349cc55cSDimitry Andric     if (FromSamples->getContext().hasAttribute(ContextShouldBeInlined))
574349cc55cSDimitry Andric       ToSamples->getContext().setAttribute(ContextShouldBeInlined);
575e8d8bef9SDimitry Andric   } else if (FromSamples) {
576e8d8bef9SDimitry Andric     // Transfer FromSamples from FromNode to ToNode
577e8d8bef9SDimitry Andric     ToNode.setFunctionSamples(FromSamples);
578*81ad6265SDimitry Andric     setContextNode(FromSamples, &ToNode);
579e8d8bef9SDimitry Andric     FromSamples->getContext().setState(SyntheticContext);
580e8d8bef9SDimitry Andric   }
581e8d8bef9SDimitry Andric }
582e8d8bef9SDimitry Andric 
583e8d8bef9SDimitry Andric ContextTrieNode &SampleContextTracker::promoteMergeContextSamplesTree(
584*81ad6265SDimitry Andric     ContextTrieNode &FromNode, ContextTrieNode &ToNodeParent) {
585e8d8bef9SDimitry Andric 
586e8d8bef9SDimitry Andric   // Ignore call site location if destination is top level under root
587e8d8bef9SDimitry Andric   LineLocation NewCallSiteLoc = LineLocation(0, 0);
588e8d8bef9SDimitry Andric   LineLocation OldCallSiteLoc = FromNode.getCallSiteLoc();
589e8d8bef9SDimitry Andric   ContextTrieNode &FromNodeParent = *FromNode.getParentContext();
590e8d8bef9SDimitry Andric   ContextTrieNode *ToNode = nullptr;
591e8d8bef9SDimitry Andric   bool MoveToRoot = (&ToNodeParent == &RootContext);
592e8d8bef9SDimitry Andric   if (!MoveToRoot) {
593e8d8bef9SDimitry Andric     NewCallSiteLoc = OldCallSiteLoc;
594e8d8bef9SDimitry Andric   }
595e8d8bef9SDimitry Andric 
596e8d8bef9SDimitry Andric   // Locate destination node, create/move if not existing
597e8d8bef9SDimitry Andric   ToNode = ToNodeParent.getChildContext(NewCallSiteLoc, FromNode.getFuncName());
598e8d8bef9SDimitry Andric   if (!ToNode) {
599e8d8bef9SDimitry Andric     // Do not delete node to move from its parent here because
600e8d8bef9SDimitry Andric     // caller is iterating over children of that parent node.
601*81ad6265SDimitry Andric     ToNode =
602*81ad6265SDimitry Andric         &moveContextSamples(ToNodeParent, NewCallSiteLoc, std::move(FromNode));
603*81ad6265SDimitry Andric     LLVM_DEBUG({
604*81ad6265SDimitry Andric       dbgs() << "  Context promoted and merged to: " << getContextString(ToNode)
605*81ad6265SDimitry Andric              << "\n";
606*81ad6265SDimitry Andric     });
607e8d8bef9SDimitry Andric   } else {
608e8d8bef9SDimitry Andric     // Destination node exists, merge samples for the context tree
609*81ad6265SDimitry Andric     mergeContextNode(FromNode, *ToNode);
610fe6060f1SDimitry Andric     LLVM_DEBUG({
611fe6060f1SDimitry Andric       if (ToNode->getFunctionSamples())
612fe6060f1SDimitry Andric         dbgs() << "  Context promoted and merged to: "
613*81ad6265SDimitry Andric                << getContextString(ToNode) << "\n";
614fe6060f1SDimitry Andric     });
615e8d8bef9SDimitry Andric 
616e8d8bef9SDimitry Andric     // Recursively promote and merge children
617e8d8bef9SDimitry Andric     for (auto &It : FromNode.getAllChildContext()) {
618e8d8bef9SDimitry Andric       ContextTrieNode &FromChildNode = It.second;
619*81ad6265SDimitry Andric       promoteMergeContextSamplesTree(FromChildNode, *ToNode);
620e8d8bef9SDimitry Andric     }
621e8d8bef9SDimitry Andric 
622e8d8bef9SDimitry Andric     // Remove children once they're all merged
623e8d8bef9SDimitry Andric     FromNode.getAllChildContext().clear();
624e8d8bef9SDimitry Andric   }
625e8d8bef9SDimitry Andric 
626e8d8bef9SDimitry Andric   // For root of subtree, remove itself from old parent too
627e8d8bef9SDimitry Andric   if (MoveToRoot)
628e8d8bef9SDimitry Andric     FromNodeParent.removeChildContext(OldCallSiteLoc, ToNode->getFuncName());
629e8d8bef9SDimitry Andric 
630e8d8bef9SDimitry Andric   return *ToNode;
631e8d8bef9SDimitry Andric }
632*81ad6265SDimitry Andric 
633*81ad6265SDimitry Andric void SampleContextTracker::createContextLessProfileMap(
634*81ad6265SDimitry Andric     SampleProfileMap &ContextLessProfiles) {
635*81ad6265SDimitry Andric   for (auto *Node : *this) {
636*81ad6265SDimitry Andric     FunctionSamples *FProfile = Node->getFunctionSamples();
637*81ad6265SDimitry Andric     // Profile's context can be empty, use ContextNode's func name.
638*81ad6265SDimitry Andric     if (FProfile)
639*81ad6265SDimitry Andric       ContextLessProfiles[Node->getFuncName()].merge(*FProfile);
640*81ad6265SDimitry Andric   }
641*81ad6265SDimitry Andric }
642e8d8bef9SDimitry Andric } // namespace llvm
643