xref: /freebsd-src/contrib/llvm-project/llvm/lib/Transforms/IPO/SampleContextTracker.cpp (revision d409305fa3838fb39b38c26fc085fb729b8766d5)
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"
17e8d8bef9SDimitry Andric #include "llvm/IR/Instructions.h"
18e8d8bef9SDimitry Andric #include "llvm/ProfileData/SampleProf.h"
19e8d8bef9SDimitry Andric #include <map>
20e8d8bef9SDimitry Andric #include <queue>
21e8d8bef9SDimitry Andric #include <vector>
22e8d8bef9SDimitry Andric 
23e8d8bef9SDimitry Andric using namespace llvm;
24e8d8bef9SDimitry Andric using namespace sampleprof;
25e8d8bef9SDimitry Andric 
26e8d8bef9SDimitry Andric #define DEBUG_TYPE "sample-context-tracker"
27e8d8bef9SDimitry Andric 
28e8d8bef9SDimitry Andric namespace llvm {
29e8d8bef9SDimitry Andric 
30e8d8bef9SDimitry Andric ContextTrieNode *ContextTrieNode::getChildContext(const LineLocation &CallSite,
31e8d8bef9SDimitry Andric                                                   StringRef CalleeName) {
32e8d8bef9SDimitry Andric   if (CalleeName.empty())
33*d409305fSDimitry Andric     return getHottestChildContext(CallSite);
34e8d8bef9SDimitry Andric 
35e8d8bef9SDimitry Andric   uint32_t Hash = nodeHash(CalleeName, CallSite);
36e8d8bef9SDimitry Andric   auto It = AllChildContext.find(Hash);
37e8d8bef9SDimitry Andric   if (It != AllChildContext.end())
38e8d8bef9SDimitry Andric     return &It->second;
39e8d8bef9SDimitry Andric   return nullptr;
40e8d8bef9SDimitry Andric }
41e8d8bef9SDimitry Andric 
42e8d8bef9SDimitry Andric ContextTrieNode *
43*d409305fSDimitry Andric ContextTrieNode::getHottestChildContext(const LineLocation &CallSite) {
44e8d8bef9SDimitry Andric   // CSFDO-TODO: This could be slow, change AllChildContext so we can
45e8d8bef9SDimitry Andric   // do point look up for child node by call site alone.
46*d409305fSDimitry Andric   // Retrieve the child node with max count for indirect call
47e8d8bef9SDimitry Andric   ContextTrieNode *ChildNodeRet = nullptr;
48*d409305fSDimitry Andric   uint64_t MaxCalleeSamples = 0;
49e8d8bef9SDimitry Andric   for (auto &It : AllChildContext) {
50e8d8bef9SDimitry Andric     ContextTrieNode &ChildNode = It.second;
51*d409305fSDimitry Andric     if (ChildNode.CallSiteLoc != CallSite)
52*d409305fSDimitry Andric       continue;
53*d409305fSDimitry Andric     FunctionSamples *Samples = ChildNode.getFunctionSamples();
54*d409305fSDimitry Andric     if (!Samples)
55*d409305fSDimitry Andric       continue;
56*d409305fSDimitry Andric     if (Samples->getTotalSamples() > MaxCalleeSamples) {
57e8d8bef9SDimitry Andric       ChildNodeRet = &ChildNode;
58*d409305fSDimitry Andric       MaxCalleeSamples = Samples->getTotalSamples();
59e8d8bef9SDimitry Andric     }
60e8d8bef9SDimitry Andric   }
61e8d8bef9SDimitry Andric 
62e8d8bef9SDimitry Andric   return ChildNodeRet;
63e8d8bef9SDimitry Andric }
64e8d8bef9SDimitry Andric 
65e8d8bef9SDimitry Andric ContextTrieNode &ContextTrieNode::moveToChildContext(
66e8d8bef9SDimitry Andric     const LineLocation &CallSite, ContextTrieNode &&NodeToMove,
67e8d8bef9SDimitry Andric     StringRef ContextStrToRemove, bool DeleteNode) {
68e8d8bef9SDimitry Andric   uint32_t Hash = nodeHash(NodeToMove.getFuncName(), CallSite);
69e8d8bef9SDimitry Andric   assert(!AllChildContext.count(Hash) && "Node to remove must exist");
70e8d8bef9SDimitry Andric   LineLocation OldCallSite = NodeToMove.CallSiteLoc;
71e8d8bef9SDimitry Andric   ContextTrieNode &OldParentContext = *NodeToMove.getParentContext();
72e8d8bef9SDimitry Andric   AllChildContext[Hash] = NodeToMove;
73e8d8bef9SDimitry Andric   ContextTrieNode &NewNode = AllChildContext[Hash];
74e8d8bef9SDimitry Andric   NewNode.CallSiteLoc = CallSite;
75e8d8bef9SDimitry Andric 
76e8d8bef9SDimitry Andric   // Walk through nodes in the moved the subtree, and update
77e8d8bef9SDimitry Andric   // FunctionSamples' context as for the context promotion.
78e8d8bef9SDimitry Andric   // We also need to set new parant link for all children.
79e8d8bef9SDimitry Andric   std::queue<ContextTrieNode *> NodeToUpdate;
80e8d8bef9SDimitry Andric   NewNode.setParentContext(this);
81e8d8bef9SDimitry Andric   NodeToUpdate.push(&NewNode);
82e8d8bef9SDimitry Andric 
83e8d8bef9SDimitry Andric   while (!NodeToUpdate.empty()) {
84e8d8bef9SDimitry Andric     ContextTrieNode *Node = NodeToUpdate.front();
85e8d8bef9SDimitry Andric     NodeToUpdate.pop();
86e8d8bef9SDimitry Andric     FunctionSamples *FSamples = Node->getFunctionSamples();
87e8d8bef9SDimitry Andric 
88e8d8bef9SDimitry Andric     if (FSamples) {
89e8d8bef9SDimitry Andric       FSamples->getContext().promoteOnPath(ContextStrToRemove);
90e8d8bef9SDimitry Andric       FSamples->getContext().setState(SyntheticContext);
91e8d8bef9SDimitry Andric       LLVM_DEBUG(dbgs() << "  Context promoted to: " << FSamples->getContext()
92e8d8bef9SDimitry Andric                         << "\n");
93e8d8bef9SDimitry Andric     }
94e8d8bef9SDimitry Andric 
95e8d8bef9SDimitry Andric     for (auto &It : Node->getAllChildContext()) {
96e8d8bef9SDimitry Andric       ContextTrieNode *ChildNode = &It.second;
97e8d8bef9SDimitry Andric       ChildNode->setParentContext(Node);
98e8d8bef9SDimitry Andric       NodeToUpdate.push(ChildNode);
99e8d8bef9SDimitry Andric     }
100e8d8bef9SDimitry Andric   }
101e8d8bef9SDimitry Andric 
102e8d8bef9SDimitry Andric   // Original context no longer needed, destroy if requested.
103e8d8bef9SDimitry Andric   if (DeleteNode)
104e8d8bef9SDimitry Andric     OldParentContext.removeChildContext(OldCallSite, NewNode.getFuncName());
105e8d8bef9SDimitry Andric 
106e8d8bef9SDimitry Andric   return NewNode;
107e8d8bef9SDimitry Andric }
108e8d8bef9SDimitry Andric 
109e8d8bef9SDimitry Andric void ContextTrieNode::removeChildContext(const LineLocation &CallSite,
110e8d8bef9SDimitry Andric                                          StringRef CalleeName) {
111e8d8bef9SDimitry Andric   uint32_t Hash = nodeHash(CalleeName, CallSite);
112e8d8bef9SDimitry Andric   // Note this essentially calls dtor and destroys that child context
113e8d8bef9SDimitry Andric   AllChildContext.erase(Hash);
114e8d8bef9SDimitry Andric }
115e8d8bef9SDimitry Andric 
116e8d8bef9SDimitry Andric std::map<uint32_t, ContextTrieNode> &ContextTrieNode::getAllChildContext() {
117e8d8bef9SDimitry Andric   return AllChildContext;
118e8d8bef9SDimitry Andric }
119e8d8bef9SDimitry Andric 
120e8d8bef9SDimitry Andric const StringRef ContextTrieNode::getFuncName() const { return FuncName; }
121e8d8bef9SDimitry Andric 
122e8d8bef9SDimitry Andric FunctionSamples *ContextTrieNode::getFunctionSamples() const {
123e8d8bef9SDimitry Andric   return FuncSamples;
124e8d8bef9SDimitry Andric }
125e8d8bef9SDimitry Andric 
126e8d8bef9SDimitry Andric void ContextTrieNode::setFunctionSamples(FunctionSamples *FSamples) {
127e8d8bef9SDimitry Andric   FuncSamples = FSamples;
128e8d8bef9SDimitry Andric }
129e8d8bef9SDimitry Andric 
130e8d8bef9SDimitry Andric LineLocation ContextTrieNode::getCallSiteLoc() const { return CallSiteLoc; }
131e8d8bef9SDimitry Andric 
132e8d8bef9SDimitry Andric ContextTrieNode *ContextTrieNode::getParentContext() const {
133e8d8bef9SDimitry Andric   return ParentContext;
134e8d8bef9SDimitry Andric }
135e8d8bef9SDimitry Andric 
136e8d8bef9SDimitry Andric void ContextTrieNode::setParentContext(ContextTrieNode *Parent) {
137e8d8bef9SDimitry Andric   ParentContext = Parent;
138e8d8bef9SDimitry Andric }
139e8d8bef9SDimitry Andric 
140e8d8bef9SDimitry Andric void ContextTrieNode::dump() {
141e8d8bef9SDimitry Andric   dbgs() << "Node: " << FuncName << "\n"
142e8d8bef9SDimitry Andric          << "  Callsite: " << CallSiteLoc << "\n"
143e8d8bef9SDimitry Andric          << "  Children:\n";
144e8d8bef9SDimitry Andric 
145e8d8bef9SDimitry Andric   for (auto &It : AllChildContext) {
146e8d8bef9SDimitry Andric     dbgs() << "    Node: " << It.second.getFuncName() << "\n";
147e8d8bef9SDimitry Andric   }
148e8d8bef9SDimitry Andric }
149e8d8bef9SDimitry Andric 
150e8d8bef9SDimitry Andric uint32_t ContextTrieNode::nodeHash(StringRef ChildName,
151e8d8bef9SDimitry Andric                                    const LineLocation &Callsite) {
152e8d8bef9SDimitry Andric   // We still use child's name for child hash, this is
153e8d8bef9SDimitry Andric   // because for children of root node, we don't have
154e8d8bef9SDimitry Andric   // different line/discriminator, and we'll rely on name
155e8d8bef9SDimitry Andric   // to differentiate children.
156e8d8bef9SDimitry Andric   uint32_t NameHash = std::hash<std::string>{}(ChildName.str());
157e8d8bef9SDimitry Andric   uint32_t LocId = (Callsite.LineOffset << 16) | Callsite.Discriminator;
158e8d8bef9SDimitry Andric   return NameHash + (LocId << 5) + LocId;
159e8d8bef9SDimitry Andric }
160e8d8bef9SDimitry Andric 
161e8d8bef9SDimitry Andric ContextTrieNode *ContextTrieNode::getOrCreateChildContext(
162e8d8bef9SDimitry Andric     const LineLocation &CallSite, StringRef CalleeName, bool AllowCreate) {
163e8d8bef9SDimitry Andric   uint32_t Hash = nodeHash(CalleeName, CallSite);
164e8d8bef9SDimitry Andric   auto It = AllChildContext.find(Hash);
165e8d8bef9SDimitry Andric   if (It != AllChildContext.end()) {
166e8d8bef9SDimitry Andric     assert(It->second.getFuncName() == CalleeName &&
167e8d8bef9SDimitry Andric            "Hash collision for child context node");
168e8d8bef9SDimitry Andric     return &It->second;
169e8d8bef9SDimitry Andric   }
170e8d8bef9SDimitry Andric 
171e8d8bef9SDimitry Andric   if (!AllowCreate)
172e8d8bef9SDimitry Andric     return nullptr;
173e8d8bef9SDimitry Andric 
174e8d8bef9SDimitry Andric   AllChildContext[Hash] = ContextTrieNode(this, CalleeName, nullptr, CallSite);
175e8d8bef9SDimitry Andric   return &AllChildContext[Hash];
176e8d8bef9SDimitry Andric }
177e8d8bef9SDimitry Andric 
178e8d8bef9SDimitry Andric // Profiler tracker than manages profiles and its associated context
179e8d8bef9SDimitry Andric SampleContextTracker::SampleContextTracker(
180e8d8bef9SDimitry Andric     StringMap<FunctionSamples> &Profiles) {
181e8d8bef9SDimitry Andric   for (auto &FuncSample : Profiles) {
182e8d8bef9SDimitry Andric     FunctionSamples *FSamples = &FuncSample.second;
183e8d8bef9SDimitry Andric     SampleContext Context(FuncSample.first(), RawContext);
184e8d8bef9SDimitry Andric     LLVM_DEBUG(dbgs() << "Tracking Context for function: " << Context << "\n");
185e8d8bef9SDimitry Andric     if (!Context.isBaseContext())
186*d409305fSDimitry Andric       FuncToCtxtProfileSet[Context.getNameWithoutContext()].insert(FSamples);
187e8d8bef9SDimitry Andric     ContextTrieNode *NewNode = getOrCreateContextPath(Context, true);
188e8d8bef9SDimitry Andric     assert(!NewNode->getFunctionSamples() &&
189e8d8bef9SDimitry Andric            "New node can't have sample profile");
190e8d8bef9SDimitry Andric     NewNode->setFunctionSamples(FSamples);
191e8d8bef9SDimitry Andric   }
192e8d8bef9SDimitry Andric }
193e8d8bef9SDimitry Andric 
194e8d8bef9SDimitry Andric FunctionSamples *
195e8d8bef9SDimitry Andric SampleContextTracker::getCalleeContextSamplesFor(const CallBase &Inst,
196e8d8bef9SDimitry Andric                                                  StringRef CalleeName) {
197e8d8bef9SDimitry Andric   LLVM_DEBUG(dbgs() << "Getting callee context for instr: " << Inst << "\n");
198e8d8bef9SDimitry Andric   DILocation *DIL = Inst.getDebugLoc();
199e8d8bef9SDimitry Andric   if (!DIL)
200e8d8bef9SDimitry Andric     return nullptr;
201e8d8bef9SDimitry Andric 
202*d409305fSDimitry Andric   // For indirect call, CalleeName will be empty, in which case the context
203*d409305fSDimitry Andric   // profile for callee with largest total samples will be returned.
204e8d8bef9SDimitry Andric   ContextTrieNode *CalleeContext = getCalleeContextFor(DIL, CalleeName);
205e8d8bef9SDimitry Andric   if (CalleeContext) {
206e8d8bef9SDimitry Andric     FunctionSamples *FSamples = CalleeContext->getFunctionSamples();
207e8d8bef9SDimitry Andric     LLVM_DEBUG(if (FSamples) {
208e8d8bef9SDimitry Andric       dbgs() << "  Callee context found: " << FSamples->getContext() << "\n";
209e8d8bef9SDimitry Andric     });
210e8d8bef9SDimitry Andric     return FSamples;
211e8d8bef9SDimitry Andric   }
212e8d8bef9SDimitry Andric 
213e8d8bef9SDimitry Andric   return nullptr;
214e8d8bef9SDimitry Andric }
215e8d8bef9SDimitry Andric 
216*d409305fSDimitry Andric std::vector<const FunctionSamples *>
217*d409305fSDimitry Andric SampleContextTracker::getIndirectCalleeContextSamplesFor(
218*d409305fSDimitry Andric     const DILocation *DIL) {
219*d409305fSDimitry Andric   std::vector<const FunctionSamples *> R;
220*d409305fSDimitry Andric   if (!DIL)
221*d409305fSDimitry Andric     return R;
222*d409305fSDimitry Andric 
223*d409305fSDimitry Andric   ContextTrieNode *CallerNode = getContextFor(DIL);
224*d409305fSDimitry Andric   LineLocation CallSite = FunctionSamples::getCallSiteIdentifier(DIL);
225*d409305fSDimitry Andric   for (auto &It : CallerNode->getAllChildContext()) {
226*d409305fSDimitry Andric     ContextTrieNode &ChildNode = It.second;
227*d409305fSDimitry Andric     if (ChildNode.getCallSiteLoc() != CallSite)
228*d409305fSDimitry Andric       continue;
229*d409305fSDimitry Andric     if (FunctionSamples *CalleeSamples = ChildNode.getFunctionSamples())
230*d409305fSDimitry Andric       R.push_back(CalleeSamples);
231*d409305fSDimitry Andric   }
232*d409305fSDimitry Andric 
233*d409305fSDimitry Andric   return R;
234*d409305fSDimitry Andric }
235*d409305fSDimitry Andric 
236e8d8bef9SDimitry Andric FunctionSamples *
237e8d8bef9SDimitry Andric SampleContextTracker::getContextSamplesFor(const DILocation *DIL) {
238e8d8bef9SDimitry Andric   assert(DIL && "Expect non-null location");
239e8d8bef9SDimitry Andric 
240e8d8bef9SDimitry Andric   ContextTrieNode *ContextNode = getContextFor(DIL);
241e8d8bef9SDimitry Andric   if (!ContextNode)
242e8d8bef9SDimitry Andric     return nullptr;
243e8d8bef9SDimitry Andric 
244e8d8bef9SDimitry Andric   // We may have inlined callees during pre-LTO compilation, in which case
245e8d8bef9SDimitry Andric   // we need to rely on the inline stack from !dbg to mark context profile
246e8d8bef9SDimitry Andric   // as inlined, instead of `MarkContextSamplesInlined` during inlining.
247e8d8bef9SDimitry Andric   // Sample profile loader walks through all instructions to get profile,
248e8d8bef9SDimitry Andric   // which calls this function. So once that is done, all previously inlined
249e8d8bef9SDimitry Andric   // context profile should be marked properly.
250e8d8bef9SDimitry Andric   FunctionSamples *Samples = ContextNode->getFunctionSamples();
251e8d8bef9SDimitry Andric   if (Samples && ContextNode->getParentContext() != &RootContext)
252e8d8bef9SDimitry Andric     Samples->getContext().setState(InlinedContext);
253e8d8bef9SDimitry Andric 
254e8d8bef9SDimitry Andric   return Samples;
255e8d8bef9SDimitry Andric }
256e8d8bef9SDimitry Andric 
257e8d8bef9SDimitry Andric FunctionSamples *
258e8d8bef9SDimitry Andric SampleContextTracker::getContextSamplesFor(const SampleContext &Context) {
259e8d8bef9SDimitry Andric   ContextTrieNode *Node = getContextFor(Context);
260e8d8bef9SDimitry Andric   if (!Node)
261e8d8bef9SDimitry Andric     return nullptr;
262e8d8bef9SDimitry Andric 
263e8d8bef9SDimitry Andric   return Node->getFunctionSamples();
264e8d8bef9SDimitry Andric }
265e8d8bef9SDimitry Andric 
266*d409305fSDimitry Andric SampleContextTracker::ContextSamplesTy &
267*d409305fSDimitry Andric SampleContextTracker::getAllContextSamplesFor(const Function &Func) {
268*d409305fSDimitry Andric   StringRef CanonName = FunctionSamples::getCanonicalFnName(Func);
269*d409305fSDimitry Andric   return FuncToCtxtProfileSet[CanonName];
270*d409305fSDimitry Andric }
271*d409305fSDimitry Andric 
272*d409305fSDimitry Andric SampleContextTracker::ContextSamplesTy &
273*d409305fSDimitry Andric SampleContextTracker::getAllContextSamplesFor(StringRef Name) {
274*d409305fSDimitry Andric   return FuncToCtxtProfileSet[Name];
275*d409305fSDimitry Andric }
276*d409305fSDimitry Andric 
277e8d8bef9SDimitry Andric FunctionSamples *SampleContextTracker::getBaseSamplesFor(const Function &Func,
278e8d8bef9SDimitry Andric                                                          bool MergeContext) {
279e8d8bef9SDimitry Andric   StringRef CanonName = FunctionSamples::getCanonicalFnName(Func);
280e8d8bef9SDimitry Andric   return getBaseSamplesFor(CanonName, MergeContext);
281e8d8bef9SDimitry Andric }
282e8d8bef9SDimitry Andric 
283e8d8bef9SDimitry Andric FunctionSamples *SampleContextTracker::getBaseSamplesFor(StringRef Name,
284e8d8bef9SDimitry Andric                                                          bool MergeContext) {
285e8d8bef9SDimitry Andric   LLVM_DEBUG(dbgs() << "Getting base profile for function: " << Name << "\n");
286e8d8bef9SDimitry Andric   // Base profile is top-level node (child of root node), so try to retrieve
287e8d8bef9SDimitry Andric   // existing top-level node for given function first. If it exists, it could be
288e8d8bef9SDimitry Andric   // that we've merged base profile before, or there's actually context-less
289e8d8bef9SDimitry Andric   // profile from the input (e.g. due to unreliable stack walking).
290e8d8bef9SDimitry Andric   ContextTrieNode *Node = getTopLevelContextNode(Name);
291e8d8bef9SDimitry Andric   if (MergeContext) {
292e8d8bef9SDimitry Andric     LLVM_DEBUG(dbgs() << "  Merging context profile into base profile: " << Name
293e8d8bef9SDimitry Andric                       << "\n");
294e8d8bef9SDimitry Andric 
295e8d8bef9SDimitry Andric     // We have profile for function under different contexts,
296e8d8bef9SDimitry Andric     // create synthetic base profile and merge context profiles
297e8d8bef9SDimitry Andric     // into base profile.
298e8d8bef9SDimitry Andric     for (auto *CSamples : FuncToCtxtProfileSet[Name]) {
299e8d8bef9SDimitry Andric       SampleContext &Context = CSamples->getContext();
300e8d8bef9SDimitry Andric       ContextTrieNode *FromNode = getContextFor(Context);
301e8d8bef9SDimitry Andric       if (FromNode == Node)
302e8d8bef9SDimitry Andric         continue;
303e8d8bef9SDimitry Andric 
304e8d8bef9SDimitry Andric       // Skip inlined context profile and also don't re-merge any context
305e8d8bef9SDimitry Andric       if (Context.hasState(InlinedContext) || Context.hasState(MergedContext))
306e8d8bef9SDimitry Andric         continue;
307e8d8bef9SDimitry Andric 
308e8d8bef9SDimitry Andric       ContextTrieNode &ToNode = promoteMergeContextSamplesTree(*FromNode);
309e8d8bef9SDimitry Andric       assert((!Node || Node == &ToNode) && "Expect only one base profile");
310e8d8bef9SDimitry Andric       Node = &ToNode;
311e8d8bef9SDimitry Andric     }
312e8d8bef9SDimitry Andric   }
313e8d8bef9SDimitry Andric 
314e8d8bef9SDimitry Andric   // Still no profile even after merge/promotion (if allowed)
315e8d8bef9SDimitry Andric   if (!Node)
316e8d8bef9SDimitry Andric     return nullptr;
317e8d8bef9SDimitry Andric 
318e8d8bef9SDimitry Andric   return Node->getFunctionSamples();
319e8d8bef9SDimitry Andric }
320e8d8bef9SDimitry Andric 
321e8d8bef9SDimitry Andric void SampleContextTracker::markContextSamplesInlined(
322e8d8bef9SDimitry Andric     const FunctionSamples *InlinedSamples) {
323e8d8bef9SDimitry Andric   assert(InlinedSamples && "Expect non-null inlined samples");
324e8d8bef9SDimitry Andric   LLVM_DEBUG(dbgs() << "Marking context profile as inlined: "
325e8d8bef9SDimitry Andric                     << InlinedSamples->getContext() << "\n");
326e8d8bef9SDimitry Andric   InlinedSamples->getContext().setState(InlinedContext);
327e8d8bef9SDimitry Andric }
328e8d8bef9SDimitry Andric 
329e8d8bef9SDimitry Andric void SampleContextTracker::promoteMergeContextSamplesTree(
330e8d8bef9SDimitry Andric     const Instruction &Inst, StringRef CalleeName) {
331e8d8bef9SDimitry Andric   LLVM_DEBUG(dbgs() << "Promoting and merging context tree for instr: \n"
332e8d8bef9SDimitry Andric                     << Inst << "\n");
333e8d8bef9SDimitry Andric   // Get the caller context for the call instruction, we don't use callee
334e8d8bef9SDimitry Andric   // name from call because there can be context from indirect calls too.
335e8d8bef9SDimitry Andric   DILocation *DIL = Inst.getDebugLoc();
336e8d8bef9SDimitry Andric   ContextTrieNode *CallerNode = getContextFor(DIL);
337e8d8bef9SDimitry Andric   if (!CallerNode)
338e8d8bef9SDimitry Andric     return;
339e8d8bef9SDimitry Andric 
340e8d8bef9SDimitry Andric   // Get the context that needs to be promoted
341*d409305fSDimitry Andric   LineLocation CallSite = FunctionSamples::getCallSiteIdentifier(DIL);
342*d409305fSDimitry Andric   // For indirect call, CalleeName will be empty, in which case we need to
343*d409305fSDimitry Andric   // promote all non-inlined child context profiles.
344*d409305fSDimitry Andric   if (CalleeName.empty()) {
345*d409305fSDimitry Andric     for (auto &It : CallerNode->getAllChildContext()) {
346*d409305fSDimitry Andric       ContextTrieNode *NodeToPromo = &It.second;
347*d409305fSDimitry Andric       if (CallSite != NodeToPromo->getCallSiteLoc())
348*d409305fSDimitry Andric         continue;
349*d409305fSDimitry Andric       FunctionSamples *FromSamples = NodeToPromo->getFunctionSamples();
350*d409305fSDimitry Andric       if (FromSamples && FromSamples->getContext().hasState(InlinedContext))
351*d409305fSDimitry Andric         continue;
352*d409305fSDimitry Andric       promoteMergeContextSamplesTree(*NodeToPromo);
353*d409305fSDimitry Andric     }
354*d409305fSDimitry Andric     return;
355*d409305fSDimitry Andric   }
356*d409305fSDimitry Andric 
357*d409305fSDimitry Andric   // Get the context for the given callee that needs to be promoted
358e8d8bef9SDimitry Andric   ContextTrieNode *NodeToPromo =
359e8d8bef9SDimitry Andric       CallerNode->getChildContext(CallSite, CalleeName);
360e8d8bef9SDimitry Andric   if (!NodeToPromo)
361e8d8bef9SDimitry Andric     return;
362e8d8bef9SDimitry Andric 
363e8d8bef9SDimitry Andric   promoteMergeContextSamplesTree(*NodeToPromo);
364e8d8bef9SDimitry Andric }
365e8d8bef9SDimitry Andric 
366e8d8bef9SDimitry Andric ContextTrieNode &SampleContextTracker::promoteMergeContextSamplesTree(
367e8d8bef9SDimitry Andric     ContextTrieNode &NodeToPromo) {
368e8d8bef9SDimitry Andric   // Promote the input node to be directly under root. This can happen
369e8d8bef9SDimitry Andric   // when we decided to not inline a function under context represented
370e8d8bef9SDimitry Andric   // by the input node. The promote and merge is then needed to reflect
371e8d8bef9SDimitry Andric   // the context profile in the base (context-less) profile.
372e8d8bef9SDimitry Andric   FunctionSamples *FromSamples = NodeToPromo.getFunctionSamples();
373e8d8bef9SDimitry Andric   assert(FromSamples && "Shouldn't promote a context without profile");
374e8d8bef9SDimitry Andric   LLVM_DEBUG(dbgs() << "  Found context tree root to promote: "
375e8d8bef9SDimitry Andric                     << FromSamples->getContext() << "\n");
376e8d8bef9SDimitry Andric 
377*d409305fSDimitry Andric   assert(!FromSamples->getContext().hasState(InlinedContext) &&
378*d409305fSDimitry Andric          "Shouldn't promote inlined context profile");
379e8d8bef9SDimitry Andric   StringRef ContextStrToRemove = FromSamples->getContext().getCallingContext();
380e8d8bef9SDimitry Andric   return promoteMergeContextSamplesTree(NodeToPromo, RootContext,
381e8d8bef9SDimitry Andric                                         ContextStrToRemove);
382e8d8bef9SDimitry Andric }
383e8d8bef9SDimitry Andric 
384e8d8bef9SDimitry Andric void SampleContextTracker::dump() {
385e8d8bef9SDimitry Andric   dbgs() << "Context Profile Tree:\n";
386e8d8bef9SDimitry Andric   std::queue<ContextTrieNode *> NodeQueue;
387e8d8bef9SDimitry Andric   NodeQueue.push(&RootContext);
388e8d8bef9SDimitry Andric 
389e8d8bef9SDimitry Andric   while (!NodeQueue.empty()) {
390e8d8bef9SDimitry Andric     ContextTrieNode *Node = NodeQueue.front();
391e8d8bef9SDimitry Andric     NodeQueue.pop();
392e8d8bef9SDimitry Andric     Node->dump();
393e8d8bef9SDimitry Andric 
394e8d8bef9SDimitry Andric     for (auto &It : Node->getAllChildContext()) {
395e8d8bef9SDimitry Andric       ContextTrieNode *ChildNode = &It.second;
396e8d8bef9SDimitry Andric       NodeQueue.push(ChildNode);
397e8d8bef9SDimitry Andric     }
398e8d8bef9SDimitry Andric   }
399e8d8bef9SDimitry Andric }
400e8d8bef9SDimitry Andric 
401e8d8bef9SDimitry Andric ContextTrieNode *
402e8d8bef9SDimitry Andric SampleContextTracker::getContextFor(const SampleContext &Context) {
403e8d8bef9SDimitry Andric   return getOrCreateContextPath(Context, false);
404e8d8bef9SDimitry Andric }
405e8d8bef9SDimitry Andric 
406e8d8bef9SDimitry Andric ContextTrieNode *
407e8d8bef9SDimitry Andric SampleContextTracker::getCalleeContextFor(const DILocation *DIL,
408e8d8bef9SDimitry Andric                                           StringRef CalleeName) {
409e8d8bef9SDimitry Andric   assert(DIL && "Expect non-null location");
410e8d8bef9SDimitry Andric 
411e8d8bef9SDimitry Andric   ContextTrieNode *CallContext = getContextFor(DIL);
412e8d8bef9SDimitry Andric   if (!CallContext)
413e8d8bef9SDimitry Andric     return nullptr;
414e8d8bef9SDimitry Andric 
415*d409305fSDimitry Andric   // When CalleeName is empty, the child context profile with max
416*d409305fSDimitry Andric   // total samples will be returned.
417e8d8bef9SDimitry Andric   return CallContext->getChildContext(
418*d409305fSDimitry Andric       FunctionSamples::getCallSiteIdentifier(DIL), CalleeName);
419e8d8bef9SDimitry Andric }
420e8d8bef9SDimitry Andric 
421e8d8bef9SDimitry Andric ContextTrieNode *SampleContextTracker::getContextFor(const DILocation *DIL) {
422e8d8bef9SDimitry Andric   assert(DIL && "Expect non-null location");
423e8d8bef9SDimitry Andric   SmallVector<std::pair<LineLocation, StringRef>, 10> S;
424e8d8bef9SDimitry Andric 
425e8d8bef9SDimitry Andric   // Use C++ linkage name if possible.
426e8d8bef9SDimitry Andric   const DILocation *PrevDIL = DIL;
427e8d8bef9SDimitry Andric   for (DIL = DIL->getInlinedAt(); DIL; DIL = DIL->getInlinedAt()) {
428e8d8bef9SDimitry Andric     StringRef Name = PrevDIL->getScope()->getSubprogram()->getLinkageName();
429e8d8bef9SDimitry Andric     if (Name.empty())
430e8d8bef9SDimitry Andric       Name = PrevDIL->getScope()->getSubprogram()->getName();
431e8d8bef9SDimitry Andric     S.push_back(
432*d409305fSDimitry Andric         std::make_pair(FunctionSamples::getCallSiteIdentifier(DIL),
433*d409305fSDimitry Andric                        PrevDIL->getScope()->getSubprogram()->getLinkageName()));
434e8d8bef9SDimitry Andric     PrevDIL = DIL;
435e8d8bef9SDimitry Andric   }
436e8d8bef9SDimitry Andric 
437e8d8bef9SDimitry Andric   // Push root node, note that root node like main may only
438e8d8bef9SDimitry Andric   // a name, but not linkage name.
439e8d8bef9SDimitry Andric   StringRef RootName = PrevDIL->getScope()->getSubprogram()->getLinkageName();
440e8d8bef9SDimitry Andric   if (RootName.empty())
441e8d8bef9SDimitry Andric     RootName = PrevDIL->getScope()->getSubprogram()->getName();
442e8d8bef9SDimitry Andric   S.push_back(std::make_pair(LineLocation(0, 0), RootName));
443e8d8bef9SDimitry Andric 
444e8d8bef9SDimitry Andric   ContextTrieNode *ContextNode = &RootContext;
445e8d8bef9SDimitry Andric   int I = S.size();
446e8d8bef9SDimitry Andric   while (--I >= 0 && ContextNode) {
447e8d8bef9SDimitry Andric     LineLocation &CallSite = S[I].first;
448e8d8bef9SDimitry Andric     StringRef &CalleeName = S[I].second;
449e8d8bef9SDimitry Andric     ContextNode = ContextNode->getChildContext(CallSite, CalleeName);
450e8d8bef9SDimitry Andric   }
451e8d8bef9SDimitry Andric 
452e8d8bef9SDimitry Andric   if (I < 0)
453e8d8bef9SDimitry Andric     return ContextNode;
454e8d8bef9SDimitry Andric 
455e8d8bef9SDimitry Andric   return nullptr;
456e8d8bef9SDimitry Andric }
457e8d8bef9SDimitry Andric 
458e8d8bef9SDimitry Andric ContextTrieNode *
459e8d8bef9SDimitry Andric SampleContextTracker::getOrCreateContextPath(const SampleContext &Context,
460e8d8bef9SDimitry Andric                                              bool AllowCreate) {
461e8d8bef9SDimitry Andric   ContextTrieNode *ContextNode = &RootContext;
462e8d8bef9SDimitry Andric   StringRef ContextRemain = Context;
463e8d8bef9SDimitry Andric   StringRef ChildContext;
464e8d8bef9SDimitry Andric   StringRef CalleeName;
465e8d8bef9SDimitry Andric   LineLocation CallSiteLoc(0, 0);
466e8d8bef9SDimitry Andric 
467e8d8bef9SDimitry Andric   while (ContextNode && !ContextRemain.empty()) {
468e8d8bef9SDimitry Andric     auto ContextSplit = SampleContext::splitContextString(ContextRemain);
469e8d8bef9SDimitry Andric     ChildContext = ContextSplit.first;
470e8d8bef9SDimitry Andric     ContextRemain = ContextSplit.second;
471e8d8bef9SDimitry Andric     LineLocation NextCallSiteLoc(0, 0);
472e8d8bef9SDimitry Andric     SampleContext::decodeContextString(ChildContext, CalleeName,
473e8d8bef9SDimitry Andric                                        NextCallSiteLoc);
474e8d8bef9SDimitry Andric 
475e8d8bef9SDimitry Andric     // Create child node at parent line/disc location
476e8d8bef9SDimitry Andric     if (AllowCreate) {
477e8d8bef9SDimitry Andric       ContextNode =
478e8d8bef9SDimitry Andric           ContextNode->getOrCreateChildContext(CallSiteLoc, CalleeName);
479e8d8bef9SDimitry Andric     } else {
480e8d8bef9SDimitry Andric       ContextNode = ContextNode->getChildContext(CallSiteLoc, CalleeName);
481e8d8bef9SDimitry Andric     }
482e8d8bef9SDimitry Andric     CallSiteLoc = NextCallSiteLoc;
483e8d8bef9SDimitry Andric   }
484e8d8bef9SDimitry Andric 
485e8d8bef9SDimitry Andric   assert((!AllowCreate || ContextNode) &&
486e8d8bef9SDimitry Andric          "Node must exist if creation is allowed");
487e8d8bef9SDimitry Andric   return ContextNode;
488e8d8bef9SDimitry Andric }
489e8d8bef9SDimitry Andric 
490e8d8bef9SDimitry Andric ContextTrieNode *SampleContextTracker::getTopLevelContextNode(StringRef FName) {
491e8d8bef9SDimitry Andric   return RootContext.getChildContext(LineLocation(0, 0), FName);
492e8d8bef9SDimitry Andric }
493e8d8bef9SDimitry Andric 
494e8d8bef9SDimitry Andric ContextTrieNode &SampleContextTracker::addTopLevelContextNode(StringRef FName) {
495e8d8bef9SDimitry Andric   assert(!getTopLevelContextNode(FName) && "Node to add must not exist");
496e8d8bef9SDimitry Andric   return *RootContext.getOrCreateChildContext(LineLocation(0, 0), FName);
497e8d8bef9SDimitry Andric }
498e8d8bef9SDimitry Andric 
499e8d8bef9SDimitry Andric void SampleContextTracker::mergeContextNode(ContextTrieNode &FromNode,
500e8d8bef9SDimitry Andric                                             ContextTrieNode &ToNode,
501e8d8bef9SDimitry Andric                                             StringRef ContextStrToRemove) {
502e8d8bef9SDimitry Andric   FunctionSamples *FromSamples = FromNode.getFunctionSamples();
503e8d8bef9SDimitry Andric   FunctionSamples *ToSamples = ToNode.getFunctionSamples();
504e8d8bef9SDimitry Andric   if (FromSamples && ToSamples) {
505e8d8bef9SDimitry Andric     // Merge/duplicate FromSamples into ToSamples
506e8d8bef9SDimitry Andric     ToSamples->merge(*FromSamples);
507e8d8bef9SDimitry Andric     ToSamples->getContext().setState(SyntheticContext);
508e8d8bef9SDimitry Andric     FromSamples->getContext().setState(MergedContext);
509e8d8bef9SDimitry Andric   } else if (FromSamples) {
510e8d8bef9SDimitry Andric     // Transfer FromSamples from FromNode to ToNode
511e8d8bef9SDimitry Andric     ToNode.setFunctionSamples(FromSamples);
512e8d8bef9SDimitry Andric     FromSamples->getContext().setState(SyntheticContext);
513e8d8bef9SDimitry Andric     FromSamples->getContext().promoteOnPath(ContextStrToRemove);
514e8d8bef9SDimitry Andric     FromNode.setFunctionSamples(nullptr);
515e8d8bef9SDimitry Andric   }
516e8d8bef9SDimitry Andric }
517e8d8bef9SDimitry Andric 
518e8d8bef9SDimitry Andric ContextTrieNode &SampleContextTracker::promoteMergeContextSamplesTree(
519e8d8bef9SDimitry Andric     ContextTrieNode &FromNode, ContextTrieNode &ToNodeParent,
520e8d8bef9SDimitry Andric     StringRef ContextStrToRemove) {
521e8d8bef9SDimitry Andric   assert(!ContextStrToRemove.empty() && "Context to remove can't be empty");
522e8d8bef9SDimitry Andric 
523e8d8bef9SDimitry Andric   // Ignore call site location if destination is top level under root
524e8d8bef9SDimitry Andric   LineLocation NewCallSiteLoc = LineLocation(0, 0);
525e8d8bef9SDimitry Andric   LineLocation OldCallSiteLoc = FromNode.getCallSiteLoc();
526e8d8bef9SDimitry Andric   ContextTrieNode &FromNodeParent = *FromNode.getParentContext();
527e8d8bef9SDimitry Andric   ContextTrieNode *ToNode = nullptr;
528e8d8bef9SDimitry Andric   bool MoveToRoot = (&ToNodeParent == &RootContext);
529e8d8bef9SDimitry Andric   if (!MoveToRoot) {
530e8d8bef9SDimitry Andric     NewCallSiteLoc = OldCallSiteLoc;
531e8d8bef9SDimitry Andric   }
532e8d8bef9SDimitry Andric 
533e8d8bef9SDimitry Andric   // Locate destination node, create/move if not existing
534e8d8bef9SDimitry Andric   ToNode = ToNodeParent.getChildContext(NewCallSiteLoc, FromNode.getFuncName());
535e8d8bef9SDimitry Andric   if (!ToNode) {
536e8d8bef9SDimitry Andric     // Do not delete node to move from its parent here because
537e8d8bef9SDimitry Andric     // caller is iterating over children of that parent node.
538e8d8bef9SDimitry Andric     ToNode = &ToNodeParent.moveToChildContext(
539e8d8bef9SDimitry Andric         NewCallSiteLoc, std::move(FromNode), ContextStrToRemove, false);
540e8d8bef9SDimitry Andric   } else {
541e8d8bef9SDimitry Andric     // Destination node exists, merge samples for the context tree
542e8d8bef9SDimitry Andric     mergeContextNode(FromNode, *ToNode, ContextStrToRemove);
543e8d8bef9SDimitry Andric     LLVM_DEBUG(dbgs() << "  Context promoted and merged to: "
544e8d8bef9SDimitry Andric                       << ToNode->getFunctionSamples()->getContext() << "\n");
545e8d8bef9SDimitry Andric 
546e8d8bef9SDimitry Andric     // Recursively promote and merge children
547e8d8bef9SDimitry Andric     for (auto &It : FromNode.getAllChildContext()) {
548e8d8bef9SDimitry Andric       ContextTrieNode &FromChildNode = It.second;
549e8d8bef9SDimitry Andric       promoteMergeContextSamplesTree(FromChildNode, *ToNode,
550e8d8bef9SDimitry Andric                                      ContextStrToRemove);
551e8d8bef9SDimitry Andric     }
552e8d8bef9SDimitry Andric 
553e8d8bef9SDimitry Andric     // Remove children once they're all merged
554e8d8bef9SDimitry Andric     FromNode.getAllChildContext().clear();
555e8d8bef9SDimitry Andric   }
556e8d8bef9SDimitry Andric 
557e8d8bef9SDimitry Andric   // For root of subtree, remove itself from old parent too
558e8d8bef9SDimitry Andric   if (MoveToRoot)
559e8d8bef9SDimitry Andric     FromNodeParent.removeChildContext(OldCallSiteLoc, ToNode->getFuncName());
560e8d8bef9SDimitry Andric 
561e8d8bef9SDimitry Andric   return *ToNode;
562e8d8bef9SDimitry Andric }
563e8d8bef9SDimitry Andric 
564*d409305fSDimitry Andric // Replace call graph edges with dynamic call edges from the profile.
565*d409305fSDimitry Andric void SampleContextTracker::addCallGraphEdges(CallGraph &CG,
566*d409305fSDimitry Andric                                              StringMap<Function *> &SymbolMap) {
567*d409305fSDimitry Andric   // Add profile call edges to the call graph.
568*d409305fSDimitry Andric   std::queue<ContextTrieNode *> NodeQueue;
569*d409305fSDimitry Andric   NodeQueue.push(&RootContext);
570*d409305fSDimitry Andric   while (!NodeQueue.empty()) {
571*d409305fSDimitry Andric     ContextTrieNode *Node = NodeQueue.front();
572*d409305fSDimitry Andric     NodeQueue.pop();
573*d409305fSDimitry Andric     Function *F = SymbolMap.lookup(Node->getFuncName());
574*d409305fSDimitry Andric     for (auto &I : Node->getAllChildContext()) {
575*d409305fSDimitry Andric       ContextTrieNode *ChildNode = &I.second;
576*d409305fSDimitry Andric       NodeQueue.push(ChildNode);
577*d409305fSDimitry Andric       if (F && !F->isDeclaration()) {
578*d409305fSDimitry Andric         Function *Callee = SymbolMap.lookup(ChildNode->getFuncName());
579*d409305fSDimitry Andric         if (Callee && !Callee->isDeclaration())
580*d409305fSDimitry Andric           CG[F]->addCalledFunction(nullptr, CG[Callee]);
581*d409305fSDimitry Andric       }
582*d409305fSDimitry Andric     }
583*d409305fSDimitry Andric   }
584*d409305fSDimitry Andric }
585e8d8bef9SDimitry Andric } // namespace llvm
586