xref: /llvm-project/llvm/lib/Transforms/IPO/SampleContextTracker.cpp (revision ce03155a1bd02fc078f710b5497be4e382bbe5d9)
16b989a17SWenlei He //===- SampleContextTracker.cpp - Context-sensitive Profile Tracker -------===//
26b989a17SWenlei He //
36b989a17SWenlei He // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
46b989a17SWenlei He // See https://llvm.org/LICENSE.txt for license information.
56b989a17SWenlei He // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
66b989a17SWenlei He //
76b989a17SWenlei He //===----------------------------------------------------------------------===//
86b989a17SWenlei He //
96b989a17SWenlei He // This file implements the SampleContextTracker used by CSSPGO.
106b989a17SWenlei He //
116b989a17SWenlei He //===----------------------------------------------------------------------===//
126b989a17SWenlei He 
136b989a17SWenlei He #include "llvm/Transforms/IPO/SampleContextTracker.h"
146b989a17SWenlei He #include "llvm/ADT/StringRef.h"
156b989a17SWenlei He #include "llvm/IR/DebugInfoMetadata.h"
1601be9be2Sserge-sans-paille #include "llvm/IR/InstrTypes.h"
1701be9be2Sserge-sans-paille #include "llvm/IR/Instruction.h"
186b989a17SWenlei He #include "llvm/ProfileData/SampleProf.h"
196b989a17SWenlei He #include <map>
206b989a17SWenlei He #include <queue>
216b989a17SWenlei He #include <vector>
226b989a17SWenlei He 
236b989a17SWenlei He using namespace llvm;
246b989a17SWenlei He using namespace sampleprof;
256b989a17SWenlei He 
266b989a17SWenlei He #define DEBUG_TYPE "sample-context-tracker"
276b989a17SWenlei He 
286b989a17SWenlei He namespace llvm {
296b989a17SWenlei He 
306b989a17SWenlei He ContextTrieNode *ContextTrieNode::getChildContext(const LineLocation &CallSite,
31ef0e0adcSWilliam Junda Huang                                                   FunctionId CalleeName) {
326b989a17SWenlei He   if (CalleeName.empty())
336bae5973SWenlei He     return getHottestChildContext(CallSite);
346b989a17SWenlei He 
355740bb80SHongtao Yu   uint64_t Hash = FunctionSamples::getCallSiteHash(CalleeName, CallSite);
366b989a17SWenlei He   auto It = AllChildContext.find(Hash);
376b989a17SWenlei He   if (It != AllChildContext.end())
386b989a17SWenlei He     return &It->second;
396b989a17SWenlei He   return nullptr;
406b989a17SWenlei He }
416b989a17SWenlei He 
426b989a17SWenlei He ContextTrieNode *
436bae5973SWenlei He ContextTrieNode::getHottestChildContext(const LineLocation &CallSite) {
446b989a17SWenlei He   // CSFDO-TODO: This could be slow, change AllChildContext so we can
456b989a17SWenlei He   // do point look up for child node by call site alone.
466bae5973SWenlei He   // Retrieve the child node with max count for indirect call
476b989a17SWenlei He   ContextTrieNode *ChildNodeRet = nullptr;
486bae5973SWenlei He   uint64_t MaxCalleeSamples = 0;
496b989a17SWenlei He   for (auto &It : AllChildContext) {
506b989a17SWenlei He     ContextTrieNode &ChildNode = It.second;
516bae5973SWenlei He     if (ChildNode.CallSiteLoc != CallSite)
526bae5973SWenlei He       continue;
536bae5973SWenlei He     FunctionSamples *Samples = ChildNode.getFunctionSamples();
546bae5973SWenlei He     if (!Samples)
556bae5973SWenlei He       continue;
566bae5973SWenlei He     if (Samples->getTotalSamples() > MaxCalleeSamples) {
576b989a17SWenlei He       ChildNodeRet = &ChildNode;
586bae5973SWenlei He       MaxCalleeSamples = Samples->getTotalSamples();
596b989a17SWenlei He     }
606b989a17SWenlei He   }
616b989a17SWenlei He 
626b989a17SWenlei He   return ChildNodeRet;
636b989a17SWenlei He }
646b989a17SWenlei He 
657e86b13cSwlei ContextTrieNode &
667e86b13cSwlei SampleContextTracker::moveContextSamples(ContextTrieNode &ToNodeParent,
677e86b13cSwlei                                          const LineLocation &CallSite,
687e86b13cSwlei                                          ContextTrieNode &&NodeToMove) {
695740bb80SHongtao Yu   uint64_t Hash =
705740bb80SHongtao Yu       FunctionSamples::getCallSiteHash(NodeToMove.getFuncName(), CallSite);
717e86b13cSwlei   std::map<uint64_t, ContextTrieNode> &AllChildContext =
727e86b13cSwlei       ToNodeParent.getAllChildContext();
736b989a17SWenlei He   assert(!AllChildContext.count(Hash) && "Node to remove must exist");
746b989a17SWenlei He   AllChildContext[Hash] = NodeToMove;
756b989a17SWenlei He   ContextTrieNode &NewNode = AllChildContext[Hash];
767e86b13cSwlei   NewNode.setCallSiteLoc(CallSite);
776b989a17SWenlei He 
786b989a17SWenlei He   // Walk through nodes in the moved the subtree, and update
796b989a17SWenlei He   // FunctionSamples' context as for the context promotion.
806b989a17SWenlei He   // We also need to set new parant link for all children.
816b989a17SWenlei He   std::queue<ContextTrieNode *> NodeToUpdate;
827e86b13cSwlei   NewNode.setParentContext(&ToNodeParent);
836b989a17SWenlei He   NodeToUpdate.push(&NewNode);
846b989a17SWenlei He 
856b989a17SWenlei He   while (!NodeToUpdate.empty()) {
866b989a17SWenlei He     ContextTrieNode *Node = NodeToUpdate.front();
876b989a17SWenlei He     NodeToUpdate.pop();
886b989a17SWenlei He     FunctionSamples *FSamples = Node->getFunctionSamples();
896b989a17SWenlei He 
906b989a17SWenlei He     if (FSamples) {
917e86b13cSwlei       setContextNode(FSamples, Node);
926b989a17SWenlei He       FSamples->getContext().setState(SyntheticContext);
936b989a17SWenlei He     }
946b989a17SWenlei He 
956b989a17SWenlei He     for (auto &It : Node->getAllChildContext()) {
966b989a17SWenlei He       ContextTrieNode *ChildNode = &It.second;
976b989a17SWenlei He       ChildNode->setParentContext(Node);
986b989a17SWenlei He       NodeToUpdate.push(ChildNode);
996b989a17SWenlei He     }
1006b989a17SWenlei He   }
1016b989a17SWenlei He 
1026b989a17SWenlei He   return NewNode;
1036b989a17SWenlei He }
1046b989a17SWenlei He 
1056b989a17SWenlei He void ContextTrieNode::removeChildContext(const LineLocation &CallSite,
106ef0e0adcSWilliam Junda Huang                                          FunctionId CalleeName) {
1075740bb80SHongtao Yu   uint64_t Hash = FunctionSamples::getCallSiteHash(CalleeName, CallSite);
1086b989a17SWenlei He   // Note this essentially calls dtor and destroys that child context
1096b989a17SWenlei He   AllChildContext.erase(Hash);
1106b989a17SWenlei He }
1116b989a17SWenlei He 
112042cefd2SHongtao Yu std::map<uint64_t, ContextTrieNode> &ContextTrieNode::getAllChildContext() {
1136b989a17SWenlei He   return AllChildContext;
1146b989a17SWenlei He }
1156b989a17SWenlei He 
116ef0e0adcSWilliam Junda Huang FunctionId ContextTrieNode::getFuncName() const { return FuncName; }
1176b989a17SWenlei He 
1186b989a17SWenlei He FunctionSamples *ContextTrieNode::getFunctionSamples() const {
1196b989a17SWenlei He   return FuncSamples;
1206b989a17SWenlei He }
1216b989a17SWenlei He 
1226b989a17SWenlei He void ContextTrieNode::setFunctionSamples(FunctionSamples *FSamples) {
1236b989a17SWenlei He   FuncSamples = FSamples;
1246b989a17SWenlei He }
1256b989a17SWenlei He 
12675801e3bSFangrui Song std::optional<uint32_t> ContextTrieNode::getFunctionSize() const {
12775801e3bSFangrui Song   return FuncSize;
12875801e3bSFangrui Song }
129eca03d27SWenlei He 
130a6f15e9aSWenlei He void ContextTrieNode::addFunctionSize(uint32_t FSize) {
131a7938c74SKazu Hirata   if (!FuncSize)
132a6f15e9aSWenlei He     FuncSize = 0;
133a6f15e9aSWenlei He 
13421c4dc79SFangrui Song   FuncSize = *FuncSize + FSize;
135a6f15e9aSWenlei He }
136eca03d27SWenlei He 
1376b989a17SWenlei He LineLocation ContextTrieNode::getCallSiteLoc() const { return CallSiteLoc; }
1386b989a17SWenlei He 
1396b989a17SWenlei He ContextTrieNode *ContextTrieNode::getParentContext() const {
1406b989a17SWenlei He   return ParentContext;
1416b989a17SWenlei He }
1426b989a17SWenlei He 
1436b989a17SWenlei He void ContextTrieNode::setParentContext(ContextTrieNode *Parent) {
1446b989a17SWenlei He   ParentContext = Parent;
1456b989a17SWenlei He }
1466b989a17SWenlei He 
1477e86b13cSwlei void ContextTrieNode::setCallSiteLoc(const LineLocation &Loc) {
1487e86b13cSwlei   CallSiteLoc = Loc;
1497e86b13cSwlei }
1507e86b13cSwlei 
151eca03d27SWenlei He void ContextTrieNode::dumpNode() {
1526b989a17SWenlei He   dbgs() << "Node: " << FuncName << "\n"
1536b989a17SWenlei He          << "  Callsite: " << CallSiteLoc << "\n"
154eca03d27SWenlei He          << "  Size: " << FuncSize << "\n"
1556b989a17SWenlei He          << "  Children:\n";
1566b989a17SWenlei He 
1576b989a17SWenlei He   for (auto &It : AllChildContext) {
1586b989a17SWenlei He     dbgs() << "    Node: " << It.second.getFuncName() << "\n";
1596b989a17SWenlei He   }
1606b989a17SWenlei He }
1616b989a17SWenlei He 
162eca03d27SWenlei He void ContextTrieNode::dumpTree() {
163eca03d27SWenlei He   dbgs() << "Context Profile Tree:\n";
164eca03d27SWenlei He   std::queue<ContextTrieNode *> NodeQueue;
165eca03d27SWenlei He   NodeQueue.push(this);
166eca03d27SWenlei He 
167eca03d27SWenlei He   while (!NodeQueue.empty()) {
168eca03d27SWenlei He     ContextTrieNode *Node = NodeQueue.front();
169eca03d27SWenlei He     NodeQueue.pop();
170eca03d27SWenlei He     Node->dumpNode();
171eca03d27SWenlei He 
172eca03d27SWenlei He     for (auto &It : Node->getAllChildContext()) {
173eca03d27SWenlei He       ContextTrieNode *ChildNode = &It.second;
174eca03d27SWenlei He       NodeQueue.push(ChildNode);
175eca03d27SWenlei He     }
176eca03d27SWenlei He   }
177eca03d27SWenlei He }
178eca03d27SWenlei He 
1796b989a17SWenlei He ContextTrieNode *ContextTrieNode::getOrCreateChildContext(
180ef0e0adcSWilliam Junda Huang     const LineLocation &CallSite, FunctionId CalleeName, bool AllowCreate) {
1815740bb80SHongtao Yu   uint64_t Hash = FunctionSamples::getCallSiteHash(CalleeName, CallSite);
1826b989a17SWenlei He   auto It = AllChildContext.find(Hash);
1836b989a17SWenlei He   if (It != AllChildContext.end()) {
1846b989a17SWenlei He     assert(It->second.getFuncName() == CalleeName &&
1856b989a17SWenlei He            "Hash collision for child context node");
1866b989a17SWenlei He     return &It->second;
1876b989a17SWenlei He   }
1886b989a17SWenlei He 
1896b989a17SWenlei He   if (!AllowCreate)
1906b989a17SWenlei He     return nullptr;
1916b989a17SWenlei He 
192a6f15e9aSWenlei He   AllChildContext[Hash] = ContextTrieNode(this, CalleeName, nullptr, CallSite);
1936b989a17SWenlei He   return &AllChildContext[Hash];
1946b989a17SWenlei He }
1956b989a17SWenlei He 
1966b989a17SWenlei He // Profiler tracker than manages profiles and its associated context
1977ca80300SHongtao Yu SampleContextTracker::SampleContextTracker(
1987ca80300SHongtao Yu     SampleProfileMap &Profiles,
1997ca80300SHongtao Yu     const DenseMap<uint64_t, StringRef> *GUIDToFuncNameMap)
2007ca80300SHongtao Yu     : GUIDToFuncNameMap(GUIDToFuncNameMap) {
2016b989a17SWenlei He   for (auto &FuncSample : Profiles) {
2026b989a17SWenlei He     FunctionSamples *FSamples = &FuncSample.second;
2037624de5bSWilliam Huang     SampleContext Context = FuncSample.second.getContext();
204b9db7036SHongtao Yu     LLVM_DEBUG(dbgs() << "Tracking Context for function: " << Context.toString()
205b9db7036SHongtao Yu                       << "\n");
2066b989a17SWenlei He     ContextTrieNode *NewNode = getOrCreateContextPath(Context, true);
2076b989a17SWenlei He     assert(!NewNode->getFunctionSamples() &&
2086b989a17SWenlei He            "New node can't have sample profile");
2096b989a17SWenlei He     NewNode->setFunctionSamples(FSamples);
2106b989a17SWenlei He   }
2117e86b13cSwlei   populateFuncToCtxtMap();
2127e86b13cSwlei }
2137e86b13cSwlei 
2147e86b13cSwlei void SampleContextTracker::populateFuncToCtxtMap() {
2157e86b13cSwlei   for (auto *Node : *this) {
2167e86b13cSwlei     FunctionSamples *FSamples = Node->getFunctionSamples();
2177e86b13cSwlei     if (FSamples) {
2187e86b13cSwlei       FSamples->getContext().setState(RawContext);
2197e86b13cSwlei       setContextNode(FSamples, Node);
2207e86b13cSwlei       FuncToCtxtProfiles[Node->getFuncName()].push_back(FSamples);
2217e86b13cSwlei     }
2227e86b13cSwlei   }
2236b989a17SWenlei He }
2246b989a17SWenlei He 
2256b989a17SWenlei He FunctionSamples *
2266b989a17SWenlei He SampleContextTracker::getCalleeContextSamplesFor(const CallBase &Inst,
2276b989a17SWenlei He                                                  StringRef CalleeName) {
2286b989a17SWenlei He   LLVM_DEBUG(dbgs() << "Getting callee context for instr: " << Inst << "\n");
2296b989a17SWenlei He   DILocation *DIL = Inst.getDebugLoc();
2306b989a17SWenlei He   if (!DIL)
2316b989a17SWenlei He     return nullptr;
2326b989a17SWenlei He 
233ee35784aSWei Mi   CalleeName = FunctionSamples::getCanonicalFnName(CalleeName);
234ef0e0adcSWilliam Junda Huang 
235ef0e0adcSWilliam Junda Huang   FunctionId FName = getRepInFormat(CalleeName);
236ee35784aSWei Mi 
2376bae5973SWenlei He   // For indirect call, CalleeName will be empty, in which case the context
2386bae5973SWenlei He   // profile for callee with largest total samples will be returned.
239ef0e0adcSWilliam Junda Huang   ContextTrieNode *CalleeContext = getCalleeContextFor(DIL, FName);
2406b989a17SWenlei He   if (CalleeContext) {
2416b989a17SWenlei He     FunctionSamples *FSamples = CalleeContext->getFunctionSamples();
2426b989a17SWenlei He     LLVM_DEBUG(if (FSamples) {
2437e86b13cSwlei       dbgs() << "  Callee context found: " << getContextString(CalleeContext)
244b9db7036SHongtao Yu              << "\n";
2456b989a17SWenlei He     });
2466b989a17SWenlei He     return FSamples;
2476b989a17SWenlei He   }
2486b989a17SWenlei He 
2496b989a17SWenlei He   return nullptr;
2506b989a17SWenlei He }
2516b989a17SWenlei He 
2526bae5973SWenlei He std::vector<const FunctionSamples *>
2536bae5973SWenlei He SampleContextTracker::getIndirectCalleeContextSamplesFor(
2546bae5973SWenlei He     const DILocation *DIL) {
2556bae5973SWenlei He   std::vector<const FunctionSamples *> R;
2566bae5973SWenlei He   if (!DIL)
2576bae5973SWenlei He     return R;
2586bae5973SWenlei He 
2596bae5973SWenlei He   ContextTrieNode *CallerNode = getContextFor(DIL);
2606bae5973SWenlei He   LineLocation CallSite = FunctionSamples::getCallSiteIdentifier(DIL);
2616bae5973SWenlei He   for (auto &It : CallerNode->getAllChildContext()) {
2626bae5973SWenlei He     ContextTrieNode &ChildNode = It.second;
2636bae5973SWenlei He     if (ChildNode.getCallSiteLoc() != CallSite)
2646bae5973SWenlei He       continue;
2656bae5973SWenlei He     if (FunctionSamples *CalleeSamples = ChildNode.getFunctionSamples())
2666bae5973SWenlei He       R.push_back(CalleeSamples);
2676bae5973SWenlei He   }
2686bae5973SWenlei He 
2696bae5973SWenlei He   return R;
2706bae5973SWenlei He }
2716bae5973SWenlei He 
2726b989a17SWenlei He FunctionSamples *
2736b989a17SWenlei He SampleContextTracker::getContextSamplesFor(const DILocation *DIL) {
2746b989a17SWenlei He   assert(DIL && "Expect non-null location");
2756b989a17SWenlei He 
2766b989a17SWenlei He   ContextTrieNode *ContextNode = getContextFor(DIL);
2776b989a17SWenlei He   if (!ContextNode)
2786b989a17SWenlei He     return nullptr;
2796b989a17SWenlei He 
2806b989a17SWenlei He   // We may have inlined callees during pre-LTO compilation, in which case
2816b989a17SWenlei He   // we need to rely on the inline stack from !dbg to mark context profile
2826b989a17SWenlei He   // as inlined, instead of `MarkContextSamplesInlined` during inlining.
2836b989a17SWenlei He   // Sample profile loader walks through all instructions to get profile,
2846b989a17SWenlei He   // which calls this function. So once that is done, all previously inlined
2856b989a17SWenlei He   // context profile should be marked properly.
2866b989a17SWenlei He   FunctionSamples *Samples = ContextNode->getFunctionSamples();
2876b989a17SWenlei He   if (Samples && ContextNode->getParentContext() != &RootContext)
2886b989a17SWenlei He     Samples->getContext().setState(InlinedContext);
2896b989a17SWenlei He 
2906b989a17SWenlei He   return Samples;
2916b989a17SWenlei He }
2926b989a17SWenlei He 
2936b989a17SWenlei He FunctionSamples *
2946b989a17SWenlei He SampleContextTracker::getContextSamplesFor(const SampleContext &Context) {
2956b989a17SWenlei He   ContextTrieNode *Node = getContextFor(Context);
2966b989a17SWenlei He   if (!Node)
2976b989a17SWenlei He     return nullptr;
2986b989a17SWenlei He 
2996b989a17SWenlei He   return Node->getFunctionSamples();
3006b989a17SWenlei He }
3016b989a17SWenlei He 
302de40f6d6SHongtao Yu SampleContextTracker::ContextSamplesTy &
303de40f6d6SHongtao Yu SampleContextTracker::getAllContextSamplesFor(const Function &Func) {
304de40f6d6SHongtao Yu   StringRef CanonName = FunctionSamples::getCanonicalFnName(Func);
305ef0e0adcSWilliam Junda Huang   return FuncToCtxtProfiles[getRepInFormat(CanonName)];
306de40f6d6SHongtao Yu }
307de40f6d6SHongtao Yu 
308de40f6d6SHongtao Yu SampleContextTracker::ContextSamplesTy &
309de40f6d6SHongtao Yu SampleContextTracker::getAllContextSamplesFor(StringRef Name) {
310ef0e0adcSWilliam Junda Huang   return FuncToCtxtProfiles[getRepInFormat(Name)];
311de40f6d6SHongtao Yu }
312de40f6d6SHongtao Yu 
3136b989a17SWenlei He FunctionSamples *SampleContextTracker::getBaseSamplesFor(const Function &Func,
3146b989a17SWenlei He                                                          bool MergeContext) {
3156b989a17SWenlei He   StringRef CanonName = FunctionSamples::getCanonicalFnName(Func);
316ef0e0adcSWilliam Junda Huang   return getBaseSamplesFor(getRepInFormat(CanonName), MergeContext);
3176b989a17SWenlei He }
3186b989a17SWenlei He 
319ef0e0adcSWilliam Junda Huang FunctionSamples *SampleContextTracker::getBaseSamplesFor(FunctionId Name,
3206b989a17SWenlei He                                                          bool MergeContext) {
3216b989a17SWenlei He   LLVM_DEBUG(dbgs() << "Getting base profile for function: " << Name << "\n");
3227ca80300SHongtao Yu 
3236b989a17SWenlei He   // Base profile is top-level node (child of root node), so try to retrieve
3246b989a17SWenlei He   // existing top-level node for given function first. If it exists, it could be
3256b989a17SWenlei He   // that we've merged base profile before, or there's actually context-less
3266b989a17SWenlei He   // profile from the input (e.g. due to unreliable stack walking).
3276b989a17SWenlei He   ContextTrieNode *Node = getTopLevelContextNode(Name);
3286b989a17SWenlei He   if (MergeContext) {
3296b989a17SWenlei He     LLVM_DEBUG(dbgs() << "  Merging context profile into base profile: " << Name
3306b989a17SWenlei He                       << "\n");
3316b989a17SWenlei He 
3326b989a17SWenlei He     // We have profile for function under different contexts,
3336b989a17SWenlei He     // create synthetic base profile and merge context profiles
3346b989a17SWenlei He     // into base profile.
335ca721042SHuihui Zhang     for (auto *CSamples : FuncToCtxtProfiles[Name]) {
3366b989a17SWenlei He       SampleContext &Context = CSamples->getContext();
3376b989a17SWenlei He       // Skip inlined context profile and also don't re-merge any context
3386b989a17SWenlei He       if (Context.hasState(InlinedContext) || Context.hasState(MergedContext))
3396b989a17SWenlei He         continue;
3406b989a17SWenlei He 
3417e86b13cSwlei       ContextTrieNode *FromNode = getContextNodeForProfile(CSamples);
342b9db7036SHongtao Yu       if (FromNode == Node)
343b9db7036SHongtao Yu         continue;
344b9db7036SHongtao Yu 
3456b989a17SWenlei He       ContextTrieNode &ToNode = promoteMergeContextSamplesTree(*FromNode);
34650dd1dbaSSimon Pilgrim       assert((!Node || Node == &ToNode) && "Expect only one base profile");
3476b989a17SWenlei He       Node = &ToNode;
3486b989a17SWenlei He     }
3496b989a17SWenlei He   }
3506b989a17SWenlei He 
3516b989a17SWenlei He   // Still no profile even after merge/promotion (if allowed)
3526b989a17SWenlei He   if (!Node)
3536b989a17SWenlei He     return nullptr;
3546b989a17SWenlei He 
3556b989a17SWenlei He   return Node->getFunctionSamples();
3566b989a17SWenlei He }
3576b989a17SWenlei He 
3586b989a17SWenlei He void SampleContextTracker::markContextSamplesInlined(
3596b989a17SWenlei He     const FunctionSamples *InlinedSamples) {
3606b989a17SWenlei He   assert(InlinedSamples && "Expect non-null inlined samples");
3616b989a17SWenlei He   LLVM_DEBUG(dbgs() << "Marking context profile as inlined: "
3627e86b13cSwlei                     << getContextString(*InlinedSamples) << "\n");
3636b989a17SWenlei He   InlinedSamples->getContext().setState(InlinedContext);
3646b989a17SWenlei He }
3656b989a17SWenlei He 
36630b02323SWenlei He ContextTrieNode &SampleContextTracker::getRootContext() { return RootContext; }
36730b02323SWenlei He 
3686b989a17SWenlei He void SampleContextTracker::promoteMergeContextSamplesTree(
369ef0e0adcSWilliam Junda Huang     const Instruction &Inst, FunctionId CalleeName) {
3706b989a17SWenlei He   LLVM_DEBUG(dbgs() << "Promoting and merging context tree for instr: \n"
3716b989a17SWenlei He                     << Inst << "\n");
3726b989a17SWenlei He   // Get the caller context for the call instruction, we don't use callee
3736b989a17SWenlei He   // name from call because there can be context from indirect calls too.
3746b989a17SWenlei He   DILocation *DIL = Inst.getDebugLoc();
3756b989a17SWenlei He   ContextTrieNode *CallerNode = getContextFor(DIL);
3766b989a17SWenlei He   if (!CallerNode)
3776b989a17SWenlei He     return;
3786b989a17SWenlei He 
3796b989a17SWenlei He   // Get the context that needs to be promoted
380224fee82SHongtao Yu   LineLocation CallSite = FunctionSamples::getCallSiteIdentifier(DIL);
3816bae5973SWenlei He   // For indirect call, CalleeName will be empty, in which case we need to
3826bae5973SWenlei He   // promote all non-inlined child context profiles.
3836bae5973SWenlei He   if (CalleeName.empty()) {
3846bae5973SWenlei He     for (auto &It : CallerNode->getAllChildContext()) {
3856bae5973SWenlei He       ContextTrieNode *NodeToPromo = &It.second;
3866bae5973SWenlei He       if (CallSite != NodeToPromo->getCallSiteLoc())
3876bae5973SWenlei He         continue;
3886bae5973SWenlei He       FunctionSamples *FromSamples = NodeToPromo->getFunctionSamples();
3896bae5973SWenlei He       if (FromSamples && FromSamples->getContext().hasState(InlinedContext))
3906bae5973SWenlei He         continue;
3916bae5973SWenlei He       promoteMergeContextSamplesTree(*NodeToPromo);
3926bae5973SWenlei He     }
3936bae5973SWenlei He     return;
3946bae5973SWenlei He   }
3956bae5973SWenlei He 
3966bae5973SWenlei He   // Get the context for the given callee that needs to be promoted
3976b989a17SWenlei He   ContextTrieNode *NodeToPromo =
3986b989a17SWenlei He       CallerNode->getChildContext(CallSite, CalleeName);
3996b989a17SWenlei He   if (!NodeToPromo)
4006b989a17SWenlei He     return;
4016b989a17SWenlei He 
4026b989a17SWenlei He   promoteMergeContextSamplesTree(*NodeToPromo);
4036b989a17SWenlei He }
4046b989a17SWenlei He 
4056b989a17SWenlei He ContextTrieNode &SampleContextTracker::promoteMergeContextSamplesTree(
4066b989a17SWenlei He     ContextTrieNode &NodeToPromo) {
4076b989a17SWenlei He   // Promote the input node to be directly under root. This can happen
4086b989a17SWenlei He   // when we decided to not inline a function under context represented
4096b989a17SWenlei He   // by the input node. The promote and merge is then needed to reflect
4106b989a17SWenlei He   // the context profile in the base (context-less) profile.
4116b989a17SWenlei He   FunctionSamples *FromSamples = NodeToPromo.getFunctionSamples();
4126b989a17SWenlei He   assert(FromSamples && "Shouldn't promote a context without profile");
413c6c124caSMikhail Goncharov   (void)FromSamples;  // Unused in release build.
414c6c124caSMikhail Goncharov 
4156b989a17SWenlei He   LLVM_DEBUG(dbgs() << "  Found context tree root to promote: "
4167e86b13cSwlei                     << getContextString(&NodeToPromo) << "\n");
4176b989a17SWenlei He 
4186bae5973SWenlei He   assert(!FromSamples->getContext().hasState(InlinedContext) &&
4196bae5973SWenlei He          "Shouldn't promote inlined context profile");
4207e86b13cSwlei   return promoteMergeContextSamplesTree(NodeToPromo, RootContext);
4216b989a17SWenlei He }
4226b989a17SWenlei He 
4237e86b13cSwlei #ifndef NDEBUG
4247e86b13cSwlei std::string
4257e86b13cSwlei SampleContextTracker::getContextString(const FunctionSamples &FSamples) const {
4267e86b13cSwlei   return getContextString(getContextNodeForProfile(&FSamples));
4277e86b13cSwlei }
4287e86b13cSwlei 
4297e86b13cSwlei std::string
4307e86b13cSwlei SampleContextTracker::getContextString(ContextTrieNode *Node) const {
4317e86b13cSwlei   SampleContextFrameVector Res;
4327e86b13cSwlei   if (Node == &RootContext)
4337e86b13cSwlei     return std::string();
4347e86b13cSwlei   Res.emplace_back(Node->getFuncName(), LineLocation(0, 0));
4357e86b13cSwlei 
4367e86b13cSwlei   ContextTrieNode *PreNode = Node;
4377e86b13cSwlei   Node = Node->getParentContext();
4387e86b13cSwlei   while (Node && Node != &RootContext) {
4397e86b13cSwlei     Res.emplace_back(Node->getFuncName(), PreNode->getCallSiteLoc());
4407e86b13cSwlei     PreNode = Node;
4417e86b13cSwlei     Node = Node->getParentContext();
4427e86b13cSwlei   }
4437e86b13cSwlei 
4447e86b13cSwlei   std::reverse(Res.begin(), Res.end());
4457e86b13cSwlei 
4467e86b13cSwlei   return SampleContext::getContextString(Res);
4477e86b13cSwlei }
4487e86b13cSwlei #endif
4497e86b13cSwlei 
450eca03d27SWenlei He void SampleContextTracker::dump() { RootContext.dumpTree(); }
4516b989a17SWenlei He 
4527ca80300SHongtao Yu StringRef SampleContextTracker::getFuncNameFor(ContextTrieNode *Node) const {
4537ca80300SHongtao Yu   if (!FunctionSamples::UseMD5)
454ef0e0adcSWilliam Junda Huang     return Node->getFuncName().stringRef();
4557ca80300SHongtao Yu   assert(GUIDToFuncNameMap && "GUIDToFuncNameMap needs to be populated first");
456ef0e0adcSWilliam Junda Huang   return GUIDToFuncNameMap->lookup(Node->getFuncName().getHashCode());
4577ca80300SHongtao Yu }
4587ca80300SHongtao Yu 
4596b989a17SWenlei He ContextTrieNode *
4606b989a17SWenlei He SampleContextTracker::getContextFor(const SampleContext &Context) {
4616b989a17SWenlei He   return getOrCreateContextPath(Context, false);
4626b989a17SWenlei He }
4636b989a17SWenlei He 
4646b989a17SWenlei He ContextTrieNode *
4656b989a17SWenlei He SampleContextTracker::getCalleeContextFor(const DILocation *DIL,
466ef0e0adcSWilliam Junda Huang                                           FunctionId CalleeName) {
4676b989a17SWenlei He   assert(DIL && "Expect non-null location");
4686b989a17SWenlei He 
4696b989a17SWenlei He   ContextTrieNode *CallContext = getContextFor(DIL);
4706b989a17SWenlei He   if (!CallContext)
4716b989a17SWenlei He     return nullptr;
4726b989a17SWenlei He 
4736bae5973SWenlei He   // When CalleeName is empty, the child context profile with max
4746bae5973SWenlei He   // total samples will be returned.
4756b989a17SWenlei He   return CallContext->getChildContext(
476224fee82SHongtao Yu       FunctionSamples::getCallSiteIdentifier(DIL), CalleeName);
4776b989a17SWenlei He }
4786b989a17SWenlei He 
4796b989a17SWenlei He ContextTrieNode *SampleContextTracker::getContextFor(const DILocation *DIL) {
4806b989a17SWenlei He   assert(DIL && "Expect non-null location");
481ef0e0adcSWilliam Junda Huang   SmallVector<std::pair<LineLocation, FunctionId>, 10> S;
4826b989a17SWenlei He 
4836b989a17SWenlei He   // Use C++ linkage name if possible.
4846b989a17SWenlei He   const DILocation *PrevDIL = DIL;
4856b989a17SWenlei He   for (DIL = DIL->getInlinedAt(); DIL; DIL = DIL->getInlinedAt()) {
4866b989a17SWenlei He     StringRef Name = PrevDIL->getScope()->getSubprogram()->getLinkageName();
4876b989a17SWenlei He     if (Name.empty())
4886b989a17SWenlei He       Name = PrevDIL->getScope()->getSubprogram()->getName();
4896b989a17SWenlei He     S.push_back(
490ef0e0adcSWilliam Junda Huang         std::make_pair(FunctionSamples::getCallSiteIdentifier(DIL),
491ef0e0adcSWilliam Junda Huang                        getRepInFormat(Name)));
4926b989a17SWenlei He     PrevDIL = DIL;
4936b989a17SWenlei He   }
4946b989a17SWenlei He 
4956b989a17SWenlei He   // Push root node, note that root node like main may only
4966b989a17SWenlei He   // a name, but not linkage name.
4976b989a17SWenlei He   StringRef RootName = PrevDIL->getScope()->getSubprogram()->getLinkageName();
4986b989a17SWenlei He   if (RootName.empty())
4996b989a17SWenlei He     RootName = PrevDIL->getScope()->getSubprogram()->getName();
500ef0e0adcSWilliam Junda Huang   S.push_back(std::make_pair(LineLocation(0, 0),
501ef0e0adcSWilliam Junda Huang                              getRepInFormat(RootName)));
5027ca80300SHongtao Yu 
5036b989a17SWenlei He   ContextTrieNode *ContextNode = &RootContext;
5046b989a17SWenlei He   int I = S.size();
5056b989a17SWenlei He   while (--I >= 0 && ContextNode) {
5066b989a17SWenlei He     LineLocation &CallSite = S[I].first;
507ef0e0adcSWilliam Junda Huang     FunctionId CalleeName = S[I].second;
5086b989a17SWenlei He     ContextNode = ContextNode->getChildContext(CallSite, CalleeName);
5096b989a17SWenlei He   }
5106b989a17SWenlei He 
5116b989a17SWenlei He   if (I < 0)
5126b989a17SWenlei He     return ContextNode;
5136b989a17SWenlei He 
5146b989a17SWenlei He   return nullptr;
5156b989a17SWenlei He }
5166b989a17SWenlei He 
5176b989a17SWenlei He ContextTrieNode *
5186b989a17SWenlei He SampleContextTracker::getOrCreateContextPath(const SampleContext &Context,
5196b989a17SWenlei He                                              bool AllowCreate) {
5206b989a17SWenlei He   ContextTrieNode *ContextNode = &RootContext;
5216b989a17SWenlei He   LineLocation CallSiteLoc(0, 0);
5226b989a17SWenlei He 
523e20d210eSKazu Hirata   for (const auto &Callsite : Context.getContextFrames()) {
5246b989a17SWenlei He     // Create child node at parent line/disc location
5256b989a17SWenlei He     if (AllowCreate) {
526fb29d812Swlei       ContextNode =
527ef0e0adcSWilliam Junda Huang           ContextNode->getOrCreateChildContext(CallSiteLoc, Callsite.Func);
5286b989a17SWenlei He     } else {
529b9db7036SHongtao Yu       ContextNode =
530ef0e0adcSWilliam Junda Huang           ContextNode->getChildContext(CallSiteLoc, Callsite.Func);
5316b989a17SWenlei He     }
532fb29d812Swlei     CallSiteLoc = Callsite.Location;
5336b989a17SWenlei He   }
5346b989a17SWenlei He 
5356b989a17SWenlei He   assert((!AllowCreate || ContextNode) &&
5366b989a17SWenlei He          "Node must exist if creation is allowed");
5376b989a17SWenlei He   return ContextNode;
5386b989a17SWenlei He }
5396b989a17SWenlei He 
540ef0e0adcSWilliam Junda Huang ContextTrieNode *
541ef0e0adcSWilliam Junda Huang SampleContextTracker::getTopLevelContextNode(FunctionId FName) {
54230b02323SWenlei He   assert(!FName.empty() && "Top level node query must provide valid name");
5436b989a17SWenlei He   return RootContext.getChildContext(LineLocation(0, 0), FName);
5446b989a17SWenlei He }
5456b989a17SWenlei He 
546ef0e0adcSWilliam Junda Huang ContextTrieNode &
547ef0e0adcSWilliam Junda Huang SampleContextTracker::addTopLevelContextNode(FunctionId FName) {
5486b989a17SWenlei He   assert(!getTopLevelContextNode(FName) && "Node to add must not exist");
5496b989a17SWenlei He   return *RootContext.getOrCreateChildContext(LineLocation(0, 0), FName);
5506b989a17SWenlei He }
5516b989a17SWenlei He 
5526b989a17SWenlei He void SampleContextTracker::mergeContextNode(ContextTrieNode &FromNode,
5537e86b13cSwlei                                             ContextTrieNode &ToNode) {
5546b989a17SWenlei He   FunctionSamples *FromSamples = FromNode.getFunctionSamples();
5556b989a17SWenlei He   FunctionSamples *ToSamples = ToNode.getFunctionSamples();
5566b989a17SWenlei He   if (FromSamples && ToSamples) {
5576b989a17SWenlei He     // Merge/duplicate FromSamples into ToSamples
5586b989a17SWenlei He     ToSamples->merge(*FromSamples);
5596b989a17SWenlei He     ToSamples->getContext().setState(SyntheticContext);
5606b989a17SWenlei He     FromSamples->getContext().setState(MergedContext);
561054487c5SWenlei He     if (FromSamples->getContext().hasAttribute(ContextShouldBeInlined))
562054487c5SWenlei He       ToSamples->getContext().setAttribute(ContextShouldBeInlined);
5636b989a17SWenlei He   } else if (FromSamples) {
5646b989a17SWenlei He     // Transfer FromSamples from FromNode to ToNode
5656b989a17SWenlei He     ToNode.setFunctionSamples(FromSamples);
5667e86b13cSwlei     setContextNode(FromSamples, &ToNode);
5676b989a17SWenlei He     FromSamples->getContext().setState(SyntheticContext);
5686b989a17SWenlei He   }
5696b989a17SWenlei He }
5706b989a17SWenlei He 
5716b989a17SWenlei He ContextTrieNode &SampleContextTracker::promoteMergeContextSamplesTree(
5727e86b13cSwlei     ContextTrieNode &FromNode, ContextTrieNode &ToNodeParent) {
5736b989a17SWenlei He 
5746b989a17SWenlei He   // Ignore call site location if destination is top level under root
5756b989a17SWenlei He   LineLocation NewCallSiteLoc = LineLocation(0, 0);
5766b989a17SWenlei He   LineLocation OldCallSiteLoc = FromNode.getCallSiteLoc();
5776b989a17SWenlei He   ContextTrieNode &FromNodeParent = *FromNode.getParentContext();
5786b989a17SWenlei He   ContextTrieNode *ToNode = nullptr;
5796b989a17SWenlei He   bool MoveToRoot = (&ToNodeParent == &RootContext);
5806b989a17SWenlei He   if (!MoveToRoot) {
5816b989a17SWenlei He     NewCallSiteLoc = OldCallSiteLoc;
5826b989a17SWenlei He   }
5836b989a17SWenlei He 
5846b989a17SWenlei He   // Locate destination node, create/move if not existing
5856b989a17SWenlei He   ToNode = ToNodeParent.getChildContext(NewCallSiteLoc, FromNode.getFuncName());
5866b989a17SWenlei He   if (!ToNode) {
5876b989a17SWenlei He     // Do not delete node to move from its parent here because
5886b989a17SWenlei He     // caller is iterating over children of that parent node.
5897e86b13cSwlei     ToNode =
5907e86b13cSwlei         &moveContextSamples(ToNodeParent, NewCallSiteLoc, std::move(FromNode));
5917e86b13cSwlei     LLVM_DEBUG({
5927e86b13cSwlei       dbgs() << "  Context promoted and merged to: " << getContextString(ToNode)
5937e86b13cSwlei              << "\n";
5947e86b13cSwlei     });
5956b989a17SWenlei He   } else {
5966b989a17SWenlei He     // Destination node exists, merge samples for the context tree
5977e86b13cSwlei     mergeContextNode(FromNode, *ToNode);
59812ac0403SHongtao Yu     LLVM_DEBUG({
59912ac0403SHongtao Yu       if (ToNode->getFunctionSamples())
60012ac0403SHongtao Yu         dbgs() << "  Context promoted and merged to: "
6017e86b13cSwlei                << getContextString(ToNode) << "\n";
60212ac0403SHongtao Yu     });
6036b989a17SWenlei He 
6046b989a17SWenlei He     // Recursively promote and merge children
6056b989a17SWenlei He     for (auto &It : FromNode.getAllChildContext()) {
6066b989a17SWenlei He       ContextTrieNode &FromChildNode = It.second;
6077e86b13cSwlei       promoteMergeContextSamplesTree(FromChildNode, *ToNode);
6086b989a17SWenlei He     }
6096b989a17SWenlei He 
6106b989a17SWenlei He     // Remove children once they're all merged
6116b989a17SWenlei He     FromNode.getAllChildContext().clear();
6126b989a17SWenlei He   }
6136b989a17SWenlei He 
6146b989a17SWenlei He   // For root of subtree, remove itself from old parent too
6156b989a17SWenlei He   if (MoveToRoot)
6166b989a17SWenlei He     FromNodeParent.removeChildContext(OldCallSiteLoc, ToNode->getFuncName());
6176b989a17SWenlei He 
6186b989a17SWenlei He   return *ToNode;
6196b989a17SWenlei He }
620aa58b7b1Swlei 
621aa58b7b1Swlei void SampleContextTracker::createContextLessProfileMap(
622aa58b7b1Swlei     SampleProfileMap &ContextLessProfiles) {
6237e86b13cSwlei   for (auto *Node : *this) {
624aa58b7b1Swlei     FunctionSamples *FProfile = Node->getFunctionSamples();
625aa58b7b1Swlei     // Profile's context can be empty, use ContextNode's func name.
6267e86b13cSwlei     if (FProfile)
627*ce03155aSMircea Trofin       ContextLessProfiles.create(Node->getFuncName()).merge(*FProfile);
628aa58b7b1Swlei   }
629aa58b7b1Swlei }
6306b989a17SWenlei He } // namespace llvm
631