LLVM 24.0.0git
MemProfContextDisambiguation.cpp
Go to the documentation of this file.
1//==-- MemProfContextDisambiguation.cpp - Disambiguate contexts -------------=//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements support for context disambiguation of allocation
10// calls for profile guided heap optimization. Specifically, it uses Memprof
11// profiles which indicate context specific allocation behavior (currently
12// distinguishing cold vs hot memory allocations). Cloning is performed to
13// expose the cold allocation call contexts, and the allocation calls are
14// subsequently annotated with an attribute for later transformation.
15//
16// The transformations can be performed either directly on IR (regular LTO), or
17// on a ThinLTO index (and later applied to the IR during the ThinLTO backend).
18// Both types of LTO operate on a the same base graph representation, which
19// uses CRTP to support either IR or Index formats.
20//
21//===----------------------------------------------------------------------===//
22
24#include "llvm/ADT/DenseMap.h"
25#include "llvm/ADT/DenseSet.h"
26#include "llvm/ADT/MapVector.h"
29#include "llvm/ADT/SmallSet.h"
31#include "llvm/ADT/Statistic.h"
38#include "llvm/IR/Module.h"
40#include "llvm/Pass.h"
43#include "llvm/Support/SHA1.h"
45#include "llvm/Transforms/IPO.h"
49#include <deque>
50#include <sstream>
51#include <vector>
52using namespace llvm;
53using namespace llvm::memprof;
54
55#define DEBUG_TYPE "memprof-context-disambiguation"
56
57STATISTIC(FunctionClonesAnalysis,
58 "Number of function clones created during whole program analysis");
59STATISTIC(FunctionClonesThinBackend,
60 "Number of function clones created during ThinLTO backend");
61STATISTIC(FunctionsClonedThinBackend,
62 "Number of functions that had clones created during ThinLTO backend");
64 FunctionCloneDuplicatesThinBackend,
65 "Number of function clone duplicates detected during ThinLTO backend");
66STATISTIC(AllocTypeNotCold, "Number of not cold static allocations (possibly "
67 "cloned) during whole program analysis");
68STATISTIC(AllocTypeCold, "Number of cold static allocations (possibly cloned) "
69 "during whole program analysis");
70STATISTIC(AllocTypeNotColdThinBackend,
71 "Number of not cold static allocations (possibly cloned) during "
72 "ThinLTO backend");
73STATISTIC(AllocTypeColdThinBackend, "Number of cold static allocations "
74 "(possibly cloned) during ThinLTO backend");
75STATISTIC(OrigAllocsThinBackend,
76 "Number of original (not cloned) allocations with memprof profiles "
77 "during ThinLTO backend");
79 AllocVersionsThinBackend,
80 "Number of allocation versions (including clones) during ThinLTO backend");
81STATISTIC(MaxAllocVersionsThinBackend,
82 "Maximum number of allocation versions created for an original "
83 "allocation during ThinLTO backend");
84STATISTIC(UnclonableAllocsThinBackend,
85 "Number of unclonable ambigous allocations during ThinLTO backend");
86STATISTIC(RemovedEdgesWithMismatchedCallees,
87 "Number of edges removed due to mismatched callees (profiled vs IR)");
88STATISTIC(FoundProfiledCalleeCount,
89 "Number of profiled callees found via tail calls");
90STATISTIC(FoundProfiledCalleeDepth,
91 "Aggregate depth of profiled callees found via tail calls");
92STATISTIC(FoundProfiledCalleeMaxDepth,
93 "Maximum depth of profiled callees found via tail calls");
94STATISTIC(FoundProfiledCalleeNonUniquelyCount,
95 "Number of profiled callees found via multiple tail call chains");
96STATISTIC(DeferredBackedges, "Number of backedges with deferred cloning");
97STATISTIC(NewMergedNodes, "Number of new nodes created during merging");
98STATISTIC(NonNewMergedNodes, "Number of non new nodes used during merging");
99STATISTIC(MissingAllocForContextId,
100 "Number of missing alloc nodes for context ids");
101STATISTIC(SkippedCallsCloning,
102 "Number of calls skipped during cloning due to unexpected operand");
103STATISTIC(MismatchedCloneAssignments,
104 "Number of callsites assigned to call multiple non-matching clones");
105STATISTIC(TotalMergeInvokes, "Number of merge invocations for nodes");
106STATISTIC(TotalMergeIters, "Number of merge iterations for nodes");
107STATISTIC(MaxMergeIters, "Max merge iterations for nodes");
108STATISTIC(NumImportantContextIds, "Number of important context ids");
109STATISTIC(NumFixupEdgeIdsInserted, "Number of fixup edge ids inserted");
110STATISTIC(NumFixupEdgesAdded, "Number of fixup edges added");
111STATISTIC(NumFixedContexts, "Number of contexts with fixed edges");
112STATISTIC(AliaseesPrevailingInDiffModuleFromAlias,
113 "Number of aliasees prevailing in a different module than its alias");
114
116 "memprof-dot-file-path-prefix", cl::init(""), cl::Hidden,
117 cl::value_desc("filename"),
118 cl::desc("Specify the path prefix of the MemProf dot files."));
119
120static cl::opt<bool> ExportToDot("memprof-export-to-dot", cl::init(false),
122 cl::desc("Export graph to dot files."));
123
124// TODO: Remove this option once new handling is validated more widely.
126 "memprof-merge-iteration", cl::init(true), cl::Hidden,
127 cl::desc("Iteratively apply merging on a node to catch new callers"));
128
129// How much of the graph to export to dot.
131 All, // The full CCG graph.
132 Alloc, // Only contexts for the specified allocation.
133 Context, // Only the specified context.
134};
135
137 "memprof-dot-scope", cl::desc("Scope of graph to export to dot"),
140 clEnumValN(DotScope::All, "all", "Export full callsite graph"),
142 "Export only nodes with contexts feeding given "
143 "-memprof-dot-alloc-id"),
144 clEnumValN(DotScope::Context, "context",
145 "Export only nodes with given -memprof-dot-context-id")));
146
148 AllocIdForDot("memprof-dot-alloc-id", cl::init(0), cl::Hidden,
149 cl::desc("Id of alloc to export if -memprof-dot-scope=alloc "
150 "or to highlight if -memprof-dot-scope=all"));
151
153 "memprof-dot-context-id", cl::init(0), cl::Hidden,
154 cl::desc("Id of context to export if -memprof-dot-scope=context or to "
155 "highlight otherwise"));
156
157static cl::opt<bool>
158 DumpCCG("memprof-dump-ccg", cl::init(false), cl::Hidden,
159 cl::desc("Dump CallingContextGraph to stdout after each stage."));
160
161static cl::opt<bool>
162 VerifyCCG("memprof-verify-ccg", cl::init(false), cl::Hidden,
163 cl::desc("Perform verification checks on CallingContextGraph."));
164
165static cl::opt<bool>
166 VerifyNodes("memprof-verify-nodes", cl::init(false), cl::Hidden,
167 cl::desc("Perform frequent verification checks on nodes."));
168
170 "memprof-import-summary",
171 cl::desc("Import summary to use for testing the ThinLTO backend via opt"),
172 cl::Hidden);
173
175 TailCallSearchDepth("memprof-tail-call-search-depth", cl::init(5),
177 cl::desc("Max depth to recursively search for missing "
178 "frames through tail calls."));
179
180// Optionally enable cloning of callsites involved with recursive cycles
182 "memprof-allow-recursive-callsites", cl::init(true), cl::Hidden,
183 cl::desc("Allow cloning of callsites involved in recursive cycles"));
184
186 "memprof-clone-recursive-contexts", cl::init(true), cl::Hidden,
187 cl::desc("Allow cloning of contexts through recursive cycles"));
188
189// Generally this is needed for correct assignment of allocation clones to
190// function clones, however, allow it to be disabled for debugging while the
191// functionality is new and being tested more widely.
192static cl::opt<bool>
193 MergeClones("memprof-merge-clones", cl::init(true), cl::Hidden,
194 cl::desc("Merge clones before assigning functions"));
195
196// When disabled, try to detect and prevent cloning of recursive contexts.
197// This is only necessary until we support cloning through recursive cycles.
198// Leave on by default for now, as disabling requires a little bit of compile
199// time overhead and doesn't affect correctness, it will just inflate the cold
200// hinted bytes reporting a bit when -memprof-report-hinted-sizes is enabled.
202 "memprof-allow-recursive-contexts", cl::init(true), cl::Hidden,
203 cl::desc("Allow cloning of contexts having recursive cycles"));
204
205// Set the minimum absolute count threshold for allowing inlining of indirect
206// calls promoted during cloning.
208 "memprof-icp-noinline-threshold", cl::init(0), cl::Hidden,
209 cl::desc("Minimum absolute count for promoted target to be inlinable"));
210
211namespace llvm {
213 "enable-memprof-context-disambiguation", cl::Hidden,
214 cl::desc("Enable MemProf context disambiguation"));
215
216// Indicate we are linking with an allocator that supports hot/cold operator
217// new interfaces.
219 "supports-hot-cold-new", cl::init(false), cl::Hidden,
220 cl::desc("Linking with hot/cold operator new interfaces"));
221
223 "memprof-require-definition-for-promotion", cl::init(false), cl::Hidden,
224 cl::desc(
225 "Require target function definition when promoting indirect calls"));
226
229
231 "memprof-top-n-important", cl::init(10), cl::Hidden,
232 cl::desc("Number of largest cold contexts to consider important"));
233
235 "memprof-fixup-important", cl::init(true), cl::Hidden,
236 cl::desc("Enables edge fixup for important contexts"));
237
239
240} // namespace llvm
241
242namespace {
243
244/// CRTP base for graphs built from either IR or ThinLTO summary index.
245///
246/// The graph represents the call contexts in all memprof metadata on allocation
247/// calls, with nodes for the allocations themselves, as well as for the calls
248/// in each context. The graph is initially built from the allocation memprof
249/// metadata (or summary) MIBs. It is then updated to match calls with callsite
250/// metadata onto the nodes, updating it to reflect any inlining performed on
251/// those calls.
252///
253/// Each MIB (representing an allocation's call context with allocation
254/// behavior) is assigned a unique context id during the graph build. The edges
255/// and nodes in the graph are decorated with the context ids they carry. This
256/// is used to correctly update the graph when cloning is performed so that we
257/// can uniquify the context for a single (possibly cloned) allocation.
258template <typename DerivedCCG, typename FuncTy, typename CallTy>
259class CallsiteContextGraph {
260public:
261 CallsiteContextGraph() = default;
262 CallsiteContextGraph(const CallsiteContextGraph &) = default;
263 CallsiteContextGraph(CallsiteContextGraph &&) = default;
264
265 /// Main entry point to perform analysis and transformations on graph.
266 bool process(function_ref<void(StringRef, StringRef, const Twine &)>
267 EmitRemark = nullptr,
268 bool AllowExtraAnalysis = false);
269
270 /// Perform cloning on the graph necessary to uniquely identify the allocation
271 /// behavior of an allocation based on its context.
272 void identifyClones();
273
274 /// Assign callsite clones to functions, cloning functions as needed to
275 /// accommodate the combinations of their callsite clones reached by callers.
276 /// For regular LTO this clones functions and callsites in the IR, but for
277 /// ThinLTO the cloning decisions are noted in the summaries and later applied
278 /// in applyImport.
279 bool assignFunctions();
280
281 void dump() const;
282 void print(raw_ostream &OS) const;
283 void printTotalSizes(raw_ostream &OS,
284 function_ref<void(StringRef, StringRef, const Twine &)>
285 EmitRemark = nullptr) const;
286
288 const CallsiteContextGraph &CCG) {
289 CCG.print(OS);
290 return OS;
291 }
292
293 friend struct GraphTraits<
294 const CallsiteContextGraph<DerivedCCG, FuncTy, CallTy> *>;
295 friend struct DOTGraphTraits<
296 const CallsiteContextGraph<DerivedCCG, FuncTy, CallTy> *>;
297
298 void exportToDot(std::string Label) const;
299
300 /// Represents a function clone via FuncTy pointer and clone number pair.
301 struct FuncInfo final
302 : public std::pair<FuncTy *, unsigned /*Clone number*/> {
303 using Base = std::pair<FuncTy *, unsigned>;
304 FuncInfo(const Base &B) : Base(B) {}
305 FuncInfo(FuncTy *F = nullptr, unsigned CloneNo = 0) : Base(F, CloneNo) {}
306 explicit operator bool() const { return this->first != nullptr; }
307 FuncTy *func() const { return this->first; }
308 unsigned cloneNo() const { return this->second; }
309 };
310
311 /// Represents a callsite clone via CallTy and clone number pair.
312 struct CallInfo final : public std::pair<CallTy, unsigned /*Clone number*/> {
313 using Base = std::pair<CallTy, unsigned>;
314 CallInfo(const Base &B) : Base(B) {}
315 CallInfo(CallTy Call = nullptr, unsigned CloneNo = 0)
316 : Base(Call, CloneNo) {}
317 explicit operator bool() const { return (bool)this->first; }
318 CallTy call() const { return this->first; }
319 unsigned cloneNo() const { return this->second; }
320 void setCloneNo(unsigned N) { this->second = N; }
321 void print(raw_ostream &OS) const {
322 if (!operator bool()) {
323 assert(!cloneNo());
324 OS << "null Call";
325 return;
326 }
327 call()->print(OS);
328 OS << "\t(clone " << cloneNo() << ")";
329 }
330 void dump() const {
331 print(dbgs());
332 dbgs() << "\n";
333 }
334 friend raw_ostream &operator<<(raw_ostream &OS, const CallInfo &Call) {
335 Call.print(OS);
336 return OS;
337 }
338 };
339
340 struct ContextEdge;
341
342 /// Node in the Callsite Context Graph
343 struct ContextNode {
344 // Assigned to nodes as they are created, useful for debugging.
345 unsigned NodeId = 0;
346
347 // Keep this for now since in the IR case where we have an Instruction* it
348 // is not as immediately discoverable. Used for printing richer information
349 // when dumping graph.
350 bool IsAllocation;
351
352 // Keeps track of when the Call was reset to null because there was
353 // recursion.
354 bool Recursive = false;
355
356 // This will be formed by ORing together the AllocationType enum values
357 // for contexts including this node.
358 uint8_t AllocTypes = 0;
359
360 // The corresponding allocation or interior call. This is the primary call
361 // for which we have created this node.
362 CallInfo Call;
363
364 // List of other calls that can be treated the same as the primary call
365 // through cloning. I.e. located in the same function and have the same
366 // (possibly pruned) stack ids. They will be updated the same way as the
367 // primary call when assigning to function clones.
368 SmallVector<CallInfo, 0> MatchingCalls;
369
370 // For alloc nodes this is a unique id assigned when constructed, and for
371 // callsite stack nodes it is the original stack id when the node is
372 // constructed from the memprof MIB metadata on the alloc nodes. Note that
373 // this is only used when matching callsite metadata onto the stack nodes
374 // created when processing the allocation memprof MIBs, and for labeling
375 // nodes in the dot graph. Therefore we don't bother to assign a value for
376 // clones.
377 uint64_t OrigStackOrAllocId = 0;
378
379 // Edges to all callees in the profiled call stacks.
380 // TODO: Should this be a map (from Callee node) for more efficient lookup?
381 std::vector<std::shared_ptr<ContextEdge>> CalleeEdges;
382
383 // Edges to all callers in the profiled call stacks.
384 // TODO: Should this be a map (from Caller node) for more efficient lookup?
385 std::vector<std::shared_ptr<ContextEdge>> CallerEdges;
386
387 // Returns true if we need to look at the callee edges for determining the
388 // node context ids and allocation type.
389 bool useCallerEdgesForContextInfo() const {
390 // Typically if the callee edges are empty either the caller edges are
391 // also empty, or this is an allocation (leaf node). However, if we are
392 // allowing recursive callsites and contexts this will be violated for
393 // incompletely cloned recursive cycles.
394 assert(!CalleeEdges.empty() || CallerEdges.empty() || IsAllocation ||
396 // When cloning for a recursive context, during cloning we might be in the
397 // midst of cloning for a recurrence and have moved context ids off of a
398 // caller edge onto the clone but not yet off of the incoming caller
399 // (back) edge. If we don't look at those we miss the fact that this node
400 // still has context ids of interest.
401 return IsAllocation || CloneRecursiveContexts;
402 }
403
404 // Compute the context ids for this node from the union of its edge context
405 // ids.
406 DenseSet<uint32_t> getContextIds() const {
407 unsigned Count = 0;
408 // Compute the number of ids for reserve below. In general we only need to
409 // look at one set of edges, typically the callee edges, since other than
410 // allocations and in some cases during recursion cloning, all the context
411 // ids on the callers should also flow out via callee edges.
412 for (auto &Edge : CalleeEdges.empty() ? CallerEdges : CalleeEdges)
413 Count += Edge->getContextIds().size();
414 DenseSet<uint32_t> ContextIds;
415 ContextIds.reserve(Count);
417 CalleeEdges, useCallerEdgesForContextInfo()
418 ? CallerEdges
419 : std::vector<std::shared_ptr<ContextEdge>>());
420 for (const auto &Edge : Edges)
421 ContextIds.insert_range(Edge->getContextIds());
422 return ContextIds;
423 }
424
425 // Compute the allocation type for this node from the OR of its edge
426 // allocation types.
427 uint8_t computeAllocType() const {
428 uint8_t BothTypes =
432 CalleeEdges, useCallerEdgesForContextInfo()
433 ? CallerEdges
434 : std::vector<std::shared_ptr<ContextEdge>>());
435 for (const auto &Edge : Edges) {
436 AllocType |= Edge->AllocTypes;
437 // Bail early if alloc type reached both, no further refinement.
438 if (AllocType == BothTypes)
439 return AllocType;
440 }
441 return AllocType;
442 }
443
444 // The context ids set for this node is empty if its edge context ids are
445 // also all empty.
446 bool emptyContextIds() const {
448 CalleeEdges, useCallerEdgesForContextInfo()
449 ? CallerEdges
450 : std::vector<std::shared_ptr<ContextEdge>>());
451 for (const auto &Edge : Edges) {
452 if (!Edge->getContextIds().empty())
453 return false;
454 }
455 return true;
456 }
457
458 // List of clones of this ContextNode, initially empty.
459 std::vector<ContextNode *> Clones;
460
461 // If a clone, points to the original uncloned node.
462 ContextNode *CloneOf = nullptr;
463
464 ContextNode(bool IsAllocation) : IsAllocation(IsAllocation), Call() {}
465
466 ContextNode(bool IsAllocation, CallInfo C)
467 : IsAllocation(IsAllocation), Call(C) {}
468
469 void addClone(ContextNode *Clone) {
470 if (CloneOf) {
471 CloneOf->Clones.push_back(Clone);
472 Clone->CloneOf = CloneOf;
473 } else {
474 Clones.push_back(Clone);
475 assert(!Clone->CloneOf);
476 Clone->CloneOf = this;
477 }
478 }
479
480 ContextNode *getOrigNode() {
481 if (!CloneOf)
482 return this;
483 return CloneOf;
484 }
485
486 void addOrUpdateCallerEdge(ContextNode *Caller, AllocationType AllocType,
487 unsigned int ContextId);
488
489 ContextEdge *findEdgeFromCallee(const ContextNode *Callee);
490 ContextEdge *findEdgeFromCaller(const ContextNode *Caller);
491 void eraseCalleeEdge(const ContextEdge *Edge);
492 void eraseCallerEdge(const ContextEdge *Edge);
493
494 void setCall(CallInfo C) { Call = std::move(C); }
495
496 bool hasCall() const { return (bool)Call.call(); }
497
498 void printCall(raw_ostream &OS) const { Call.print(OS); }
499
500 // True if this node was effectively removed from the graph, in which case
501 // it should have an allocation type of None and empty context ids.
502 bool isRemoved() const {
503 // Typically if the callee edges are empty either the caller edges are
504 // also empty, or this is an allocation (leaf node). However, if we are
505 // allowing recursive callsites and contexts this will be violated for
506 // incompletely cloned recursive cycles.
508 (AllocTypes == (uint8_t)AllocationType::None) ==
509 emptyContextIds());
510 return AllocTypes == (uint8_t)AllocationType::None;
511 }
512
513 void dump() const;
514 void print(raw_ostream &OS) const;
515
516 friend raw_ostream &operator<<(raw_ostream &OS, const ContextNode &Node) {
517 Node.print(OS);
518 return OS;
519 }
520 };
521
522 /// Edge in the Callsite Context Graph from a ContextNode N to a caller or
523 /// callee.
524 struct ContextEdge {
525 ContextNode *Callee;
526 ContextNode *Caller;
527
528 // This will be formed by ORing together the AllocationType enum values
529 // for contexts including this edge.
530 uint8_t AllocTypes = 0;
531
532 // Set just before initiating cloning when cloning of recursive contexts is
533 // enabled. Used to defer cloning of backedges until we have done cloning of
534 // the callee node for non-backedge caller edges. This exposes cloning
535 // opportunities through the backedge of the cycle.
536 // TODO: Note that this is not updated during cloning, and it is unclear
537 // whether that would be needed.
538 bool IsBackedge = false;
539
540 // The set of IDs for contexts including this edge.
541 DenseSet<uint32_t> ContextIds;
542
543 ContextEdge(ContextNode *Callee, ContextNode *Caller, uint8_t AllocType,
544 DenseSet<uint32_t> ContextIds)
545 : Callee(Callee), Caller(Caller), AllocTypes(AllocType),
546 ContextIds(std::move(ContextIds)) {}
547
548 DenseSet<uint32_t> &getContextIds() { return ContextIds; }
549
550 // Helper to clear the fields of this edge when we are removing it from the
551 // graph.
552 inline void clear() {
553 ContextIds.clear();
554 AllocTypes = (uint8_t)AllocationType::None;
555 Caller = nullptr;
556 Callee = nullptr;
557 }
558
559 // Check if edge was removed from the graph. This is useful while iterating
560 // over a copy of edge lists when performing operations that mutate the
561 // graph in ways that might remove one of the edges.
562 inline bool isRemoved() const {
563 if (Callee || Caller)
564 return false;
565 // Any edges that have been removed from the graph but are still in a
566 // shared_ptr somewhere should have all fields null'ed out by clear()
567 // above.
568 assert(AllocTypes == (uint8_t)AllocationType::None);
569 assert(ContextIds.empty());
570 return true;
571 }
572
573 void dump() const;
574 void print(raw_ostream &OS) const;
575
576 friend raw_ostream &operator<<(raw_ostream &OS, const ContextEdge &Edge) {
577 Edge.print(OS);
578 return OS;
579 }
580 };
581
582 /// Helpers to remove edges that have allocation type None (due to not
583 /// carrying any context ids) after transformations.
584 void removeNoneTypeCalleeEdges(ContextNode *Node);
585 void removeNoneTypeCallerEdges(ContextNode *Node);
586 void
587 recursivelyRemoveNoneTypeCalleeEdges(ContextNode *Node,
589
590protected:
591 /// Get a list of nodes corresponding to the stack ids in the given callsite
592 /// context.
593 template <class NodeT, class IteratorT>
594 std::vector<uint64_t>
595 getStackIdsWithContextNodes(CallStack<NodeT, IteratorT> &CallsiteContext);
596
597 /// Adds nodes for the given allocation and any stack ids on its memprof MIB
598 /// metadata (or summary).
599 ContextNode *addAllocNode(CallInfo Call, const FuncTy *F);
600
601 /// Adds nodes for the given MIB stack ids.
602 template <class NodeT, class IteratorT>
603 void addStackNodesForMIB(
604 ContextNode *AllocNode, CallStack<NodeT, IteratorT> &StackContext,
606 ArrayRef<ContextTotalSize> ContextSizeInfo,
607 std::map<uint64_t, uint32_t> &TotalSizeToContextIdTopNCold);
608
609 /// Matches all callsite metadata (or summary) to the nodes created for
610 /// allocation memprof MIB metadata, synthesizing new nodes to reflect any
611 /// inlining performed on those callsite instructions.
612 void updateStackNodes();
613
614 /// Optionally fixup edges for the N largest cold contexts to better enable
615 /// cloning. This is particularly helpful if the context includes recursion
616 /// as well as inlining, resulting in a single stack node for multiple stack
617 /// ids in the context. With recursion it is particularly difficult to get the
618 /// edge updates correct as in the general case we have lost the original
619 /// stack id ordering for the context. Do more expensive fixup for the largest
620 /// contexts, controlled by MemProfTopNImportant and MemProfFixupImportant.
621 void fixupImportantContexts();
622
623 /// Update graph to conservatively handle any callsite stack nodes that target
624 /// multiple different callee target functions.
625 void handleCallsitesWithMultipleTargets();
626
627 /// Mark backedges via the standard DFS based backedge algorithm.
628 void markBackedges();
629
630 /// Merge clones generated during cloning for different allocations but that
631 /// are called by the same caller node, to ensure proper function assignment.
632 void mergeClones();
633
634 // Try to partition calls on the given node (already placed into the AllCalls
635 // array) by callee function, creating new copies of Node as needed to hold
636 // calls with different callees, and moving the callee edges appropriately.
637 // Returns true if partitioning was successful.
638 bool partitionCallsByCallee(
639 ContextNode *Node, ArrayRef<CallInfo> AllCalls,
640 std::vector<std::pair<CallInfo, ContextNode *>> &NewCallToNode);
641
642 /// Save lists of calls with MemProf metadata in each function, for faster
643 /// iteration.
644 MapVector<FuncTy *, std::vector<CallInfo>> FuncToCallsWithMetadata;
645
646 /// Map from callsite node to the enclosing caller function.
647 std::map<const ContextNode *, const FuncTy *> NodeToCallingFunc;
648
649 // When exporting to dot, and an allocation id is specified, contains the
650 // context ids on that allocation.
651 DenseSet<uint32_t> DotAllocContextIds;
652
653private:
654 using EdgeIter = typename std::vector<std::shared_ptr<ContextEdge>>::iterator;
655
656 // Structure to keep track of information for each call as we are matching
657 // non-allocation callsites onto context nodes created from the allocation
658 // call metadata / summary contexts.
659 struct CallContextInfo {
660 // The callsite we're trying to match.
661 CallTy Call;
662 // The callsites stack ids that have a context node in the graph.
663 std::vector<uint64_t> StackIds;
664 // The function containing this callsite.
665 const FuncTy *Func;
666 // Initially empty, if needed this will be updated to contain the context
667 // ids for use in a new context node created for this callsite.
668 DenseSet<uint32_t> ContextIds;
669 };
670
671 /// Helper to remove edge from graph, updating edge iterator if it is provided
672 /// (in which case CalleeIter indicates which edge list is being iterated).
673 /// This will also perform the necessary clearing of the ContextEdge members
674 /// to enable later checking if the edge has been removed (since we may have
675 /// other copies of the shared_ptr in existence, and in fact rely on this to
676 /// enable removal while iterating over a copy of a node's edge list).
677 void removeEdgeFromGraph(ContextEdge *Edge, EdgeIter *EI = nullptr,
678 bool CalleeIter = true);
679
680 /// Assigns the given Node to calls at or inlined into the location with
681 /// the Node's stack id, after post order traversing and processing its
682 /// caller nodes. Uses the call information recorded in the given
683 /// StackIdToMatchingCalls map, and creates new nodes for inlined sequences
684 /// as needed. Called by updateStackNodes which sets up the given
685 /// StackIdToMatchingCalls map.
686 void assignStackNodesPostOrder(
687 ContextNode *Node, DenseSet<const ContextNode *> &Visited,
688 DenseMap<uint64_t, std::vector<CallContextInfo>> &StackIdToMatchingCalls,
689 DenseMap<CallInfo, CallInfo> &CallToMatchingCall,
690 const DenseSet<uint32_t> &ImportantContextIds);
691
692 /// Duplicates the given set of context ids, updating the provided
693 /// map from each original id with the newly generated context ids,
694 /// and returning the new duplicated id set.
695 DenseSet<uint32_t> duplicateContextIds(
696 const DenseSet<uint32_t> &StackSequenceContextIds,
697 DenseMap<uint32_t, DenseSet<uint32_t>> &OldToNewContextIds);
698
699 /// Propagates all duplicated context ids across the graph.
700 void propagateDuplicateContextIds(
701 const DenseMap<uint32_t, DenseSet<uint32_t>> &OldToNewContextIds);
702
703 /// Connect the NewNode to OrigNode's callees if TowardsCallee is true,
704 /// else to its callers. Also updates OrigNode's edges to remove any context
705 /// ids moved to the newly created edge.
706 void connectNewNode(ContextNode *NewNode, ContextNode *OrigNode,
707 bool TowardsCallee,
708 DenseSet<uint32_t> RemainingContextIds);
709
710 /// Get the stack id corresponding to the given Id or Index (for IR this will
711 /// return itself, for a summary index this will return the id recorded in the
712 /// index for that stack id index value).
713 uint64_t getStackId(uint64_t IdOrIndex) const {
714 return static_cast<const DerivedCCG *>(this)->getStackId(IdOrIndex);
715 }
716
717 /// Returns true if the given call targets the callee of the given edge, or if
718 /// we were able to identify the call chain through intermediate tail calls.
719 /// In the latter case new context nodes are added to the graph for the
720 /// identified tail calls, and their synthesized nodes are added to
721 /// TailCallToContextNodeMap. The EdgeIter is updated in the latter case for
722 /// the updated edges and to prepare it for an increment in the caller.
723 bool
724 calleesMatch(CallTy Call, EdgeIter &EI,
725 MapVector<CallInfo, ContextNode *> &TailCallToContextNodeMap);
726
727 // Return the callee function of the given call, or nullptr if it can't be
728 // determined
729 const FuncTy *getCalleeFunc(CallTy Call) {
730 return static_cast<DerivedCCG *>(this)->getCalleeFunc(Call);
731 }
732
733 /// Returns true if the given call targets the given function, or if we were
734 /// able to identify the call chain through intermediate tail calls (in which
735 /// case FoundCalleeChain will be populated).
736 bool calleeMatchesFunc(
737 CallTy Call, const FuncTy *Func, const FuncTy *CallerFunc,
738 std::vector<std::pair<CallTy, FuncTy *>> &FoundCalleeChain) {
739 return static_cast<DerivedCCG *>(this)->calleeMatchesFunc(
740 Call, Func, CallerFunc, FoundCalleeChain);
741 }
742
743 /// Returns true if both call instructions have the same callee.
744 bool sameCallee(CallTy Call1, CallTy Call2) {
745 return static_cast<DerivedCCG *>(this)->sameCallee(Call1, Call2);
746 }
747
748 /// Get a list of nodes corresponding to the stack ids in the given
749 /// callsite's context.
750 std::vector<uint64_t> getStackIdsWithContextNodesForCall(CallTy Call) {
751 return static_cast<DerivedCCG *>(this)->getStackIdsWithContextNodesForCall(
752 Call);
753 }
754
755 /// Get the last stack id in the context for callsite.
756 uint64_t getLastStackId(CallTy Call) {
757 return static_cast<DerivedCCG *>(this)->getLastStackId(Call);
758 }
759
760 /// Update the allocation call to record type of allocated memory.
761 void updateAllocationCall(CallInfo &Call, AllocationType AllocType) {
762 AllocType == AllocationType::Cold ? AllocTypeCold++ : AllocTypeNotCold++;
763 static_cast<DerivedCCG *>(this)->updateAllocationCall(Call, AllocType);
764 }
765
766 /// Get the AllocationType assigned to the given allocation instruction clone.
767 AllocationType getAllocationCallType(const CallInfo &Call) const {
768 return static_cast<const DerivedCCG *>(this)->getAllocationCallType(Call);
769 }
770
771 /// Update non-allocation call to invoke (possibly cloned) function
772 /// CalleeFunc.
773 void updateCall(CallInfo &CallerCall, FuncInfo CalleeFunc) {
774 static_cast<DerivedCCG *>(this)->updateCall(CallerCall, CalleeFunc);
775 }
776
777 /// Clone the given function for the given callsite, recording mapping of all
778 /// of the functions tracked calls to their new versions in the CallMap.
779 /// Assigns new clones to clone number CloneNo.
780 FuncInfo cloneFunctionForCallsite(
781 FuncInfo &Func, CallInfo &Call, DenseMap<CallInfo, CallInfo> &CallMap,
782 std::vector<CallInfo> &CallsWithMetadataInFunc, unsigned CloneNo) {
783 return static_cast<DerivedCCG *>(this)->cloneFunctionForCallsite(
784 Func, Call, CallMap, CallsWithMetadataInFunc, CloneNo);
785 }
786
787 /// Gets a label to use in the dot graph for the given call clone in the given
788 /// function.
789 std::string getLabel(const FuncTy *Func, const CallTy Call,
790 unsigned CloneNo) const {
791 return static_cast<const DerivedCCG *>(this)->getLabel(Func, Call, CloneNo);
792 }
793
794 // Create and return a new ContextNode.
795 ContextNode *createNewNode(bool IsAllocation, const FuncTy *F = nullptr,
796 CallInfo C = CallInfo()) {
797 NodeOwner.push_back(std::make_unique<ContextNode>(IsAllocation, C));
798 auto *NewNode = NodeOwner.back().get();
799 if (F)
800 NodeToCallingFunc[NewNode] = F;
801 NewNode->NodeId = NodeOwner.size();
802 return NewNode;
803 }
804
805 /// Helpers to find the node corresponding to the given call or stackid.
806 ContextNode *getNodeForInst(const CallInfo &C);
807 ContextNode *getNodeForAlloc(const CallInfo &C);
808 ContextNode *getNodeForStackId(uint64_t StackId);
809
810 /// Computes the alloc type corresponding to the given context ids, by
811 /// unioning their recorded alloc types.
812 uint8_t computeAllocType(DenseSet<uint32_t> &ContextIds) const;
813
814 /// Returns the allocation type of the intersection of the contexts of two
815 /// nodes (based on their provided context id sets), optimized for the case
816 /// when Node1Ids is smaller than Node2Ids.
817 uint8_t intersectAllocTypesImpl(const DenseSet<uint32_t> &Node1Ids,
818 const DenseSet<uint32_t> &Node2Ids) const;
819
820 /// Returns the allocation type of the intersection of the contexts of two
821 /// nodes (based on their provided context id sets).
822 uint8_t intersectAllocTypes(const DenseSet<uint32_t> &Node1Ids,
823 const DenseSet<uint32_t> &Node2Ids) const;
824
825 /// Create a clone of Edge's callee and move Edge to that new callee node,
826 /// performing the necessary context id and allocation type updates.
827 /// If ContextIdsToMove is non-empty, only that subset of Edge's ids are
828 /// moved to an edge to the new callee.
829 ContextNode *
830 moveEdgeToNewCalleeClone(const std::shared_ptr<ContextEdge> &Edge,
831 DenseSet<uint32_t> ContextIdsToMove = {});
832
833 /// Change the callee of Edge to existing callee clone NewCallee, performing
834 /// the necessary context id and allocation type updates.
835 /// If ContextIdsToMove is non-empty, only that subset of Edge's ids are
836 /// moved to an edge to the new callee.
837 void moveEdgeToExistingCalleeClone(const std::shared_ptr<ContextEdge> &Edge,
838 ContextNode *NewCallee,
839 bool NewClone = false,
840 DenseSet<uint32_t> ContextIdsToMove = {});
841
842 /// Change the caller of the edge at the given callee edge iterator to be
843 /// NewCaller, performing the necessary context id and allocation type
844 /// updates. This is similar to the above moveEdgeToExistingCalleeClone, but
845 /// a simplified version of it as we always move the given edge and all of its
846 /// context ids.
847 void moveCalleeEdgeToNewCaller(const std::shared_ptr<ContextEdge> &Edge,
848 ContextNode *NewCaller);
849
850 /// Recursive helper for marking backedges via DFS.
851 void markBackedges(ContextNode *Node, DenseSet<const ContextNode *> &Visited,
852 DenseSet<const ContextNode *> &CurrentStack);
853
854 /// Recursive helper for merging clones.
855 void
856 mergeClones(ContextNode *Node, DenseSet<const ContextNode *> &Visited,
857 DenseMap<uint32_t, ContextNode *> &ContextIdToAllocationNode);
858 /// Main worker for merging callee clones for a given node.
859 void mergeNodeCalleeClones(
860 ContextNode *Node, DenseSet<const ContextNode *> &Visited,
861 DenseMap<uint32_t, ContextNode *> &ContextIdToAllocationNode);
862 /// Helper to find other callers of the given set of callee edges that can
863 /// share the same callee merge node.
864 void findOtherCallersToShareMerge(
865 ContextNode *Node, std::vector<std::shared_ptr<ContextEdge>> &CalleeEdges,
866 DenseMap<uint32_t, ContextNode *> &ContextIdToAllocationNode,
867 DenseSet<ContextNode *> &OtherCallersToShareMerge);
868
869 /// Recursively perform cloning on the graph for the given Node and its
870 /// callers, in order to uniquely identify the allocation behavior of an
871 /// allocation given its context. The context ids of the allocation being
872 /// processed are given in AllocContextIds.
873 void identifyClones(ContextNode *Node, DenseSet<const ContextNode *> &Visited,
874 const DenseSet<uint32_t> &AllocContextIds);
875
876 /// Map from each context ID to the AllocationType assigned to that context.
877 DenseMap<uint32_t, AllocationType> ContextIdToAllocationType;
878
879 /// Map from each contextID to the profiled full contexts and their total
880 /// sizes (there may be more than one due to context trimming),
881 /// optionally populated when requested (via MemProfReportHintedSizes or
882 /// MinClonedColdBytePercent).
883 DenseMap<uint32_t, std::vector<ContextTotalSize>> ContextIdToContextSizeInfos;
884
885 /// Identifies the context node created for a stack id when adding the MIB
886 /// contexts to the graph. This is used to locate the context nodes when
887 /// trying to assign the corresponding callsites with those stack ids to these
888 /// nodes.
889 DenseMap<uint64_t, ContextNode *> StackEntryIdToContextNodeMap;
890
891 /// Saves information for the contexts identified as important (the largest
892 /// cold contexts up to MemProfTopNImportant).
893 struct ImportantContextInfo {
894 // The original list of leaf first stack ids corresponding to this context.
895 std::vector<uint64_t> StackIds;
896 // Max length of stack ids corresponding to a single stack ContextNode for
897 // this context (i.e. the max length of a key in StackIdsToNode below).
898 unsigned MaxLength = 0;
899 // Mapping of slices of the stack ids to the corresponding ContextNode
900 // (there can be multiple stack ids due to inlining). Populated when
901 // updating stack nodes while matching them to the IR or summary.
902 std::map<std::vector<uint64_t>, ContextNode *> StackIdsToNode;
903 };
904
905 // Map of important full context ids to information about each.
906 DenseMap<uint32_t, ImportantContextInfo> ImportantContextIdInfo;
907
908 // For each important context id found in Node (if any), records the list of
909 // stack ids that corresponded to the given callsite Node. There can be more
910 // than one in the case of inlining.
911 void recordStackNode(std::vector<uint64_t> &StackIds, ContextNode *Node,
912 // We pass in the Node's context ids to avoid the
913 // overhead of computing them as the caller already has
914 // them in some cases.
915 const DenseSet<uint32_t> &NodeContextIds,
916 const DenseSet<uint32_t> &ImportantContextIds) {
918 assert(ImportantContextIds.empty());
919 return;
920 }
922 set_intersection(NodeContextIds, ImportantContextIds);
923 if (Ids.empty())
924 return;
925 auto Size = StackIds.size();
926 for (auto Id : Ids) {
927 auto &Entry = ImportantContextIdInfo[Id];
928 Entry.StackIdsToNode[StackIds] = Node;
929 // Keep track of the max to simplify later analysis.
930 if (Size > Entry.MaxLength)
931 Entry.MaxLength = Size;
932 }
933 }
934
935 /// Maps to track the calls to their corresponding nodes in the graph.
936 MapVector<CallInfo, ContextNode *> AllocationCallToContextNodeMap;
937 MapVector<CallInfo, ContextNode *> NonAllocationCallToContextNodeMap;
938
939 /// Owner of all ContextNode unique_ptrs.
940 std::vector<std::unique_ptr<ContextNode>> NodeOwner;
941
942 /// Perform sanity checks on graph when requested.
943 void check() const;
944
945 /// Keeps track of the last unique context id assigned.
946 unsigned int LastContextId = 0;
947};
948
949template <typename DerivedCCG, typename FuncTy, typename CallTy>
950using ContextNode =
951 typename CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::ContextNode;
952template <typename DerivedCCG, typename FuncTy, typename CallTy>
953using ContextEdge =
954 typename CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::ContextEdge;
955template <typename DerivedCCG, typename FuncTy, typename CallTy>
956using FuncInfo =
957 typename CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::FuncInfo;
958template <typename DerivedCCG, typename FuncTy, typename CallTy>
959using CallInfo =
960 typename CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::CallInfo;
961
962/// CRTP derived class for graphs built from IR (regular LTO).
963class ModuleCallsiteContextGraph
964 : public CallsiteContextGraph<ModuleCallsiteContextGraph, Function,
965 Instruction *> {
966public:
967 ModuleCallsiteContextGraph(
968 Module &M,
969 llvm::function_ref<OptimizationRemarkEmitter &(Function *)> OREGetter);
970
971private:
972 friend CallsiteContextGraph<ModuleCallsiteContextGraph, Function,
973 Instruction *>;
974
975 uint64_t getStackId(uint64_t IdOrIndex) const;
976 const Function *getCalleeFunc(Instruction *Call);
977 bool calleeMatchesFunc(
978 Instruction *Call, const Function *Func, const Function *CallerFunc,
979 std::vector<std::pair<Instruction *, Function *>> &FoundCalleeChain);
980 bool sameCallee(Instruction *Call1, Instruction *Call2);
981 bool findProfiledCalleeThroughTailCalls(
982 const Function *ProfiledCallee, Value *CurCallee, unsigned Depth,
983 std::vector<std::pair<Instruction *, Function *>> &FoundCalleeChain,
984 bool &FoundMultipleCalleeChains);
985 uint64_t getLastStackId(Instruction *Call);
986 std::vector<uint64_t> getStackIdsWithContextNodesForCall(Instruction *Call);
987 void updateAllocationCall(CallInfo &Call, AllocationType AllocType);
988 AllocationType getAllocationCallType(const CallInfo &Call) const;
989 void updateCall(CallInfo &CallerCall, FuncInfo CalleeFunc);
990 CallsiteContextGraph<ModuleCallsiteContextGraph, Function,
991 Instruction *>::FuncInfo
992 cloneFunctionForCallsite(FuncInfo &Func, CallInfo &Call,
993 DenseMap<CallInfo, CallInfo> &CallMap,
994 std::vector<CallInfo> &CallsWithMetadataInFunc,
995 unsigned CloneNo);
996 std::string getLabel(const Function *Func, const Instruction *Call,
997 unsigned CloneNo) const;
998
999 const Module &Mod;
1000 llvm::function_ref<OptimizationRemarkEmitter &(Function *)> OREGetter;
1001};
1002
1003/// Represents a call in the summary index graph, which can either be an
1004/// allocation or an interior callsite node in an allocation's context.
1005/// Holds a pointer to the corresponding data structure in the index.
1006struct IndexCall : public PointerUnion<CallsiteInfo *, AllocInfo *> {
1007 IndexCall() : PointerUnion() {}
1008 IndexCall(std::nullptr_t) : IndexCall() {}
1009 IndexCall(CallsiteInfo *StackNode) : PointerUnion(StackNode) {}
1010 IndexCall(AllocInfo *AllocNode) : PointerUnion(AllocNode) {}
1011 IndexCall(PointerUnion PT) : PointerUnion(PT) {}
1012
1013 IndexCall *operator->() { return this; }
1014
1015 void print(raw_ostream &OS) const {
1016 PointerUnion<CallsiteInfo *, AllocInfo *> Base = *this;
1018 OS << *AI;
1019 } else {
1021 assert(CI);
1022 OS << *CI;
1023 }
1024 }
1025};
1026} // namespace
1027
1028namespace llvm {
1029template <> struct simplify_type<IndexCall> {
1031 static SimpleType getSimplifiedValue(IndexCall &Val) { return Val; }
1032};
1033template <> struct simplify_type<const IndexCall> {
1035 static SimpleType getSimplifiedValue(const IndexCall &Val) { return Val; }
1036};
1037} // namespace llvm
1038
1039namespace {
1040/// CRTP derived class for graphs built from summary index (ThinLTO).
1041class IndexCallsiteContextGraph
1042 : public CallsiteContextGraph<IndexCallsiteContextGraph, FunctionSummary,
1043 IndexCall> {
1044public:
1045 IndexCallsiteContextGraph(
1046 ModuleSummaryIndex &Index,
1047 llvm::function_ref<bool(GlobalValue::GUID, const GlobalValueSummary *)>
1048 isPrevailing);
1049
1050 ~IndexCallsiteContextGraph() {
1051 // Now that we are done with the graph it is safe to add the new
1052 // CallsiteInfo structs to the function summary vectors. The graph nodes
1053 // point into locations within these vectors, so we don't want to add them
1054 // any earlier.
1055 for (auto &I : FunctionCalleesToSynthesizedCallsiteInfos) {
1056 auto *FS = I.first;
1057 for (auto &Callsite : I.second)
1058 FS->addCallsite(std::move(*Callsite.second));
1059 }
1060 }
1061
1062private:
1063 friend CallsiteContextGraph<IndexCallsiteContextGraph, FunctionSummary,
1064 IndexCall>;
1065
1066 uint64_t getStackId(uint64_t IdOrIndex) const;
1067 const FunctionSummary *getCalleeFunc(IndexCall &Call);
1068 bool calleeMatchesFunc(
1069 IndexCall &Call, const FunctionSummary *Func,
1070 const FunctionSummary *CallerFunc,
1071 std::vector<std::pair<IndexCall, FunctionSummary *>> &FoundCalleeChain);
1072 bool sameCallee(IndexCall &Call1, IndexCall &Call2);
1073 bool findProfiledCalleeThroughTailCalls(
1074 ValueInfo ProfiledCallee, ValueInfo CurCallee, unsigned Depth,
1075 std::vector<std::pair<IndexCall, FunctionSummary *>> &FoundCalleeChain,
1076 bool &FoundMultipleCalleeChains);
1077 uint64_t getLastStackId(IndexCall &Call);
1078 std::vector<uint64_t> getStackIdsWithContextNodesForCall(IndexCall &Call);
1079 void updateAllocationCall(CallInfo &Call, AllocationType AllocType);
1080 AllocationType getAllocationCallType(const CallInfo &Call) const;
1081 void updateCall(CallInfo &CallerCall, FuncInfo CalleeFunc);
1082 CallsiteContextGraph<IndexCallsiteContextGraph, FunctionSummary,
1083 IndexCall>::FuncInfo
1084 cloneFunctionForCallsite(FuncInfo &Func, CallInfo &Call,
1085 DenseMap<CallInfo, CallInfo> &CallMap,
1086 std::vector<CallInfo> &CallsWithMetadataInFunc,
1087 unsigned CloneNo);
1088 std::string getLabel(const FunctionSummary *Func, const IndexCall &Call,
1089 unsigned CloneNo) const;
1090 DenseSet<GlobalValue::GUID> findAliaseeGUIDsPrevailingInDifferentModule();
1091
1092 // Saves mapping from function summaries containing memprof records back to
1093 // its VI, for use in checking and debugging.
1094 std::map<const FunctionSummary *, ValueInfo> FSToVIMap;
1095
1096 const ModuleSummaryIndex &Index;
1097 llvm::function_ref<bool(GlobalValue::GUID, const GlobalValueSummary *)>
1098 isPrevailing;
1099
1100 // Saves/owns the callsite info structures synthesized for missing tail call
1101 // frames that we discover while building the graph.
1102 // It maps from the summary of the function making the tail call, to a map
1103 // of callee ValueInfo to corresponding synthesized callsite info.
1104 DenseMap<FunctionSummary *,
1105 std::map<ValueInfo, std::unique_ptr<CallsiteInfo>>>
1106 FunctionCalleesToSynthesizedCallsiteInfos;
1107};
1108} // namespace
1109
1110template <>
1111struct llvm::DenseMapInfo<CallsiteContextGraph<
1112 ModuleCallsiteContextGraph, Function, Instruction *>::CallInfo>
1114template <>
1115struct llvm::DenseMapInfo<CallsiteContextGraph<
1116 IndexCallsiteContextGraph, FunctionSummary, IndexCall>::CallInfo>
1117 : public DenseMapInfo<std::pair<IndexCall, unsigned>> {};
1118template <>
1119struct llvm::DenseMapInfo<IndexCall>
1120 : public DenseMapInfo<PointerUnion<CallsiteInfo *, AllocInfo *>> {};
1121
1122namespace {
1123
1124// Map the uint8_t alloc types (which may contain NotCold|Cold) to the alloc
1125// type we should actually use on the corresponding allocation.
1126// If we can't clone a node that has NotCold+Cold alloc type, we will fall
1127// back to using NotCold. So don't bother cloning to distinguish NotCold+Cold
1128// from NotCold.
1129AllocationType allocTypeToUse(uint8_t AllocTypes) {
1130 assert(AllocTypes != (uint8_t)AllocationType::None);
1131 if (AllocTypes ==
1134 else
1135 return (AllocationType)AllocTypes;
1136}
1137
1138// Helper to check if the alloc types for all edges recorded in the
1139// InAllocTypes vector match the alloc types for all edges in the Edges
1140// vector.
1141template <typename DerivedCCG, typename FuncTy, typename CallTy>
1142bool allocTypesMatch(
1143 const std::vector<uint8_t> &InAllocTypes,
1144 const std::vector<std::shared_ptr<ContextEdge<DerivedCCG, FuncTy, CallTy>>>
1145 &Edges) {
1146 // This should be called only when the InAllocTypes vector was computed for
1147 // this set of Edges. Make sure the sizes are the same.
1148 assert(InAllocTypes.size() == Edges.size());
1149 return std::equal(
1150 InAllocTypes.begin(), InAllocTypes.end(), Edges.begin(), Edges.end(),
1151 [](const uint8_t &l,
1152 const std::shared_ptr<ContextEdge<DerivedCCG, FuncTy, CallTy>> &r) {
1153 // Can share if one of the edges is None type - don't
1154 // care about the type along that edge as it doesn't
1155 // exist for those context ids.
1156 if (l == (uint8_t)AllocationType::None ||
1157 r->AllocTypes == (uint8_t)AllocationType::None)
1158 return true;
1159 return allocTypeToUse(l) == allocTypeToUse(r->AllocTypes);
1160 });
1161}
1162
1163// Helper to check if the alloc types for all edges recorded in the
1164// InAllocTypes vector match the alloc types for callee edges in the given
1165// clone. Because the InAllocTypes were computed from the original node's callee
1166// edges, and other cloning could have happened after this clone was created, we
1167// need to find the matching clone callee edge, which may or may not exist.
1168template <typename DerivedCCG, typename FuncTy, typename CallTy>
1169bool allocTypesMatchClone(
1170 const std::vector<uint8_t> &InAllocTypes,
1171 const ContextNode<DerivedCCG, FuncTy, CallTy> *Clone) {
1172 const ContextNode<DerivedCCG, FuncTy, CallTy> *Node = Clone->CloneOf;
1173 assert(Node);
1174 // InAllocTypes should have been computed for the original node's callee
1175 // edges.
1176 assert(InAllocTypes.size() == Node->CalleeEdges.size());
1177 // First create a map of the clone callee edge callees to the edge alloc type.
1179 EdgeCalleeMap;
1180 for (const auto &E : Clone->CalleeEdges) {
1181 assert(!EdgeCalleeMap.contains(E->Callee));
1182 EdgeCalleeMap[E->Callee] = E->AllocTypes;
1183 }
1184 // Next, walk the original node's callees, and look for the corresponding
1185 // clone edge to that callee.
1186 for (unsigned I = 0; I < Node->CalleeEdges.size(); I++) {
1187 auto Iter = EdgeCalleeMap.find(Node->CalleeEdges[I]->Callee);
1188 // Not found is ok, we will simply add an edge if we use this clone.
1189 if (Iter == EdgeCalleeMap.end())
1190 continue;
1191 // Can share if one of the edges is None type - don't
1192 // care about the type along that edge as it doesn't
1193 // exist for those context ids.
1194 if (InAllocTypes[I] == (uint8_t)AllocationType::None ||
1195 Iter->second == (uint8_t)AllocationType::None)
1196 continue;
1197 if (allocTypeToUse(Iter->second) != allocTypeToUse(InAllocTypes[I]))
1198 return false;
1199 }
1200 return true;
1201}
1202
1203} // end anonymous namespace
1204
1205template <typename DerivedCCG, typename FuncTy, typename CallTy>
1206typename CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::ContextNode *
1207CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::getNodeForInst(
1208 const CallInfo &C) {
1209 ContextNode *Node = getNodeForAlloc(C);
1210 if (Node)
1211 return Node;
1212
1213 return NonAllocationCallToContextNodeMap.lookup(C);
1214}
1215
1216template <typename DerivedCCG, typename FuncTy, typename CallTy>
1217typename CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::ContextNode *
1218CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::getNodeForAlloc(
1219 const CallInfo &C) {
1220 return AllocationCallToContextNodeMap.lookup(C);
1221}
1222
1223template <typename DerivedCCG, typename FuncTy, typename CallTy>
1224typename CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::ContextNode *
1225CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::getNodeForStackId(
1226 uint64_t StackId) {
1227 auto StackEntryNode = StackEntryIdToContextNodeMap.find(StackId);
1228 if (StackEntryNode != StackEntryIdToContextNodeMap.end())
1229 return StackEntryNode->second;
1230 return nullptr;
1231}
1232
1233template <typename DerivedCCG, typename FuncTy, typename CallTy>
1234void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::ContextNode::
1235 addOrUpdateCallerEdge(ContextNode *Caller, AllocationType AllocType,
1236 unsigned int ContextId) {
1237 for (auto &Edge : CallerEdges) {
1238 if (Edge->Caller == Caller) {
1239 Edge->AllocTypes |= (uint8_t)AllocType;
1240 Edge->getContextIds().insert(ContextId);
1241 return;
1242 }
1243 }
1244 std::shared_ptr<ContextEdge> Edge = std::make_shared<ContextEdge>(
1245 this, Caller, (uint8_t)AllocType, DenseSet<uint32_t>({ContextId}));
1246 CallerEdges.push_back(Edge);
1247 Caller->CalleeEdges.push_back(Edge);
1248}
1249
1250template <typename DerivedCCG, typename FuncTy, typename CallTy>
1251void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::removeEdgeFromGraph(
1252 ContextEdge *Edge, EdgeIter *EI, bool CalleeIter) {
1253 assert(!EI || (*EI)->get() == Edge);
1254 assert(!Edge->isRemoved());
1255 // Save the Caller and Callee pointers so we can erase Edge from their edge
1256 // lists after clearing Edge below. We do the clearing first in case it is
1257 // destructed after removing from the edge lists (if those were the last
1258 // shared_ptr references to Edge).
1259 auto *Callee = Edge->Callee;
1260 auto *Caller = Edge->Caller;
1261
1262 // Make sure the edge fields are cleared out so we can properly detect
1263 // removed edges if Edge is not destructed because there is still a shared_ptr
1264 // reference.
1265 Edge->clear();
1266
1267#ifndef NDEBUG
1268 auto CalleeCallerCount = Callee->CallerEdges.size();
1269 auto CallerCalleeCount = Caller->CalleeEdges.size();
1270#endif
1271 if (!EI) {
1272 Callee->eraseCallerEdge(Edge);
1273 Caller->eraseCalleeEdge(Edge);
1274 } else if (CalleeIter) {
1275 Callee->eraseCallerEdge(Edge);
1276 *EI = Caller->CalleeEdges.erase(*EI);
1277 } else {
1278 Caller->eraseCalleeEdge(Edge);
1279 *EI = Callee->CallerEdges.erase(*EI);
1280 }
1281 assert(Callee->CallerEdges.size() < CalleeCallerCount);
1282 assert(Caller->CalleeEdges.size() < CallerCalleeCount);
1283}
1284
1285template <typename DerivedCCG, typename FuncTy, typename CallTy>
1286void CallsiteContextGraph<
1287 DerivedCCG, FuncTy, CallTy>::removeNoneTypeCalleeEdges(ContextNode *Node) {
1288 for (auto EI = Node->CalleeEdges.begin(); EI != Node->CalleeEdges.end();) {
1289 auto Edge = *EI;
1290 if (Edge->AllocTypes == (uint8_t)AllocationType::None) {
1291 assert(Edge->ContextIds.empty());
1292 removeEdgeFromGraph(Edge.get(), &EI, /*CalleeIter=*/true);
1293 } else
1294 ++EI;
1295 }
1296}
1297
1298template <typename DerivedCCG, typename FuncTy, typename CallTy>
1299void CallsiteContextGraph<
1300 DerivedCCG, FuncTy, CallTy>::removeNoneTypeCallerEdges(ContextNode *Node) {
1301 for (auto EI = Node->CallerEdges.begin(); EI != Node->CallerEdges.end();) {
1302 auto Edge = *EI;
1303 if (Edge->AllocTypes == (uint8_t)AllocationType::None) {
1304 assert(Edge->ContextIds.empty());
1305 Edge->Caller->eraseCalleeEdge(Edge.get());
1306 EI = Node->CallerEdges.erase(EI);
1307 } else
1308 ++EI;
1309 }
1310}
1311
1312template <typename DerivedCCG, typename FuncTy, typename CallTy>
1313typename CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::ContextEdge *
1314CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::ContextNode::
1315 findEdgeFromCallee(const ContextNode *Callee) {
1316 for (const auto &Edge : CalleeEdges)
1317 if (Edge->Callee == Callee)
1318 return Edge.get();
1319 return nullptr;
1320}
1321
1322template <typename DerivedCCG, typename FuncTy, typename CallTy>
1323typename CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::ContextEdge *
1324CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::ContextNode::
1325 findEdgeFromCaller(const ContextNode *Caller) {
1326 for (const auto &Edge : CallerEdges)
1327 if (Edge->Caller == Caller)
1328 return Edge.get();
1329 return nullptr;
1330}
1331
1332template <typename DerivedCCG, typename FuncTy, typename CallTy>
1333void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::ContextNode::
1334 eraseCalleeEdge(const ContextEdge *Edge) {
1335 auto EI = llvm::find_if(
1336 CalleeEdges, [Edge](const std::shared_ptr<ContextEdge> &CalleeEdge) {
1337 return CalleeEdge.get() == Edge;
1338 });
1339 assert(EI != CalleeEdges.end());
1340 CalleeEdges.erase(EI);
1341}
1342
1343template <typename DerivedCCG, typename FuncTy, typename CallTy>
1344void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::ContextNode::
1345 eraseCallerEdge(const ContextEdge *Edge) {
1346 auto EI = llvm::find_if(
1347 CallerEdges, [Edge](const std::shared_ptr<ContextEdge> &CallerEdge) {
1348 return CallerEdge.get() == Edge;
1349 });
1350 assert(EI != CallerEdges.end());
1351 CallerEdges.erase(EI);
1352}
1353
1354template <typename DerivedCCG, typename FuncTy, typename CallTy>
1355uint8_t CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::computeAllocType(
1356 DenseSet<uint32_t> &ContextIds) const {
1357 uint8_t BothTypes =
1358 (uint8_t)AllocationType::Cold | (uint8_t)AllocationType::NotCold;
1359 uint8_t AllocType = (uint8_t)AllocationType::None;
1360 for (auto Id : ContextIds) {
1361 AllocType |= (uint8_t)ContextIdToAllocationType.at(Id);
1362 // Bail early if alloc type reached both, no further refinement.
1363 if (AllocType == BothTypes)
1364 return AllocType;
1365 }
1366 return AllocType;
1367}
1368
1369template <typename DerivedCCG, typename FuncTy, typename CallTy>
1370uint8_t
1371CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::intersectAllocTypesImpl(
1372 const DenseSet<uint32_t> &Node1Ids,
1373 const DenseSet<uint32_t> &Node2Ids) const {
1374 uint8_t BothTypes =
1375 (uint8_t)AllocationType::Cold | (uint8_t)AllocationType::NotCold;
1376 uint8_t AllocType = (uint8_t)AllocationType::None;
1377 for (auto Id : Node1Ids) {
1378 if (!Node2Ids.count(Id))
1379 continue;
1380 AllocType |= (uint8_t)ContextIdToAllocationType.at(Id);
1381 // Bail early if alloc type reached both, no further refinement.
1382 if (AllocType == BothTypes)
1383 return AllocType;
1384 }
1385 return AllocType;
1386}
1387
1388template <typename DerivedCCG, typename FuncTy, typename CallTy>
1389uint8_t CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::intersectAllocTypes(
1390 const DenseSet<uint32_t> &Node1Ids,
1391 const DenseSet<uint32_t> &Node2Ids) const {
1392 if (Node1Ids.size() < Node2Ids.size())
1393 return intersectAllocTypesImpl(Node1Ids, Node2Ids);
1394 else
1395 return intersectAllocTypesImpl(Node2Ids, Node1Ids);
1396}
1397
1398template <typename DerivedCCG, typename FuncTy, typename CallTy>
1399typename CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::ContextNode *
1400CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::addAllocNode(
1401 CallInfo Call, const FuncTy *F) {
1402 assert(!getNodeForAlloc(Call));
1403 ContextNode *AllocNode = createNewNode(/*IsAllocation=*/true, F, Call);
1404 AllocationCallToContextNodeMap[Call] = AllocNode;
1405 // Use LastContextId as a uniq id for MIB allocation nodes.
1406 AllocNode->OrigStackOrAllocId = LastContextId;
1407 // Alloc type should be updated as we add in the MIBs. We should assert
1408 // afterwards that it is not still None.
1409 AllocNode->AllocTypes = (uint8_t)AllocationType::None;
1410
1411 return AllocNode;
1412}
1413
1414static std::string getAllocTypeString(uint8_t AllocTypes) {
1415 if (!AllocTypes)
1416 return "None";
1417 std::string Str;
1418 if (AllocTypes & (uint8_t)AllocationType::NotCold)
1419 Str += "NotCold";
1420 if (AllocTypes & (uint8_t)AllocationType::Cold)
1421 Str += "Cold";
1422 return Str;
1423}
1424
1425template <typename DerivedCCG, typename FuncTy, typename CallTy>
1426template <class NodeT, class IteratorT>
1427void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::addStackNodesForMIB(
1428 ContextNode *AllocNode, CallStack<NodeT, IteratorT> &StackContext,
1429 CallStack<NodeT, IteratorT> &CallsiteContext, AllocationType AllocType,
1430 ArrayRef<ContextTotalSize> ContextSizeInfo,
1431 std::map<uint64_t, uint32_t> &TotalSizeToContextIdTopNCold) {
1432 // Treating the hot alloc type as NotCold before the disambiguation for "hot"
1433 // is done.
1434 if (AllocType == AllocationType::Hot)
1435 AllocType = AllocationType::NotCold;
1436
1437 ContextIdToAllocationType[++LastContextId] = AllocType;
1438
1439 bool IsImportant = false;
1440 if (!ContextSizeInfo.empty()) {
1441 auto &Entry = ContextIdToContextSizeInfos[LastContextId];
1442 // If this is a cold allocation, and we are collecting non-zero largest
1443 // contexts, see if this is a candidate.
1444 if (AllocType == AllocationType::Cold && MemProfTopNImportant > 0) {
1445 uint64_t TotalCold = 0;
1446 for (auto &CSI : ContextSizeInfo)
1447 TotalCold += CSI.TotalSize;
1448 // Record this context if either we haven't found the first top-n largest
1449 // yet, or if it is larger than the smallest already recorded.
1450 if (TotalSizeToContextIdTopNCold.size() < MemProfTopNImportant ||
1451 // Since TotalSizeToContextIdTopNCold is a std::map, it is implicitly
1452 // sorted in ascending size of its key which is the size.
1453 TotalCold > TotalSizeToContextIdTopNCold.begin()->first) {
1454 if (TotalSizeToContextIdTopNCold.size() == MemProfTopNImportant) {
1455 // Remove old one and its associated entries.
1456 auto IdToRemove = TotalSizeToContextIdTopNCold.begin()->second;
1457 TotalSizeToContextIdTopNCold.erase(
1458 TotalSizeToContextIdTopNCold.begin());
1459 assert(ImportantContextIdInfo.count(IdToRemove));
1460 ImportantContextIdInfo.erase(IdToRemove);
1461 }
1462 TotalSizeToContextIdTopNCold[TotalCold] = LastContextId;
1463 IsImportant = true;
1464 }
1465 }
1466 Entry.insert(Entry.begin(), ContextSizeInfo.begin(), ContextSizeInfo.end());
1467 }
1468
1469 // Update alloc type and context ids for this MIB.
1470 AllocNode->AllocTypes |= (uint8_t)AllocType;
1471
1472 // Now add or update nodes for each stack id in alloc's context.
1473 // Later when processing the stack ids on non-alloc callsites we will adjust
1474 // for any inlining in the context.
1475 ContextNode *PrevNode = AllocNode;
1476 // Look for recursion (direct recursion should have been collapsed by
1477 // module summary analysis, here we should just be detecting mutual
1478 // recursion). Mark these nodes so we don't try to clone.
1479 SmallSet<uint64_t, 8> StackIdSet;
1480 // Skip any on the allocation call (inlining).
1481 for (auto ContextIter = StackContext.beginAfterSharedPrefix(CallsiteContext);
1482 ContextIter != StackContext.end(); ++ContextIter) {
1483 auto StackId = getStackId(*ContextIter);
1484 if (IsImportant)
1485 ImportantContextIdInfo[LastContextId].StackIds.push_back(StackId);
1486 ContextNode *StackNode = getNodeForStackId(StackId);
1487 if (!StackNode) {
1488 StackNode = createNewNode(/*IsAllocation=*/false);
1489 StackEntryIdToContextNodeMap[StackId] = StackNode;
1490 StackNode->OrigStackOrAllocId = StackId;
1491 }
1492 // Marking a node recursive will prevent its cloning completely, even for
1493 // non-recursive contexts flowing through it.
1495 auto Ins = StackIdSet.insert(StackId);
1496 if (!Ins.second)
1497 StackNode->Recursive = true;
1498 }
1499 StackNode->AllocTypes |= (uint8_t)AllocType;
1500 PrevNode->addOrUpdateCallerEdge(StackNode, AllocType, LastContextId);
1501 PrevNode = StackNode;
1502 }
1503}
1504
1505template <typename DerivedCCG, typename FuncTy, typename CallTy>
1506DenseSet<uint32_t>
1507CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::duplicateContextIds(
1508 const DenseSet<uint32_t> &StackSequenceContextIds,
1509 DenseMap<uint32_t, DenseSet<uint32_t>> &OldToNewContextIds) {
1510 DenseSet<uint32_t> NewContextIds;
1511 for (auto OldId : StackSequenceContextIds) {
1512 NewContextIds.insert(++LastContextId);
1513 OldToNewContextIds[OldId].insert(LastContextId);
1514 assert(ContextIdToAllocationType.count(OldId));
1515 // The new context has the same allocation type and size info as original.
1516 ContextIdToAllocationType[LastContextId] = ContextIdToAllocationType[OldId];
1517 auto CSI = ContextIdToContextSizeInfos.find(OldId);
1518 if (CSI != ContextIdToContextSizeInfos.end())
1519 ContextIdToContextSizeInfos[LastContextId] = CSI->second;
1520 if (DotAllocContextIds.contains(OldId))
1521 DotAllocContextIds.insert(LastContextId);
1522 }
1523 return NewContextIds;
1524}
1525
1526template <typename DerivedCCG, typename FuncTy, typename CallTy>
1527void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::
1528 propagateDuplicateContextIds(
1529 const DenseMap<uint32_t, DenseSet<uint32_t>> &OldToNewContextIds) {
1530 // Build a set of duplicated context ids corresponding to the input id set.
1531 auto GetNewIds = [&OldToNewContextIds](const DenseSet<uint32_t> &ContextIds) {
1532 DenseSet<uint32_t> NewIds;
1533 for (auto Id : ContextIds)
1534 if (auto NewId = OldToNewContextIds.find(Id);
1535 NewId != OldToNewContextIds.end())
1536 NewIds.insert_range(NewId->second);
1537 return NewIds;
1538 };
1539
1540 // Recursively update context ids sets along caller edges.
1541 auto UpdateCallers = [&](ContextNode *Node,
1542 DenseSet<const ContextEdge *> &Visited,
1543 auto &&UpdateCallers) -> void {
1544 for (const auto &Edge : Node->CallerEdges) {
1545 auto Inserted = Visited.insert(Edge.get());
1546 if (!Inserted.second)
1547 continue;
1548 ContextNode *NextNode = Edge->Caller;
1549 DenseSet<uint32_t> NewIdsToAdd = GetNewIds(Edge->getContextIds());
1550 // Only need to recursively iterate to NextNode via this caller edge if
1551 // it resulted in any added ids to NextNode.
1552 if (!NewIdsToAdd.empty()) {
1553 Edge->getContextIds().insert_range(NewIdsToAdd);
1554 UpdateCallers(NextNode, Visited, UpdateCallers);
1555 }
1556 }
1557 };
1558
1559 DenseSet<const ContextEdge *> Visited;
1560 for (auto &Entry : AllocationCallToContextNodeMap) {
1561 auto *Node = Entry.second;
1562 UpdateCallers(Node, Visited, UpdateCallers);
1563 }
1564}
1565
1566template <typename DerivedCCG, typename FuncTy, typename CallTy>
1567void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::connectNewNode(
1568 ContextNode *NewNode, ContextNode *OrigNode, bool TowardsCallee,
1569 // This must be passed by value to make a copy since it will be adjusted
1570 // as ids are moved.
1571 DenseSet<uint32_t> RemainingContextIds) {
1572 auto &OrigEdges =
1573 TowardsCallee ? OrigNode->CalleeEdges : OrigNode->CallerEdges;
1574 DenseSet<uint32_t> RecursiveContextIds;
1575 DenseSet<uint32_t> AllCallerContextIds;
1577 // Identify which context ids are recursive which is needed to properly
1578 // update the RemainingContextIds set. The relevant recursive context ids
1579 // are those that are in multiple edges.
1580 for (auto &CE : OrigEdges) {
1581 AllCallerContextIds.reserve(CE->getContextIds().size());
1582 for (auto Id : CE->getContextIds())
1583 if (!AllCallerContextIds.insert(Id).second)
1584 RecursiveContextIds.insert(Id);
1585 }
1586 }
1587 // Increment iterator in loop so that we can remove edges as needed.
1588 for (auto EI = OrigEdges.begin(); EI != OrigEdges.end();) {
1589 auto Edge = *EI;
1590 DenseSet<uint32_t> NewEdgeContextIds;
1591 DenseSet<uint32_t> NotFoundContextIds;
1592 // Remove any matching context ids from Edge, return set that were found and
1593 // removed, these are the new edge's context ids. Also update the remaining
1594 // (not found ids).
1595 set_subtract(Edge->getContextIds(), RemainingContextIds, NewEdgeContextIds,
1596 NotFoundContextIds);
1597 // Update the remaining context ids set for the later edges. This is a
1598 // compile time optimization.
1599 if (RecursiveContextIds.empty()) {
1600 // No recursive ids, so all of the previously remaining context ids that
1601 // were not seen on this edge are the new remaining set.
1602 RemainingContextIds.swap(NotFoundContextIds);
1603 } else {
1604 // Keep the recursive ids in the remaining set as we expect to see those
1605 // on another edge. We can remove the non-recursive remaining ids that
1606 // were seen on this edge, however. We already have the set of remaining
1607 // ids that were on this edge (in NewEdgeContextIds). Figure out which are
1608 // non-recursive and only remove those. Note that despite the higher
1609 // overhead of updating the remaining context ids set when recursion
1610 // handling is enabled, it was found to be at worst performance neutral
1611 // and in one case a clear win.
1612 DenseSet<uint32_t> NonRecursiveRemainingCurEdgeIds =
1613 set_difference(NewEdgeContextIds, RecursiveContextIds);
1614 set_subtract(RemainingContextIds, NonRecursiveRemainingCurEdgeIds);
1615 }
1616 // If no matching context ids for this edge, skip it.
1617 if (NewEdgeContextIds.empty()) {
1618 ++EI;
1619 continue;
1620 }
1621 if (TowardsCallee) {
1622 uint8_t NewAllocType = computeAllocType(NewEdgeContextIds);
1623 auto NewEdge = std::make_shared<ContextEdge>(
1624 Edge->Callee, NewNode, NewAllocType, std::move(NewEdgeContextIds));
1625 NewNode->CalleeEdges.push_back(NewEdge);
1626 NewEdge->Callee->CallerEdges.push_back(NewEdge);
1627 } else {
1628 uint8_t NewAllocType = computeAllocType(NewEdgeContextIds);
1629 auto NewEdge = std::make_shared<ContextEdge>(
1630 NewNode, Edge->Caller, NewAllocType, std::move(NewEdgeContextIds));
1631 NewNode->CallerEdges.push_back(NewEdge);
1632 NewEdge->Caller->CalleeEdges.push_back(NewEdge);
1633 }
1634 // Remove old edge if context ids empty.
1635 if (Edge->getContextIds().empty()) {
1636 removeEdgeFromGraph(Edge.get(), &EI, TowardsCallee);
1637 continue;
1638 }
1639 ++EI;
1640 }
1641}
1642
1643template <typename DerivedCCG, typename FuncTy, typename CallTy>
1644static void checkEdge(
1645 const std::shared_ptr<ContextEdge<DerivedCCG, FuncTy, CallTy>> &Edge) {
1646 // Confirm that alloc type is not None and that we have at least one context
1647 // id.
1648 assert(Edge->AllocTypes != (uint8_t)AllocationType::None);
1649 assert(!Edge->ContextIds.empty());
1650}
1651
1652template <typename DerivedCCG, typename FuncTy, typename CallTy>
1653static void checkNode(const ContextNode<DerivedCCG, FuncTy, CallTy> *Node,
1654 bool CheckEdges = true) {
1655 if (Node->isRemoved())
1656 return;
1657#ifndef NDEBUG
1658 // Compute node's context ids once for use in asserts.
1659 auto NodeContextIds = Node->getContextIds();
1660#endif
1661 // Node's context ids should be the union of both its callee and caller edge
1662 // context ids.
1663 if (Node->CallerEdges.size()) {
1664 DenseSet<uint32_t> CallerEdgeContextIds(
1665 Node->CallerEdges.front()->ContextIds);
1666 for (const auto &Edge : llvm::drop_begin(Node->CallerEdges)) {
1667 if (CheckEdges)
1669 set_union(CallerEdgeContextIds, Edge->ContextIds);
1670 }
1671 // Node can have more context ids than callers if some contexts terminate at
1672 // node and some are longer. If we are allowing recursive callsites and
1673 // contexts this will be violated for incompletely cloned recursive cycles,
1674 // so skip the checking in that case.
1676 NodeContextIds == CallerEdgeContextIds ||
1677 set_is_subset(CallerEdgeContextIds, NodeContextIds));
1678 }
1679 if (Node->CalleeEdges.size()) {
1680 DenseSet<uint32_t> CalleeEdgeContextIds(
1681 Node->CalleeEdges.front()->ContextIds);
1682 for (const auto &Edge : llvm::drop_begin(Node->CalleeEdges)) {
1683 if (CheckEdges)
1685 set_union(CalleeEdgeContextIds, Edge->getContextIds());
1686 }
1687 // If we are allowing recursive callsites and contexts this will be violated
1688 // for incompletely cloned recursive cycles, so skip the checking in that
1689 // case.
1691 NodeContextIds == CalleeEdgeContextIds);
1692 }
1693 // FIXME: Since this checking is only invoked under an option, we should
1694 // change the error checking from using assert to something that will trigger
1695 // an error on a release build.
1696#ifndef NDEBUG
1697 // Make sure we don't end up with duplicate edges between the same caller and
1698 // callee.
1700 for (const auto &E : Node->CalleeEdges)
1701 NodeSet.insert(E->Callee);
1702 assert(NodeSet.size() == Node->CalleeEdges.size());
1703#endif
1704}
1705
1706template <typename DerivedCCG, typename FuncTy, typename CallTy>
1707void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::
1708 assignStackNodesPostOrder(ContextNode *Node,
1709 DenseSet<const ContextNode *> &Visited,
1710 DenseMap<uint64_t, std::vector<CallContextInfo>>
1711 &StackIdToMatchingCalls,
1712 DenseMap<CallInfo, CallInfo> &CallToMatchingCall,
1713 const DenseSet<uint32_t> &ImportantContextIds) {
1714 auto Inserted = Visited.insert(Node);
1715 if (!Inserted.second)
1716 return;
1717 // Post order traversal. Iterate over a copy since we may add nodes and
1718 // therefore new callers during the recursive call, invalidating any
1719 // iterator over the original edge vector. We don't need to process these
1720 // new nodes as they were already processed on creation.
1721 auto CallerEdges = Node->CallerEdges;
1722 for (auto &Edge : CallerEdges) {
1723 // Skip any that have been removed during the recursion.
1724 if (Edge->isRemoved()) {
1725 assert(!is_contained(Node->CallerEdges, Edge));
1726 continue;
1727 }
1728 assignStackNodesPostOrder(Edge->Caller, Visited, StackIdToMatchingCalls,
1729 CallToMatchingCall, ImportantContextIds);
1730 }
1731
1732 // If this node's stack id is in the map, update the graph to contain new
1733 // nodes representing any inlining at interior callsites. Note we move the
1734 // associated context ids over to the new nodes.
1735
1736 // Ignore this node if it is for an allocation or we didn't record any
1737 // stack id lists ending at it.
1738 if (Node->IsAllocation ||
1739 !StackIdToMatchingCalls.count(Node->OrigStackOrAllocId))
1740 return;
1741
1742 auto &Calls = StackIdToMatchingCalls[Node->OrigStackOrAllocId];
1743 // Handle the simple case first. A single call with a single stack id.
1744 // In this case there is no need to create any new context nodes, simply
1745 // assign the context node for stack id to this Call.
1746 if (Calls.size() == 1) {
1747 auto &[Call, Ids, Func, SavedContextIds] = Calls[0];
1748 if (Ids.size() == 1) {
1749 assert(SavedContextIds.empty());
1750 // It should be this Node
1751 assert(Node == getNodeForStackId(Ids[0]));
1752 if (Node->Recursive)
1753 return;
1754 Node->setCall(Call);
1755 NonAllocationCallToContextNodeMap[Call] = Node;
1756 NodeToCallingFunc[Node] = Func;
1757 recordStackNode(Ids, Node, Node->getContextIds(), ImportantContextIds);
1758 return;
1759 }
1760 }
1761
1762#ifndef NDEBUG
1763 // Find the node for the last stack id, which should be the same
1764 // across all calls recorded for this id, and is this node's id.
1765 uint64_t LastId = Node->OrigStackOrAllocId;
1766 ContextNode *LastNode = getNodeForStackId(LastId);
1767 // We should only have kept stack ids that had nodes.
1768 assert(LastNode);
1769 assert(LastNode == Node);
1770#else
1771 ContextNode *LastNode = Node;
1772#endif
1773
1774 // Compute the last node's context ids once, as it is shared by all calls in
1775 // this entry.
1776 DenseSet<uint32_t> LastNodeContextIds = LastNode->getContextIds();
1777
1778 [[maybe_unused]] bool PrevIterCreatedNode = false;
1779 bool CreatedNode = false;
1780 for (unsigned I = 0; I < Calls.size();
1781 I++, PrevIterCreatedNode = CreatedNode) {
1782 CreatedNode = false;
1783 auto &[Call, Ids, Func, SavedContextIds] = Calls[I];
1784 // Skip any for which we didn't assign any ids, these don't get a node in
1785 // the graph.
1786 if (SavedContextIds.empty()) {
1787 // If this call has a matching call (located in the same function and
1788 // having the same stack ids), simply add it to the context node created
1789 // for its matching call earlier. These can be treated the same through
1790 // cloning and get updated at the same time.
1791 if (!CallToMatchingCall.contains(Call))
1792 continue;
1793 auto MatchingCall = CallToMatchingCall[Call];
1794 if (!NonAllocationCallToContextNodeMap.contains(MatchingCall)) {
1795 // This should only happen if we had a prior iteration, and it didn't
1796 // create a node because of the below recomputation of context ids
1797 // finding none remaining and continuing early.
1798 assert(I > 0 && !PrevIterCreatedNode);
1799 continue;
1800 }
1801 NonAllocationCallToContextNodeMap[MatchingCall]->MatchingCalls.push_back(
1802 Call);
1803 continue;
1804 }
1805
1806 assert(LastId == Ids.back());
1807
1808 // Recompute the context ids for this stack id sequence (the
1809 // intersection of the context ids of the corresponding nodes).
1810 // Start with the ids we saved in the map for this call, which could be
1811 // duplicated context ids. We have to recompute as we might have overlap
1812 // overlap between the saved context ids for different last nodes, and
1813 // removed them already during the post order traversal.
1814 set_intersect(SavedContextIds, LastNodeContextIds);
1815 ContextNode *PrevNode = LastNode;
1816 bool Skip = false;
1817 // Iterate backwards through the stack Ids, starting after the last Id
1818 // in the list, which was handled once outside for all Calls.
1819 for (auto IdIter = Ids.rbegin() + 1; IdIter != Ids.rend(); IdIter++) {
1820 auto Id = *IdIter;
1821 ContextNode *CurNode = getNodeForStackId(Id);
1822 // We should only have kept stack ids that had nodes and weren't
1823 // recursive.
1824 assert(CurNode);
1825 assert(!CurNode->Recursive);
1826
1827 auto *Edge = CurNode->findEdgeFromCaller(PrevNode);
1828 if (!Edge) {
1829 Skip = true;
1830 break;
1831 }
1832 PrevNode = CurNode;
1833
1834 // Update the context ids, which is the intersection of the ids along
1835 // all edges in the sequence.
1836 set_intersect(SavedContextIds, Edge->getContextIds());
1837
1838 // If we now have no context ids for clone, skip this call.
1839 if (SavedContextIds.empty()) {
1840 Skip = true;
1841 break;
1842 }
1843 }
1844 if (Skip)
1845 continue;
1846
1847 // Create new context node.
1848 ContextNode *NewNode = createNewNode(/*IsAllocation=*/false, Func, Call);
1849 NonAllocationCallToContextNodeMap[Call] = NewNode;
1850 CreatedNode = true;
1851 NewNode->AllocTypes = computeAllocType(SavedContextIds);
1852
1853 ContextNode *FirstNode = getNodeForStackId(Ids[0]);
1854 assert(FirstNode);
1855
1856 // Connect to callees of innermost stack frame in inlined call chain.
1857 // This updates context ids for FirstNode's callee's to reflect those
1858 // moved to NewNode.
1859 connectNewNode(NewNode, FirstNode, /*TowardsCallee=*/true, SavedContextIds);
1860
1861 // Connect to callers of outermost stack frame in inlined call chain.
1862 // This updates context ids for FirstNode's caller's to reflect those
1863 // moved to NewNode.
1864 connectNewNode(NewNode, LastNode, /*TowardsCallee=*/false, SavedContextIds);
1865
1866 // Now we need to remove context ids from edges/nodes between First and
1867 // Last Node.
1868 PrevNode = nullptr;
1869 for (auto Id : Ids) {
1870 ContextNode *CurNode = getNodeForStackId(Id);
1871 // We should only have kept stack ids that had nodes.
1872 assert(CurNode);
1873
1874 // Remove the context ids moved to NewNode from CurNode, and the
1875 // edge from the prior node.
1876 if (PrevNode) {
1877 auto *PrevEdge = CurNode->findEdgeFromCallee(PrevNode);
1878 // If the sequence contained recursion, we might have already removed
1879 // some edges during the connectNewNode calls above.
1880 if (!PrevEdge) {
1881 PrevNode = CurNode;
1882 continue;
1883 }
1884 set_subtract(PrevEdge->getContextIds(), SavedContextIds);
1885 if (PrevEdge->getContextIds().empty())
1886 removeEdgeFromGraph(PrevEdge);
1887 }
1888 // Since we update the edges from leaf to tail, only look at the callee
1889 // edges. This isn't an alloc node, so if there are no callee edges, the
1890 // alloc type is None.
1891 CurNode->AllocTypes = CurNode->CalleeEdges.empty()
1892 ? (uint8_t)AllocationType::None
1893 : CurNode->computeAllocType();
1894 PrevNode = CurNode;
1895 }
1896
1897 recordStackNode(Ids, NewNode, SavedContextIds, ImportantContextIds);
1898
1899 if (VerifyNodes) {
1900 checkNode<DerivedCCG, FuncTy, CallTy>(NewNode, /*CheckEdges=*/true);
1901 for (auto Id : Ids) {
1902 ContextNode *CurNode = getNodeForStackId(Id);
1903 // We should only have kept stack ids that had nodes.
1904 assert(CurNode);
1905 checkNode<DerivedCCG, FuncTy, CallTy>(CurNode, /*CheckEdges=*/true);
1906 }
1907 }
1908 }
1909}
1910
1911template <typename DerivedCCG, typename FuncTy, typename CallTy>
1912void CallsiteContextGraph<DerivedCCG, FuncTy,
1913 CallTy>::fixupImportantContexts() {
1914 if (ImportantContextIdInfo.empty())
1915 return;
1916
1917 // Update statistics as we are done building this map at this point.
1918 NumImportantContextIds = ImportantContextIdInfo.size();
1919
1921 return;
1922
1923 if (ExportToDot)
1924 exportToDot("beforestackfixup");
1925
1926 // For each context we identified as important, walk through the saved context
1927 // stack ids in order from leaf upwards, and make sure all edges are correct.
1928 // These can be difficult to get right when updating the graph while mapping
1929 // nodes onto summary or IR, especially when there is recursion. In
1930 // particular, when we have created new nodes to reflect inlining, it is
1931 // sometimes impossible to know exactly how to update the edges in the face of
1932 // recursion, as we have lost the original ordering of the stack ids in the
1933 // contexts.
1934 // TODO: Consider only doing this if we detect the context has recursive
1935 // cycles.
1936 //
1937 // I.e. assume we have a context with stack ids like: {A B A C A D E}
1938 // and let's say A was inlined into B, C, and D. The original graph will have
1939 // multiple recursive cycles through A. When we match the original context
1940 // nodes onto the IR or summary, we will merge {A B} into one context node,
1941 // {A C} onto another, and {A D} onto another. Looking at the stack sequence
1942 // above, we should end up with a non-cyclic set of edges like:
1943 // {AB} <- {AC} <- {AD} <- E. However, because we normally have lost the
1944 // original ordering, we won't get the edges correct initially (it's
1945 // impossible without the original ordering). Here we do the fixup (add and
1946 // removing edges where necessary) for this context. In the
1947 // ImportantContextInfo struct in this case we should have a MaxLength = 2,
1948 // and map entries for {A B}, {A C}, {A D}, and {E}.
1949 for (auto &[CurContextId, Info] : ImportantContextIdInfo) {
1950 if (Info.StackIdsToNode.empty())
1951 continue;
1952 bool Changed = false;
1953 ContextNode *PrevNode = nullptr;
1954 ContextNode *CurNode = nullptr;
1955 DenseSet<const ContextEdge *> VisitedEdges;
1956 ArrayRef<uint64_t> AllStackIds(Info.StackIds);
1957 // Try to identify what callsite ContextNode maps to which slice of the
1958 // context's ordered stack ids.
1959 for (unsigned I = 0; I < AllStackIds.size(); I++, PrevNode = CurNode) {
1960 // We will do this greedily, trying up to MaxLength stack ids in a row, to
1961 // see if we recorded a context node for that sequence.
1962 auto Len = Info.MaxLength;
1963 auto LenToEnd = AllStackIds.size() - I;
1964 if (Len > LenToEnd)
1965 Len = LenToEnd;
1966 CurNode = nullptr;
1967 // Try to find a recorded context node starting with the longest length
1968 // recorded, and on down until we check for just a single stack node.
1969 for (; Len > 0; Len--) {
1970 // Get the slice of the original stack id sequence to check.
1971 auto CheckStackIds = AllStackIds.slice(I, Len);
1972 auto EntryIt = Info.StackIdsToNode.find(CheckStackIds);
1973 if (EntryIt == Info.StackIdsToNode.end())
1974 continue;
1975 CurNode = EntryIt->second;
1976 // Skip forward so we don't try to look for the ones we just matched.
1977 // We increment by Len - 1, because the outer for loop will increment I.
1978 I += Len - 1;
1979 break;
1980 }
1981 // Give up if we couldn't find a node. Since we need to clone from the
1982 // leaf allocation upwards, no sense in doing anymore fixup further up
1983 // the context if we couldn't match part of the original stack context
1984 // onto a callsite node.
1985 if (!CurNode)
1986 break;
1987 // No edges to fix up until we have a pair of nodes that should be
1988 // adjacent in the graph.
1989 if (!PrevNode)
1990 continue;
1991 // See if we already have a call edge from CurNode to PrevNode.
1992 auto *CurEdge = PrevNode->findEdgeFromCaller(CurNode);
1993 if (CurEdge) {
1994 // We already have an edge. Make sure it contains this context id.
1995 if (CurEdge->getContextIds().insert(CurContextId).second) {
1996 NumFixupEdgeIdsInserted++;
1997 Changed = true;
1998 }
1999 } else {
2000 // No edge exists - add one.
2001 NumFixupEdgesAdded++;
2002 DenseSet<uint32_t> ContextIds({CurContextId});
2003 auto AllocType = computeAllocType(ContextIds);
2004 auto NewEdge = std::make_shared<ContextEdge>(
2005 PrevNode, CurNode, AllocType, std::move(ContextIds));
2006 PrevNode->CallerEdges.push_back(NewEdge);
2007 CurNode->CalleeEdges.push_back(NewEdge);
2008 // Save the new edge for the below handling.
2009 CurEdge = NewEdge.get();
2010 Changed = true;
2011 }
2012 VisitedEdges.insert(CurEdge);
2013 // Now remove this context id from any other caller edges calling
2014 // PrevNode.
2015 for (auto &Edge : PrevNode->CallerEdges) {
2016 // Skip the edge updating/created above and edges we have already
2017 // visited (due to recursion).
2018 if (Edge.get() != CurEdge && !VisitedEdges.contains(Edge.get()))
2019 Edge->getContextIds().erase(CurContextId);
2020 }
2021 }
2022 if (Changed)
2023 NumFixedContexts++;
2024 }
2025}
2026
2027template <typename DerivedCCG, typename FuncTy, typename CallTy>
2028void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::updateStackNodes() {
2029 // Map of stack id to all calls with that as the last (outermost caller)
2030 // callsite id that has a context node (some might not due to pruning
2031 // performed during matching of the allocation profile contexts).
2032 // The CallContextInfo contains the Call and a list of its stack ids with
2033 // ContextNodes, the function containing Call, and the set of context ids
2034 // the analysis will eventually identify for use in any new node created
2035 // for that callsite.
2036 DenseMap<uint64_t, std::vector<CallContextInfo>> StackIdToMatchingCalls;
2037 for (auto &[Func, CallsWithMetadata] : FuncToCallsWithMetadata) {
2038 for (auto &Call : CallsWithMetadata) {
2039 // Ignore allocations, already handled.
2040 if (AllocationCallToContextNodeMap.count(Call))
2041 continue;
2042 auto StackIdsWithContextNodes =
2043 getStackIdsWithContextNodesForCall(Call.call());
2044 // If there were no nodes created for MIBs on allocs (maybe this was in
2045 // the unambiguous part of the MIB stack that was pruned), ignore.
2046 if (StackIdsWithContextNodes.empty())
2047 continue;
2048 // Otherwise, record this Call along with the list of ids for the last
2049 // (outermost caller) stack id with a node.
2050 StackIdToMatchingCalls[StackIdsWithContextNodes.back()].push_back(
2051 {Call.call(), StackIdsWithContextNodes, Func, {}});
2052 }
2053 }
2054
2055 // First make a pass through all stack ids that correspond to a call,
2056 // as identified in the above loop. Compute the context ids corresponding to
2057 // each of these calls when they correspond to multiple stack ids due to
2058 // due to inlining. Perform any duplication of context ids required when
2059 // there is more than one call with the same stack ids. Their (possibly newly
2060 // duplicated) context ids are saved in the StackIdToMatchingCalls map.
2061 DenseMap<uint32_t, DenseSet<uint32_t>> OldToNewContextIds;
2062 // Save a map from each call to any that are found to match it. I.e. located
2063 // in the same function and have the same (possibly pruned) stack ids. We use
2064 // this to avoid creating extra graph nodes as they can be treated the same.
2065 DenseMap<CallInfo, CallInfo> CallToMatchingCall;
2066 for (auto &It : StackIdToMatchingCalls) {
2067 auto &Calls = It.getSecond();
2068 // Skip single calls with a single stack id. These don't need a new node.
2069 if (Calls.size() == 1) {
2070 auto &Ids = Calls[0].StackIds;
2071 if (Ids.size() == 1)
2072 continue;
2073 }
2074 // In order to do the best and maximal matching of inlined calls to context
2075 // node sequences we will sort the vectors of stack ids in descending order
2076 // of length, and within each length, lexicographically by stack id. The
2077 // latter is so that we can specially handle calls that have identical stack
2078 // id sequences (either due to cloning or artificially because of the MIB
2079 // context pruning). Those with the same Ids are then sorted by function to
2080 // facilitate efficiently mapping them to the same context node.
2081 // Because the functions are pointers, to ensure a stable sort first assign
2082 // each function pointer to its first index in the Calls array, and then use
2083 // that to sort by.
2084 DenseMap<const FuncTy *, unsigned> FuncToIndex;
2085 for (const auto &[Idx, CallCtxInfo] : enumerate(Calls))
2086 FuncToIndex.insert({CallCtxInfo.Func, Idx});
2088 Calls,
2089 [&FuncToIndex](const CallContextInfo &A, const CallContextInfo &B) {
2090 return A.StackIds.size() > B.StackIds.size() ||
2091 (A.StackIds.size() == B.StackIds.size() &&
2092 (A.StackIds < B.StackIds ||
2093 (A.StackIds == B.StackIds &&
2094 FuncToIndex[A.Func] < FuncToIndex[B.Func])));
2095 });
2096
2097 // Find the node for the last stack id, which should be the same
2098 // across all calls recorded for this id, and is the id for this
2099 // entry in the StackIdToMatchingCalls map.
2100 uint64_t LastId = It.getFirst();
2101 ContextNode *LastNode = getNodeForStackId(LastId);
2102 // We should only have kept stack ids that had nodes.
2103 assert(LastNode);
2104
2105 if (LastNode->Recursive)
2106 continue;
2107
2108 // Initialize the context ids with the last node's. We will subsequently
2109 // refine the context ids by computing the intersection along all edges.
2110 DenseSet<uint32_t> LastNodeContextIds = LastNode->getContextIds();
2111 assert(!LastNodeContextIds.empty());
2112
2113#ifndef NDEBUG
2114 // Save the set of functions seen for a particular set of the same stack
2115 // ids. This is used to ensure that they have been correctly sorted to be
2116 // adjacent in the Calls list, since we rely on that to efficiently place
2117 // all such matching calls onto the same context node.
2118 DenseSet<const FuncTy *> MatchingIdsFuncSet;
2119#endif
2120
2121 for (unsigned I = 0; I < Calls.size(); I++) {
2122 auto &[Call, Ids, Func, SavedContextIds] = Calls[I];
2123 assert(SavedContextIds.empty());
2124 assert(LastId == Ids.back());
2125
2126#ifndef NDEBUG
2127 // If this call has a different set of ids than the last one, clear the
2128 // set used to ensure they are sorted properly.
2129 if (I > 0 && Ids != Calls[I - 1].StackIds)
2130 MatchingIdsFuncSet.clear();
2131#endif
2132
2133 // First compute the context ids for this stack id sequence (the
2134 // intersection of the context ids of the corresponding nodes).
2135 // Start with the remaining saved ids for the last node.
2136 assert(!LastNodeContextIds.empty());
2137 DenseSet<uint32_t> StackSequenceContextIds = LastNodeContextIds;
2138
2139 ContextNode *PrevNode = LastNode;
2140 ContextNode *CurNode = LastNode;
2141 bool Skip = false;
2142
2143 // Iterate backwards through the stack Ids, starting after the last Id
2144 // in the list, which was handled once outside for all Calls.
2145 for (auto IdIter = Ids.rbegin() + 1; IdIter != Ids.rend(); IdIter++) {
2146 auto Id = *IdIter;
2147 CurNode = getNodeForStackId(Id);
2148 // We should only have kept stack ids that had nodes.
2149 assert(CurNode);
2150
2151 if (CurNode->Recursive) {
2152 Skip = true;
2153 break;
2154 }
2155
2156 auto *Edge = CurNode->findEdgeFromCaller(PrevNode);
2157 // If there is no edge then the nodes belong to different MIB contexts,
2158 // and we should skip this inlined context sequence. For example, this
2159 // particular inlined context may include stack ids A->B, and we may
2160 // indeed have nodes for both A and B, but it is possible that they were
2161 // never profiled in sequence in a single MIB for any allocation (i.e.
2162 // we might have profiled an allocation that involves the callsite A,
2163 // but through a different one of its callee callsites, and we might
2164 // have profiled an allocation that involves callsite B, but reached
2165 // from a different caller callsite).
2166 if (!Edge) {
2167 Skip = true;
2168 break;
2169 }
2170 PrevNode = CurNode;
2171
2172 // Update the context ids, which is the intersection of the ids along
2173 // all edges in the sequence.
2174 set_intersect(StackSequenceContextIds, Edge->getContextIds());
2175
2176 // If we now have no context ids for clone, skip this call.
2177 if (StackSequenceContextIds.empty()) {
2178 Skip = true;
2179 break;
2180 }
2181 }
2182 if (Skip)
2183 continue;
2184
2185 // If some of this call's stack ids did not have corresponding nodes (due
2186 // to pruning), don't include any context ids for contexts that extend
2187 // beyond these nodes. Otherwise we would be matching part of unrelated /
2188 // not fully matching stack contexts. To do this, subtract any context ids
2189 // found in caller nodes of the last node found above.
2190 if (Ids.back() != getLastStackId(Call)) {
2191 for (const auto &PE : LastNode->CallerEdges) {
2192 set_subtract(StackSequenceContextIds, PE->getContextIds());
2193 if (StackSequenceContextIds.empty())
2194 break;
2195 }
2196 // If we now have no context ids for clone, skip this call.
2197 if (StackSequenceContextIds.empty())
2198 continue;
2199 }
2200
2201#ifndef NDEBUG
2202 // If the prior call had the same stack ids this set would not be empty.
2203 // Check if we already have a call that "matches" because it is located
2204 // in the same function. If the Calls list was sorted properly we should
2205 // not encounter this situation as all such entries should be adjacent
2206 // and processed in bulk further below.
2207 assert(!MatchingIdsFuncSet.contains(Func));
2208
2209 MatchingIdsFuncSet.insert(Func);
2210#endif
2211
2212 // Check if the next set of stack ids is the same (since the Calls vector
2213 // of tuples is sorted by the stack ids we can just look at the next one).
2214 // If so, save them in the CallToMatchingCall map so that they get
2215 // assigned to the same context node, and skip them.
2216 bool DuplicateContextIds = false;
2217 for (unsigned J = I + 1; J < Calls.size(); J++) {
2218 auto &CallCtxInfo = Calls[J];
2219 auto &NextIds = CallCtxInfo.StackIds;
2220 if (NextIds != Ids)
2221 break;
2222 auto *NextFunc = CallCtxInfo.Func;
2223 if (NextFunc != Func) {
2224 // We have another Call with the same ids but that cannot share this
2225 // node, must duplicate ids for it.
2226 DuplicateContextIds = true;
2227 break;
2228 }
2229 auto &NextCall = CallCtxInfo.Call;
2230 CallToMatchingCall[NextCall] = Call;
2231 // Update I so that it gets incremented correctly to skip this call.
2232 I = J;
2233 }
2234
2235 // If we don't have duplicate context ids, then we can assign all the
2236 // context ids computed for the original node sequence to this call.
2237 // If there are duplicate calls with the same stack ids then we synthesize
2238 // new context ids that are duplicates of the originals. These are
2239 // assigned to SavedContextIds, which is a reference into the map entry
2240 // for this call, allowing us to access these ids later on.
2241 OldToNewContextIds.reserve(OldToNewContextIds.size() +
2242 StackSequenceContextIds.size());
2243 SavedContextIds =
2244 DuplicateContextIds
2245 ? duplicateContextIds(StackSequenceContextIds, OldToNewContextIds)
2246 : StackSequenceContextIds;
2247 assert(!SavedContextIds.empty());
2248
2249 if (!DuplicateContextIds) {
2250 // Update saved last node's context ids to remove those that are
2251 // assigned to other calls, so that it is ready for the next call at
2252 // this stack id.
2253 set_subtract(LastNodeContextIds, StackSequenceContextIds);
2254 if (LastNodeContextIds.empty())
2255 break;
2256 }
2257 }
2258 }
2259
2260 // Propagate the duplicate context ids over the graph.
2261 propagateDuplicateContextIds(OldToNewContextIds);
2262
2263 if (VerifyCCG)
2264 check();
2265
2266 // Now perform a post-order traversal over the graph, starting with the
2267 // allocation nodes, essentially processing nodes from callers to callees.
2268 // For any that contains an id in the map, update the graph to contain new
2269 // nodes representing any inlining at interior callsites. Note we move the
2270 // associated context ids over to the new nodes.
2271 DenseSet<const ContextNode *> Visited;
2272 DenseSet<uint32_t> ImportantContextIds(llvm::from_range,
2273 ImportantContextIdInfo.keys());
2274 for (auto &Entry : AllocationCallToContextNodeMap)
2275 assignStackNodesPostOrder(Entry.second, Visited, StackIdToMatchingCalls,
2276 CallToMatchingCall, ImportantContextIds);
2277
2278 fixupImportantContexts();
2279
2280 if (VerifyCCG)
2281 check();
2282}
2283
2284uint64_t ModuleCallsiteContextGraph::getLastStackId(Instruction *Call) {
2285 CallStack<MDNode, MDNode::op_iterator> CallsiteContext(
2286 Call->getMetadata(LLVMContext::MD_callsite));
2287 return CallsiteContext.back();
2288}
2289
2290uint64_t IndexCallsiteContextGraph::getLastStackId(IndexCall &Call) {
2292 CallStack<CallsiteInfo, SmallVector<unsigned>::const_iterator>
2293 CallsiteContext(dyn_cast_if_present<CallsiteInfo *>(Call));
2294 // Need to convert index into stack id.
2295 return Index.getStackIdAtIndex(CallsiteContext.back());
2296}
2297
2298static const std::string MemProfCloneSuffix = ".memprof.";
2299
2300static std::string getMemProfFuncName(Twine Base, unsigned CloneNo) {
2301 // We use CloneNo == 0 to refer to the original version, which doesn't get
2302 // renamed with a suffix.
2303 if (!CloneNo)
2304 return Base.str();
2305 return (Base + MemProfCloneSuffix + Twine(CloneNo)).str();
2306}
2307
2308static bool isMemProfClone(const Function &F) {
2309 return F.getName().contains(MemProfCloneSuffix);
2310}
2311
2312// Return the clone number of the given function by extracting it from the
2313// memprof suffix. Assumes the caller has already confirmed it is a memprof
2314// clone.
2315static unsigned getMemProfCloneNum(const Function &F) {
2317 auto Pos = F.getName().find_last_of('.');
2318 assert(Pos > 0);
2319 unsigned CloneNo;
2320 bool Err = F.getName().drop_front(Pos + 1).getAsInteger(10, CloneNo);
2321 assert(!Err);
2322 (void)Err;
2323 return CloneNo;
2324}
2325
2326std::string ModuleCallsiteContextGraph::getLabel(const Function *Func,
2327 const Instruction *Call,
2328 unsigned CloneNo) const {
2329 return (Twine(Call->getFunction()->getName()) + " -> " +
2330 cast<CallBase>(Call)->getCalledFunction()->getName())
2331 .str();
2332}
2333
2334std::string IndexCallsiteContextGraph::getLabel(const FunctionSummary *Func,
2335 const IndexCall &Call,
2336 unsigned CloneNo) const {
2337 auto VI = FSToVIMap.find(Func);
2338 assert(VI != FSToVIMap.end());
2339 std::string CallerName = getMemProfFuncName(VI->second.name(), CloneNo);
2341 return CallerName + " -> alloc";
2342 else {
2343 auto *Callsite = dyn_cast_if_present<CallsiteInfo *>(Call);
2344 return CallerName + " -> " +
2345 getMemProfFuncName(Callsite->Callee.name(),
2346 Callsite->Clones[CloneNo]);
2347 }
2348}
2349
2350std::vector<uint64_t>
2351ModuleCallsiteContextGraph::getStackIdsWithContextNodesForCall(
2352 Instruction *Call) {
2353 CallStack<MDNode, MDNode::op_iterator> CallsiteContext(
2354 Call->getMetadata(LLVMContext::MD_callsite));
2355 return getStackIdsWithContextNodes<MDNode, MDNode::op_iterator>(
2356 CallsiteContext);
2357}
2358
2359std::vector<uint64_t>
2360IndexCallsiteContextGraph::getStackIdsWithContextNodesForCall(IndexCall &Call) {
2362 CallStack<CallsiteInfo, SmallVector<unsigned>::const_iterator>
2363 CallsiteContext(dyn_cast_if_present<CallsiteInfo *>(Call));
2364 return getStackIdsWithContextNodes<CallsiteInfo,
2365 SmallVector<unsigned>::const_iterator>(
2366 CallsiteContext);
2367}
2368
2369template <typename DerivedCCG, typename FuncTy, typename CallTy>
2370template <class NodeT, class IteratorT>
2371std::vector<uint64_t>
2372CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::getStackIdsWithContextNodes(
2373 CallStack<NodeT, IteratorT> &CallsiteContext) {
2374 std::vector<uint64_t> StackIds;
2375 for (auto IdOrIndex : CallsiteContext) {
2376 auto StackId = getStackId(IdOrIndex);
2377 ContextNode *Node = getNodeForStackId(StackId);
2378 if (!Node)
2379 break;
2380 StackIds.push_back(StackId);
2381 }
2382 return StackIds;
2383}
2384
2385ModuleCallsiteContextGraph::ModuleCallsiteContextGraph(
2386 Module &M,
2387 llvm::function_ref<OptimizationRemarkEmitter &(Function *)> OREGetter)
2388 : Mod(M), OREGetter(OREGetter) {
2389 // Map for keeping track of the largest cold contexts up to the number given
2390 // by MemProfTopNImportant. Must be a std::map (not DenseMap) because keys
2391 // must be sorted.
2392 std::map<uint64_t, uint32_t> TotalSizeToContextIdTopNCold;
2393 for (auto &F : M) {
2394 std::vector<CallInfo> CallsWithMetadata;
2395 for (auto &BB : F) {
2396 for (auto &I : BB) {
2397 if (!isa<CallBase>(I))
2398 continue;
2399 if (auto *MemProfMD = I.getMetadata(LLVMContext::MD_memprof)) {
2400 CallsWithMetadata.push_back(&I);
2401 auto *AllocNode = addAllocNode(&I, &F);
2402 auto *CallsiteMD = I.getMetadata(LLVMContext::MD_callsite);
2403 assert(CallsiteMD);
2404 CallStack<MDNode, MDNode::op_iterator> CallsiteContext(CallsiteMD);
2405 // Add all of the MIBs and their stack nodes.
2406 for (auto &MDOp : MemProfMD->operands()) {
2407 auto *MIBMD = cast<const MDNode>(MDOp);
2408 std::vector<ContextTotalSize> ContextSizeInfo;
2409 // Collect the context size information if it exists.
2410 if (MIBMD->getNumOperands() > 2) {
2411 for (unsigned I = 2; I < MIBMD->getNumOperands(); I++) {
2412 MDNode *ContextSizePair =
2413 dyn_cast<MDNode>(MIBMD->getOperand(I));
2414 assert(ContextSizePair->getNumOperands() == 2);
2416 ContextSizePair->getOperand(0))
2417 ->getZExtValue();
2419 ContextSizePair->getOperand(1))
2420 ->getZExtValue();
2421 ContextSizeInfo.push_back({FullStackId, TotalSize});
2422 }
2423 }
2427 addStackNodesForMIB<MDNode, MDNode::op_iterator>(
2428 AllocNode, StackContext, CallsiteContext,
2429 getMIBAllocType(MIBMD), ContextSizeInfo,
2430 TotalSizeToContextIdTopNCold);
2431 }
2432 // If exporting the graph to dot and an allocation id of interest was
2433 // specified, record all the context ids for this allocation node.
2434 if (ExportToDot && AllocNode->OrigStackOrAllocId == AllocIdForDot)
2435 DotAllocContextIds = AllocNode->getContextIds();
2436 assert(AllocNode->AllocTypes != (uint8_t)AllocationType::None);
2437 // Memprof and callsite metadata on memory allocations no longer
2438 // needed.
2439 I.setMetadata(LLVMContext::MD_memprof, nullptr);
2440 I.setMetadata(LLVMContext::MD_callsite, nullptr);
2441 }
2442 // For callsite metadata, add to list for this function for later use.
2443 else if (I.getMetadata(LLVMContext::MD_callsite)) {
2444 CallsWithMetadata.push_back(&I);
2445 }
2446 }
2447 }
2448 if (!CallsWithMetadata.empty())
2449 FuncToCallsWithMetadata[&F] = CallsWithMetadata;
2450 }
2451
2452 if (DumpCCG) {
2453 dbgs() << "CCG before updating call stack chains:\n";
2454 dbgs() << *this;
2455 }
2456
2457 if (ExportToDot)
2458 exportToDot("prestackupdate");
2459
2460 updateStackNodes();
2461
2462 if (ExportToDot)
2463 exportToDot("poststackupdate");
2464
2465 handleCallsitesWithMultipleTargets();
2466
2467 markBackedges();
2468
2469 // Strip off remaining callsite metadata, no longer needed.
2470 for (auto &FuncEntry : FuncToCallsWithMetadata)
2471 for (auto &Call : FuncEntry.second)
2472 Call.call()->setMetadata(LLVMContext::MD_callsite, nullptr);
2473}
2474
2475// Finds the set of GUIDs for weak aliasees that are prevailing in different
2476// modules than any of their aliases. We need to handle these specially.
2478IndexCallsiteContextGraph::findAliaseeGUIDsPrevailingInDifferentModule() {
2479 DenseSet<GlobalValue::GUID> AliaseeGUIDs;
2480 for (auto &I : Index) {
2481 auto VI = Index.getValueInfo(I);
2482 for (auto &S : VI.getSummaryList()) {
2483 // We only care about aliases to functions.
2484 auto *AS = dyn_cast<AliasSummary>(S.get());
2485 if (!AS)
2486 continue;
2487 auto *AliaseeSummary = &AS->getAliasee();
2488 auto *AliaseeFS = dyn_cast<FunctionSummary>(AliaseeSummary);
2489 if (!AliaseeFS)
2490 continue;
2491 // Skip this summary if it is not for the prevailing symbol for this GUID.
2492 // The linker doesn't resolve local linkage values so don't check whether
2493 // those are prevailing.
2494 if (!GlobalValue::isLocalLinkage(S->linkage()) &&
2495 !isPrevailing(VI.getGUID(), S.get()))
2496 continue;
2497 // Prevailing aliasee could be in a different module only if it is weak.
2498 if (!GlobalValue::isWeakForLinker(AliaseeSummary->linkage()))
2499 continue;
2500 auto AliaseeGUID = AS->getAliaseeGUID();
2501 // If the aliasee copy in this module is not prevailing, record it.
2502 if (!isPrevailing(AliaseeGUID, AliaseeSummary))
2503 AliaseeGUIDs.insert(AliaseeGUID);
2504 }
2505 }
2506 AliaseesPrevailingInDiffModuleFromAlias += AliaseeGUIDs.size();
2507 return AliaseeGUIDs;
2508}
2509
2510IndexCallsiteContextGraph::IndexCallsiteContextGraph(
2511 ModuleSummaryIndex &Index,
2512 llvm::function_ref<bool(GlobalValue::GUID, const GlobalValueSummary *)>
2513 isPrevailing)
2514 : Index(Index), isPrevailing(isPrevailing) {
2515 // Since we use the aliasee summary info to create the necessary clones for
2516 // its aliases, conservatively skip recording the aliasee function's callsites
2517 // in the CCG for any that are prevailing in a different module than one of
2518 // its aliases. We could record the necessary information to do this in the
2519 // summary, but this case should not be common.
2520 DenseSet<GlobalValue::GUID> GUIDsToSkip =
2521 findAliaseeGUIDsPrevailingInDifferentModule();
2522 // Map for keeping track of the largest cold contexts up to the number given
2523 // by MemProfTopNImportant. Must be a std::map (not DenseMap) because keys
2524 // must be sorted.
2525 std::map<uint64_t, uint32_t> TotalSizeToContextIdTopNCold;
2526 // Sort by GUID for deterministic graph construction order.
2527 // TODO: This sort has a measurable cost on the thin link when memprof is
2528 // enabled. Investigate gating it behind an option that is only enabled for
2529 // tests that check internal state.
2530 for (const auto &I : Index.sortedGlobalValueSummariesRange()) {
2531 auto VI = Index.getValueInfo(I);
2532 if (GUIDsToSkip.contains(VI.getGUID()))
2533 continue;
2534 for (auto &S : VI.getSummaryList()) {
2535 // We should only add the prevailing nodes. Otherwise we may try to clone
2536 // in a weak copy that won't be linked (and may be different than the
2537 // prevailing version).
2538 // We only keep the memprof summary on the prevailing copy now when
2539 // building the combined index, as a space optimization, however don't
2540 // rely on this optimization. The linker doesn't resolve local linkage
2541 // values so don't check whether those are prevailing.
2542 if (!GlobalValue::isLocalLinkage(S->linkage()) &&
2543 !isPrevailing(VI.getGUID(), S.get()))
2544 continue;
2545 auto *FS = dyn_cast<FunctionSummary>(S.get());
2546 if (!FS)
2547 continue;
2548 std::vector<CallInfo> CallsWithMetadata;
2549 if (!FS->allocs().empty()) {
2550 for (auto &AN : FS->mutableAllocs()) {
2551 // This can happen because of recursion elimination handling that
2552 // currently exists in ModuleSummaryAnalysis. Skip these for now.
2553 // We still added them to the summary because we need to be able to
2554 // correlate properly in applyImport in the backends.
2555 if (AN.MIBs.empty())
2556 continue;
2557 IndexCall AllocCall(&AN);
2558 CallsWithMetadata.push_back(AllocCall);
2559 auto *AllocNode = addAllocNode(AllocCall, FS);
2560 // Pass an empty CallStack to the CallsiteContext (second)
2561 // parameter, since for ThinLTO we already collapsed out the inlined
2562 // stack ids on the allocation call during ModuleSummaryAnalysis.
2564 EmptyContext;
2565 unsigned I = 0;
2567 AN.ContextSizeInfos.size() == AN.MIBs.size());
2568 // Now add all of the MIBs and their stack nodes.
2569 for (auto &MIB : AN.MIBs) {
2571 StackContext(&MIB);
2572 std::vector<ContextTotalSize> ContextSizeInfo;
2573 if (!AN.ContextSizeInfos.empty()) {
2574 for (auto [FullStackId, TotalSize] : AN.ContextSizeInfos[I])
2575 ContextSizeInfo.push_back({FullStackId, TotalSize});
2576 }
2577 addStackNodesForMIB<MIBInfo, SmallVector<unsigned>::const_iterator>(
2578 AllocNode, StackContext, EmptyContext, MIB.AllocType,
2579 ContextSizeInfo, TotalSizeToContextIdTopNCold);
2580 I++;
2581 }
2582 // If exporting the graph to dot and an allocation id of interest was
2583 // specified, record all the context ids for this allocation node.
2584 if (ExportToDot && AllocNode->OrigStackOrAllocId == AllocIdForDot)
2585 DotAllocContextIds = AllocNode->getContextIds();
2586 assert(AllocNode->AllocTypes != (uint8_t)AllocationType::None);
2587 // Initialize version 0 on the summary alloc node to the current alloc
2588 // type, unless it has both types in which case make it default, so
2589 // that in the case where we aren't able to clone the original version
2590 // always ends up with the default allocation behavior.
2591 AN.Versions[0] = (uint8_t)allocTypeToUse(AllocNode->AllocTypes);
2592 }
2593 }
2594 // For callsite metadata, add to list for this function for later use.
2595 if (!FS->callsites().empty())
2596 for (auto &SN : FS->mutableCallsites()) {
2597 IndexCall StackNodeCall(&SN);
2598 CallsWithMetadata.push_back(StackNodeCall);
2599 }
2600
2601 if (!CallsWithMetadata.empty())
2602 FuncToCallsWithMetadata[FS] = CallsWithMetadata;
2603
2604 if (!FS->allocs().empty() || !FS->callsites().empty())
2605 FSToVIMap[FS] = VI;
2606 }
2607 }
2608
2609 if (DumpCCG) {
2610 dbgs() << "CCG before updating call stack chains:\n";
2611 dbgs() << *this;
2612 }
2613
2614 if (ExportToDot)
2615 exportToDot("prestackupdate");
2616
2617 updateStackNodes();
2618
2619 if (ExportToDot)
2620 exportToDot("poststackupdate");
2621
2622 handleCallsitesWithMultipleTargets();
2623
2624 markBackedges();
2625}
2626
2627template <typename DerivedCCG, typename FuncTy, typename CallTy>
2628void CallsiteContextGraph<DerivedCCG, FuncTy,
2629 CallTy>::handleCallsitesWithMultipleTargets() {
2630 // Look for and workaround callsites that call multiple functions.
2631 // This can happen for indirect calls, which needs better handling, and in
2632 // more rare cases (e.g. macro expansion).
2633 // TODO: To fix this for indirect calls we will want to perform speculative
2634 // devirtualization using either the normal PGO info with ICP, or using the
2635 // information in the profiled MemProf contexts. We can do this prior to
2636 // this transformation for regular LTO, and for ThinLTO we can simulate that
2637 // effect in the summary and perform the actual speculative devirtualization
2638 // while cloning in the ThinLTO backend.
2639
2640 // Keep track of the new nodes synthesized for discovered tail calls missing
2641 // from the profiled contexts.
2642 MapVector<CallInfo, ContextNode *> TailCallToContextNodeMap;
2643
2644 std::vector<std::pair<CallInfo, ContextNode *>> NewCallToNode;
2645 for (auto &Entry : NonAllocationCallToContextNodeMap) {
2646 auto *Node = Entry.second;
2647 assert(Node->Clones.empty());
2648 // Check all node callees and see if in the same function.
2649 // We need to check all of the calls recorded in this Node, because in some
2650 // cases we may have had multiple calls with the same debug info calling
2651 // different callees. This can happen, for example, when an object is
2652 // constructed in the paramter list - the destructor call of the object has
2653 // the same debug info (line/col) as the call the object was passed to.
2654 // Here we will prune any that don't match all callee nodes.
2655 std::vector<CallInfo> AllCalls;
2656 AllCalls.reserve(Node->MatchingCalls.size() + 1);
2657 AllCalls.push_back(Node->Call);
2658 llvm::append_range(AllCalls, Node->MatchingCalls);
2659
2660 // First see if we can partition the calls by callee function, creating new
2661 // nodes to host each set of calls calling the same callees. This is
2662 // necessary for support indirect calls with ThinLTO, for which we
2663 // synthesized CallsiteInfo records for each target. They will all have the
2664 // same callsite stack ids and would be sharing a context node at this
2665 // point. We need to perform separate cloning for each, which will be
2666 // applied along with speculative devirtualization in the ThinLTO backends
2667 // as needed. Note this does not currently support looking through tail
2668 // calls, it is unclear if we need that for indirect call targets.
2669 // First partition calls by callee func. Map indexed by func, value is
2670 // struct with list of matching calls, assigned node.
2671 if (partitionCallsByCallee(Node, AllCalls, NewCallToNode))
2672 continue;
2673
2674 auto It = AllCalls.begin();
2675 // Iterate through the calls until we find the first that matches.
2676 for (; It != AllCalls.end(); ++It) {
2677 auto ThisCall = *It;
2678 bool Match = true;
2679 for (auto EI = Node->CalleeEdges.begin(); EI != Node->CalleeEdges.end();
2680 ++EI) {
2681 auto Edge = *EI;
2682 if (!Edge->Callee->hasCall())
2683 continue;
2684 assert(NodeToCallingFunc.count(Edge->Callee));
2685 // Check if the called function matches that of the callee node.
2686 if (!calleesMatch(ThisCall.call(), EI, TailCallToContextNodeMap)) {
2687 Match = false;
2688 break;
2689 }
2690 }
2691 // Found a call that matches the callee nodes, we can quit now.
2692 if (Match) {
2693 // If the first match is not the primary call on the Node, update it
2694 // now. We will update the list of matching calls further below.
2695 if (Node->Call != ThisCall) {
2696 Node->setCall(ThisCall);
2697 // We need to update the NonAllocationCallToContextNodeMap, but don't
2698 // want to do this during iteration over that map, so save the calls
2699 // that need updated entries.
2700 NewCallToNode.push_back({ThisCall, Node});
2701 }
2702 break;
2703 }
2704 }
2705 // We will update this list below (or leave it cleared if there was no
2706 // match found above).
2707 Node->MatchingCalls.clear();
2708 // If we hit the end of the AllCalls vector, no call matching the callee
2709 // nodes was found, clear the call information in the node.
2710 if (It == AllCalls.end()) {
2711 RemovedEdgesWithMismatchedCallees++;
2712 // Work around by setting Node to have a null call, so it gets
2713 // skipped during cloning. Otherwise assignFunctions will assert
2714 // because its data structures are not designed to handle this case.
2715 Node->setCall(CallInfo());
2716 continue;
2717 }
2718 // Now add back any matching calls that call the same function as the
2719 // matching primary call on Node.
2720 for (++It; It != AllCalls.end(); ++It) {
2721 auto ThisCall = *It;
2722 if (!sameCallee(Node->Call.call(), ThisCall.call()))
2723 continue;
2724 Node->MatchingCalls.push_back(ThisCall);
2725 }
2726 }
2727
2728 // Remove all mismatched nodes identified in the above loop from the node map
2729 // (checking whether they have a null call which is set above). For a
2730 // MapVector like NonAllocationCallToContextNodeMap it is much more efficient
2731 // to do the removal via remove_if than by individually erasing entries above.
2732 // Also remove any entries if we updated the node's primary call above.
2733 NonAllocationCallToContextNodeMap.remove_if([](const auto &it) {
2734 return !it.second->hasCall() || it.second->Call != it.first;
2735 });
2736
2737 // Add entries for any new primary calls recorded above.
2738 for (auto &[Call, Node] : NewCallToNode)
2739 NonAllocationCallToContextNodeMap[Call] = Node;
2740
2741 // Add the new nodes after the above loop so that the iteration is not
2742 // invalidated.
2743 for (auto &[Call, Node] : TailCallToContextNodeMap)
2744 NonAllocationCallToContextNodeMap[Call] = Node;
2745}
2746
2747template <typename DerivedCCG, typename FuncTy, typename CallTy>
2748bool CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::partitionCallsByCallee(
2749 ContextNode *Node, ArrayRef<CallInfo> AllCalls,
2750 std::vector<std::pair<CallInfo, ContextNode *>> &NewCallToNode) {
2751 // Struct to keep track of all the calls having the same callee function,
2752 // and the node we eventually assign to them. Eventually we will record the
2753 // context node assigned to this group of calls.
2754 struct CallsWithSameCallee {
2755 std::vector<CallInfo> Calls;
2756 ContextNode *Node = nullptr;
2757 };
2758
2759 // First partition calls by callee function. Build map from each function
2760 // to the list of matching calls.
2762 for (auto ThisCall : AllCalls) {
2763 auto *F = getCalleeFunc(ThisCall.call());
2764 if (F)
2765 CalleeFuncToCallInfo[F].Calls.push_back(ThisCall);
2766 }
2767
2768 // Next, walk through all callee edges. For each callee node, get its
2769 // containing function and see if it was recorded in the above map (meaning we
2770 // have at least one matching call). Build another map from each callee node
2771 // with a matching call to the structure instance created above containing all
2772 // the calls.
2774 for (const auto &Edge : Node->CalleeEdges) {
2775 if (!Edge->Callee->hasCall())
2776 continue;
2777 const FuncTy *ProfiledCalleeFunc = NodeToCallingFunc[Edge->Callee];
2778 if (CalleeFuncToCallInfo.contains(ProfiledCalleeFunc))
2779 CalleeNodeToCallInfo[Edge->Callee] =
2780 &CalleeFuncToCallInfo[ProfiledCalleeFunc];
2781 }
2782
2783 // If there are entries in the second map, then there were no matching
2784 // calls/callees, nothing to do here. Return so we can go to the handling that
2785 // looks through tail calls.
2786 if (CalleeNodeToCallInfo.empty())
2787 return false;
2788
2789 // Walk through all callee edges again. Any and all callee edges that didn't
2790 // match any calls (callee not in the CalleeNodeToCallInfo map) are moved to a
2791 // new caller node (UnmatchedCalleesNode) which gets a null call so that it is
2792 // ignored during cloning. If it is in the map, then we use the node recorded
2793 // in that entry (creating it if needed), and move the callee edge to it.
2794 // The first callee will use the original node instead of creating a new one.
2795 // Note that any of the original calls on this node (in AllCalls) that didn't
2796 // have a callee function automatically get dropped from the node as part of
2797 // this process.
2798 ContextNode *UnmatchedCalleesNode = nullptr;
2799 // Track whether we already assigned original node to a callee.
2800 bool UsedOrigNode = false;
2801 assert(NodeToCallingFunc[Node]);
2802 // Iterate over a copy of Node's callee edges, since we may need to remove
2803 // edges in moveCalleeEdgeToNewCaller, and this simplifies the handling and
2804 // makes it less error-prone.
2805 auto CalleeEdges = Node->CalleeEdges;
2806 for (auto &Edge : CalleeEdges) {
2807 if (!Edge->Callee->hasCall())
2808 continue;
2809
2810 // Will be updated below to point to whatever (caller) node this callee edge
2811 // should be moved to.
2812 ContextNode *CallerNodeToUse = nullptr;
2813
2814 // Handle the case where there were no matching calls first. Move this
2815 // callee edge to the UnmatchedCalleesNode, creating it if needed.
2816 if (!CalleeNodeToCallInfo.contains(Edge->Callee)) {
2817 if (!UnmatchedCalleesNode)
2818 UnmatchedCalleesNode =
2819 createNewNode(/*IsAllocation=*/false, NodeToCallingFunc[Node]);
2820 CallerNodeToUse = UnmatchedCalleesNode;
2821 } else {
2822 // Look up the information recorded for this callee node, and use the
2823 // recorded caller node (creating it if needed).
2824 auto *Info = CalleeNodeToCallInfo[Edge->Callee];
2825 if (!Info->Node) {
2826 // If we haven't assigned any callees to the original node use it.
2827 if (!UsedOrigNode) {
2828 Info->Node = Node;
2829 // Clear the set of matching calls which will be updated below.
2830 Node->MatchingCalls.clear();
2831 UsedOrigNode = true;
2832 } else
2833 Info->Node =
2834 createNewNode(/*IsAllocation=*/false, NodeToCallingFunc[Node]);
2835 assert(!Info->Calls.empty());
2836 // The first call becomes the primary call for this caller node, and the
2837 // rest go in the matching calls list.
2838 Info->Node->setCall(Info->Calls.front());
2839 llvm::append_range(Info->Node->MatchingCalls,
2840 llvm::drop_begin(Info->Calls));
2841 // Save the primary call to node correspondence so that we can update
2842 // the NonAllocationCallToContextNodeMap, which is being iterated in the
2843 // caller of this function.
2844 NewCallToNode.push_back({Info->Node->Call, Info->Node});
2845 }
2846 CallerNodeToUse = Info->Node;
2847 }
2848
2849 // Don't need to move edge if we are using the original node;
2850 if (CallerNodeToUse == Node)
2851 continue;
2852
2853 moveCalleeEdgeToNewCaller(Edge, CallerNodeToUse);
2854 }
2855 // Now that we are done moving edges, clean up any caller edges that ended
2856 // up with no type or context ids. During moveCalleeEdgeToNewCaller all
2857 // caller edges from Node are replicated onto the new callers, and it
2858 // simplifies the handling to leave them until we have moved all
2859 // edges/context ids.
2860 for (auto &I : CalleeNodeToCallInfo)
2861 removeNoneTypeCallerEdges(I.second->Node);
2862 if (UnmatchedCalleesNode)
2863 removeNoneTypeCallerEdges(UnmatchedCalleesNode);
2864 removeNoneTypeCallerEdges(Node);
2865
2866 return true;
2867}
2868
2869uint64_t ModuleCallsiteContextGraph::getStackId(uint64_t IdOrIndex) const {
2870 // In the Module (IR) case this is already the Id.
2871 return IdOrIndex;
2872}
2873
2874uint64_t IndexCallsiteContextGraph::getStackId(uint64_t IdOrIndex) const {
2875 // In the Index case this is an index into the stack id list in the summary
2876 // index, convert it to an Id.
2877 return Index.getStackIdAtIndex(IdOrIndex);
2878}
2879
2880template <typename DerivedCCG, typename FuncTy, typename CallTy>
2881bool CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::calleesMatch(
2882 CallTy Call, EdgeIter &EI,
2883 MapVector<CallInfo, ContextNode *> &TailCallToContextNodeMap) {
2884 auto Edge = *EI;
2885 const FuncTy *ProfiledCalleeFunc = NodeToCallingFunc[Edge->Callee];
2886 const FuncTy *CallerFunc = NodeToCallingFunc[Edge->Caller];
2887 // Will be populated in order of callee to caller if we find a chain of tail
2888 // calls between the profiled caller and callee.
2889 std::vector<std::pair<CallTy, FuncTy *>> FoundCalleeChain;
2890 if (!calleeMatchesFunc(Call, ProfiledCalleeFunc, CallerFunc,
2891 FoundCalleeChain))
2892 return false;
2893
2894 // The usual case where the profiled callee matches that of the IR/summary.
2895 if (FoundCalleeChain.empty())
2896 return true;
2897
2898 auto AddEdge = [Edge, &EI](ContextNode *Caller, ContextNode *Callee) {
2899 auto *CurEdge = Callee->findEdgeFromCaller(Caller);
2900 // If there is already an edge between these nodes, simply update it and
2901 // return.
2902 if (CurEdge) {
2903 CurEdge->ContextIds.insert_range(Edge->ContextIds);
2904 CurEdge->AllocTypes |= Edge->AllocTypes;
2905 return;
2906 }
2907 // Otherwise, create a new edge and insert it into the caller and callee
2908 // lists.
2909 auto NewEdge = std::make_shared<ContextEdge>(
2910 Callee, Caller, Edge->AllocTypes, Edge->ContextIds);
2911 Callee->CallerEdges.push_back(NewEdge);
2912 if (Caller == Edge->Caller) {
2913 // If we are inserting the new edge into the current edge's caller, insert
2914 // the new edge before the current iterator position, and then increment
2915 // back to the current edge.
2916 EI = Caller->CalleeEdges.insert(EI, NewEdge);
2917 ++EI;
2918 assert(*EI == Edge &&
2919 "Iterator position not restored after insert and increment");
2920 } else
2921 Caller->CalleeEdges.push_back(NewEdge);
2922 };
2923
2924 // Create new nodes for each found callee and connect in between the profiled
2925 // caller and callee.
2926 auto *CurCalleeNode = Edge->Callee;
2927 for (auto &[NewCall, Func] : FoundCalleeChain) {
2928 ContextNode *NewNode = nullptr;
2929 // First check if we have already synthesized a node for this tail call.
2930 if (TailCallToContextNodeMap.count(NewCall)) {
2931 NewNode = TailCallToContextNodeMap[NewCall];
2932 NewNode->AllocTypes |= Edge->AllocTypes;
2933 } else {
2934 FuncToCallsWithMetadata[Func].push_back({NewCall});
2935 // Create Node and record node info.
2936 NewNode = createNewNode(/*IsAllocation=*/false, Func, NewCall);
2937 TailCallToContextNodeMap[NewCall] = NewNode;
2938 NewNode->AllocTypes = Edge->AllocTypes;
2939 }
2940
2941 // Hook up node to its callee node
2942 AddEdge(NewNode, CurCalleeNode);
2943
2944 CurCalleeNode = NewNode;
2945 }
2946
2947 // Hook up edge's original caller to new callee node.
2948 AddEdge(Edge->Caller, CurCalleeNode);
2949
2950#ifndef NDEBUG
2951 // Save this because Edge's fields get cleared below when removed.
2952 auto *Caller = Edge->Caller;
2953#endif
2954
2955 // Remove old edge
2956 removeEdgeFromGraph(Edge.get(), &EI, /*CalleeIter=*/true);
2957
2958 // To simplify the increment of EI in the caller, subtract one from EI.
2959 // In the final AddEdge call we would have either added a new callee edge,
2960 // to Edge->Caller, or found an existing one. Either way we are guaranteed
2961 // that there is at least one callee edge.
2962 assert(!Caller->CalleeEdges.empty());
2963 --EI;
2964
2965 return true;
2966}
2967
2968bool ModuleCallsiteContextGraph::findProfiledCalleeThroughTailCalls(
2969 const Function *ProfiledCallee, Value *CurCallee, unsigned Depth,
2970 std::vector<std::pair<Instruction *, Function *>> &FoundCalleeChain,
2971 bool &FoundMultipleCalleeChains) {
2972 // Stop recursive search if we have already explored the maximum specified
2973 // depth.
2975 return false;
2976
2977 auto SaveCallsiteInfo = [&](Instruction *Callsite, Function *F) {
2978 FoundCalleeChain.push_back({Callsite, F});
2979 };
2980
2981 auto *CalleeFunc = dyn_cast<Function>(CurCallee);
2982 if (!CalleeFunc) {
2983 auto *Alias = dyn_cast<GlobalAlias>(CurCallee);
2984 assert(Alias);
2985 CalleeFunc = dyn_cast<Function>(Alias->getAliasee());
2986 assert(CalleeFunc);
2987 }
2988
2989 // Look for tail calls in this function, and check if they either call the
2990 // profiled callee directly, or indirectly (via a recursive search).
2991 // Only succeed if there is a single unique tail call chain found between the
2992 // profiled caller and callee, otherwise we could perform incorrect cloning.
2993 bool FoundSingleCalleeChain = false;
2994 for (auto &BB : *CalleeFunc) {
2995 for (auto &I : BB) {
2996 auto *CB = dyn_cast<CallBase>(&I);
2997 if (!CB || !CB->isTailCall())
2998 continue;
2999 auto *CalledValue = CB->getCalledOperand();
3000 auto *CalledFunction = CB->getCalledFunction();
3001 if (CalledValue && !CalledFunction) {
3002 CalledValue = CalledValue->stripPointerCasts();
3003 // Stripping pointer casts can reveal a called function.
3004 CalledFunction = dyn_cast<Function>(CalledValue);
3005 }
3006 // Check if this is an alias to a function. If so, get the
3007 // called aliasee for the checks below.
3008 if (auto *GA = dyn_cast<GlobalAlias>(CalledValue)) {
3009 assert(!CalledFunction &&
3010 "Expected null called function in callsite for alias");
3011 CalledFunction = dyn_cast<Function>(GA->getAliaseeObject());
3012 }
3013 if (!CalledFunction)
3014 continue;
3015 if (CalledFunction == ProfiledCallee) {
3016 if (FoundSingleCalleeChain) {
3017 FoundMultipleCalleeChains = true;
3018 return false;
3019 }
3020 FoundSingleCalleeChain = true;
3021 FoundProfiledCalleeCount++;
3022 FoundProfiledCalleeDepth += Depth;
3023 if (Depth > FoundProfiledCalleeMaxDepth)
3024 FoundProfiledCalleeMaxDepth = Depth;
3025 SaveCallsiteInfo(&I, CalleeFunc);
3026 } else if (findProfiledCalleeThroughTailCalls(
3027 ProfiledCallee, CalledFunction, Depth + 1,
3028 FoundCalleeChain, FoundMultipleCalleeChains)) {
3029 // findProfiledCalleeThroughTailCalls should not have returned
3030 // true if FoundMultipleCalleeChains.
3031 assert(!FoundMultipleCalleeChains);
3032 if (FoundSingleCalleeChain) {
3033 FoundMultipleCalleeChains = true;
3034 return false;
3035 }
3036 FoundSingleCalleeChain = true;
3037 SaveCallsiteInfo(&I, CalleeFunc);
3038 } else if (FoundMultipleCalleeChains)
3039 return false;
3040 }
3041 }
3042
3043 return FoundSingleCalleeChain;
3044}
3045
3046const Function *ModuleCallsiteContextGraph::getCalleeFunc(Instruction *Call) {
3047 auto *CB = dyn_cast<CallBase>(Call);
3048 if (!CB->getCalledOperand() || CB->isIndirectCall())
3049 return nullptr;
3050 auto *CalleeVal = CB->getCalledOperand()->stripPointerCasts();
3051 auto *Alias = dyn_cast<GlobalAlias>(CalleeVal);
3052 if (Alias)
3053 return dyn_cast<Function>(Alias->getAliasee());
3054 return dyn_cast<Function>(CalleeVal);
3055}
3056
3057bool ModuleCallsiteContextGraph::calleeMatchesFunc(
3058 Instruction *Call, const Function *Func, const Function *CallerFunc,
3059 std::vector<std::pair<Instruction *, Function *>> &FoundCalleeChain) {
3060 auto *CB = dyn_cast<CallBase>(Call);
3061 if (!CB->getCalledOperand() || CB->isIndirectCall())
3062 return false;
3063 auto *CalleeVal = CB->getCalledOperand()->stripPointerCasts();
3064 auto *CalleeFunc = dyn_cast<Function>(CalleeVal);
3065 if (CalleeFunc == Func)
3066 return true;
3067 auto *Alias = dyn_cast<GlobalAlias>(CalleeVal);
3068 if (Alias && Alias->getAliasee() == Func)
3069 return true;
3070
3071 // Recursively search for the profiled callee through tail calls starting with
3072 // the actual Callee. The discovered tail call chain is saved in
3073 // FoundCalleeChain, and we will fixup the graph to include these callsites
3074 // after returning.
3075 // FIXME: We will currently redo the same recursive walk if we find the same
3076 // mismatched callee from another callsite. We can improve this with more
3077 // bookkeeping of the created chain of new nodes for each mismatch.
3078 unsigned Depth = 1;
3079 bool FoundMultipleCalleeChains = false;
3080 if (!findProfiledCalleeThroughTailCalls(Func, CalleeVal, Depth,
3081 FoundCalleeChain,
3082 FoundMultipleCalleeChains)) {
3083 LLVM_DEBUG(dbgs() << "Not found through unique tail call chain: "
3084 << Func->getName() << " from " << CallerFunc->getName()
3085 << " that actually called " << CalleeVal->getName()
3086 << (FoundMultipleCalleeChains
3087 ? " (found multiple possible chains)"
3088 : "")
3089 << "\n");
3090 if (FoundMultipleCalleeChains)
3091 FoundProfiledCalleeNonUniquelyCount++;
3092 return false;
3093 }
3094
3095 return true;
3096}
3097
3098bool ModuleCallsiteContextGraph::sameCallee(Instruction *Call1,
3099 Instruction *Call2) {
3100 auto *CB1 = cast<CallBase>(Call1);
3101 if (!CB1->getCalledOperand() || CB1->isIndirectCall())
3102 return false;
3103 auto *CalleeVal1 = CB1->getCalledOperand()->stripPointerCasts();
3104 auto *CalleeFunc1 = dyn_cast<Function>(CalleeVal1);
3105 auto *CB2 = cast<CallBase>(Call2);
3106 if (!CB2->getCalledOperand() || CB2->isIndirectCall())
3107 return false;
3108 auto *CalleeVal2 = CB2->getCalledOperand()->stripPointerCasts();
3109 auto *CalleeFunc2 = dyn_cast<Function>(CalleeVal2);
3110 return CalleeFunc1 == CalleeFunc2;
3111}
3112
3113bool IndexCallsiteContextGraph::findProfiledCalleeThroughTailCalls(
3114 ValueInfo ProfiledCallee, ValueInfo CurCallee, unsigned Depth,
3115 std::vector<std::pair<IndexCall, FunctionSummary *>> &FoundCalleeChain,
3116 bool &FoundMultipleCalleeChains) {
3117 // Stop recursive search if we have already explored the maximum specified
3118 // depth.
3120 return false;
3121
3122 auto CreateAndSaveCallsiteInfo = [&](ValueInfo Callee, FunctionSummary *FS) {
3123 // Make a CallsiteInfo for each discovered callee, if one hasn't already
3124 // been synthesized.
3125 if (!FunctionCalleesToSynthesizedCallsiteInfos.count(FS) ||
3126 !FunctionCalleesToSynthesizedCallsiteInfos[FS].count(Callee))
3127 // StackIds is empty (we don't have debug info available in the index for
3128 // these callsites)
3129 FunctionCalleesToSynthesizedCallsiteInfos[FS][Callee] =
3130 std::make_unique<CallsiteInfo>(Callee, SmallVector<unsigned>());
3131 CallsiteInfo *NewCallsiteInfo =
3132 FunctionCalleesToSynthesizedCallsiteInfos[FS][Callee].get();
3133 FoundCalleeChain.push_back({NewCallsiteInfo, FS});
3134 };
3135
3136 // Look for tail calls in this function, and check if they either call the
3137 // profiled callee directly, or indirectly (via a recursive search).
3138 // Only succeed if there is a single unique tail call chain found between the
3139 // profiled caller and callee, otherwise we could perform incorrect cloning.
3140 bool FoundSingleCalleeChain = false;
3141 for (auto &S : CurCallee.getSummaryList()) {
3142 if (!GlobalValue::isLocalLinkage(S->linkage()) &&
3143 !isPrevailing(CurCallee.getGUID(), S.get()))
3144 continue;
3145 auto *FS = dyn_cast<FunctionSummary>(S->getBaseObject());
3146 if (!FS)
3147 continue;
3148 auto FSVI = CurCallee;
3149 auto *AS = dyn_cast<AliasSummary>(S.get());
3150 if (AS)
3151 FSVI = AS->getAliaseeVI();
3152 for (auto &CallEdge : FS->calls()) {
3153 if (!CallEdge.second.hasTailCall())
3154 continue;
3155 if (CallEdge.first == ProfiledCallee) {
3156 if (FoundSingleCalleeChain) {
3157 FoundMultipleCalleeChains = true;
3158 return false;
3159 }
3160 FoundSingleCalleeChain = true;
3161 FoundProfiledCalleeCount++;
3162 FoundProfiledCalleeDepth += Depth;
3163 if (Depth > FoundProfiledCalleeMaxDepth)
3164 FoundProfiledCalleeMaxDepth = Depth;
3165 CreateAndSaveCallsiteInfo(CallEdge.first, FS);
3166 // Add FS to FSToVIMap in case it isn't already there.
3167 assert(!FSToVIMap.count(FS) || FSToVIMap[FS] == FSVI);
3168 FSToVIMap[FS] = FSVI;
3169 } else if (findProfiledCalleeThroughTailCalls(
3170 ProfiledCallee, CallEdge.first, Depth + 1,
3171 FoundCalleeChain, FoundMultipleCalleeChains)) {
3172 // findProfiledCalleeThroughTailCalls should not have returned
3173 // true if FoundMultipleCalleeChains.
3174 assert(!FoundMultipleCalleeChains);
3175 if (FoundSingleCalleeChain) {
3176 FoundMultipleCalleeChains = true;
3177 return false;
3178 }
3179 FoundSingleCalleeChain = true;
3180 CreateAndSaveCallsiteInfo(CallEdge.first, FS);
3181 // Add FS to FSToVIMap in case it isn't already there.
3182 assert(!FSToVIMap.count(FS) || FSToVIMap[FS] == FSVI);
3183 FSToVIMap[FS] = FSVI;
3184 } else if (FoundMultipleCalleeChains)
3185 return false;
3186 }
3187 }
3188
3189 return FoundSingleCalleeChain;
3190}
3191
3192const FunctionSummary *
3193IndexCallsiteContextGraph::getCalleeFunc(IndexCall &Call) {
3194 ValueInfo Callee = dyn_cast_if_present<CallsiteInfo *>(Call)->Callee;
3195 if (Callee.getSummaryList().empty())
3196 return nullptr;
3197 return dyn_cast<FunctionSummary>(Callee.getSummaryList()[0]->getBaseObject());
3198}
3199
3200bool IndexCallsiteContextGraph::calleeMatchesFunc(
3201 IndexCall &Call, const FunctionSummary *Func,
3202 const FunctionSummary *CallerFunc,
3203 std::vector<std::pair<IndexCall, FunctionSummary *>> &FoundCalleeChain) {
3204 ValueInfo Callee = dyn_cast_if_present<CallsiteInfo *>(Call)->Callee;
3205 // If there is no summary list then this is a call to an externally defined
3206 // symbol.
3207 AliasSummary *Alias =
3208 Callee.getSummaryList().empty()
3209 ? nullptr
3210 : dyn_cast<AliasSummary>(Callee.getSummaryList()[0].get());
3211 assert(FSToVIMap.count(Func));
3212 auto FuncVI = FSToVIMap[Func];
3213 if (Callee == FuncVI ||
3214 // If callee is an alias, check the aliasee, since only function
3215 // summary base objects will contain the stack node summaries and thus
3216 // get a context node.
3217 (Alias && Alias->getAliaseeVI() == FuncVI))
3218 return true;
3219
3220 // Recursively search for the profiled callee through tail calls starting with
3221 // the actual Callee. The discovered tail call chain is saved in
3222 // FoundCalleeChain, and we will fixup the graph to include these callsites
3223 // after returning.
3224 // FIXME: We will currently redo the same recursive walk if we find the same
3225 // mismatched callee from another callsite. We can improve this with more
3226 // bookkeeping of the created chain of new nodes for each mismatch.
3227 unsigned Depth = 1;
3228 bool FoundMultipleCalleeChains = false;
3229 if (!findProfiledCalleeThroughTailCalls(
3230 FuncVI, Callee, Depth, FoundCalleeChain, FoundMultipleCalleeChains)) {
3231 LLVM_DEBUG(dbgs() << "Not found through unique tail call chain: " << FuncVI
3232 << " from " << FSToVIMap[CallerFunc]
3233 << " that actually called " << Callee
3234 << (FoundMultipleCalleeChains
3235 ? " (found multiple possible chains)"
3236 : "")
3237 << "\n");
3238 if (FoundMultipleCalleeChains)
3239 FoundProfiledCalleeNonUniquelyCount++;
3240 return false;
3241 }
3242
3243 return true;
3244}
3245
3246bool IndexCallsiteContextGraph::sameCallee(IndexCall &Call1, IndexCall &Call2) {
3247 ValueInfo Callee1 = dyn_cast_if_present<CallsiteInfo *>(Call1)->Callee;
3248 ValueInfo Callee2 = dyn_cast_if_present<CallsiteInfo *>(Call2)->Callee;
3249 return Callee1 == Callee2;
3250}
3251
3252template <typename DerivedCCG, typename FuncTy, typename CallTy>
3253void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::ContextNode::dump()
3254 const {
3255 print(dbgs());
3256 dbgs() << "\n";
3257}
3258
3259template <typename DerivedCCG, typename FuncTy, typename CallTy>
3260void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::ContextNode::print(
3261 raw_ostream &OS) const {
3262 OS << "Node " << this << "\n";
3263 OS << "\t";
3264 printCall(OS);
3265 if (Recursive)
3266 OS << " (recursive)";
3267 OS << "\n";
3268 if (!MatchingCalls.empty()) {
3269 OS << "\tMatchingCalls:\n";
3270 for (auto &MatchingCall : MatchingCalls) {
3271 OS << "\t";
3272 MatchingCall.print(OS);
3273 OS << "\n";
3274 }
3275 }
3276 OS << "\tNodeId: " << NodeId << "\n";
3277 OS << "\tAllocTypes: " << getAllocTypeString(AllocTypes) << "\n";
3278 OS << "\tContextIds:";
3279 // Make a copy of the computed context ids that we can sort for stability.
3280 auto ContextIds = getContextIds();
3281 std::vector<uint32_t> SortedIds(ContextIds.begin(), ContextIds.end());
3282 std::sort(SortedIds.begin(), SortedIds.end());
3283 for (auto Id : SortedIds)
3284 OS << " " << Id;
3285 OS << "\n";
3286 OS << "\tCalleeEdges:\n";
3287 for (auto &Edge : CalleeEdges)
3288 OS << "\t\t" << *Edge << " (Callee NodeId: " << Edge->Callee->NodeId
3289 << ")\n";
3290 OS << "\tCallerEdges:\n";
3291 for (auto &Edge : CallerEdges)
3292 OS << "\t\t" << *Edge << " (Caller NodeId: " << Edge->Caller->NodeId
3293 << ")\n";
3294 if (!Clones.empty()) {
3295 OS << "\tClones: ";
3296 ListSeparator LS;
3297 for (auto *C : Clones)
3298 OS << LS << C << " NodeId: " << C->NodeId;
3299 OS << "\n";
3300 } else if (CloneOf) {
3301 OS << "\tClone of " << CloneOf << " NodeId: " << CloneOf->NodeId << "\n";
3302 }
3303}
3304
3305template <typename DerivedCCG, typename FuncTy, typename CallTy>
3306void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::ContextEdge::dump()
3307 const {
3308 print(dbgs());
3309 dbgs() << "\n";
3310}
3311
3312template <typename DerivedCCG, typename FuncTy, typename CallTy>
3313void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::ContextEdge::print(
3314 raw_ostream &OS) const {
3315 OS << "Edge from Callee " << Callee << " to Caller: " << Caller
3316 << (IsBackedge ? " (BE)" : "")
3317 << " AllocTypes: " << getAllocTypeString(AllocTypes);
3318 OS << " ContextIds:";
3319 std::vector<uint32_t> SortedIds(ContextIds.begin(), ContextIds.end());
3320 std::sort(SortedIds.begin(), SortedIds.end());
3321 for (auto Id : SortedIds)
3322 OS << " " << Id;
3323}
3324
3325template <typename DerivedCCG, typename FuncTy, typename CallTy>
3326void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::dump() const {
3327 print(dbgs());
3328}
3329
3330template <typename DerivedCCG, typename FuncTy, typename CallTy>
3331void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::print(
3332 raw_ostream &OS) const {
3333 OS << "Callsite Context Graph:\n";
3334 using GraphType = const CallsiteContextGraph<DerivedCCG, FuncTy, CallTy> *;
3335 for (const auto Node : nodes<GraphType>(this)) {
3336 if (Node->isRemoved())
3337 continue;
3338 Node->print(OS);
3339 OS << "\n";
3340 }
3341}
3342
3343template <typename DerivedCCG, typename FuncTy, typename CallTy>
3344void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::printTotalSizes(
3345 raw_ostream &OS,
3346 function_ref<void(StringRef, StringRef, const Twine &)> EmitRemark) const {
3347 using GraphType = const CallsiteContextGraph<DerivedCCG, FuncTy, CallTy> *;
3348 for (const auto Node : nodes<GraphType>(this)) {
3349 if (Node->isRemoved())
3350 continue;
3351 if (!Node->IsAllocation)
3352 continue;
3353 DenseSet<uint32_t> ContextIds = Node->getContextIds();
3354 auto AllocTypeFromCall = getAllocationCallType(Node->Call);
3355 std::vector<uint32_t> SortedIds(ContextIds.begin(), ContextIds.end());
3356 std::sort(SortedIds.begin(), SortedIds.end());
3357 for (auto Id : SortedIds) {
3358 auto TypeI = ContextIdToAllocationType.find(Id);
3359 assert(TypeI != ContextIdToAllocationType.end());
3360 auto CSI = ContextIdToContextSizeInfos.find(Id);
3361 if (CSI != ContextIdToContextSizeInfos.end()) {
3362 for (auto &Info : CSI->second) {
3363 std::string Msg =
3364 "MemProf hinting: " + getAllocTypeString((uint8_t)TypeI->second) +
3365 " full allocation context " + std::to_string(Info.FullStackId) +
3366 " with total size " + std::to_string(Info.TotalSize) + " is " +
3367 getAllocTypeString(Node->AllocTypes) + " after cloning";
3368 if (allocTypeToUse(Node->AllocTypes) != AllocTypeFromCall)
3369 Msg += " marked " + getAllocTypeString((uint8_t)AllocTypeFromCall) +
3370 " due to cold byte percent";
3371 // Print the internal context id to aid debugging and visualization.
3372 Msg += " (internal context id " + std::to_string(Id) + ")";
3374 OS << Msg << "\n";
3375 if (EmitRemark)
3376 EmitRemark(DEBUG_TYPE, "MemProfReport", Msg);
3377 }
3378 } else {
3379 // This is only emitted if the context size info is not present.
3380 std::string Msg =
3381 "MemProf hinting: " + getAllocTypeString((uint8_t)TypeI->second) +
3382 " context is " + getAllocTypeString(Node->AllocTypes) +
3383 " after cloning";
3384 if (allocTypeToUse(Node->AllocTypes) != AllocTypeFromCall)
3385 Msg += " marked " + getAllocTypeString((uint8_t)AllocTypeFromCall) +
3386 " due to cold byte percent";
3387 // Print the internal context id to aid debugging and visualization.
3388 Msg += " (internal context id " + std::to_string(Id) + ")";
3390 OS << Msg << "\n";
3391 if (EmitRemark)
3392 EmitRemark(DEBUG_TYPE, "MemProfReport", Msg);
3393 }
3394 }
3395 }
3396}
3397
3398template <typename DerivedCCG, typename FuncTy, typename CallTy>
3399void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::check() const {
3400 using GraphType = const CallsiteContextGraph<DerivedCCG, FuncTy, CallTy> *;
3401 for (const auto Node : nodes<GraphType>(this)) {
3402 checkNode<DerivedCCG, FuncTy, CallTy>(Node, /*CheckEdges=*/false);
3403 for (auto &Edge : Node->CallerEdges)
3405 }
3406}
3407
3408template <typename DerivedCCG, typename FuncTy, typename CallTy>
3409struct GraphTraits<const CallsiteContextGraph<DerivedCCG, FuncTy, CallTy> *> {
3410 using GraphType = const CallsiteContextGraph<DerivedCCG, FuncTy, CallTy> *;
3411 using NodeRef = const ContextNode<DerivedCCG, FuncTy, CallTy> *;
3412
3413 using NodePtrTy = std::unique_ptr<ContextNode<DerivedCCG, FuncTy, CallTy>>;
3414 static NodeRef getNode(const NodePtrTy &P) { return P.get(); }
3415
3418 decltype(&getNode)>;
3419
3421 return nodes_iterator(G->NodeOwner.begin(), &getNode);
3422 }
3423
3425 return nodes_iterator(G->NodeOwner.end(), &getNode);
3426 }
3427
3429 return G->NodeOwner.begin()->get();
3430 }
3431
3432 using EdgePtrTy = std::shared_ptr<ContextEdge<DerivedCCG, FuncTy, CallTy>>;
3433 static const ContextNode<DerivedCCG, FuncTy, CallTy> *
3435 return P->Callee;
3436 }
3437
3439 mapped_iterator<typename std::vector<std::shared_ptr<ContextEdge<
3440 DerivedCCG, FuncTy, CallTy>>>::const_iterator,
3441 decltype(&GetCallee)>;
3442
3444 return ChildIteratorType(N->CalleeEdges.begin(), &GetCallee);
3445 }
3446
3448 return ChildIteratorType(N->CalleeEdges.end(), &GetCallee);
3449 }
3450};
3451
3452template <typename DerivedCCG, typename FuncTy, typename CallTy>
3453struct DOTGraphTraits<const CallsiteContextGraph<DerivedCCG, FuncTy, CallTy> *>
3454 : public DefaultDOTGraphTraits {
3455 DOTGraphTraits(bool IsSimple = false) : DefaultDOTGraphTraits(IsSimple) {
3456 // If the user requested the full graph to be exported, but provided an
3457 // allocation id, or if the user gave a context id and requested more than
3458 // just a specific context to be exported, note that highlighting is
3459 // enabled.
3460 DoHighlight =
3461 (AllocIdForDot.getNumOccurrences() && DotGraphScope == DotScope::All) ||
3462 (ContextIdForDot.getNumOccurrences() &&
3464 }
3465
3466 using GraphType = const CallsiteContextGraph<DerivedCCG, FuncTy, CallTy> *;
3468 using NodeRef = typename GTraits::NodeRef;
3469 using ChildIteratorType = typename GTraits::ChildIteratorType;
3470
3471 static std::string getNodeLabel(NodeRef Node, GraphType G) {
3472 std::string LabelString =
3473 (Twine("OrigId: ") + (Node->IsAllocation ? "Alloc" : "") +
3474 Twine(Node->OrigStackOrAllocId) + " NodeId: " + Twine(Node->NodeId))
3475 .str();
3476 LabelString += "\n";
3477 if (Node->hasCall()) {
3478 auto Func = G->NodeToCallingFunc.find(Node);
3479 assert(Func != G->NodeToCallingFunc.end());
3480 LabelString +=
3481 G->getLabel(Func->second, Node->Call.call(), Node->Call.cloneNo());
3482 for (auto &MatchingCall : Node->MatchingCalls) {
3483 LabelString += "\n";
3484 LabelString += G->getLabel(Func->second, MatchingCall.call(),
3485 MatchingCall.cloneNo());
3486 }
3487 } else {
3488 LabelString += "null call";
3489 if (Node->Recursive)
3490 LabelString += " (recursive)";
3491 else
3492 LabelString += " (external)";
3493 }
3494 return LabelString;
3495 }
3496
3498 auto ContextIds = Node->getContextIds();
3499 // If highlighting enabled, see if this node contains any of the context ids
3500 // of interest. If so, it will use a different color and a larger fontsize
3501 // (which makes the node larger as well).
3502 bool Highlight = false;
3503 if (DoHighlight) {
3504 assert(ContextIdForDot.getNumOccurrences() ||
3505 AllocIdForDot.getNumOccurrences());
3506 if (ContextIdForDot.getNumOccurrences())
3507 Highlight = ContextIds.contains(ContextIdForDot);
3508 else
3509 Highlight = set_intersects(ContextIds, G->DotAllocContextIds);
3510 }
3511 std::string AttributeString = (Twine("tooltip=\"") + getNodeId(Node) + " " +
3512 getContextIds(ContextIds) + "\"")
3513 .str();
3514 // Default fontsize is 14
3515 if (Highlight)
3516 AttributeString += ",fontsize=\"30\"";
3517 AttributeString +=
3518 (Twine(",fillcolor=\"") + getColor(Node->AllocTypes, Highlight) + "\"")
3519 .str();
3520 if (Node->CloneOf) {
3521 AttributeString += ",color=\"blue\"";
3522 AttributeString += ",style=\"filled,bold,dashed\"";
3523 } else
3524 AttributeString += ",style=\"filled\"";
3525 return AttributeString;
3526 }
3527
3528 static std::string getEdgeAttributes(NodeRef, ChildIteratorType ChildIter,
3529 GraphType G) {
3530 auto &Edge = *(ChildIter.getCurrent());
3531 // If highlighting enabled, see if this edge contains any of the context ids
3532 // of interest. If so, it will use a different color and a heavier arrow
3533 // size and weight (the larger weight makes the highlighted path
3534 // straighter).
3535 bool Highlight = false;
3536 if (DoHighlight) {
3537 assert(ContextIdForDot.getNumOccurrences() ||
3538 AllocIdForDot.getNumOccurrences());
3539 if (ContextIdForDot.getNumOccurrences())
3540 Highlight = Edge->ContextIds.contains(ContextIdForDot);
3541 else
3542 Highlight = set_intersects(Edge->ContextIds, G->DotAllocContextIds);
3543 }
3544 auto Color = getColor(Edge->AllocTypes, Highlight);
3545 std::string AttributeString =
3546 (Twine("tooltip=\"") + getContextIds(Edge->ContextIds) + "\"" +
3547 // fillcolor is the arrow head and color is the line
3548 Twine(",fillcolor=\"") + Color + "\"" + Twine(",color=\"") + Color +
3549 "\"")
3550 .str();
3551 if (Edge->IsBackedge)
3552 AttributeString += ",style=\"dotted\"";
3553 // Default penwidth and weight are both 1.
3554 if (Highlight)
3555 AttributeString += ",penwidth=\"2.0\",weight=\"2\"";
3556 return AttributeString;
3557 }
3558
3559 // Since the NodeOwners list includes nodes that are no longer connected to
3560 // the graph, skip them here.
3562 if (Node->isRemoved())
3563 return true;
3564 // If a scope smaller than the full graph was requested, see if this node
3565 // contains any of the context ids of interest.
3567 return !set_intersects(Node->getContextIds(), G->DotAllocContextIds);
3569 return !Node->getContextIds().contains(ContextIdForDot);
3570 return false;
3571 }
3572
3573private:
3574 static std::string getContextIds(const DenseSet<uint32_t> &ContextIds) {
3575 std::string IdString = "ContextIds:";
3576 if (ContextIds.size() < 100) {
3577 std::vector<uint32_t> SortedIds(ContextIds.begin(), ContextIds.end());
3578 std::sort(SortedIds.begin(), SortedIds.end());
3579 for (auto Id : SortedIds)
3580 IdString += (" " + Twine(Id)).str();
3581 } else {
3582 IdString += (" (" + Twine(ContextIds.size()) + " ids)").str();
3583 }
3584 return IdString;
3585 }
3586
3587 static std::string getColor(uint8_t AllocTypes, bool Highlight) {
3588 // If DoHighlight is not enabled, we want to use the highlight colors for
3589 // NotCold and Cold, and the non-highlight color for NotCold+Cold. This is
3590 // both compatible with the color scheme before highlighting was supported,
3591 // and for the NotCold+Cold color the non-highlight color is a bit more
3592 // readable.
3593 if (AllocTypes == (uint8_t)AllocationType::NotCold)
3594 // Color "brown1" actually looks like a lighter red.
3595 return !DoHighlight || Highlight ? "brown1" : "lightpink";
3596 if (AllocTypes == (uint8_t)AllocationType::Cold)
3597 return !DoHighlight || Highlight ? "cyan" : "lightskyblue";
3598 if (AllocTypes ==
3599 ((uint8_t)AllocationType::NotCold | (uint8_t)AllocationType::Cold))
3600 return Highlight ? "magenta" : "mediumorchid1";
3601 return "gray";
3602 }
3603
3604 static std::string getNodeId(NodeRef Node) {
3605 std::stringstream SStream;
3606 SStream << std::hex << "N0x" << (unsigned long long)Node;
3607 std::string Result = SStream.str();
3608 return Result;
3609 }
3610
3611 // True if we should highlight a specific context or allocation's contexts in
3612 // the emitted graph.
3613 static bool DoHighlight;
3614};
3615
3616template <typename DerivedCCG, typename FuncTy, typename CallTy>
3617bool DOTGraphTraits<
3618 const CallsiteContextGraph<DerivedCCG, FuncTy, CallTy> *>::DoHighlight =
3619 false;
3620
3621template <typename DerivedCCG, typename FuncTy, typename CallTy>
3622void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::exportToDot(
3623 std::string Label) const {
3624 WriteGraph(this, "", false, Label,
3625 DotFilePathPrefix + "ccg." + Label + ".dot");
3626}
3627
3628template <typename DerivedCCG, typename FuncTy, typename CallTy>
3629typename CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::ContextNode *
3630CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::moveEdgeToNewCalleeClone(
3631 const std::shared_ptr<ContextEdge> &Edge,
3632 DenseSet<uint32_t> ContextIdsToMove) {
3633 ContextNode *Node = Edge->Callee;
3634 assert(NodeToCallingFunc.count(Node));
3635 ContextNode *Clone =
3636 createNewNode(Node->IsAllocation, NodeToCallingFunc[Node], Node->Call);
3637 Node->addClone(Clone);
3638 Clone->MatchingCalls = Node->MatchingCalls;
3639 moveEdgeToExistingCalleeClone(Edge, Clone, /*NewClone=*/true,
3640 ContextIdsToMove);
3641 return Clone;
3642}
3643
3644template <typename DerivedCCG, typename FuncTy, typename CallTy>
3645void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::
3646 moveEdgeToExistingCalleeClone(const std::shared_ptr<ContextEdge> &Edge,
3647 ContextNode *NewCallee, bool NewClone,
3648 DenseSet<uint32_t> ContextIdsToMove) {
3649 // NewCallee and Edge's current callee must be clones of the same original
3650 // node (Edge's current callee may be the original node too).
3651 assert(NewCallee->getOrigNode() == Edge->Callee->getOrigNode());
3652
3653 bool EdgeIsRecursive = Edge->Callee == Edge->Caller;
3654
3655 ContextNode *OldCallee = Edge->Callee;
3656
3657 // We might already have an edge to the new callee from earlier cloning for a
3658 // different allocation. If one exists we will reuse it.
3659 auto ExistingEdgeToNewCallee = NewCallee->findEdgeFromCaller(Edge->Caller);
3660
3661 // Callers will pass an empty ContextIdsToMove set when they want to move the
3662 // edge. Copy in Edge's ids for simplicity.
3663 if (ContextIdsToMove.empty())
3664 ContextIdsToMove = Edge->getContextIds();
3665
3666 // If we are moving all of Edge's ids, then just move the whole Edge.
3667 // Otherwise only move the specified subset, to a new edge if needed.
3668 if (Edge->getContextIds().size() == ContextIdsToMove.size()) {
3669 // First, update the alloc types on New Callee from Edge.
3670 // Do this before we potentially clear Edge's fields below!
3671 NewCallee->AllocTypes |= Edge->AllocTypes;
3672 // Moving the whole Edge.
3673 if (ExistingEdgeToNewCallee) {
3674 // Since we already have an edge to NewCallee, simply move the ids
3675 // onto it, and remove the existing Edge.
3676 ExistingEdgeToNewCallee->getContextIds().insert_range(ContextIdsToMove);
3677 ExistingEdgeToNewCallee->AllocTypes |= Edge->AllocTypes;
3678 assert(Edge->ContextIds == ContextIdsToMove);
3679 removeEdgeFromGraph(Edge.get());
3680 } else {
3681 // Otherwise just reconnect Edge to NewCallee.
3682 Edge->Callee = NewCallee;
3683 NewCallee->CallerEdges.push_back(Edge);
3684 // Remove it from callee where it was previously connected.
3685 OldCallee->eraseCallerEdge(Edge.get());
3686 // Don't need to update Edge's context ids since we are simply
3687 // reconnecting it.
3688 }
3689 } else {
3690 // Only moving a subset of Edge's ids.
3691 // Compute the alloc type of the subset of ids being moved.
3692 auto CallerEdgeAllocType = computeAllocType(ContextIdsToMove);
3693 if (ExistingEdgeToNewCallee) {
3694 // Since we already have an edge to NewCallee, simply move the ids
3695 // onto it.
3696 ExistingEdgeToNewCallee->getContextIds().insert_range(ContextIdsToMove);
3697 ExistingEdgeToNewCallee->AllocTypes |= CallerEdgeAllocType;
3698 } else {
3699 // Otherwise, create a new edge to NewCallee for the ids being moved.
3700 auto NewEdge = std::make_shared<ContextEdge>(
3701 NewCallee, Edge->Caller, CallerEdgeAllocType, ContextIdsToMove);
3702 Edge->Caller->CalleeEdges.push_back(NewEdge);
3703 NewCallee->CallerEdges.push_back(NewEdge);
3704 }
3705 // In either case, need to update the alloc types on NewCallee, and remove
3706 // those ids and update the alloc type on the original Edge.
3707 NewCallee->AllocTypes |= CallerEdgeAllocType;
3708 set_subtract(Edge->ContextIds, ContextIdsToMove);
3709 Edge->AllocTypes = computeAllocType(Edge->ContextIds);
3710 }
3711 // Now walk the old callee node's callee edges and move Edge's context ids
3712 // over to the corresponding edge into the clone (which is created here if
3713 // this is a newly created clone).
3714 for (auto &OldCalleeEdge : OldCallee->CalleeEdges) {
3715 ContextNode *CalleeToUse = OldCalleeEdge->Callee;
3716 // If this is a direct recursion edge, use NewCallee (the clone) as the
3717 // callee as well, so that any edge updated/created here is also direct
3718 // recursive.
3719 if (CalleeToUse == OldCallee) {
3720 // If this is a recursive edge, see if we already moved a recursive edge
3721 // (which would have to have been this one) - if we were only moving a
3722 // subset of context ids it would still be on OldCallee.
3723 if (EdgeIsRecursive) {
3724 assert(OldCalleeEdge == Edge);
3725 continue;
3726 }
3727 CalleeToUse = NewCallee;
3728 }
3729 // The context ids moving to the new callee are the subset of this edge's
3730 // context ids and the context ids on the caller edge being moved.
3731 DenseSet<uint32_t> EdgeContextIdsToMove =
3732 set_intersection(OldCalleeEdge->getContextIds(), ContextIdsToMove);
3733 set_subtract(OldCalleeEdge->getContextIds(), EdgeContextIdsToMove);
3734 OldCalleeEdge->AllocTypes =
3735 computeAllocType(OldCalleeEdge->getContextIds());
3736 if (!NewClone) {
3737 // Update context ids / alloc type on corresponding edge to NewCallee.
3738 // There is a chance this may not exist if we are reusing an existing
3739 // clone, specifically during function assignment, where we would have
3740 // removed none type edges after creating the clone. If we can't find
3741 // a corresponding edge there, fall through to the cloning below.
3742 if (auto *NewCalleeEdge = NewCallee->findEdgeFromCallee(CalleeToUse)) {
3743 NewCalleeEdge->getContextIds().insert_range(EdgeContextIdsToMove);
3744 NewCalleeEdge->AllocTypes |= computeAllocType(EdgeContextIdsToMove);
3745 continue;
3746 }
3747 }
3748 auto NewEdge = std::make_shared<ContextEdge>(
3749 CalleeToUse, NewCallee, computeAllocType(EdgeContextIdsToMove),
3750 EdgeContextIdsToMove);
3751 NewCallee->CalleeEdges.push_back(NewEdge);
3752 NewEdge->Callee->CallerEdges.push_back(NewEdge);
3753 }
3754 // Recompute the node alloc type now that its callee edges have been
3755 // updated (since we will compute from those edges).
3756 OldCallee->AllocTypes = OldCallee->computeAllocType();
3757 // OldCallee alloc type should be None iff its context id set is now empty.
3758 assert((OldCallee->AllocTypes == (uint8_t)AllocationType::None) ==
3759 OldCallee->emptyContextIds());
3760 if (VerifyCCG) {
3761 checkNode<DerivedCCG, FuncTy, CallTy>(OldCallee, /*CheckEdges=*/false);
3762 checkNode<DerivedCCG, FuncTy, CallTy>(NewCallee, /*CheckEdges=*/false);
3763 for (const auto &OldCalleeEdge : OldCallee->CalleeEdges)
3764 checkNode<DerivedCCG, FuncTy, CallTy>(OldCalleeEdge->Callee,
3765 /*CheckEdges=*/false);
3766 for (const auto &NewCalleeEdge : NewCallee->CalleeEdges)
3767 checkNode<DerivedCCG, FuncTy, CallTy>(NewCalleeEdge->Callee,
3768 /*CheckEdges=*/false);
3769 }
3770}
3771
3772template <typename DerivedCCG, typename FuncTy, typename CallTy>
3773void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::
3774 moveCalleeEdgeToNewCaller(const std::shared_ptr<ContextEdge> &Edge,
3775 ContextNode *NewCaller) {
3776 auto *OldCallee = Edge->Callee;
3777 auto *NewCallee = OldCallee;
3778 // If this edge was direct recursive, make any new/updated edge also direct
3779 // recursive to NewCaller.
3780 bool Recursive = Edge->Caller == Edge->Callee;
3781 if (Recursive)
3782 NewCallee = NewCaller;
3783
3784 ContextNode *OldCaller = Edge->Caller;
3785 OldCaller->eraseCalleeEdge(Edge.get());
3786
3787 // We might already have an edge to the new caller. If one exists we will
3788 // reuse it.
3789 auto ExistingEdgeToNewCaller = NewCaller->findEdgeFromCallee(NewCallee);
3790
3791 if (ExistingEdgeToNewCaller) {
3792 // Since we already have an edge to NewCaller, simply move the ids
3793 // onto it, and remove the existing Edge.
3794 ExistingEdgeToNewCaller->getContextIds().insert_range(
3795 Edge->getContextIds());
3796 ExistingEdgeToNewCaller->AllocTypes |= Edge->AllocTypes;
3797 Edge->ContextIds.clear();
3798 Edge->AllocTypes = (uint8_t)AllocationType::None;
3799 OldCallee->eraseCallerEdge(Edge.get());
3800 } else {
3801 // Otherwise just reconnect Edge to NewCaller.
3802 Edge->Caller = NewCaller;
3803 NewCaller->CalleeEdges.push_back(Edge);
3804 if (Recursive) {
3805 assert(NewCallee == NewCaller);
3806 // In the case of (direct) recursive edges, we update the callee as well
3807 // so that it becomes recursive on the new caller.
3808 Edge->Callee = NewCallee;
3809 NewCallee->CallerEdges.push_back(Edge);
3810 OldCallee->eraseCallerEdge(Edge.get());
3811 }
3812 // Don't need to update Edge's context ids since we are simply
3813 // reconnecting it.
3814 }
3815 // In either case, need to update the alloc types on New Caller.
3816 NewCaller->AllocTypes |= Edge->AllocTypes;
3817
3818 // Now walk the old caller node's caller edges and move Edge's context ids
3819 // over to the corresponding edge into the node (which is created here if
3820 // this is a newly created node). We can tell whether this is a newly created
3821 // node by seeing if it has any caller edges yet.
3822#ifndef NDEBUG
3823 bool IsNewNode = NewCaller->CallerEdges.empty();
3824#endif
3825 // If we just moved a direct recursive edge, presumably its context ids should
3826 // also flow out of OldCaller via some other non-recursive callee edge. We
3827 // don't want to remove the recursive context ids from other caller edges yet,
3828 // otherwise the context ids get into an inconsistent state on OldCaller.
3829 // We will update these context ids on the non-recursive caller edge when and
3830 // if they are updated on the non-recursive callee.
3831 if (!Recursive) {
3832 for (auto &OldCallerEdge : OldCaller->CallerEdges) {
3833 auto OldCallerCaller = OldCallerEdge->Caller;
3834 // The context ids moving to the new caller are the subset of this edge's
3835 // context ids and the context ids on the callee edge being moved.
3836 DenseSet<uint32_t> EdgeContextIdsToMove = set_intersection(
3837 OldCallerEdge->getContextIds(), Edge->getContextIds());
3838 if (OldCaller == OldCallerCaller) {
3839 OldCallerCaller = NewCaller;
3840 // Don't actually move this one. The caller will move it directly via a
3841 // call to this function with this as the Edge if it is appropriate to
3842 // move to a diff node that has a matching callee (itself).
3843 continue;
3844 }
3845 set_subtract(OldCallerEdge->getContextIds(), EdgeContextIdsToMove);
3846 OldCallerEdge->AllocTypes =
3847 computeAllocType(OldCallerEdge->getContextIds());
3848 // In this function we expect that any pre-existing node already has edges
3849 // from the same callers as the old node. That should be true in the
3850 // current use case, where we will remove None-type edges after copying
3851 // over all caller edges from the callee.
3852 auto *ExistingCallerEdge = NewCaller->findEdgeFromCaller(OldCallerCaller);
3853 // Since we would have skipped caller edges when moving a direct recursive
3854 // edge, this may not hold true when recursive handling enabled.
3855 assert(IsNewNode || ExistingCallerEdge || AllowRecursiveCallsites);
3856 if (ExistingCallerEdge) {
3857 ExistingCallerEdge->getContextIds().insert_range(EdgeContextIdsToMove);
3858 ExistingCallerEdge->AllocTypes |=
3859 computeAllocType(EdgeContextIdsToMove);
3860 continue;
3861 }
3862 auto NewEdge = std::make_shared<ContextEdge>(
3863 NewCaller, OldCallerCaller, computeAllocType(EdgeContextIdsToMove),
3864 EdgeContextIdsToMove);
3865 NewCaller->CallerEdges.push_back(NewEdge);
3866 NewEdge->Caller->CalleeEdges.push_back(NewEdge);
3867 }
3868 }
3869 // Recompute the node alloc type now that its caller edges have been
3870 // updated (since we will compute from those edges).
3871 OldCaller->AllocTypes = OldCaller->computeAllocType();
3872 // OldCaller alloc type should be None iff its context id set is now empty.
3873 assert((OldCaller->AllocTypes == (uint8_t)AllocationType::None) ==
3874 OldCaller->emptyContextIds());
3875 if (VerifyCCG) {
3876 checkNode<DerivedCCG, FuncTy, CallTy>(OldCaller, /*CheckEdges=*/false);
3877 checkNode<DerivedCCG, FuncTy, CallTy>(NewCaller, /*CheckEdges=*/false);
3878 for (const auto &OldCallerEdge : OldCaller->CallerEdges)
3879 checkNode<DerivedCCG, FuncTy, CallTy>(OldCallerEdge->Caller,
3880 /*CheckEdges=*/false);
3881 for (const auto &NewCallerEdge : NewCaller->CallerEdges)
3882 checkNode<DerivedCCG, FuncTy, CallTy>(NewCallerEdge->Caller,
3883 /*CheckEdges=*/false);
3884 }
3885}
3886
3887template <typename DerivedCCG, typename FuncTy, typename CallTy>
3888void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::
3889 recursivelyRemoveNoneTypeCalleeEdges(
3890 ContextNode *Node, DenseSet<const ContextNode *> &Visited) {
3891 auto Inserted = Visited.insert(Node);
3892 if (!Inserted.second)
3893 return;
3894
3895 removeNoneTypeCalleeEdges(Node);
3896
3897 for (auto *Clone : Node->Clones)
3898 recursivelyRemoveNoneTypeCalleeEdges(Clone, Visited);
3899
3900 // The recursive call may remove some of this Node's caller edges.
3901 // Iterate over a copy and skip any that were removed.
3902 auto CallerEdges = Node->CallerEdges;
3903 for (auto &Edge : CallerEdges) {
3904 // Skip any that have been removed by an earlier recursive call.
3905 if (Edge->isRemoved()) {
3906 assert(!is_contained(Node->CallerEdges, Edge));
3907 continue;
3908 }
3909 recursivelyRemoveNoneTypeCalleeEdges(Edge->Caller, Visited);
3910 }
3911}
3912
3913// This is the standard DFS based backedge discovery algorithm.
3914template <typename DerivedCCG, typename FuncTy, typename CallTy>
3915void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::markBackedges() {
3916 // If we are cloning recursive contexts, find and mark backedges from all root
3917 // callers, using the typical DFS based backedge analysis.
3919 return;
3920 DenseSet<const ContextNode *> Visited;
3921 DenseSet<const ContextNode *> CurrentStack;
3922 for (auto &Entry : NonAllocationCallToContextNodeMap) {
3923 auto *Node = Entry.second;
3924 if (Node->isRemoved())
3925 continue;
3926 // It is a root if it doesn't have callers.
3927 if (!Node->CallerEdges.empty())
3928 continue;
3929 markBackedges(Node, Visited, CurrentStack);
3930 assert(CurrentStack.empty());
3931 }
3932}
3933
3934// Recursive helper for above markBackedges method.
3935template <typename DerivedCCG, typename FuncTy, typename CallTy>
3936void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::markBackedges(
3937 ContextNode *Node, DenseSet<const ContextNode *> &Visited,
3938 DenseSet<const ContextNode *> &CurrentStack) {
3939 auto I = Visited.insert(Node);
3940 // We should only call this for unvisited nodes.
3941 assert(I.second);
3942 (void)I;
3943 for (auto &CalleeEdge : Node->CalleeEdges) {
3944 auto *Callee = CalleeEdge->Callee;
3945 if (Visited.count(Callee)) {
3946 // Since this was already visited we need to check if it is currently on
3947 // the recursive stack in which case it is a backedge.
3948 if (CurrentStack.count(Callee))
3949 CalleeEdge->IsBackedge = true;
3950 continue;
3951 }
3952 CurrentStack.insert(Callee);
3953 markBackedges(Callee, Visited, CurrentStack);
3954 CurrentStack.erase(Callee);
3955 }
3956}
3957
3958template <typename DerivedCCG, typename FuncTy, typename CallTy>
3959void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::identifyClones() {
3960 DenseSet<const ContextNode *> Visited;
3961 for (auto &Entry : AllocationCallToContextNodeMap) {
3962 Visited.clear();
3963 identifyClones(Entry.second, Visited, Entry.second->getContextIds());
3964 }
3965 Visited.clear();
3966 for (auto &Entry : AllocationCallToContextNodeMap)
3967 recursivelyRemoveNoneTypeCalleeEdges(Entry.second, Visited);
3968 if (VerifyCCG)
3969 check();
3970}
3971
3972// helper function to check an AllocType is cold or notcold or both.
3979
3980template <typename DerivedCCG, typename FuncTy, typename CallTy>
3981void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::identifyClones(
3982 ContextNode *Node, DenseSet<const ContextNode *> &Visited,
3983 const DenseSet<uint32_t> &AllocContextIds) {
3984 if (VerifyNodes)
3985 checkNode<DerivedCCG, FuncTy, CallTy>(Node, /*CheckEdges=*/false);
3986 assert(!Node->CloneOf);
3987
3988 // If Node as a null call, then either it wasn't found in the module (regular
3989 // LTO) or summary index (ThinLTO), or there were other conditions blocking
3990 // cloning (e.g. recursion, calls multiple targets, etc).
3991 // Do this here so that we don't try to recursively clone callers below, which
3992 // isn't useful at least for this node.
3993 if (!Node->hasCall())
3994 return;
3995
3996 // No need to look at any callers if allocation type already unambiguous.
3997 if (hasSingleAllocType(Node->AllocTypes))
3998 return;
3999
4000#ifndef NDEBUG
4001 auto Insert =
4002#endif
4003 Visited.insert(Node);
4004 // We should not have visited this node yet.
4005 assert(Insert.second);
4006 // The recursive call to identifyClones may delete the current edge from the
4007 // CallerEdges vector. Make a copy and iterate on that, simpler than passing
4008 // in an iterator and having recursive call erase from it. Other edges may
4009 // also get removed during the recursion, which will have null Callee and
4010 // Caller pointers (and are deleted later), so we skip those below.
4011 {
4012 auto CallerEdges = Node->CallerEdges;
4013 for (auto &Edge : CallerEdges) {
4014 // Skip any that have been removed by an earlier recursive call.
4015 if (Edge->isRemoved()) {
4016 assert(!is_contained(Node->CallerEdges, Edge));
4017 continue;
4018 }
4019 // Defer backedges. See comments further below where these edges are
4020 // handled during the cloning of this Node.
4021 if (Edge->IsBackedge) {
4022 // We should only mark these if cloning recursive contexts, where we
4023 // need to do this deferral.
4025 continue;
4026 }
4027 // Ignore any caller we previously visited via another edge.
4028 if (!Visited.count(Edge->Caller) && !Edge->Caller->CloneOf) {
4029 identifyClones(Edge->Caller, Visited, AllocContextIds);
4030 }
4031 }
4032 }
4033
4034 // Check if we reached an unambiguous call or have have only a single caller.
4035 if (hasSingleAllocType(Node->AllocTypes) || Node->CallerEdges.size() <= 1)
4036 return;
4037
4038 // We need to clone.
4039
4040 // Try to keep the original version as alloc type NotCold. This will make
4041 // cases with indirect calls or any other situation with an unknown call to
4042 // the original function get the default behavior. We do this by sorting the
4043 // CallerEdges of the Node we will clone by alloc type.
4044 //
4045 // Give NotCold edge the lowest sort priority so those edges are at the end of
4046 // the caller edges vector, and stay on the original version (since the below
4047 // code clones greedily until it finds all remaining edges have the same type
4048 // and leaves the remaining ones on the original Node).
4049 //
4050 // We shouldn't actually have any None type edges, so the sorting priority for
4051 // that is arbitrary, and we assert in that case below.
4052 const unsigned AllocTypeCloningPriority[] = {/*None*/ 3, /*NotCold*/ 4,
4053 /*Cold*/ 1,
4054 /*NotColdCold*/ 2};
4055 llvm::stable_sort(Node->CallerEdges,
4056 [&](const std::shared_ptr<ContextEdge> &A,
4057 const std::shared_ptr<ContextEdge> &B) {
4058 // Nodes with non-empty context ids should be sorted
4059 // before those with empty context ids.
4060 if (A->ContextIds.empty())
4061 // Either B ContextIds are non-empty (in which case we
4062 // should return false because B < A), or B ContextIds
4063 // are empty, in which case they are equal, and we
4064 // should maintain the original relative ordering.
4065 return false;
4066 if (B->ContextIds.empty())
4067 return true;
4068
4069 if (A->AllocTypes == B->AllocTypes)
4070 // Use the first context id for each edge as a
4071 // tie-breaker.
4072 return *A->ContextIds.begin() < *B->ContextIds.begin();
4073 return AllocTypeCloningPriority[A->AllocTypes] <
4074 AllocTypeCloningPriority[B->AllocTypes];
4075 });
4076
4077 assert(Node->AllocTypes != (uint8_t)AllocationType::None);
4078
4079 DenseSet<uint32_t> RecursiveContextIds;
4081 // If we are allowing recursive callsites, but have also disabled recursive
4082 // contexts, look for context ids that show up in multiple caller edges.
4084 DenseSet<uint32_t> AllCallerContextIds;
4085 for (auto &CE : Node->CallerEdges) {
4086 // Resize to the largest set of caller context ids, since we know the
4087 // final set will be at least that large.
4088 AllCallerContextIds.reserve(CE->getContextIds().size());
4089 for (auto Id : CE->getContextIds())
4090 if (!AllCallerContextIds.insert(Id).second)
4091 RecursiveContextIds.insert(Id);
4092 }
4093 }
4094
4095 // Iterate until we find no more opportunities for disambiguating the alloc
4096 // types via cloning. In most cases this loop will terminate once the Node
4097 // has a single allocation type, in which case no more cloning is needed.
4098 // Iterate over a copy of Node's caller edges, since we may need to remove
4099 // edges in the moveEdgeTo* methods, and this simplifies the handling and
4100 // makes it less error-prone.
4101 auto CallerEdges = Node->CallerEdges;
4102 for (auto &CallerEdge : CallerEdges) {
4103 // Skip any that have been removed by an earlier recursive call.
4104 if (CallerEdge->isRemoved()) {
4105 assert(!is_contained(Node->CallerEdges, CallerEdge));
4106 continue;
4107 }
4108 assert(CallerEdge->Callee == Node);
4109
4110 // See if cloning the prior caller edge left this node with a single alloc
4111 // type or a single caller. In that case no more cloning of Node is needed.
4112 if (hasSingleAllocType(Node->AllocTypes) || Node->CallerEdges.size() <= 1)
4113 break;
4114
4115 // If the caller was not successfully matched to a call in the IR/summary,
4116 // there is no point in trying to clone for it as we can't update that call.
4117 if (!CallerEdge->Caller->hasCall())
4118 continue;
4119
4120 // Only need to process the ids along this edge pertaining to the given
4121 // allocation.
4122 auto CallerEdgeContextsForAlloc =
4123 set_intersection(CallerEdge->getContextIds(), AllocContextIds);
4124 if (!RecursiveContextIds.empty())
4125 CallerEdgeContextsForAlloc =
4126 set_difference(CallerEdgeContextsForAlloc, RecursiveContextIds);
4127 if (CallerEdgeContextsForAlloc.empty())
4128 continue;
4129
4130 auto CallerAllocTypeForAlloc = computeAllocType(CallerEdgeContextsForAlloc);
4131
4132 // Compute the node callee edge alloc types corresponding to the context ids
4133 // for this caller edge.
4134 std::vector<uint8_t> CalleeEdgeAllocTypesForCallerEdge;
4135 CalleeEdgeAllocTypesForCallerEdge.reserve(Node->CalleeEdges.size());
4136 for (auto &CalleeEdge : Node->CalleeEdges)
4137 CalleeEdgeAllocTypesForCallerEdge.push_back(intersectAllocTypes(
4138 CalleeEdge->getContextIds(), CallerEdgeContextsForAlloc));
4139
4140 // Don't clone if doing so will not disambiguate any alloc types amongst
4141 // caller edges (including the callee edges that would be cloned).
4142 // Otherwise we will simply move all edges to the clone.
4143 //
4144 // First check if by cloning we will disambiguate the caller allocation
4145 // type from node's allocation type. Query allocTypeToUse so that we don't
4146 // bother cloning to distinguish NotCold+Cold from NotCold. Note that
4147 // neither of these should be None type.
4148 //
4149 // Then check if by cloning node at least one of the callee edges will be
4150 // disambiguated by splitting out different context ids.
4151 //
4152 // However, always do the cloning if this is a backedge, in which case we
4153 // have not yet cloned along this caller edge.
4154 assert(CallerEdge->AllocTypes != (uint8_t)AllocationType::None);
4155 assert(Node->AllocTypes != (uint8_t)AllocationType::None);
4156 if (!CallerEdge->IsBackedge &&
4157 allocTypeToUse(CallerAllocTypeForAlloc) ==
4158 allocTypeToUse(Node->AllocTypes) &&
4159 allocTypesMatch<DerivedCCG, FuncTy, CallTy>(
4160 CalleeEdgeAllocTypesForCallerEdge, Node->CalleeEdges)) {
4161 continue;
4162 }
4163
4164 if (CallerEdge->IsBackedge) {
4165 // We should only mark these if cloning recursive contexts, where we
4166 // need to do this deferral.
4168 DeferredBackedges++;
4169 }
4170
4171 // If this is a backedge, we now do recursive cloning starting from its
4172 // caller since we may have moved unambiguous caller contexts to a clone
4173 // of this Node in a previous iteration of the current loop, giving more
4174 // opportunity for cloning through the backedge. Because we sorted the
4175 // caller edges earlier so that cold caller edges are first, we would have
4176 // visited and cloned this node for any unamibiguously cold non-recursive
4177 // callers before any ambiguous backedge callers. Note that we don't do this
4178 // if the caller is already cloned or visited during cloning (e.g. via a
4179 // different context path from the allocation).
4180 // TODO: Can we do better in the case where the caller was already visited?
4181 if (CallerEdge->IsBackedge && !CallerEdge->Caller->CloneOf &&
4182 !Visited.count(CallerEdge->Caller)) {
4183 const auto OrigIdCount = CallerEdge->getContextIds().size();
4184 // Now do the recursive cloning of this backedge's caller, which was
4185 // deferred earlier.
4186 identifyClones(CallerEdge->Caller, Visited, CallerEdgeContextsForAlloc);
4187 removeNoneTypeCalleeEdges(CallerEdge->Caller);
4188 // See if the recursive call to identifyClones moved the context ids to a
4189 // new edge from this node to a clone of caller, and switch to looking at
4190 // that new edge so that we clone Node for the new caller clone.
4191 bool UpdatedEdge = false;
4192 if (OrigIdCount > CallerEdge->getContextIds().size()) {
4193 for (auto E : Node->CallerEdges) {
4194 // Only interested in clones of the current edges caller.
4195 if (E->Caller->CloneOf != CallerEdge->Caller)
4196 continue;
4197 // See if this edge contains any of the context ids originally on the
4198 // current caller edge.
4199 auto CallerEdgeContextsForAllocNew =
4200 set_intersection(CallerEdgeContextsForAlloc, E->getContextIds());
4201 if (CallerEdgeContextsForAllocNew.empty())
4202 continue;
4203 // Make sure we don't pick a previously existing caller edge of this
4204 // Node, which would be processed on a different iteration of the
4205 // outer loop over the saved CallerEdges.
4206 if (llvm::is_contained(CallerEdges, E))
4207 continue;
4208 // The CallerAllocTypeForAlloc and CalleeEdgeAllocTypesForCallerEdge
4209 // are updated further below for all cases where we just invoked
4210 // identifyClones recursively.
4211 CallerEdgeContextsForAlloc.swap(CallerEdgeContextsForAllocNew);
4212 CallerEdge = E;
4213 UpdatedEdge = true;
4214 break;
4215 }
4216 }
4217 // If cloning removed this edge (and we didn't update it to a new edge
4218 // above), we're done with this edge. It's possible we moved all of the
4219 // context ids to an existing clone, in which case there's no need to do
4220 // further processing for them.
4221 if (CallerEdge->isRemoved())
4222 continue;
4223
4224 // Now we need to update the information used for the cloning decisions
4225 // further below, as we may have modified edges and their context ids.
4226
4227 // Note if we changed the CallerEdge above we would have already updated
4228 // the context ids.
4229 if (!UpdatedEdge) {
4230 CallerEdgeContextsForAlloc = set_intersection(
4231 CallerEdgeContextsForAlloc, CallerEdge->getContextIds());
4232 if (CallerEdgeContextsForAlloc.empty())
4233 continue;
4234 }
4235 // Update the other information that depends on the edges and on the now
4236 // updated CallerEdgeContextsForAlloc.
4237 CallerAllocTypeForAlloc = computeAllocType(CallerEdgeContextsForAlloc);
4238 CalleeEdgeAllocTypesForCallerEdge.clear();
4239 for (auto &CalleeEdge : Node->CalleeEdges) {
4240 CalleeEdgeAllocTypesForCallerEdge.push_back(intersectAllocTypes(
4241 CalleeEdge->getContextIds(), CallerEdgeContextsForAlloc));
4242 }
4243 }
4244
4245 // First see if we can use an existing clone. Check each clone and its
4246 // callee edges for matching alloc types.
4247 ContextNode *Clone = nullptr;
4248 for (auto *CurClone : Node->Clones) {
4249 if (allocTypeToUse(CurClone->AllocTypes) !=
4250 allocTypeToUse(CallerAllocTypeForAlloc))
4251 continue;
4252
4253 bool BothSingleAlloc = hasSingleAllocType(CurClone->AllocTypes) &&
4254 hasSingleAllocType(CallerAllocTypeForAlloc);
4255 // The above check should mean that if both have single alloc types that
4256 // they should be equal.
4257 assert(!BothSingleAlloc ||
4258 CurClone->AllocTypes == CallerAllocTypeForAlloc);
4259
4260 // If either both have a single alloc type (which are the same), or if the
4261 // clone's callee edges have the same alloc types as those for the current
4262 // allocation on Node's callee edges (CalleeEdgeAllocTypesForCallerEdge),
4263 // then we can reuse this clone.
4264 if (BothSingleAlloc || allocTypesMatchClone<DerivedCCG, FuncTy, CallTy>(
4265 CalleeEdgeAllocTypesForCallerEdge, CurClone)) {
4266 Clone = CurClone;
4267 break;
4268 }
4269 }
4270
4271 // The edge iterator is adjusted when we move the CallerEdge to the clone.
4272 if (Clone)
4273 moveEdgeToExistingCalleeClone(CallerEdge, Clone, /*NewClone=*/false,
4274 CallerEdgeContextsForAlloc);
4275 else
4276 Clone = moveEdgeToNewCalleeClone(CallerEdge, CallerEdgeContextsForAlloc);
4277
4278 // Sanity check that no alloc types on clone or its edges are None.
4279 assert(Clone->AllocTypes != (uint8_t)AllocationType::None);
4280 }
4281
4282 // We should still have some context ids on the original Node.
4283 assert(!Node->emptyContextIds());
4284
4285 // Sanity check that no alloc types on node or edges are None.
4286 assert(Node->AllocTypes != (uint8_t)AllocationType::None);
4287
4288 if (VerifyNodes)
4289 checkNode<DerivedCCG, FuncTy, CallTy>(Node, /*CheckEdges=*/false);
4290}
4291
4292void ModuleCallsiteContextGraph::updateAllocationCall(
4293 CallInfo &Call, AllocationType AllocType) {
4294 std::string AllocTypeString = getAllocTypeAttributeString(AllocType);
4296 auto A = llvm::Attribute::get(Call.call()->getFunction()->getContext(),
4297 "memprof", AllocTypeString);
4298 cast<CallBase>(Call.call())->addFnAttr(A);
4299 OREGetter(Call.call()->getFunction())
4300 .emit(OptimizationRemark(DEBUG_TYPE, "MemprofAttribute", Call.call())
4301 << ore::NV("AllocationCall", Call.call()) << " in clone "
4302 << ore::NV("Caller", Call.call()->getFunction())
4303 << " marked with memprof allocation attribute "
4304 << ore::NV("Attribute", AllocTypeString));
4305}
4306
4307void IndexCallsiteContextGraph::updateAllocationCall(CallInfo &Call,
4309 auto *AI = cast<AllocInfo *>(Call.call());
4310 assert(AI);
4311 assert(AI->Versions.size() > Call.cloneNo());
4312 AI->Versions[Call.cloneNo()] = (uint8_t)AllocType;
4313}
4314
4316ModuleCallsiteContextGraph::getAllocationCallType(const CallInfo &Call) const {
4317 const auto *CB = cast<CallBase>(Call.call());
4318 if (!CB->getAttributes().hasFnAttr("memprof"))
4319 return AllocationType::None;
4320 return CB->getAttributes().getFnAttr("memprof").getValueAsString() == "cold"
4321 ? AllocationType::Cold
4322 : AllocationType::NotCold;
4323}
4324
4326IndexCallsiteContextGraph::getAllocationCallType(const CallInfo &Call) const {
4327 const auto *AI = cast<AllocInfo *>(Call.call());
4328 assert(AI->Versions.size() > Call.cloneNo());
4329 return (AllocationType)AI->Versions[Call.cloneNo()];
4330}
4331
4332void ModuleCallsiteContextGraph::updateCall(CallInfo &CallerCall,
4333 FuncInfo CalleeFunc) {
4334 auto *CurF = getCalleeFunc(CallerCall.call());
4335 auto NewCalleeCloneNo = CalleeFunc.cloneNo();
4336 if (isMemProfClone(*CurF)) {
4337 // If we already assigned this callsite to call a specific non-default
4338 // clone (i.e. not the original function which is clone 0), ensure that we
4339 // aren't trying to now update it to call a different clone, which is
4340 // indicative of a bug in the graph or function assignment.
4341 auto CurCalleeCloneNo = getMemProfCloneNum(*CurF);
4342 if (CurCalleeCloneNo != NewCalleeCloneNo) {
4343 LLVM_DEBUG(dbgs() << "Mismatch in call clone assignment: was "
4344 << CurCalleeCloneNo << " now " << NewCalleeCloneNo
4345 << "\n");
4346 MismatchedCloneAssignments++;
4347 }
4348 }
4349 if (NewCalleeCloneNo > 0)
4350 cast<CallBase>(CallerCall.call())->setCalledFunction(CalleeFunc.func());
4351 OREGetter(CallerCall.call()->getFunction())
4352 .emit(OptimizationRemark(DEBUG_TYPE, "MemprofCall", CallerCall.call())
4353 << ore::NV("Call", CallerCall.call()) << " in clone "
4354 << ore::NV("Caller", CallerCall.call()->getFunction())
4355 << " assigned to call function clone "
4356 << ore::NV("Callee", CalleeFunc.func()));
4357}
4358
4359void IndexCallsiteContextGraph::updateCall(CallInfo &CallerCall,
4360 FuncInfo CalleeFunc) {
4361 auto *CI = cast<CallsiteInfo *>(CallerCall.call());
4362 assert(CI &&
4363 "Caller cannot be an allocation which should not have profiled calls");
4364 assert(CI->Clones.size() > CallerCall.cloneNo());
4365 auto NewCalleeCloneNo = CalleeFunc.cloneNo();
4366 auto &CurCalleeCloneNo = CI->Clones[CallerCall.cloneNo()];
4367 // If we already assigned this callsite to call a specific non-default
4368 // clone (i.e. not the original function which is clone 0), ensure that we
4369 // aren't trying to now update it to call a different clone, which is
4370 // indicative of a bug in the graph or function assignment.
4371 if (CurCalleeCloneNo != 0 && CurCalleeCloneNo != NewCalleeCloneNo) {
4372 LLVM_DEBUG(dbgs() << "Mismatch in call clone assignment: was "
4373 << CurCalleeCloneNo << " now " << NewCalleeCloneNo
4374 << "\n");
4375 MismatchedCloneAssignments++;
4376 }
4377 CurCalleeCloneNo = NewCalleeCloneNo;
4378}
4379
4380// Update the debug information attached to NewFunc to use the clone Name. Note
4381// this needs to be done for both any existing DISubprogram for the definition,
4382// as well as any separate declaration DISubprogram.
4384 assert(Name == NewFunc->getName());
4385 auto *SP = NewFunc->getSubprogram();
4386 if (!SP)
4387 return;
4388 auto *MDName = MDString::get(NewFunc->getParent()->getContext(), Name);
4389 SP->replaceLinkageName(MDName);
4390 DISubprogram *Decl = SP->getDeclaration();
4391 if (!Decl)
4392 return;
4393 TempDISubprogram NewDecl = Decl->clone();
4394 NewDecl->replaceLinkageName(MDName);
4395 SP->replaceDeclaration(MDNode::replaceWithUniqued(std::move(NewDecl)));
4396}
4397
4398CallsiteContextGraph<ModuleCallsiteContextGraph, Function,
4399 Instruction *>::FuncInfo
4400ModuleCallsiteContextGraph::cloneFunctionForCallsite(
4401 FuncInfo &Func, CallInfo &Call, DenseMap<CallInfo, CallInfo> &CallMap,
4402 std::vector<CallInfo> &CallsWithMetadataInFunc, unsigned CloneNo) {
4403 // Use existing LLVM facilities for cloning and obtaining Call in clone
4404 ValueToValueMapTy VMap;
4405 auto *NewFunc = CloneFunction(Func.func(), VMap);
4406 std::string Name = getMemProfFuncName(Func.func()->getName(), CloneNo);
4407 assert(!Func.func()->getParent()->getFunction(Name));
4408 NewFunc->setName(Name);
4409 updateSubprogramLinkageName(NewFunc, Name);
4410 for (auto &Inst : CallsWithMetadataInFunc) {
4411 // This map always has the initial version in it.
4412 assert(Inst.cloneNo() == 0);
4413 CallMap[Inst] = {cast<Instruction>(VMap[Inst.call()]), CloneNo};
4414 }
4415 OREGetter(Func.func())
4416 .emit(OptimizationRemark(DEBUG_TYPE, "MemprofClone", Func.func())
4417 << "created clone " << ore::NV("NewFunction", NewFunc));
4418 return {NewFunc, CloneNo};
4419}
4420
4421CallsiteContextGraph<IndexCallsiteContextGraph, FunctionSummary,
4422 IndexCall>::FuncInfo
4423IndexCallsiteContextGraph::cloneFunctionForCallsite(
4424 FuncInfo &Func, CallInfo &Call, DenseMap<CallInfo, CallInfo> &CallMap,
4425 std::vector<CallInfo> &CallsWithMetadataInFunc, unsigned CloneNo) {
4426 // Check how many clones we have of Call (and therefore function).
4427 // The next clone number is the current size of versions array.
4428 // Confirm this matches the CloneNo provided by the caller, which is based on
4429 // the number of function clones we have.
4430 assert(CloneNo == (isa<AllocInfo *>(Call.call())
4431 ? cast<AllocInfo *>(Call.call())->Versions.size()
4432 : cast<CallsiteInfo *>(Call.call())->Clones.size()));
4433 // Walk all the instructions in this function. Create a new version for
4434 // each (by adding an entry to the Versions/Clones summary array), and copy
4435 // over the version being called for the function clone being cloned here.
4436 // Additionally, add an entry to the CallMap for the new function clone,
4437 // mapping the original call (clone 0, what is in CallsWithMetadataInFunc)
4438 // to the new call clone.
4439 for (auto &Inst : CallsWithMetadataInFunc) {
4440 // This map always has the initial version in it.
4441 assert(Inst.cloneNo() == 0);
4442 if (auto *AI = dyn_cast<AllocInfo *>(Inst.call())) {
4443 assert(AI->Versions.size() == CloneNo);
4444 // We assign the allocation type later (in updateAllocationCall), just add
4445 // an entry for it here.
4446 AI->Versions.push_back(0);
4447 } else {
4448 auto *CI = cast<CallsiteInfo *>(Inst.call());
4449 assert(CI && CI->Clones.size() == CloneNo);
4450 // We assign the clone number later (in updateCall), just add an entry for
4451 // it here.
4452 CI->Clones.push_back(0);
4453 }
4454 CallMap[Inst] = {Inst.call(), CloneNo};
4455 }
4456 return {Func.func(), CloneNo};
4457}
4458
4459// We perform cloning for each allocation node separately. However, this
4460// sometimes results in a situation where the same node calls multiple
4461// clones of the same callee, created for different allocations. This
4462// causes issues when assigning functions to these clones, as each node can
4463// in reality only call a single callee clone.
4464//
4465// To address this, before assigning functions, merge callee clone nodes as
4466// needed using a post order traversal from the allocations. We attempt to
4467// use existing clones as the merge node when legal, and to share them
4468// among callers with the same properties (callers calling the same set of
4469// callee clone nodes for the same allocations).
4470//
4471// Without this fix, in some cases incorrect function assignment will lead
4472// to calling the wrong allocation clone.
4473template <typename DerivedCCG, typename FuncTy, typename CallTy>
4474void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::mergeClones() {
4475 if (!MergeClones)
4476 return;
4477
4478 // Generate a map from context id to the associated allocation node for use
4479 // when merging clones.
4480 DenseMap<uint32_t, ContextNode *> ContextIdToAllocationNode;
4481 for (auto &Entry : AllocationCallToContextNodeMap) {
4482 auto *Node = Entry.second;
4483 for (auto Id : Node->getContextIds())
4484 ContextIdToAllocationNode[Id] = Node->getOrigNode();
4485 for (auto *Clone : Node->Clones) {
4486 for (auto Id : Clone->getContextIds())
4487 ContextIdToAllocationNode[Id] = Clone->getOrigNode();
4488 }
4489 }
4490
4491 // Post order traversal starting from allocations to ensure each callsite
4492 // calls a single clone of its callee. Callee nodes that are clones of each
4493 // other are merged (via new merge nodes if needed) to achieve this.
4494 DenseSet<const ContextNode *> Visited;
4495 for (auto &Entry : AllocationCallToContextNodeMap) {
4496 auto *Node = Entry.second;
4497
4498 mergeClones(Node, Visited, ContextIdToAllocationNode);
4499
4500 // Make a copy so the recursive post order traversal that may create new
4501 // clones doesn't mess up iteration. Note that the recursive traversal
4502 // itself does not call mergeClones on any of these nodes, which are all
4503 // (clones of) allocations.
4504 auto Clones = Node->Clones;
4505 for (auto *Clone : Clones)
4506 mergeClones(Clone, Visited, ContextIdToAllocationNode);
4507 }
4508
4509 if (DumpCCG) {
4510 dbgs() << "CCG after merging:\n";
4511 dbgs() << *this;
4512 }
4513 if (ExportToDot)
4514 exportToDot("aftermerge");
4515
4516 if (VerifyCCG) {
4517 check();
4518 }
4519}
4520
4521// Recursive helper for above mergeClones method.
4522template <typename DerivedCCG, typename FuncTy, typename CallTy>
4523void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::mergeClones(
4524 ContextNode *Node, DenseSet<const ContextNode *> &Visited,
4525 DenseMap<uint32_t, ContextNode *> &ContextIdToAllocationNode) {
4526 auto Inserted = Visited.insert(Node);
4527 if (!Inserted.second)
4528 return;
4529
4530 // Iteratively perform merging on this node to handle new caller nodes created
4531 // during the recursive traversal. We could do something more elegant such as
4532 // maintain a worklist, but this is a simple approach that doesn't cause a
4533 // measureable compile time effect, as most nodes don't have many caller
4534 // edges to check.
4535 bool FoundUnvisited = true;
4536 unsigned Iters = 0;
4537 while (FoundUnvisited) {
4538 Iters++;
4539 FoundUnvisited = false;
4540 // Make a copy since the recursive call may move a caller edge to a new
4541 // callee, messing up the iterator.
4542 auto CallerEdges = Node->CallerEdges;
4543 for (auto CallerEdge : CallerEdges) {
4544 // Skip any caller edge moved onto a different callee during recursion.
4545 if (CallerEdge->Callee != Node)
4546 continue;
4547 // If we found an unvisited caller, note that we should check the caller
4548 // edges again as mergeClones may add or change caller nodes.
4549 if (DoMergeIteration && !Visited.contains(CallerEdge->Caller))
4550 FoundUnvisited = true;
4551 mergeClones(CallerEdge->Caller, Visited, ContextIdToAllocationNode);
4552 }
4553 }
4554
4555 TotalMergeInvokes++;
4556 TotalMergeIters += Iters;
4557 if (Iters > MaxMergeIters)
4558 MaxMergeIters = Iters;
4559
4560 // Merge for this node after we handle its callers.
4561 mergeNodeCalleeClones(Node, Visited, ContextIdToAllocationNode);
4562}
4563
4564template <typename DerivedCCG, typename FuncTy, typename CallTy>
4565void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::mergeNodeCalleeClones(
4566 ContextNode *Node, DenseSet<const ContextNode *> &Visited,
4567 DenseMap<uint32_t, ContextNode *> &ContextIdToAllocationNode) {
4568 // Ignore Node if we moved all of its contexts to clones.
4569 if (Node->emptyContextIds())
4570 return;
4571
4572 // First identify groups of clones among Node's callee edges, by building
4573 // a map from each callee base node to the associated callee edges from Node.
4574 MapVector<ContextNode *, std::vector<std::shared_ptr<ContextEdge>>>
4575 OrigNodeToCloneEdges;
4576 for (const auto &E : Node->CalleeEdges) {
4577 auto *Callee = E->Callee;
4578 if (!Callee->CloneOf && Callee->Clones.empty())
4579 continue;
4580 ContextNode *Base = Callee->getOrigNode();
4581 OrigNodeToCloneEdges[Base].push_back(E);
4582 }
4583
4584 // Helper for callee edge sorting below. Return true if A's callee has fewer
4585 // caller edges than B, or if A is a clone and B is not, or if A's first
4586 // context id is smaller than B's.
4587 auto CalleeCallerEdgeLessThan = [](const std::shared_ptr<ContextEdge> &A,
4588 const std::shared_ptr<ContextEdge> &B) {
4589 if (A->Callee->CallerEdges.size() != B->Callee->CallerEdges.size())
4590 return A->Callee->CallerEdges.size() < B->Callee->CallerEdges.size();
4591 if (A->Callee->CloneOf && !B->Callee->CloneOf)
4592 return true;
4593 else if (!A->Callee->CloneOf && B->Callee->CloneOf)
4594 return false;
4595 // Use the first context id for each edge as a
4596 // tie-breaker.
4597 return *A->ContextIds.begin() < *B->ContextIds.begin();
4598 };
4599
4600 // Process each set of callee clones called by Node, performing the needed
4601 // merging.
4602 for (auto Entry : OrigNodeToCloneEdges) {
4603 // CalleeEdges is the set of edges from Node reaching callees that are
4604 // mutual clones of each other.
4605 auto &CalleeEdges = Entry.second;
4606 auto NumCalleeClones = CalleeEdges.size();
4607 // A single edge means there is no merging needed.
4608 if (NumCalleeClones == 1)
4609 continue;
4610 // Sort the CalleeEdges calling this group of clones in ascending order of
4611 // their caller edge counts, putting the original non-clone node first in
4612 // cases of a tie. This simplifies finding an existing node to use as the
4613 // merge node.
4614 llvm::stable_sort(CalleeEdges, CalleeCallerEdgeLessThan);
4615
4616 /// Find other callers of the given set of callee edges that can
4617 /// share the same callee merge node. See the comments at this method
4618 /// definition for details.
4619 DenseSet<ContextNode *> OtherCallersToShareMerge;
4620 findOtherCallersToShareMerge(Node, CalleeEdges, ContextIdToAllocationNode,
4621 OtherCallersToShareMerge);
4622
4623 // Now do the actual merging. Identify existing or create a new MergeNode
4624 // during the first iteration. Move each callee over, along with edges from
4625 // other callers we've determined above can share the same merge node.
4626 ContextNode *MergeNode = nullptr;
4627 DenseMap<ContextNode *, unsigned> CallerToMoveCount;
4628 for (auto CalleeEdge : CalleeEdges) {
4629 auto *OrigCallee = CalleeEdge->Callee;
4630 // If we don't have a MergeNode yet (only happens on the first iteration,
4631 // as a new one will be created when we go to move the first callee edge
4632 // over as needed), see if we can use this callee.
4633 if (!MergeNode) {
4634 // If there are no other callers, simply use this callee.
4635 if (CalleeEdge->Callee->CallerEdges.size() == 1) {
4636 MergeNode = OrigCallee;
4637 NonNewMergedNodes++;
4638 continue;
4639 }
4640 // Otherwise, if we have identified other caller nodes that can share
4641 // the merge node with Node, see if all of OrigCallee's callers are
4642 // going to share the same merge node. In that case we can use callee
4643 // (since all of its callers would move to the new merge node).
4644 if (!OtherCallersToShareMerge.empty()) {
4645 bool MoveAllCallerEdges = true;
4646 for (auto CalleeCallerE : OrigCallee->CallerEdges) {
4647 if (CalleeCallerE == CalleeEdge)
4648 continue;
4649 if (!OtherCallersToShareMerge.contains(CalleeCallerE->Caller)) {
4650 MoveAllCallerEdges = false;
4651 break;
4652 }
4653 }
4654 // If we are going to move all callers over, we can use this callee as
4655 // the MergeNode.
4656 if (MoveAllCallerEdges) {
4657 MergeNode = OrigCallee;
4658 NonNewMergedNodes++;
4659 continue;
4660 }
4661 }
4662 }
4663 // Move this callee edge, creating a new merge node if necessary.
4664 if (MergeNode) {
4665 assert(MergeNode != OrigCallee);
4666 moveEdgeToExistingCalleeClone(CalleeEdge, MergeNode,
4667 /*NewClone*/ false);
4668 } else {
4669 MergeNode = moveEdgeToNewCalleeClone(CalleeEdge);
4670 NewMergedNodes++;
4671 }
4672 // Now move all identified edges from other callers over to the merge node
4673 // as well.
4674 if (!OtherCallersToShareMerge.empty()) {
4675 // Make and iterate over a copy of OrigCallee's caller edges because
4676 // some of these will be moved off of the OrigCallee and that would mess
4677 // up the iteration from OrigCallee.
4678 auto OrigCalleeCallerEdges = OrigCallee->CallerEdges;
4679 for (auto &CalleeCallerE : OrigCalleeCallerEdges) {
4680 if (CalleeCallerE == CalleeEdge)
4681 continue;
4682 if (!OtherCallersToShareMerge.contains(CalleeCallerE->Caller))
4683 continue;
4684 CallerToMoveCount[CalleeCallerE->Caller]++;
4685 moveEdgeToExistingCalleeClone(CalleeCallerE, MergeNode,
4686 /*NewClone*/ false);
4687 }
4688 }
4689 removeNoneTypeCalleeEdges(OrigCallee);
4690 removeNoneTypeCalleeEdges(MergeNode);
4691 }
4692 }
4693}
4694
4695// Look for other nodes that have edges to the same set of callee
4696// clones as the current Node. Those can share the eventual merge node
4697// (reducing cloning and binary size overhead) iff:
4698// - they have edges to the same set of callee clones
4699// - each callee edge reaches a subset of the same allocations as Node's
4700// corresponding edge to the same callee clone.
4701// The second requirement is to ensure that we don't undo any of the
4702// necessary cloning to distinguish contexts with different allocation
4703// behavior.
4704// FIXME: This is somewhat conservative, as we really just need to ensure
4705// that they don't reach the same allocations as contexts on edges from Node
4706// going to any of the *other* callee clones being merged. However, that
4707// requires more tracking and checking to get right.
4708template <typename DerivedCCG, typename FuncTy, typename CallTy>
4709void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::
4710 findOtherCallersToShareMerge(
4711 ContextNode *Node,
4712 std::vector<std::shared_ptr<ContextEdge>> &CalleeEdges,
4713 DenseMap<uint32_t, ContextNode *> &ContextIdToAllocationNode,
4714 DenseSet<ContextNode *> &OtherCallersToShareMerge) {
4715 auto NumCalleeClones = CalleeEdges.size();
4716 // This map counts how many edges to the same callee clone exist for other
4717 // caller nodes of each callee clone.
4718 DenseMap<ContextNode *, unsigned> OtherCallersToSharedCalleeEdgeCount;
4719 // Counts the number of other caller nodes that have edges to all callee
4720 // clones that don't violate the allocation context checking.
4721 unsigned PossibleOtherCallerNodes = 0;
4722
4723 // We only need to look at other Caller nodes if the first callee edge has
4724 // multiple callers (recall they are sorted in ascending order above).
4725 if (CalleeEdges[0]->Callee->CallerEdges.size() < 2)
4726 return;
4727
4728 // For each callee edge:
4729 // - Collect the count of other caller nodes calling the same callees.
4730 // - Collect the alloc nodes reached by contexts on each callee edge.
4731 DenseMap<ContextEdge *, DenseSet<ContextNode *>> CalleeEdgeToAllocNodes;
4732 for (auto CalleeEdge : CalleeEdges) {
4733 assert(CalleeEdge->Callee->CallerEdges.size() > 1);
4734 // For each other caller of the same callee, increment the count of
4735 // edges reaching the same callee clone.
4736 for (auto CalleeCallerEdges : CalleeEdge->Callee->CallerEdges) {
4737 if (CalleeCallerEdges->Caller == Node) {
4738 assert(CalleeCallerEdges == CalleeEdge);
4739 continue;
4740 }
4741 OtherCallersToSharedCalleeEdgeCount[CalleeCallerEdges->Caller]++;
4742 // If this caller edge now reaches all of the same callee clones,
4743 // increment the count of candidate other caller nodes.
4744 if (OtherCallersToSharedCalleeEdgeCount[CalleeCallerEdges->Caller] ==
4745 NumCalleeClones)
4746 PossibleOtherCallerNodes++;
4747 }
4748 // Collect the alloc nodes reached by contexts on each callee edge, for
4749 // later analysis.
4750 for (auto Id : CalleeEdge->getContextIds()) {
4751 auto *Alloc = ContextIdToAllocationNode.lookup(Id);
4752 if (!Alloc) {
4753 // FIXME: unclear why this happens occasionally, presumably
4754 // imperfect graph updates possibly with recursion.
4755 MissingAllocForContextId++;
4756 continue;
4757 }
4758 CalleeEdgeToAllocNodes[CalleeEdge.get()].insert(Alloc);
4759 }
4760 }
4761
4762 // Now walk the callee edges again, and make sure that for each candidate
4763 // caller node all of its edges to the callees reach the same allocs (or
4764 // a subset) as those along the corresponding callee edge from Node.
4765 for (auto CalleeEdge : CalleeEdges) {
4766 assert(CalleeEdge->Callee->CallerEdges.size() > 1);
4767 // Stop if we do not have any (more) candidate other caller nodes.
4768 if (!PossibleOtherCallerNodes)
4769 break;
4770 auto &CurCalleeAllocNodes = CalleeEdgeToAllocNodes[CalleeEdge.get()];
4771 // Check each other caller of this callee clone.
4772 for (auto &CalleeCallerE : CalleeEdge->Callee->CallerEdges) {
4773 // Not interested in the callee edge from Node itself.
4774 if (CalleeCallerE == CalleeEdge)
4775 continue;
4776 // Skip any callers that didn't have callee edges to all the same
4777 // callee clones.
4778 if (OtherCallersToSharedCalleeEdgeCount[CalleeCallerE->Caller] !=
4779 NumCalleeClones)
4780 continue;
4781 // Make sure that each context along edge from candidate caller node
4782 // reaches an allocation also reached by this callee edge from Node.
4783 for (auto Id : CalleeCallerE->getContextIds()) {
4784 auto *Alloc = ContextIdToAllocationNode.lookup(Id);
4785 if (!Alloc)
4786 continue;
4787 // If not, simply reset the map entry to 0 so caller is ignored, and
4788 // reduce the count of candidate other caller nodes.
4789 if (!CurCalleeAllocNodes.contains(Alloc)) {
4790 OtherCallersToSharedCalleeEdgeCount[CalleeCallerE->Caller] = 0;
4791 PossibleOtherCallerNodes--;
4792 break;
4793 }
4794 }
4795 }
4796 }
4797
4798 if (!PossibleOtherCallerNodes)
4799 return;
4800
4801 // Build the set of other caller nodes that can use the same callee merge
4802 // node.
4803 for (auto &[OtherCaller, Count] : OtherCallersToSharedCalleeEdgeCount) {
4804 if (Count != NumCalleeClones)
4805 continue;
4806 OtherCallersToShareMerge.insert(OtherCaller);
4807 }
4808}
4809
4810// This method assigns cloned callsites to functions, cloning the functions as
4811// needed. The assignment is greedy and proceeds roughly as follows:
4812//
4813// For each function Func:
4814// For each call with graph Node having clones:
4815// Initialize ClonesWorklist to Node and its clones
4816// Initialize NodeCloneCount to 0
4817// While ClonesWorklist is not empty:
4818// Clone = pop front ClonesWorklist
4819// NodeCloneCount++
4820// If Func has been cloned less than NodeCloneCount times:
4821// If NodeCloneCount is 1:
4822// Assign Clone to original Func
4823// Continue
4824// Create a new function clone
4825// If other callers not assigned to call a function clone yet:
4826// Assign them to call new function clone
4827// Continue
4828// Assign any other caller calling the cloned version to new clone
4829//
4830// For each caller of Clone:
4831// If caller is assigned to call a specific function clone:
4832// If we cannot assign Clone to that function clone:
4833// Create new callsite Clone NewClone
4834// Add NewClone to ClonesWorklist
4835// Continue
4836// Assign Clone to existing caller's called function clone
4837// Else:
4838// If Clone not already assigned to a function clone:
4839// Assign to first function clone without assignment
4840// Assign caller to selected function clone
4841// For each call with graph Node having clones:
4842// If number func clones > number call's callsite Node clones:
4843// Record func CallInfo clones without Node clone in UnassignedCallClones
4844// For callsite Nodes in DFS order from allocations:
4845// If IsAllocation:
4846// Update allocation with alloc type
4847// Else:
4848// For Call, all MatchingCalls, and associated UnnassignedCallClones:
4849// Update call to call recorded callee clone
4850//
4851template <typename DerivedCCG, typename FuncTy, typename CallTy>
4852bool CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::assignFunctions() {
4853 bool Changed = false;
4854
4855 mergeClones();
4856
4857 // Keep track of the assignment of nodes (callsites) to function clones they
4858 // call.
4859 DenseMap<ContextNode *, FuncInfo> CallsiteToCalleeFuncCloneMap;
4860
4861 // Update caller node to call function version CalleeFunc, by recording the
4862 // assignment in CallsiteToCalleeFuncCloneMap.
4863 auto RecordCalleeFuncOfCallsite = [&](ContextNode *Caller,
4864 const FuncInfo &CalleeFunc) {
4865 assert(Caller->hasCall());
4866 CallsiteToCalleeFuncCloneMap[Caller] = CalleeFunc;
4867 };
4868
4869 // Information for a single clone of this Func.
4870 struct FuncCloneInfo {
4871 // The function clone.
4872 FuncInfo FuncClone;
4873 // Remappings of each call of interest (from original uncloned call to the
4874 // corresponding cloned call in this function clone).
4875 DenseMap<CallInfo, CallInfo> CallMap;
4876 };
4877
4878 // Map to keep track of information needed to update calls in function clones
4879 // when their corresponding callsite node was not itself cloned for that
4880 // function clone. Because of call context pruning (i.e. we only keep as much
4881 // caller information as needed to distinguish hot vs cold), we may not have
4882 // caller edges coming to each callsite node from all possible function
4883 // callers. A function clone may get created for other callsites in the
4884 // function for which there are caller edges that were not pruned. Any other
4885 // callsites in that function clone, which were not themselved cloned for
4886 // that function clone, should get updated the same way as the corresponding
4887 // callsite in the original function (which may call a clone of its callee).
4888 //
4889 // We build this map after completing function cloning for each function, so
4890 // that we can record the information from its call maps before they are
4891 // destructed. The map will be used as we update calls to update any still
4892 // unassigned call clones. Note that we may create new node clones as we clone
4893 // other functions, so later on we check which node clones were still not
4894 // created. To this end, the inner map is a map from function clone number to
4895 // the list of calls cloned for that function (can be more than one due to the
4896 // Node's MatchingCalls array).
4897 //
4898 // The alternative is creating new callsite clone nodes below as we clone the
4899 // function, but that is tricker to get right and likely more overhead.
4900 //
4901 // Inner map is a std::map so sorted by key (clone number), in order to get
4902 // ordered remarks in the full LTO case.
4903 DenseMap<const ContextNode *, std::map<unsigned, SmallVector<CallInfo, 0>>>
4904 UnassignedCallClones;
4905
4906 // Walk all functions for which we saw calls with memprof metadata, and handle
4907 // cloning for each of its calls.
4908 for (auto &[Func, CallsWithMetadata] : FuncToCallsWithMetadata) {
4909 FuncInfo OrigFunc(Func);
4910 // Map from each clone number of OrigFunc to information about that function
4911 // clone (the function clone FuncInfo and call remappings). The index into
4912 // the vector is the clone number, as function clones are created and
4913 // numbered sequentially.
4914 std::vector<FuncCloneInfo> FuncCloneInfos;
4915 for (auto &Call : CallsWithMetadata) {
4916 ContextNode *Node = getNodeForInst(Call);
4917 // Skip call if we do not have a node for it (all uses of its stack ids
4918 // were either on inlined chains or pruned from the MIBs), or if we did
4919 // not create any clones for it.
4920 if (!Node || Node->Clones.empty())
4921 continue;
4922 assert(Node->hasCall() &&
4923 "Not having a call should have prevented cloning");
4924
4925 // Track the assignment of function clones to clones of the current
4926 // callsite Node being handled.
4927 std::map<FuncInfo, ContextNode *> FuncCloneToCurNodeCloneMap;
4928
4929 // Assign callsite version CallsiteClone to function version FuncClone,
4930 // and also assign (possibly cloned) Call to CallsiteClone.
4931 auto AssignCallsiteCloneToFuncClone = [&](const FuncInfo &FuncClone,
4932 CallInfo &Call,
4933 ContextNode *CallsiteClone,
4934 bool IsAlloc) {
4935 // Record the clone of callsite node assigned to this function clone.
4936 FuncCloneToCurNodeCloneMap[FuncClone] = CallsiteClone;
4937
4938 assert(FuncCloneInfos.size() > FuncClone.cloneNo());
4939 DenseMap<CallInfo, CallInfo> &CallMap =
4940 FuncCloneInfos[FuncClone.cloneNo()].CallMap;
4941 CallInfo CallClone(Call);
4942 if (auto It = CallMap.find(Call); It != CallMap.end())
4943 CallClone = It->second;
4944 CallsiteClone->setCall(CallClone);
4945 // Need to do the same for all matching calls.
4946 for (auto &MatchingCall : Node->MatchingCalls) {
4947 CallInfo CallClone(MatchingCall);
4948 if (auto It = CallMap.find(MatchingCall); It != CallMap.end())
4949 CallClone = It->second;
4950 // Updates the call in the list.
4951 MatchingCall = CallClone;
4952 }
4953 };
4954
4955 // Invokes moveEdgeToNewCalleeClone which creates a new clone, and then
4956 // performs the necessary fixups (removing none type edges, and
4957 // importantly, propagating any function call assignment of the original
4958 // node to the new clone).
4959 auto MoveEdgeToNewCalleeCloneAndSetUp =
4960 [&](const std::shared_ptr<ContextEdge> &Edge) {
4961 ContextNode *OrigCallee = Edge->Callee;
4962 ContextNode *NewClone = moveEdgeToNewCalleeClone(Edge);
4963 removeNoneTypeCalleeEdges(NewClone);
4964 assert(NewClone->AllocTypes != (uint8_t)AllocationType::None);
4965 // If the original Callee was already assigned to call a specific
4966 // function version, make sure its new clone is assigned to call
4967 // that same function clone.
4968 if (CallsiteToCalleeFuncCloneMap.count(OrigCallee))
4969 RecordCalleeFuncOfCallsite(
4970 NewClone, CallsiteToCalleeFuncCloneMap[OrigCallee]);
4971 return NewClone;
4972 };
4973
4974 // Keep track of the clones of callsite Node that need to be assigned to
4975 // function clones. This list may be expanded in the loop body below if we
4976 // find additional cloning is required.
4977 std::deque<ContextNode *> ClonesWorklist;
4978 // Ignore original Node if we moved all of its contexts to clones.
4979 if (!Node->emptyContextIds())
4980 ClonesWorklist.push_back(Node);
4981 llvm::append_range(ClonesWorklist, Node->Clones);
4982
4983 // Now walk through all of the clones of this callsite Node that we need,
4984 // and determine the assignment to a corresponding clone of the current
4985 // function (creating new function clones as needed).
4986 unsigned NodeCloneCount = 0;
4987 while (!ClonesWorklist.empty()) {
4988 ContextNode *Clone = ClonesWorklist.front();
4989 ClonesWorklist.pop_front();
4990 NodeCloneCount++;
4991 if (VerifyNodes)
4993
4994 // Need to create a new function clone if we have more callsite clones
4995 // than existing function clones, which would have been assigned to an
4996 // earlier clone in the list (we assign callsite clones to function
4997 // clones greedily).
4998 if (FuncCloneInfos.size() < NodeCloneCount) {
4999 // If this is the first callsite copy, assign to original function.
5000 if (NodeCloneCount == 1) {
5001 // Since FuncCloneInfos is empty in this case, no clones have
5002 // been created for this function yet, and no callers should have
5003 // been assigned a function clone for this callee node yet.
5005 Clone->CallerEdges, [&](const std::shared_ptr<ContextEdge> &E) {
5006 return CallsiteToCalleeFuncCloneMap.count(E->Caller);
5007 }));
5008 // Initialize with empty call map, assign Clone to original function
5009 // and its callers, and skip to the next clone.
5010 FuncCloneInfos.push_back(
5011 {OrigFunc, DenseMap<CallInfo, CallInfo>()});
5012 AssignCallsiteCloneToFuncClone(
5013 OrigFunc, Call, Clone,
5014 AllocationCallToContextNodeMap.count(Call));
5015 for (auto &CE : Clone->CallerEdges) {
5016 // Ignore any caller that does not have a recorded callsite Call.
5017 if (!CE->Caller->hasCall())
5018 continue;
5019 RecordCalleeFuncOfCallsite(CE->Caller, OrigFunc);
5020 }
5021 continue;
5022 }
5023
5024 // First locate which copy of OrigFunc to clone again. If a caller
5025 // of this callsite clone was already assigned to call a particular
5026 // function clone, we need to redirect all of those callers to the
5027 // new function clone, and update their other callees within this
5028 // function.
5029 FuncInfo PreviousAssignedFuncClone;
5030 auto EI = llvm::find_if(
5031 Clone->CallerEdges, [&](const std::shared_ptr<ContextEdge> &E) {
5032 return CallsiteToCalleeFuncCloneMap.count(E->Caller);
5033 });
5034 bool CallerAssignedToCloneOfFunc = false;
5035 if (EI != Clone->CallerEdges.end()) {
5036 const std::shared_ptr<ContextEdge> &Edge = *EI;
5037 PreviousAssignedFuncClone =
5038 CallsiteToCalleeFuncCloneMap[Edge->Caller];
5039 CallerAssignedToCloneOfFunc = true;
5040 }
5041
5042 // Clone function and save it along with the CallInfo map created
5043 // during cloning in the FuncCloneInfos.
5044 DenseMap<CallInfo, CallInfo> NewCallMap;
5045 unsigned CloneNo = FuncCloneInfos.size();
5046 assert(CloneNo > 0 && "Clone 0 is the original function, which "
5047 "should already exist in the map");
5048 FuncInfo NewFuncClone = cloneFunctionForCallsite(
5049 OrigFunc, Call, NewCallMap, CallsWithMetadata, CloneNo);
5050 FuncCloneInfos.push_back({NewFuncClone, std::move(NewCallMap)});
5051 FunctionClonesAnalysis++;
5052 Changed = true;
5053
5054 // If no caller callsites were already assigned to a clone of this
5055 // function, we can simply assign this clone to the new func clone
5056 // and update all callers to it, then skip to the next clone.
5057 if (!CallerAssignedToCloneOfFunc) {
5058 AssignCallsiteCloneToFuncClone(
5059 NewFuncClone, Call, Clone,
5060 AllocationCallToContextNodeMap.count(Call));
5061 for (auto &CE : Clone->CallerEdges) {
5062 // Ignore any caller that does not have a recorded callsite Call.
5063 if (!CE->Caller->hasCall())
5064 continue;
5065 RecordCalleeFuncOfCallsite(CE->Caller, NewFuncClone);
5066 }
5067 continue;
5068 }
5069
5070 // We may need to do additional node cloning in this case.
5071 // Reset the CallsiteToCalleeFuncCloneMap entry for any callers
5072 // that were previously assigned to call PreviousAssignedFuncClone,
5073 // to record that they now call NewFuncClone.
5074 // The none type edge removal may remove some of this Clone's caller
5075 // edges, if it is reached via another of its caller's callees.
5076 // Iterate over a copy and skip any that were removed.
5077 auto CallerEdges = Clone->CallerEdges;
5078 for (auto CE : CallerEdges) {
5079 // Skip any that have been removed on an earlier iteration.
5080 if (CE->isRemoved()) {
5081 assert(!is_contained(Clone->CallerEdges, CE));
5082 continue;
5083 }
5084 assert(CE);
5085 // Ignore any caller that does not have a recorded callsite Call.
5086 if (!CE->Caller->hasCall())
5087 continue;
5088
5089 if (!CallsiteToCalleeFuncCloneMap.count(CE->Caller) ||
5090 // We subsequently fall through to later handling that
5091 // will perform any additional cloning required for
5092 // callers that were calling other function clones.
5093 CallsiteToCalleeFuncCloneMap[CE->Caller] !=
5094 PreviousAssignedFuncClone)
5095 continue;
5096
5097 RecordCalleeFuncOfCallsite(CE->Caller, NewFuncClone);
5098
5099 // If we are cloning a function that was already assigned to some
5100 // callers, then essentially we are creating new callsite clones
5101 // of the other callsites in that function that are reached by those
5102 // callers. Clone the other callees of the current callsite's caller
5103 // that were already assigned to PreviousAssignedFuncClone
5104 // accordingly. This is important since we subsequently update the
5105 // calls from the nodes in the graph and their assignments to callee
5106 // functions recorded in CallsiteToCalleeFuncCloneMap.
5107 // The none type edge removal may remove some of this caller's
5108 // callee edges, if it is reached via another of its callees.
5109 // Iterate over a copy and skip any that were removed.
5110 auto CalleeEdges = CE->Caller->CalleeEdges;
5111 for (auto CalleeEdge : CalleeEdges) {
5112 // Skip any that have been removed on an earlier iteration when
5113 // cleaning up newly None type callee edges.
5114 if (CalleeEdge->isRemoved()) {
5115 assert(!is_contained(CE->Caller->CalleeEdges, CalleeEdge));
5116 continue;
5117 }
5118 assert(CalleeEdge);
5119 ContextNode *Callee = CalleeEdge->Callee;
5120 // Skip the current callsite, we are looking for other
5121 // callsites Caller calls, as well as any that does not have a
5122 // recorded callsite Call.
5123 if (Callee == Clone || !Callee->hasCall())
5124 continue;
5125 // Skip direct recursive calls. We don't need/want to clone the
5126 // caller node again, and this loop will not behave as expected if
5127 // we tried.
5128 if (Callee == CalleeEdge->Caller)
5129 continue;
5130 ContextNode *NewClone =
5131 MoveEdgeToNewCalleeCloneAndSetUp(CalleeEdge);
5132 // Moving the edge may have resulted in some none type
5133 // callee edges on the original Callee.
5134 removeNoneTypeCalleeEdges(Callee);
5135 // Update NewClone with the new Call clone of this callsite's Call
5136 // created for the new function clone created earlier.
5137 // Recall that we have already ensured when building the graph
5138 // that each caller can only call callsites within the same
5139 // function, so we are guaranteed that Callee Call is in the
5140 // current OrigFunc.
5141 // CallMap is set up as indexed by original Call at clone 0.
5142 CallInfo OrigCall(Callee->getOrigNode()->Call);
5143 OrigCall.setCloneNo(0);
5144 DenseMap<CallInfo, CallInfo> &CallMap =
5145 FuncCloneInfos[NewFuncClone.cloneNo()].CallMap;
5146 assert(CallMap.count(OrigCall));
5147 CallInfo NewCall(CallMap[OrigCall]);
5148 assert(NewCall);
5149 NewClone->setCall(NewCall);
5150 // Need to do the same for all matching calls.
5151 for (auto &MatchingCall : NewClone->MatchingCalls) {
5152 CallInfo OrigMatchingCall(MatchingCall);
5153 OrigMatchingCall.setCloneNo(0);
5154 assert(CallMap.count(OrigMatchingCall));
5155 CallInfo NewCall(CallMap[OrigMatchingCall]);
5156 assert(NewCall);
5157 // Updates the call in the list.
5158 MatchingCall = NewCall;
5159 }
5160 }
5161 }
5162 // Fall through to handling below to perform the recording of the
5163 // function for this callsite clone. This enables handling of cases
5164 // where the callers were assigned to different clones of a function.
5165 }
5166
5167 auto FindFirstAvailFuncClone = [&]() {
5168 // Find first function in FuncCloneInfos without an assigned
5169 // clone of this callsite Node. We should always have one
5170 // available at this point due to the earlier cloning when the
5171 // FuncCloneInfos size was smaller than the clone number.
5172 for (auto &CF : FuncCloneInfos) {
5173 if (!FuncCloneToCurNodeCloneMap.count(CF.FuncClone))
5174 return CF.FuncClone;
5175 }
5177 "Expected an available func clone for this callsite clone");
5178 };
5179
5180 // See if we can use existing function clone. Walk through
5181 // all caller edges to see if any have already been assigned to
5182 // a clone of this callsite's function. If we can use it, do so. If not,
5183 // because that function clone is already assigned to a different clone
5184 // of this callsite, then we need to clone again.
5185 // Basically, this checking is needed to handle the case where different
5186 // caller functions/callsites may need versions of this function
5187 // containing different mixes of callsite clones across the different
5188 // callsites within the function. If that happens, we need to create
5189 // additional function clones to handle the various combinations.
5190 //
5191 // Keep track of any new clones of this callsite created by the
5192 // following loop, as well as any existing clone that we decided to
5193 // assign this clone to.
5194 std::map<FuncInfo, ContextNode *> FuncCloneToNewCallsiteCloneMap;
5195 FuncInfo FuncCloneAssignedToCurCallsiteClone;
5196 // Iterate over a copy of Clone's caller edges, since we may need to
5197 // remove edges in the moveEdgeTo* methods, and this simplifies the
5198 // handling and makes it less error-prone.
5199 auto CloneCallerEdges = Clone->CallerEdges;
5200 for (auto &Edge : CloneCallerEdges) {
5201 // Skip removed edges (due to direct recursive edges updated when
5202 // updating callee edges when moving an edge and subsequently
5203 // removed by call to removeNoneTypeCalleeEdges on the Clone).
5204 if (Edge->isRemoved())
5205 continue;
5206 // Ignore any caller that does not have a recorded callsite Call.
5207 if (!Edge->Caller->hasCall())
5208 continue;
5209 // If this caller already assigned to call a version of OrigFunc, need
5210 // to ensure we can assign this callsite clone to that function clone.
5211 if (CallsiteToCalleeFuncCloneMap.count(Edge->Caller)) {
5212 FuncInfo FuncCloneCalledByCaller =
5213 CallsiteToCalleeFuncCloneMap[Edge->Caller];
5214 // First we need to confirm that this function clone is available
5215 // for use by this callsite node clone.
5216 //
5217 // While FuncCloneToCurNodeCloneMap is built only for this Node and
5218 // its callsite clones, one of those callsite clones X could have
5219 // been assigned to the same function clone called by Edge's caller
5220 // - if Edge's caller calls another callsite within Node's original
5221 // function, and that callsite has another caller reaching clone X.
5222 // We need to clone Node again in this case.
5223 if ((FuncCloneToCurNodeCloneMap.count(FuncCloneCalledByCaller) &&
5224 FuncCloneToCurNodeCloneMap[FuncCloneCalledByCaller] !=
5225 Clone) ||
5226 // Detect when we have multiple callers of this callsite that
5227 // have already been assigned to specific, and different, clones
5228 // of OrigFunc (due to other unrelated callsites in Func they
5229 // reach via call contexts). Is this Clone of callsite Node
5230 // assigned to a different clone of OrigFunc? If so, clone Node
5231 // again.
5232 (FuncCloneAssignedToCurCallsiteClone &&
5233 FuncCloneAssignedToCurCallsiteClone !=
5234 FuncCloneCalledByCaller)) {
5235 // We need to use a different newly created callsite clone, in
5236 // order to assign it to another new function clone on a
5237 // subsequent iteration over the Clones array (adjusted below).
5238 // Note we specifically do not reset the
5239 // CallsiteToCalleeFuncCloneMap entry for this caller, so that
5240 // when this new clone is processed later we know which version of
5241 // the function to copy (so that other callsite clones we have
5242 // assigned to that function clone are properly cloned over). See
5243 // comments in the function cloning handling earlier.
5244
5245 // Check if we already have cloned this callsite again while
5246 // walking through caller edges, for a caller calling the same
5247 // function clone. If so, we can move this edge to that new clone
5248 // rather than creating yet another new clone.
5249 if (FuncCloneToNewCallsiteCloneMap.count(
5250 FuncCloneCalledByCaller)) {
5251 ContextNode *NewClone =
5252 FuncCloneToNewCallsiteCloneMap[FuncCloneCalledByCaller];
5253 moveEdgeToExistingCalleeClone(Edge, NewClone);
5254 // Cleanup any none type edges cloned over.
5255 removeNoneTypeCalleeEdges(NewClone);
5256 } else {
5257 // Create a new callsite clone.
5258 ContextNode *NewClone = MoveEdgeToNewCalleeCloneAndSetUp(Edge);
5259 FuncCloneToNewCallsiteCloneMap[FuncCloneCalledByCaller] =
5260 NewClone;
5261 // Add to list of clones and process later.
5262 ClonesWorklist.push_back(NewClone);
5263 }
5264 // Moving the caller edge may have resulted in some none type
5265 // callee edges.
5266 removeNoneTypeCalleeEdges(Clone);
5267 // We will handle the newly created callsite clone in a subsequent
5268 // iteration over this Node's Clones.
5269 continue;
5270 }
5271
5272 // Otherwise, we can use the function clone already assigned to this
5273 // caller.
5274 if (!FuncCloneAssignedToCurCallsiteClone) {
5275 FuncCloneAssignedToCurCallsiteClone = FuncCloneCalledByCaller;
5276 // Assign Clone to FuncCloneCalledByCaller
5277 AssignCallsiteCloneToFuncClone(
5278 FuncCloneCalledByCaller, Call, Clone,
5279 AllocationCallToContextNodeMap.count(Call));
5280 } else
5281 // Don't need to do anything - callsite is already calling this
5282 // function clone.
5283 assert(FuncCloneAssignedToCurCallsiteClone ==
5284 FuncCloneCalledByCaller);
5285
5286 } else {
5287 // We have not already assigned this caller to a version of
5288 // OrigFunc. Do the assignment now.
5289
5290 // First check if we have already assigned this callsite clone to a
5291 // clone of OrigFunc for another caller during this iteration over
5292 // its caller edges.
5293 if (!FuncCloneAssignedToCurCallsiteClone) {
5294 FuncCloneAssignedToCurCallsiteClone = FindFirstAvailFuncClone();
5295 assert(FuncCloneAssignedToCurCallsiteClone);
5296 // Assign Clone to FuncCloneAssignedToCurCallsiteClone
5297 AssignCallsiteCloneToFuncClone(
5298 FuncCloneAssignedToCurCallsiteClone, Call, Clone,
5299 AllocationCallToContextNodeMap.count(Call));
5300 } else
5301 assert(FuncCloneToCurNodeCloneMap
5302 [FuncCloneAssignedToCurCallsiteClone] == Clone);
5303 // Update callers to record function version called.
5304 RecordCalleeFuncOfCallsite(Edge->Caller,
5305 FuncCloneAssignedToCurCallsiteClone);
5306 }
5307 }
5308 // If we didn't assign a function clone to this callsite clone yet, e.g.
5309 // none of its callers has a non-null call, do the assignment here.
5310 // We want to ensure that every callsite clone is assigned to some
5311 // function clone, so that the call updates below work as expected.
5312 // In particular if this is the original callsite, we want to ensure it
5313 // is assigned to the original function, otherwise the original function
5314 // will appear available for assignment to other callsite clones,
5315 // leading to unintended effects. For one, the unknown and not updated
5316 // callers will call into cloned paths leading to the wrong hints,
5317 // because they still call the original function (clone 0). Also,
5318 // because all callsites start out as being clone 0 by default, we can't
5319 // easily distinguish between callsites explicitly assigned to clone 0
5320 // vs those never assigned, which can lead to multiple updates of the
5321 // calls when invoking updateCall below, with mismatched clone values.
5322 // TODO: Add a flag to the callsite nodes or some other mechanism to
5323 // better distinguish and identify callsite clones that are not getting
5324 // assigned to function clones as expected.
5325 if (!FuncCloneAssignedToCurCallsiteClone) {
5326 FuncCloneAssignedToCurCallsiteClone = FindFirstAvailFuncClone();
5327 assert(FuncCloneAssignedToCurCallsiteClone &&
5328 "No available func clone for this callsite clone");
5329 AssignCallsiteCloneToFuncClone(
5330 FuncCloneAssignedToCurCallsiteClone, Call, Clone,
5331 /*IsAlloc=*/AllocationCallToContextNodeMap.contains(Call));
5332 }
5333 }
5334 if (VerifyCCG) {
5336 for (const auto &PE : Node->CalleeEdges)
5338 for (const auto &CE : Node->CallerEdges)
5340 for (auto *Clone : Node->Clones) {
5342 for (const auto &PE : Clone->CalleeEdges)
5344 for (const auto &CE : Clone->CallerEdges)
5346 }
5347 }
5348 }
5349
5350 if (FuncCloneInfos.size() < 2)
5351 continue;
5352
5353 // In this case there is more than just the original function copy.
5354 // Record call clones of any callsite nodes in the function that did not
5355 // themselves get cloned for all of the function clones.
5356 for (auto &Call : CallsWithMetadata) {
5357 ContextNode *Node = getNodeForInst(Call);
5358 if (!Node || !Node->hasCall() || Node->emptyContextIds())
5359 continue;
5360 // If Node has enough clones already to cover all function clones, we can
5361 // skip it. Need to add one for the original copy.
5362 // Use >= in case there were clones that were skipped due to having empty
5363 // context ids
5364 if (Node->Clones.size() + 1 >= FuncCloneInfos.size())
5365 continue;
5366 // First collect all function clones we cloned this callsite node for.
5367 // They may not be sequential due to empty clones e.g.
5368 DenseSet<unsigned> NodeCallClones;
5369 for (auto *C : Node->Clones)
5370 NodeCallClones.insert(C->Call.cloneNo());
5371 unsigned I = 0;
5372 // Now check all the function clones.
5373 for (auto &FC : FuncCloneInfos) {
5374 // Function clones should be sequential.
5375 assert(FC.FuncClone.cloneNo() == I);
5376 // Skip the first clone which got the original call.
5377 // Also skip any other clones created for this Node.
5378 if (++I == 1 || NodeCallClones.contains(I)) {
5379 continue;
5380 }
5381 // Record the call clones created for this callsite in this function
5382 // clone.
5383 auto &CallVector = UnassignedCallClones[Node][I];
5384 DenseMap<CallInfo, CallInfo> &CallMap = FC.CallMap;
5385 if (auto It = CallMap.find(Call); It != CallMap.end()) {
5386 CallInfo CallClone = It->second;
5387 CallVector.push_back(CallClone);
5388 } else {
5389 // All but the original clone (skipped earlier) should have an entry
5390 // for all calls.
5391 assert(false && "Expected to find call in CallMap");
5392 }
5393 // Need to do the same for all matching calls.
5394 for (auto &MatchingCall : Node->MatchingCalls) {
5395 if (auto It = CallMap.find(MatchingCall); It != CallMap.end()) {
5396 CallInfo CallClone = It->second;
5397 CallVector.push_back(CallClone);
5398 } else {
5399 // All but the original clone (skipped earlier) should have an entry
5400 // for all calls.
5401 assert(false && "Expected to find call in CallMap");
5402 }
5403 }
5404 }
5405 }
5406 }
5407
5408 uint8_t BothTypes =
5409 (uint8_t)AllocationType::Cold | (uint8_t)AllocationType::NotCold;
5410
5411 auto UpdateCalls = [&](ContextNode *Node,
5412 DenseSet<const ContextNode *> &Visited,
5413 auto &&UpdateCalls) {
5414 auto Inserted = Visited.insert(Node);
5415 if (!Inserted.second)
5416 return;
5417
5418 for (auto *Clone : Node->Clones)
5419 UpdateCalls(Clone, Visited, UpdateCalls);
5420
5421 for (auto &Edge : Node->CallerEdges)
5422 UpdateCalls(Edge->Caller, Visited, UpdateCalls);
5423
5424 // Skip if either no call to update, or if we ended up with no context ids
5425 // (we moved all edges onto other clones).
5426 if (!Node->hasCall() || Node->emptyContextIds())
5427 return;
5428
5429 if (Node->IsAllocation) {
5430 auto AT = allocTypeToUse(Node->AllocTypes);
5431 // If the allocation type is ambiguous, and more aggressive hinting
5432 // has been enabled via the MinClonedColdBytePercent flag, see if this
5433 // allocation should be hinted cold anyway because its fraction cold bytes
5434 // allocated is at least the given threshold.
5435 if (Node->AllocTypes == BothTypes && MinClonedColdBytePercent < 100 &&
5436 !ContextIdToContextSizeInfos.empty()) {
5437 uint64_t TotalCold = 0;
5438 uint64_t Total = 0;
5439 for (auto Id : Node->getContextIds()) {
5440 auto TypeI = ContextIdToAllocationType.find(Id);
5441 assert(TypeI != ContextIdToAllocationType.end());
5442 auto CSI = ContextIdToContextSizeInfos.find(Id);
5443 if (CSI != ContextIdToContextSizeInfos.end()) {
5444 for (auto &Info : CSI->second) {
5445 Total += Info.TotalSize;
5446 if (TypeI->second == AllocationType::Cold)
5447 TotalCold += Info.TotalSize;
5448 }
5449 }
5450 }
5451 if (TotalCold * 100 >= Total * MinClonedColdBytePercent)
5452 AT = AllocationType::Cold;
5453 }
5454 updateAllocationCall(Node->Call, AT);
5455 assert(Node->MatchingCalls.empty());
5456 return;
5457 }
5458
5459 if (!CallsiteToCalleeFuncCloneMap.count(Node))
5460 return;
5461
5462 auto CalleeFunc = CallsiteToCalleeFuncCloneMap[Node];
5463 updateCall(Node->Call, CalleeFunc);
5464 // Update all the matching calls as well.
5465 for (auto &Call : Node->MatchingCalls)
5466 updateCall(Call, CalleeFunc);
5467
5468 // Now update all calls recorded earlier that are still in function clones
5469 // which don't have a clone of this callsite node.
5470 if (!UnassignedCallClones.contains(Node))
5471 return;
5472 DenseSet<unsigned> NodeCallClones;
5473 for (auto *C : Node->Clones)
5474 NodeCallClones.insert(C->Call.cloneNo());
5475 // Note that we already confirmed Node is in this map a few lines above.
5476 auto &ClonedCalls = UnassignedCallClones[Node];
5477 for (auto &[CloneNo, CallVector] : ClonedCalls) {
5478 // Should start at 1 as we never create an entry for original node.
5479 assert(CloneNo > 0);
5480 // If we subsequently created a clone, skip this one.
5481 if (NodeCallClones.contains(CloneNo))
5482 continue;
5483 // Use the original Node's CalleeFunc.
5484 for (auto &Call : CallVector)
5485 updateCall(Call, CalleeFunc);
5486 }
5487 };
5488
5489 // Performs DFS traversal starting from allocation nodes to update calls to
5490 // reflect cloning decisions recorded earlier. For regular LTO this will
5491 // update the actual calls in the IR to call the appropriate function clone
5492 // (and add attributes to allocation calls), whereas for ThinLTO the decisions
5493 // are recorded in the summary entries.
5494 DenseSet<const ContextNode *> Visited;
5495 for (auto &Entry : AllocationCallToContextNodeMap)
5496 UpdateCalls(Entry.second, Visited, UpdateCalls);
5497
5498 return Changed;
5499}
5500
5501// Compute a SHA1 hash of the callsite and alloc version information of clone I
5502// in the summary, to use in detection of duplicate clones.
5504 SHA1 Hasher;
5505 // Update hash with any callsites that call non-default (non-zero) callee
5506 // versions.
5507 for (auto &SN : FS->callsites()) {
5508 // In theory all callsites and allocs in this function should have the same
5509 // number of clone entries, but handle any discrepancies gracefully below
5510 // for NDEBUG builds.
5511 assert(
5512 SN.Clones.size() > I &&
5513 "Callsite summary has fewer entries than other summaries in function");
5514 if (SN.Clones.size() <= I || !SN.Clones[I])
5515 continue;
5516 uint8_t Data[sizeof(SN.Clones[I])];
5517 support::endian::write32le(Data, SN.Clones[I]);
5518 Hasher.update(Data);
5519 }
5520 // Update hash with any allocs that have non-default (non-None) hints.
5521 for (auto &AN : FS->allocs()) {
5522 // In theory all callsites and allocs in this function should have the same
5523 // number of clone entries, but handle any discrepancies gracefully below
5524 // for NDEBUG builds.
5525 assert(AN.Versions.size() > I &&
5526 "Alloc summary has fewer entries than other summaries in function");
5527 if (AN.Versions.size() <= I ||
5528 (AllocationType)AN.Versions[I] == AllocationType::None)
5529 continue;
5530 Hasher.update(ArrayRef<uint8_t>(&AN.Versions[I], 1));
5531 }
5532 return support::endian::read64le(Hasher.result().data());
5533}
5534
5536 Function &F, unsigned NumClones, Module &M, OptimizationRemarkEmitter &ORE,
5538 &FuncToAliasMap,
5539 FunctionSummary *FS) {
5540 auto TakeDeclNameAndReplace = [](GlobalValue *DeclGV, GlobalValue *NewGV) {
5541 // We might have created this when adjusting callsite in another
5542 // function. It should be a declaration.
5543 assert(DeclGV->isDeclaration());
5544 NewGV->takeName(DeclGV);
5545 DeclGV->replaceAllUsesWith(NewGV);
5546 DeclGV->eraseFromParent();
5547 };
5548
5549 // Handle aliases to this function, and create analogous alias clones to the
5550 // provided clone of this function.
5551 auto CloneFuncAliases = [&](Function *NewF, unsigned I) {
5552 if (!FuncToAliasMap.count(&F))
5553 return;
5554 for (auto *A : FuncToAliasMap[&F]) {
5555 std::string AliasName = getMemProfFuncName(A->getName(), I);
5556 auto *PrevA = M.getNamedAlias(AliasName);
5557 auto *NewA = GlobalAlias::create(A->getValueType(),
5558 A->getType()->getPointerAddressSpace(),
5559 A->getLinkage(), AliasName, NewF);
5560 NewA->copyAttributesFrom(A);
5561 if (PrevA)
5562 TakeDeclNameAndReplace(PrevA, NewA);
5563 }
5564 };
5565
5566 // The first "clone" is the original copy, we should only call this if we
5567 // needed to create new clones.
5568 assert(NumClones > 1);
5570 VMaps.reserve(NumClones - 1);
5571 FunctionsClonedThinBackend++;
5572
5573 // Map of hash of callsite/alloc versions to the instantiated function clone
5574 // (possibly the original) implementing those calls. Used to avoid
5575 // instantiating duplicate function clones.
5576 // FIXME: Ideally the thin link would not generate such duplicate clones to
5577 // start with, but right now it happens due to phase ordering in the function
5578 // assignment and possible new clones that produces. We simply make each
5579 // duplicate an alias to the matching instantiated clone recorded in the map
5580 // (except for available_externally which are made declarations as they would
5581 // be aliases in the prevailing module, and available_externally aliases are
5582 // not well supported right now).
5584
5585 // Save the hash of the original function version.
5586 HashToFunc[ComputeHash(FS, 0)] = &F;
5587
5588 for (unsigned I = 1; I < NumClones; I++) {
5589 VMaps.emplace_back(std::make_unique<ValueToValueMapTy>());
5590 std::string Name = getMemProfFuncName(F.getName(), I);
5591 auto Hash = ComputeHash(FS, I);
5592 // If this clone would duplicate a previously seen clone, don't generate the
5593 // duplicate clone body, just make an alias to satisfy any (potentially
5594 // cross-module) references.
5595 if (HashToFunc.contains(Hash)) {
5596 FunctionCloneDuplicatesThinBackend++;
5597 auto *Func = HashToFunc[Hash];
5598 if (Func->hasAvailableExternallyLinkage()) {
5599 // Skip these as EliminateAvailableExternallyPass does not handle
5600 // available_externally aliases correctly and we end up with an
5601 // available_externally alias to a declaration. Just create a
5602 // declaration for now as we know we will have a definition in another
5603 // module.
5604 auto Decl = M.getOrInsertFunction(Name, Func->getFunctionType());
5605 ORE.emit(OptimizationRemark(DEBUG_TYPE, "MemprofClone", &F)
5606 << "created clone decl " << ore::NV("Decl", Decl.getCallee()));
5607 continue;
5608 }
5609 auto *PrevF = M.getFunction(Name);
5610 auto *Alias = GlobalAlias::create(Name, Func);
5611 if (PrevF)
5612 TakeDeclNameAndReplace(PrevF, Alias);
5613 ORE.emit(OptimizationRemark(DEBUG_TYPE, "MemprofClone", &F)
5614 << "created clone alias " << ore::NV("Alias", Alias));
5615
5616 // Now handle aliases to this function, and clone those as well.
5617 CloneFuncAliases(Func, I);
5618 continue;
5619 }
5620 auto *NewF = CloneFunction(&F, *VMaps.back());
5621 HashToFunc[Hash] = NewF;
5622 FunctionClonesThinBackend++;
5623 // Strip memprof and callsite metadata from clone as they are no longer
5624 // needed.
5625 for (auto &BB : *NewF) {
5626 for (auto &Inst : BB) {
5627 Inst.setMetadata(LLVMContext::MD_memprof, nullptr);
5628 Inst.setMetadata(LLVMContext::MD_callsite, nullptr);
5629 }
5630 }
5631 auto *PrevF = M.getFunction(Name);
5632 if (PrevF)
5633 TakeDeclNameAndReplace(PrevF, NewF);
5634 else
5635 NewF->setName(Name);
5636 updateSubprogramLinkageName(NewF, Name);
5637 ORE.emit(OptimizationRemark(DEBUG_TYPE, "MemprofClone", &F)
5638 << "created clone " << ore::NV("NewFunction", NewF));
5639
5640 // Now handle aliases to this function, and clone those as well.
5641 CloneFuncAliases(NewF, I);
5642 }
5643 return VMaps;
5644}
5645
5646// Locate the summary for F. This is complicated by the fact that it might
5647// have been internalized or promoted.
5649 const ModuleSummaryIndex *ImportSummary,
5650 const Function *CallingFunc = nullptr) {
5651 // FIXME: Ideally we would retain the original GUID in some fashion on the
5652 // function (e.g. as metadata), but for now do our best to locate the
5653 // summary without that information.
5654 ValueInfo TheFnVI = ImportSummary->getValueInfo(F.getGUID());
5655 if (!TheFnVI)
5656 // See if theFn was internalized, by checking index directly with
5657 // original name (this avoids the name adjustment done by getGUID() for
5658 // internal symbols).
5659 TheFnVI = ImportSummary->getValueInfo(
5661 if (TheFnVI)
5662 return TheFnVI;
5663 // Now query with the original name before any promotion was performed.
5664 StringRef OrigName =
5666 // When this pass is enabled, we always add thinlto_src_file provenance
5667 // metadata to imported function definitions, which allows us to recreate the
5668 // original internal symbol's GUID.
5669 auto SrcFileMD = F.getMetadata("thinlto_src_file");
5670 // If this is a call to an imported/promoted local for which we didn't import
5671 // the definition, the metadata will not exist on the declaration. However,
5672 // since we are doing this early, before any inlining in the LTO backend, we
5673 // can simply look at the metadata on the calling function which must have
5674 // been from the same module if F was an internal symbol originally.
5675 if (!SrcFileMD && F.isDeclaration()) {
5676 // We would only call this for a declaration for a direct callsite, in which
5677 // case the caller would have provided the calling function pointer.
5678 assert(CallingFunc);
5679 SrcFileMD = CallingFunc->getMetadata("thinlto_src_file");
5680 // If this is a promoted local (OrigName != F.getName()), since this is a
5681 // declaration, it must be imported from a different module and therefore we
5682 // should always find the metadata on its calling function. Any call to a
5683 // promoted local that came from this module should still be a definition.
5684 assert(SrcFileMD || OrigName == F.getName());
5685 }
5686 StringRef SrcFile = M.getSourceFileName();
5687 if (SrcFileMD)
5688 SrcFile = dyn_cast<MDString>(SrcFileMD->getOperand(0))->getString();
5689 std::string OrigId = GlobalValue::getGlobalIdentifier(
5690 OrigName, GlobalValue::InternalLinkage, SrcFile);
5691 TheFnVI = ImportSummary->getValueInfo(
5693 // Internal func in original module may have gotten a numbered suffix if we
5694 // imported an external function with the same name. This happens
5695 // automatically during IR linking for naming conflicts. It would have to
5696 // still be internal in that case (otherwise it would have been renamed on
5697 // promotion in which case we wouldn't have a naming conflict).
5698 if (!TheFnVI && OrigName == F.getName() && F.hasLocalLinkage() &&
5699 F.getName().contains('.')) {
5700 OrigName = F.getName().rsplit('.').first;
5702 OrigName, GlobalValue::InternalLinkage, SrcFile);
5703 TheFnVI = ImportSummary->getValueInfo(
5705 }
5706 // The only way we may not have a VI is if this is a declaration created for
5707 // an imported reference. For distributed ThinLTO we may not have a VI for
5708 // such declarations in the distributed summary.
5709 assert(TheFnVI || F.isDeclaration());
5710 return TheFnVI;
5711}
5712
5713bool MemProfContextDisambiguation::initializeIndirectCallPromotionInfo(
5714 Module &M) {
5715 ICallAnalysis = std::make_unique<ICallPromotionAnalysis>();
5716 Symtab = std::make_unique<InstrProfSymtab>();
5717 // Don't add canonical names, to avoid multiple functions to the symtab
5718 // when they both have the same root name with "." suffixes stripped.
5719 // If we pick the wrong one then this could lead to incorrect ICP and calling
5720 // a memprof clone that we don't actually create (resulting in linker unsats).
5721 // What this means is that the GUID of the function (or its PGOFuncName
5722 // metadata) *must* match that in the VP metadata to allow promotion.
5723 // In practice this should not be a limitation, since local functions should
5724 // have PGOFuncName metadata and global function names shouldn't need any
5725 // special handling (they should not get the ".llvm.*" suffix that the
5726 // canonicalization handling is attempting to strip).
5727 if (Error E = Symtab->create(M, /*InLTO=*/true, /*AddCanonical=*/false)) {
5728 std::string SymtabFailure = toString(std::move(E));
5729 M.getContext().emitError("Failed to create symtab: " + SymtabFailure);
5730 return false;
5731 }
5732 return true;
5733}
5734
5735#ifndef NDEBUG
5736// Sanity check that the MIB stack ids match between the summary and
5737// instruction metadata.
5739 const AllocInfo &AllocNode, const MDNode *MemProfMD,
5740 const CallStack<MDNode, MDNode::op_iterator> &CallsiteContext,
5741 const ModuleSummaryIndex *ImportSummary) {
5742 auto MIBIter = AllocNode.MIBs.begin();
5743 for (auto &MDOp : MemProfMD->operands()) {
5744 assert(MIBIter != AllocNode.MIBs.end());
5745 auto StackIdIndexIter = MIBIter->StackIdIndices.begin();
5746 auto *MIBMD = cast<const MDNode>(MDOp);
5747 MDNode *StackMDNode = getMIBStackNode(MIBMD);
5748 assert(StackMDNode);
5749 CallStack<MDNode, MDNode::op_iterator> StackContext(StackMDNode);
5750 auto ContextIterBegin =
5751 StackContext.beginAfterSharedPrefix(CallsiteContext);
5752 // Skip the checking on the first iteration.
5753 uint64_t LastStackContextId =
5754 (ContextIterBegin != StackContext.end() && *ContextIterBegin == 0) ? 1
5755 : 0;
5756 for (auto ContextIter = ContextIterBegin; ContextIter != StackContext.end();
5757 ++ContextIter) {
5758 // If this is a direct recursion, simply skip the duplicate
5759 // entries, to be consistent with how the summary ids were
5760 // generated during ModuleSummaryAnalysis.
5761 if (LastStackContextId == *ContextIter)
5762 continue;
5763 LastStackContextId = *ContextIter;
5764 assert(StackIdIndexIter != MIBIter->StackIdIndices.end());
5765 assert(ImportSummary->getStackIdAtIndex(*StackIdIndexIter) ==
5766 *ContextIter);
5767 StackIdIndexIter++;
5768 }
5769 MIBIter++;
5770 }
5771}
5772#endif
5773
5774bool MemProfContextDisambiguation::applyImport(Module &M) {
5775 assert(ImportSummary);
5776 bool Changed = false;
5777
5778 // We also need to clone any aliases that reference cloned functions, because
5779 // the modified callsites may invoke via the alias. Keep track of the aliases
5780 // for each function.
5781 std::map<const Function *, SmallPtrSet<const GlobalAlias *, 1>>
5782 FuncToAliasMap;
5783 for (auto &A : M.aliases()) {
5784 auto *Aliasee = A.getAliaseeObject();
5785 if (auto *F = dyn_cast<Function>(Aliasee))
5786 FuncToAliasMap[F].insert(&A);
5787 }
5788
5789 if (!initializeIndirectCallPromotionInfo(M))
5790 return false;
5791
5792 for (auto &F : M) {
5793 if (F.isDeclaration() || isMemProfClone(F))
5794 continue;
5795
5796 OptimizationRemarkEmitter ORE(&F);
5797
5799 bool ClonesCreated = false;
5800 unsigned NumClonesCreated = 0;
5801 auto CloneFuncIfNeeded = [&](unsigned NumClones, FunctionSummary *FS) {
5802 // We should at least have version 0 which is the original copy.
5803 assert(NumClones > 0);
5804 // If only one copy needed use original.
5805 if (NumClones == 1)
5806 return;
5807 // If we already performed cloning of this function, confirm that the
5808 // requested number of clones matches (the thin link should ensure the
5809 // number of clones for each constituent callsite is consistent within
5810 // each function), before returning.
5811 if (ClonesCreated) {
5812 assert(NumClonesCreated == NumClones);
5813 return;
5814 }
5815 VMaps = createFunctionClones(F, NumClones, M, ORE, FuncToAliasMap, FS);
5816 // The first "clone" is the original copy, which doesn't have a VMap.
5817 assert(VMaps.size() == NumClones - 1);
5818 Changed = true;
5819 ClonesCreated = true;
5820 NumClonesCreated = NumClones;
5821 };
5822
5823 auto CloneCallsite = [&](const CallsiteInfo &StackNode, CallBase *CB,
5824 Function *CalledFunction, FunctionSummary *FS) {
5825 // Perform cloning if not yet done.
5826 CloneFuncIfNeeded(/*NumClones=*/StackNode.Clones.size(), FS);
5827
5828 assert(!isMemProfClone(*CalledFunction));
5829
5830 // Because we update the cloned calls by calling setCalledOperand (see
5831 // comment below), out of an abundance of caution make sure the called
5832 // function was actually the called operand (or its aliasee). We also
5833 // strip pointer casts when looking for calls (to match behavior during
5834 // summary generation), however, with opaque pointers in theory this
5835 // should not be an issue. Note we still clone the current function
5836 // (containing this call) above, as that could be needed for its callers.
5837 auto *GA = dyn_cast_or_null<GlobalAlias>(CB->getCalledOperand());
5838 if (CalledFunction != CB->getCalledOperand() &&
5839 (!GA || CalledFunction != GA->getAliaseeObject())) {
5840 SkippedCallsCloning++;
5841 return;
5842 }
5843 // Update the calls per the summary info.
5844 // Save orig name since it gets updated in the first iteration
5845 // below.
5846 auto CalleeOrigName = CalledFunction->getName();
5847 for (unsigned J = 0; J < StackNode.Clones.size(); J++) {
5848 // If the VMap is empty, this clone was a duplicate of another and was
5849 // created as an alias or a declaration.
5850 if (J > 0 && VMaps[J - 1]->empty())
5851 continue;
5852 // Do nothing if this version calls the original version of its
5853 // callee.
5854 if (!StackNode.Clones[J])
5855 continue;
5856 auto NewF = M.getOrInsertFunction(
5857 getMemProfFuncName(CalleeOrigName, StackNode.Clones[J]),
5858 CalledFunction->getFunctionType());
5859 CallBase *CBClone;
5860 // Copy 0 is the original function.
5861 if (!J)
5862 CBClone = CB;
5863 else
5864 CBClone = cast<CallBase>((*VMaps[J - 1])[CB]);
5865 // Set the called operand directly instead of calling setCalledFunction,
5866 // as the latter mutates the function type on the call. In rare cases
5867 // we may have a slightly different type on a callee function
5868 // declaration due to it being imported from a different module with
5869 // incomplete types. We really just want to change the name of the
5870 // function to the clone, and not make any type changes.
5871 CBClone->setCalledOperand(NewF.getCallee());
5872 ORE.emit(OptimizationRemark(DEBUG_TYPE, "MemprofCall", CBClone)
5873 << ore::NV("Call", CBClone) << " in clone "
5874 << ore::NV("Caller", CBClone->getFunction())
5875 << " assigned to call function clone "
5876 << ore::NV("Callee", NewF.getCallee()));
5877 }
5878 };
5879
5880 // Locate the summary for F.
5881 ValueInfo TheFnVI = findValueInfoForFunc(F, M, ImportSummary);
5882 // If not found, this could be an imported local (see comment in
5883 // findValueInfoForFunc). Skip for now as it will be cloned in its original
5884 // module (where it would have been promoted to global scope so should
5885 // satisfy any reference in this module).
5886 if (!TheFnVI)
5887 continue;
5888
5889 auto *GVSummary =
5890 ImportSummary->findSummaryInModule(TheFnVI, M.getModuleIdentifier());
5891 if (!GVSummary) {
5892 // Must have been imported, use the summary which matches the definition。
5893 // (might be multiple if this was a linkonce_odr).
5894 auto SrcModuleMD = F.getMetadata("thinlto_src_module");
5895 assert(SrcModuleMD &&
5896 "enable-import-metadata is needed to emit thinlto_src_module");
5897 StringRef SrcModule =
5898 dyn_cast<MDString>(SrcModuleMD->getOperand(0))->getString();
5899 for (auto &GVS : TheFnVI.getSummaryList()) {
5900 if (GVS->modulePath() == SrcModule) {
5901 GVSummary = GVS.get();
5902 break;
5903 }
5904 }
5905 // TODO: Put back the assert once we have metadata on imported copies of
5906 // aliases linking them back to the original alias GUID, which would allow
5907 // us to locate the alias summary here.
5908 // assert(GVSummary && GVSummary->modulePath() == SrcModule);
5909 }
5910
5911 // GVSummary can be null if this is a function imported as a copy of an
5912 // alias, and we don't have the aliasee's summary in our distributed index.
5913 // TODO: Once we can locate the original GUID for imported aliases (e.g. via
5914 // TBD additional metadata), we should find the alias summary instead, and
5915 // we can remove this check and fall back to the original check below.
5916 if (!GVSummary)
5917 continue;
5918
5919 // If this was an imported alias skip it as we won't have the function
5920 // summary, and it should be cloned in the original module.
5921 if (isa<AliasSummary>(GVSummary))
5922 continue;
5923
5924 auto *FS = cast<FunctionSummary>(GVSummary->getBaseObject());
5925
5926 if (FS->allocs().empty() && FS->callsites().empty())
5927 continue;
5928
5929 auto SI = FS->callsites().begin();
5930 auto AI = FS->allocs().begin();
5931
5932 // To handle callsite infos synthesized for tail calls which have missing
5933 // frames in the profiled context, map callee VI to the synthesized callsite
5934 // info.
5935 DenseMap<ValueInfo, CallsiteInfo> MapTailCallCalleeVIToCallsite;
5936 // Iterate the callsites for this function in reverse, since we place all
5937 // those synthesized for tail calls at the end.
5938 for (auto CallsiteIt = FS->callsites().rbegin();
5939 CallsiteIt != FS->callsites().rend(); CallsiteIt++) {
5940 auto &Callsite = *CallsiteIt;
5941 // Stop as soon as we see a non-synthesized callsite info (see comment
5942 // above loop). All the entries added for discovered tail calls have empty
5943 // stack ids.
5944 if (!Callsite.StackIdIndices.empty())
5945 break;
5946 MapTailCallCalleeVIToCallsite.insert({Callsite.Callee, Callsite});
5947 }
5948
5949 // Keeps track of needed ICP for the function.
5950 SmallVector<ICallAnalysisData> ICallAnalysisInfo;
5951
5952 // Assume for now that the instructions are in the exact same order
5953 // as when the summary was created, but confirm this is correct by
5954 // matching the stack ids.
5955 for (auto &BB : F) {
5956 for (auto &I : BB) {
5957 auto *CB = dyn_cast<CallBase>(&I);
5958 // Same handling as when creating module summary.
5959 if (!mayHaveMemprofSummary(CB))
5960 continue;
5961
5962 auto *CalledValue = CB->getCalledOperand();
5963 auto *CalledFunction = CB->getCalledFunction();
5964 if (CalledValue && !CalledFunction) {
5965 CalledValue = CalledValue->stripPointerCasts();
5966 // Stripping pointer casts can reveal a called function.
5967 CalledFunction = dyn_cast<Function>(CalledValue);
5968 }
5969 // Check if this is an alias to a function. If so, get the
5970 // called aliasee for the checks below.
5971 if (auto *GA = dyn_cast<GlobalAlias>(CalledValue)) {
5972 assert(!CalledFunction &&
5973 "Expected null called function in callsite for alias");
5974 CalledFunction = dyn_cast<Function>(GA->getAliaseeObject());
5975 }
5976
5977 CallStack<MDNode, MDNode::op_iterator> CallsiteContext(
5978 I.getMetadata(LLVMContext::MD_callsite));
5979 auto *MemProfMD = I.getMetadata(LLVMContext::MD_memprof);
5980
5981 // Include allocs that were already assigned a memprof function
5982 // attribute in the statistics. Only do this for those that do not have
5983 // memprof metadata, since we add an "ambiguous" memprof attribute by
5984 // default.
5985 if (CB->getAttributes().hasFnAttr("memprof") && !MemProfMD) {
5986 CB->getAttributes().getFnAttr("memprof").getValueAsString() == "cold"
5987 ? AllocTypeColdThinBackend++
5988 : AllocTypeNotColdThinBackend++;
5989 OrigAllocsThinBackend++;
5990 AllocVersionsThinBackend++;
5991 if (!MaxAllocVersionsThinBackend)
5992 MaxAllocVersionsThinBackend = 1;
5993 continue;
5994 }
5995
5996 if (MemProfMD) {
5997 // Consult the next alloc node.
5998 assert(AI != FS->allocs().end());
5999 auto &AllocNode = *(AI++);
6000
6001#ifndef NDEBUG
6002 checkAllocContextIds(AllocNode, MemProfMD, CallsiteContext,
6003 ImportSummary);
6004#endif
6005
6006 // Perform cloning if not yet done.
6007 CloneFuncIfNeeded(/*NumClones=*/AllocNode.Versions.size(), FS);
6008
6009 OrigAllocsThinBackend++;
6010 AllocVersionsThinBackend += AllocNode.Versions.size();
6011 if (MaxAllocVersionsThinBackend < AllocNode.Versions.size())
6012 MaxAllocVersionsThinBackend = AllocNode.Versions.size();
6013
6014 // If there is only one version that means we didn't end up
6015 // considering this function for cloning, and in that case the alloc
6016 // will still be none type or should have gotten the default NotCold.
6017 // Skip that after calling clone helper since that does some sanity
6018 // checks that confirm we haven't decided yet that we need cloning.
6019 // We might have a single version that is cold due to the
6020 // MinClonedColdBytePercent heuristic, make sure we don't skip in that
6021 // case.
6022 if (AllocNode.Versions.size() == 1 &&
6023 (AllocationType)AllocNode.Versions[0] != AllocationType::Cold) {
6024 assert((AllocationType)AllocNode.Versions[0] ==
6025 AllocationType::NotCold ||
6026 (AllocationType)AllocNode.Versions[0] ==
6027 AllocationType::None);
6028 UnclonableAllocsThinBackend++;
6029 continue;
6030 }
6031
6032 // All versions should have a singular allocation type.
6033 assert(llvm::none_of(AllocNode.Versions, [](uint8_t Type) {
6034 return Type == ((uint8_t)AllocationType::NotCold |
6035 (uint8_t)AllocationType::Cold);
6036 }));
6037
6038 // Update the allocation types per the summary info.
6039 for (unsigned J = 0; J < AllocNode.Versions.size(); J++) {
6040 // If the VMap is empty, this clone was a duplicate of another and
6041 // was created as an alias or a declaration.
6042 if (J > 0 && VMaps[J - 1]->empty())
6043 continue;
6044 // Ignore any that didn't get an assigned allocation type.
6045 if (AllocNode.Versions[J] == (uint8_t)AllocationType::None)
6046 continue;
6047 AllocationType AllocTy = (AllocationType)AllocNode.Versions[J];
6048 AllocTy == AllocationType::Cold ? AllocTypeColdThinBackend++
6049 : AllocTypeNotColdThinBackend++;
6050 std::string AllocTypeString = getAllocTypeAttributeString(AllocTy);
6051 auto A = llvm::Attribute::get(F.getContext(), "memprof",
6052 AllocTypeString);
6053 CallBase *CBClone;
6054 // Copy 0 is the original function.
6055 if (!J)
6056 CBClone = CB;
6057 else
6058 // Since VMaps are only created for new clones, we index with
6059 // clone J-1 (J==0 is the original clone and does not have a VMaps
6060 // entry).
6061 CBClone = cast<CallBase>((*VMaps[J - 1])[CB]);
6063 CBClone->addFnAttr(A);
6064 ORE.emit(OptimizationRemark(DEBUG_TYPE, "MemprofAttribute", CBClone)
6065 << ore::NV("AllocationCall", CBClone) << " in clone "
6066 << ore::NV("Caller", CBClone->getFunction())
6067 << " marked with memprof allocation attribute "
6068 << ore::NV("Attribute", AllocTypeString));
6069 }
6070 } else if (!CallsiteContext.empty()) {
6071 if (!CalledFunction) {
6072#ifndef NDEBUG
6073 // We should have skipped inline assembly calls.
6074 auto *CI = dyn_cast<CallInst>(CB);
6075 assert(!CI || !CI->isInlineAsm());
6076#endif
6077 // We should have skipped direct calls via a Constant.
6078 assert(CalledValue && !isa<Constant>(CalledValue));
6079
6080 // This is an indirect call, see if we have profile information and
6081 // whether any clones were recorded for the profiled targets (that
6082 // we synthesized CallsiteInfo summary records for when building the
6083 // index).
6084 auto NumClones =
6085 recordICPInfo(CB, FS->callsites(), SI, ICallAnalysisInfo);
6086
6087 // Perform cloning if not yet done. This is done here in case
6088 // we don't need to do ICP, but might need to clone this
6089 // function as it is the target of other cloned calls.
6090 if (NumClones)
6091 CloneFuncIfNeeded(NumClones, FS);
6092 }
6093
6094 else {
6095 // Consult the next callsite node.
6096 assert(SI != FS->callsites().end());
6097 auto &StackNode = *(SI++);
6098
6099#ifndef NDEBUG
6100 // Sanity check that the stack ids match between the summary and
6101 // instruction metadata.
6102 auto StackIdIndexIter = StackNode.StackIdIndices.begin();
6103 for (auto StackId : CallsiteContext) {
6104 assert(StackIdIndexIter != StackNode.StackIdIndices.end());
6105 assert(ImportSummary->getStackIdAtIndex(*StackIdIndexIter) ==
6106 StackId);
6107 StackIdIndexIter++;
6108 }
6109#endif
6110
6111 CloneCallsite(StackNode, CB, CalledFunction, FS);
6112 }
6113 } else if (CB->isTailCall() && CalledFunction) {
6114 // Locate the synthesized callsite info for the callee VI, if any was
6115 // created, and use that for cloning.
6116 ValueInfo CalleeVI =
6117 findValueInfoForFunc(*CalledFunction, M, ImportSummary, &F);
6118 if (CalleeVI && MapTailCallCalleeVIToCallsite.count(CalleeVI)) {
6119 auto Callsite = MapTailCallCalleeVIToCallsite.find(CalleeVI);
6120 assert(Callsite != MapTailCallCalleeVIToCallsite.end());
6121 CloneCallsite(Callsite->second, CB, CalledFunction, FS);
6122 }
6123 }
6124 }
6125 }
6126
6127 // Now do any promotion required for cloning.
6128 performICP(M, FS->callsites(), VMaps, ICallAnalysisInfo, ORE);
6129 }
6130
6131 // We skip some of the functions and instructions above, so remove all the
6132 // metadata in a single sweep here.
6133 for (auto &F : M) {
6134 // We can skip memprof clones because createFunctionClones already strips
6135 // the metadata from the newly created clones.
6136 if (F.isDeclaration() || isMemProfClone(F))
6137 continue;
6138 for (auto &BB : F) {
6139 for (auto &I : BB) {
6140 if (!isa<CallBase>(I))
6141 continue;
6142 I.setMetadata(LLVMContext::MD_memprof, nullptr);
6143 I.setMetadata(LLVMContext::MD_callsite, nullptr);
6144 }
6145 }
6146 }
6147
6148 return Changed;
6149}
6150
6151unsigned MemProfContextDisambiguation::recordICPInfo(
6152 CallBase *CB, ArrayRef<CallsiteInfo> AllCallsites,
6154 SmallVector<ICallAnalysisData> &ICallAnalysisInfo) {
6155 // First see if we have profile information for this indirect call.
6156 uint32_t NumCandidates;
6157 uint64_t TotalCount;
6158 auto CandidateProfileData =
6159 ICallAnalysis->getPromotionCandidatesForInstruction(
6160 CB, TotalCount, NumCandidates, MaxSummaryIndirectEdges);
6161 if (CandidateProfileData.empty())
6162 return 0;
6163
6164 // Iterate through all of the candidate profiled targets along with the
6165 // CallsiteInfo summary records synthesized for them when building the index,
6166 // and see if any are cloned and/or refer to clones.
6167 bool ICPNeeded = false;
6168 unsigned NumClones = 0;
6169 size_t CallsiteInfoStartIndex = std::distance(AllCallsites.begin(), SI);
6170 for (const auto &Candidate : CandidateProfileData) {
6171#ifndef NDEBUG
6172 auto CalleeValueInfo =
6173#endif
6174 ImportSummary->getValueInfo(Candidate.Value);
6175 // We might not have a ValueInfo if this is a distributed
6176 // ThinLTO backend and decided not to import that function.
6177 assert(!CalleeValueInfo || SI->Callee == CalleeValueInfo);
6178 assert(SI != AllCallsites.end());
6179 auto &StackNode = *(SI++);
6180 // See if any of the clones of the indirect callsite for this
6181 // profiled target should call a cloned version of the profiled
6182 // target. We only need to do the ICP here if so.
6183 ICPNeeded |= llvm::any_of(StackNode.Clones,
6184 [](unsigned CloneNo) { return CloneNo != 0; });
6185 // Every callsite in the same function should have been cloned the same
6186 // number of times.
6187 assert(!NumClones || NumClones == StackNode.Clones.size());
6188 NumClones = StackNode.Clones.size();
6189 }
6190 if (!ICPNeeded)
6191 return NumClones;
6192 // Save information for ICP, which is performed later to avoid messing up the
6193 // current function traversal.
6194 ICallAnalysisInfo.push_back({CB, CandidateProfileData.vec(), NumCandidates,
6195 TotalCount, CallsiteInfoStartIndex});
6196 return NumClones;
6197}
6198
6199void MemProfContextDisambiguation::performICP(
6200 Module &M, ArrayRef<CallsiteInfo> AllCallsites,
6201 ArrayRef<std::unique_ptr<ValueToValueMapTy>> VMaps,
6202 ArrayRef<ICallAnalysisData> ICallAnalysisInfo,
6203 OptimizationRemarkEmitter &ORE) {
6204 // Now do any promotion required for cloning. Specifically, for each
6205 // recorded ICP candidate (which was only recorded because one clone of that
6206 // candidate should call a cloned target), we perform ICP (speculative
6207 // devirtualization) for each clone of the callsite, and update its callee
6208 // to the appropriate clone. Note that the ICP compares against the original
6209 // version of the target, which is what is in the vtable.
6210 for (auto &Info : ICallAnalysisInfo) {
6211 auto *CB = Info.CB;
6212 auto CallsiteIndex = Info.CallsiteInfoStartIndex;
6213 auto TotalCount = Info.TotalCount;
6214 unsigned NumClones = 0;
6215 SmallVector<InstrProfValueData, 8> RemainingCandidates;
6216
6217 for (auto &Candidate : Info.CandidateProfileData) {
6218 auto &StackNode = AllCallsites[CallsiteIndex++];
6219
6220 // All calls in the same function must have the same number of clones.
6221 assert(!NumClones || NumClones == StackNode.Clones.size());
6222 NumClones = StackNode.Clones.size();
6223
6224 // See if the target is in the module. If it wasn't imported, it is
6225 // possible that this profile could have been collected on a different
6226 // target (or version of the code), and we need to be conservative
6227 // (similar to what is done in the ICP pass).
6228 Function *TargetFunction = Symtab->getFunction(Candidate.Value);
6229 if (TargetFunction == nullptr ||
6230 // Any ThinLTO global dead symbol removal should have already
6231 // occurred, so it should be safe to promote when the target is a
6232 // declaration.
6233 // TODO: Remove internal option once more fully tested.
6235 TargetFunction->isDeclaration())) {
6236 ORE.emit([&]() {
6237 return OptimizationRemarkMissed(DEBUG_TYPE, "UnableToFindTarget", CB)
6238 << "Memprof cannot promote indirect call: target with md5sum "
6239 << ore::NV("target md5sum", Candidate.Value) << " not found";
6240 });
6241 // FIXME: See if we can use the new declaration importing support to
6242 // at least get the declarations imported for this case. Hot indirect
6243 // targets should have been imported normally, however.
6244 RemainingCandidates.push_back(Candidate);
6245 continue;
6246 }
6247
6248 // Check if legal to promote
6249 const char *Reason = nullptr;
6250 if (!isLegalToPromote(*CB, TargetFunction, &Reason)) {
6251 ORE.emit([&]() {
6252 return OptimizationRemarkMissed(DEBUG_TYPE, "UnableToPromote", CB)
6253 << "Memprof cannot promote indirect call to "
6254 << ore::NV("TargetFunction", TargetFunction)
6255 << " with count of " << ore::NV("TotalCount", TotalCount)
6256 << ": " << Reason;
6257 });
6258 RemainingCandidates.push_back(Candidate);
6259 continue;
6260 }
6261
6262 assert(!isMemProfClone(*TargetFunction));
6263
6264 // Handle each call clone, applying ICP so that each clone directly
6265 // calls the specified callee clone, guarded by the appropriate ICP
6266 // check.
6267 CallBase *CBClone = CB;
6268 for (unsigned J = 0; J < NumClones; J++) {
6269 // If the VMap is empty, this clone was a duplicate of another and was
6270 // created as an alias or a declaration.
6271 if (J > 0 && VMaps[J - 1]->empty())
6272 continue;
6273 // Copy 0 is the original function.
6274 if (J > 0)
6275 CBClone = cast<CallBase>((*VMaps[J - 1])[CB]);
6276 // We do the promotion using the original name, so that the comparison
6277 // is against the name in the vtable. Then just below, change the new
6278 // direct call to call the cloned function.
6279 auto &DirectCall =
6280 pgo::promoteIndirectCall(*CBClone, TargetFunction, Candidate.Count,
6281 TotalCount, isSamplePGO, &ORE);
6282 auto *TargetToUse = TargetFunction;
6283 // Call original if this version calls the original version of its
6284 // callee.
6285 if (StackNode.Clones[J]) {
6286 TargetToUse =
6287 cast<Function>(M.getOrInsertFunction(
6288 getMemProfFuncName(TargetFunction->getName(),
6289 StackNode.Clones[J]),
6290 TargetFunction->getFunctionType())
6291 .getCallee());
6292 }
6293 DirectCall.setCalledFunction(TargetToUse);
6294 // During matching we generate synthetic VP metadata for indirect calls
6295 // not already having any, from the memprof profile's callee GUIDs. If
6296 // we subsequently promote and inline those callees, we currently lose
6297 // the ability to generate this synthetic VP metadata. Optionally apply
6298 // a noinline attribute to promoted direct calls, where the threshold is
6299 // set to capture synthetic VP metadata targets which get a count of 1.
6301 Candidate.Count < MemProfICPNoInlineThreshold)
6302 DirectCall.setIsNoInline();
6303 ORE.emit(OptimizationRemark(DEBUG_TYPE, "MemprofCall", CBClone)
6304 << ore::NV("Call", CBClone) << " in clone "
6305 << ore::NV("Caller", CBClone->getFunction())
6306 << " promoted and assigned to call function clone "
6307 << ore::NV("Callee", TargetToUse));
6308 }
6309
6310 // Update TotalCount (all clones should get same count above)
6311 TotalCount -= Candidate.Count;
6312 }
6313 // Adjust the MD.prof metadata for all clones, now that we have the new
6314 // TotalCount and the remaining candidates.
6315 CallBase *CBClone = CB;
6316 for (unsigned J = 0; J < NumClones; J++) {
6317 // If the VMap is empty, this clone was a duplicate of another and was
6318 // created as an alias or a declaration.
6319 if (J > 0 && VMaps[J - 1]->empty())
6320 continue;
6321 // Copy 0 is the original function.
6322 if (J > 0)
6323 CBClone = cast<CallBase>((*VMaps[J - 1])[CB]);
6324 // First delete the old one.
6325 CBClone->setMetadata(LLVMContext::MD_prof, nullptr);
6326 // If all promoted, we don't need the MD.prof metadata.
6327 // Otherwise we need update with the un-promoted records back.
6328 if (TotalCount != 0)
6329 annotateValueSite(M, *CBClone, RemainingCandidates, TotalCount,
6330 IPVK_IndirectCallTarget, Info.NumCandidates);
6331 }
6332 }
6333}
6334
6335template <typename DerivedCCG, typename FuncTy, typename CallTy>
6336bool CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::process(
6337 function_ref<void(StringRef, StringRef, const Twine &)> EmitRemark,
6338 bool AllowExtraAnalysis) {
6339 if (DumpCCG) {
6340 dbgs() << "CCG before cloning:\n";
6341 dbgs() << *this;
6342 }
6343 if (ExportToDot)
6344 exportToDot("postbuild");
6345
6346 if (VerifyCCG) {
6347 check();
6348 }
6349
6350 identifyClones();
6351
6352 if (VerifyCCG) {
6353 check();
6354 }
6355
6356 if (DumpCCG) {
6357 dbgs() << "CCG after cloning:\n";
6358 dbgs() << *this;
6359 }
6360 if (ExportToDot)
6361 exportToDot("cloned");
6362
6363 bool Changed = assignFunctions();
6364
6365 if (DumpCCG) {
6366 dbgs() << "CCG after assigning function clones:\n";
6367 dbgs() << *this;
6368 }
6369 if (ExportToDot)
6370 exportToDot("clonefuncassign");
6371
6372 if (MemProfReportHintedSizes || AllowExtraAnalysis)
6373 printTotalSizes(errs(), EmitRemark);
6374
6375 return Changed;
6376}
6377
6378bool MemProfContextDisambiguation::processModule(
6379 Module &M,
6380 llvm::function_ref<OptimizationRemarkEmitter &(Function *)> OREGetter) {
6381
6382 // If we have an import summary, then the cloning decisions were made during
6383 // the thin link on the index. Apply them and return.
6384 if (ImportSummary)
6385 return applyImport(M);
6386
6387 // TODO: If/when other types of memprof cloning are enabled beyond just for
6388 // hot and cold, we will need to change this to individually control the
6389 // AllocationType passed to addStackNodesForMIB during CCG construction.
6390 // Note that we specifically check this after applying imports above, so that
6391 // the option isn't needed to be passed to distributed ThinLTO backend
6392 // clang processes, which won't necessarily have visibility into the linker
6393 // dependences. Instead the information is communicated from the LTO link to
6394 // the backends via the combined summary index.
6395 if (!SupportsHotColdNew)
6396 return false;
6397
6398 ModuleCallsiteContextGraph CCG(M, OREGetter);
6399 // TODO: Set up remarks for regular LTO. We need to decide what function to
6400 // use in the callback.
6401 return CCG.process();
6402}
6403
6405 const ModuleSummaryIndex *Summary, bool isSamplePGO)
6406 : ImportSummary(Summary), isSamplePGO(isSamplePGO) {
6407 // Check the dot graph printing options once here, to make sure we have valid
6408 // and expected combinations.
6409 if (DotGraphScope == DotScope::Alloc && !AllocIdForDot.getNumOccurrences())
6411 "-memprof-dot-scope=alloc requires -memprof-dot-alloc-id");
6413 !ContextIdForDot.getNumOccurrences())
6415 "-memprof-dot-scope=context requires -memprof-dot-context-id");
6416 if (DotGraphScope == DotScope::All && AllocIdForDot.getNumOccurrences() &&
6417 ContextIdForDot.getNumOccurrences())
6419 "-memprof-dot-scope=all can't have both -memprof-dot-alloc-id and "
6420 "-memprof-dot-context-id");
6421 if (ImportSummary) {
6422 // The MemProfImportSummary should only be used for testing ThinLTO
6423 // distributed backend handling via opt, in which case we don't have a
6424 // summary from the pass pipeline.
6426 return;
6427 }
6428 if (MemProfImportSummary.empty())
6429 return;
6430
6431 auto ReadSummaryFile =
6433 if (!ReadSummaryFile) {
6434 logAllUnhandledErrors(ReadSummaryFile.takeError(), errs(),
6435 "Error loading file '" + MemProfImportSummary +
6436 "': ");
6437 return;
6438 }
6439 auto ImportSummaryForTestingOrErr = getModuleSummaryIndex(**ReadSummaryFile);
6440 if (!ImportSummaryForTestingOrErr) {
6441 logAllUnhandledErrors(ImportSummaryForTestingOrErr.takeError(), errs(),
6442 "Error parsing file '" + MemProfImportSummary +
6443 "': ");
6444 return;
6445 }
6446 ImportSummaryForTesting = std::move(*ImportSummaryForTestingOrErr);
6447 ImportSummary = ImportSummaryForTesting.get();
6448}
6449
6452 auto &FAM = AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
6453 auto OREGetter = [&](Function *F) -> OptimizationRemarkEmitter & {
6454 return FAM.getResult<OptimizationRemarkEmitterAnalysis>(*F);
6455 };
6456 if (!processModule(M, OREGetter))
6457 return PreservedAnalyses::all();
6458 return PreservedAnalyses::none();
6459}
6460
6462 ModuleSummaryIndex &Index,
6464 isPrevailing,
6465 LLVMContext &Ctx,
6466 function_ref<void(StringRef, StringRef, const Twine &)> EmitRemark) {
6467 // TODO: If/when other types of memprof cloning are enabled beyond just for
6468 // hot and cold, we will need to change this to individually control the
6469 // AllocationType passed to addStackNodesForMIB during CCG construction.
6470 // The index was set from the option, so these should be in sync.
6471 assert(Index.withSupportsHotColdNew() == SupportsHotColdNew);
6472 if (!SupportsHotColdNew)
6473 return;
6474
6475 bool AllowExtraAnalysis =
6477
6478 IndexCallsiteContextGraph CCG(Index, isPrevailing);
6479 CCG.process(EmitRemark, AllowExtraAnalysis);
6480}
6481
6482// Strips MemProf attributes and metadata. Can be invoked by the pass pipeline
6483// when we don't have an index that has recorded that we are linking with
6484// allocation libraries containing the necessary APIs for downstream
6485// transformations.
6487 // The profile matcher applies hotness attributes directly for allocations,
6488 // and those will cause us to generate calls to the hot/cold interfaces
6489 // unconditionally. If supports-hot-cold-new was not enabled in the LTO
6490 // link then assume we don't want these calls (e.g. not linking with
6491 // the appropriate library, or otherwise trying to disable this behavior).
6492 bool Changed = false;
6493 for (auto &F : M) {
6494 for (auto &BB : F) {
6495 for (auto &I : BB) {
6496 auto *CI = dyn_cast<CallBase>(&I);
6497 if (!CI)
6498 continue;
6499 if (CI->hasFnAttr("memprof")) {
6500 CI->removeFnAttr("memprof");
6501 Changed = true;
6502 }
6503 if (!CI->hasMetadata(LLVMContext::MD_callsite)) {
6504 assert(!CI->hasMetadata(LLVMContext::MD_memprof));
6505 continue;
6506 }
6507 // Strip off all memprof metadata as it is no longer needed.
6508 // Importantly, this avoids the addition of new memprof attributes
6509 // after inlining propagation.
6510 CI->setMetadata(LLVMContext::MD_memprof, nullptr);
6511 CI->setMetadata(LLVMContext::MD_callsite, nullptr);
6512 Changed = true;
6513 }
6514 }
6515 }
6516 if (!Changed)
6517 return PreservedAnalyses::all();
6518 return PreservedAnalyses::none();
6519}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
aarch64 promote const
unsigned uint64_t
Unify divergent function exit nodes
static void print(raw_ostream &Out, object::Archive::Kind Kind, T Val)
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
#define clEnumValN(ENUMVAL, FLAGNAME, DESC)
This file defines the DenseMap class.
This file defines the DenseSet and SmallDenseSet classes.
#define DEBUG_TYPE
Module.h This file contains the declarations for the Module class.
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
#define G(x, y, z)
Definition MD5.cpp:55
Machine Check Debug Module
This file implements a map that provides insertion order iteration.
static cl::opt< unsigned > TailCallSearchDepth("memprof-tail-call-search-depth", cl::init(5), cl::Hidden, cl::desc("Max depth to recursively search for missing " "frames through tail calls."))
uint64_t ComputeHash(const FunctionSummary *FS, unsigned I)
static cl::opt< DotScope > DotGraphScope("memprof-dot-scope", cl::desc("Scope of graph to export to dot"), cl::Hidden, cl::init(DotScope::All), cl::values(clEnumValN(DotScope::All, "all", "Export full callsite graph"), clEnumValN(DotScope::Alloc, "alloc", "Export only nodes with contexts feeding given " "-memprof-dot-alloc-id"), clEnumValN(DotScope::Context, "context", "Export only nodes with given -memprof-dot-context-id")))
static cl::opt< bool > DoMergeIteration("memprof-merge-iteration", cl::init(true), cl::Hidden, cl::desc("Iteratively apply merging on a node to catch new callers"))
static bool isMemProfClone(const Function &F)
static cl::opt< unsigned > AllocIdForDot("memprof-dot-alloc-id", cl::init(0), cl::Hidden, cl::desc("Id of alloc to export if -memprof-dot-scope=alloc " "or to highlight if -memprof-dot-scope=all"))
static cl::opt< unsigned > ContextIdForDot("memprof-dot-context-id", cl::init(0), cl::Hidden, cl::desc("Id of context to export if -memprof-dot-scope=context or to " "highlight otherwise"))
static cl::opt< bool > ExportToDot("memprof-export-to-dot", cl::init(false), cl::Hidden, cl::desc("Export graph to dot files."))
static void checkEdge(const std::shared_ptr< ContextEdge< DerivedCCG, FuncTy, CallTy > > &Edge)
static cl::opt< bool > AllowRecursiveCallsites("memprof-allow-recursive-callsites", cl::init(true), cl::Hidden, cl::desc("Allow cloning of callsites involved in recursive cycles"))
bool checkColdOrNotCold(uint8_t AllocType)
static ValueInfo findValueInfoForFunc(const Function &F, const Module &M, const ModuleSummaryIndex *ImportSummary, const Function *CallingFunc=nullptr)
static cl::opt< bool > CloneRecursiveContexts("memprof-clone-recursive-contexts", cl::init(true), cl::Hidden, cl::desc("Allow cloning of contexts through recursive cycles"))
static std::string getAllocTypeString(uint8_t AllocTypes)
bool DOTGraphTraits< constCallsiteContextGraph< DerivedCCG, FuncTy, CallTy > * >::DoHighlight
static unsigned getMemProfCloneNum(const Function &F)
static cl::opt< unsigned > MemProfICPNoInlineThreshold("memprof-icp-noinline-threshold", cl::init(0), cl::Hidden, cl::desc("Minimum absolute count for promoted target to be inlinable"))
static SmallVector< std::unique_ptr< ValueToValueMapTy >, 4 > createFunctionClones(Function &F, unsigned NumClones, Module &M, OptimizationRemarkEmitter &ORE, std::map< const Function *, SmallPtrSet< const GlobalAlias *, 1 > > &FuncToAliasMap, FunctionSummary *FS)
static cl::opt< bool > VerifyCCG("memprof-verify-ccg", cl::init(false), cl::Hidden, cl::desc("Perform verification checks on CallingContextGraph."))
static void checkNode(const ContextNode< DerivedCCG, FuncTy, CallTy > *Node, bool CheckEdges=true)
static cl::opt< bool > MergeClones("memprof-merge-clones", cl::init(true), cl::Hidden, cl::desc("Merge clones before assigning functions"))
static std::string getMemProfFuncName(Twine Base, unsigned CloneNo)
static cl::opt< std::string > MemProfImportSummary("memprof-import-summary", cl::desc("Import summary to use for testing the ThinLTO backend via opt"), cl::Hidden)
static const std::string MemProfCloneSuffix
static void updateSubprogramLinkageName(Function *NewFunc, StringRef Name)
static cl::opt< bool > AllowRecursiveContexts("memprof-allow-recursive-contexts", cl::init(true), cl::Hidden, cl::desc("Allow cloning of contexts having recursive cycles"))
static cl::opt< std::string > DotFilePathPrefix("memprof-dot-file-path-prefix", cl::init(""), cl::Hidden, cl::value_desc("filename"), cl::desc("Specify the path prefix of the MemProf dot files."))
static cl::opt< bool > VerifyNodes("memprof-verify-nodes", cl::init(false), cl::Hidden, cl::desc("Perform frequent verification checks on nodes."))
static void checkAllocContextIds(const AllocInfo &AllocNode, const MDNode *MemProfMD, const CallStack< MDNode, MDNode::op_iterator > &CallsiteContext, const ModuleSummaryIndex *ImportSummary)
static cl::opt< bool > DumpCCG("memprof-dump-ccg", cl::init(false), cl::Hidden, cl::desc("Dump CallingContextGraph to stdout after each stage."))
AllocType
This is the interface to build a ModuleSummaryIndex for a module.
ModuleSummaryIndex.h This file contains the declarations the classes that hold the module index and s...
#define P(N)
if(auto Err=PB.parsePassPipeline(MPM, Passes)) return wrap(std MPM run * Mod
FunctionAnalysisManager FAM
if(PassOpts->AAPipeline)
const char * Msg
std::pair< BasicBlock *, BasicBlock * > Edge
This file defines generic set operations that may be used on set's of different types,...
This file defines the SmallPtrSet class.
This file defines the SmallSet class.
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Definition Statistic.h:171
This file contains some functions that are useful when dealing with strings.
#define LLVM_DEBUG(...)
Definition Debug.h:119
void print(OutputBuffer &OB) const
ValueInfo getAliaseeVI() const
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
iterator end() const
Definition ArrayRef.h:130
const_pointer iterator
Definition ArrayRef.h:47
iterator begin() const
Definition ArrayRef.h:129
bool empty() const
Check if the array is empty.
Definition ArrayRef.h:136
static LLVM_ABI Attribute get(LLVMContext &Context, AttrKind Kind, uint64_t Val=0)
Return a uniquified Attribute object.
void addFnAttr(Attribute::AttrKind Kind)
Adds the attribute to the function.
void setCalledOperand(Value *V)
Subprogram description. Uses SubclassData1.
ValueT lookup(const_arg_type_t< KeyT > Val) const
Return the entry for the specified key, or a default constructed value if no such entry exists.
Definition DenseMap.h:250
iterator find(const_arg_type_t< KeyT > Val)
Definition DenseMap.h:223
unsigned size() const
Definition DenseMap.h:172
bool empty() const
Definition DenseMap.h:171
size_type count(const_arg_type_t< KeyT > Val) const
Return 1 if the specified key is in the map, 0 otherwise.
Definition DenseMap.h:219
iterator end()
Definition DenseMap.h:141
bool contains(const_arg_type_t< KeyT > Val) const
Return true if the specified key is in the map, false otherwise.
Definition DenseMap.h:214
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Definition DenseMap.h:284
void reserve(size_type NumEntries)
Grow the densemap so that it can contain at least NumEntries items before resizing again.
Definition DenseMap.h:176
Implements a dense probed hash-table based set.
Definition DenseSet.h:281
Function summary information to aid decisions and implementation of importing.
FunctionType * getFunctionType() const
Returns the FunctionType for me.
Definition Function.h:211
DISubprogram * getSubprogram() const
Get the attached subprogram.
const Function & getFunction() const
Definition Function.h:166
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition Function.cpp:353
static LLVM_ABI GlobalAlias * create(Type *Ty, unsigned AddressSpace, LinkageTypes Linkage, const Twine &Name, Constant *Aliasee, Module *Parent)
If a parent module is specified, the alias is automatically inserted into the end of the specified mo...
Definition Globals.cpp:692
Function and variable summary information to aid decisions and implementation of importing.
static LLVM_ABI GUID getGUIDAssumingExternalLinkage(StringRef GlobalName)
Return a 64-bit global unique ID constructed from the name of a global symbol.
Definition Globals.cpp:80
static bool isLocalLinkage(LinkageTypes Linkage)
LLVM_ABI bool isDeclaration() const
Return true if the primary definition of this global value is outside of the current translation unit...
Definition Globals.cpp:408
uint64_t GUID
Declare a type to represent a global unique identifier for a global value.
Module * getParent()
Get the module that this global value is contained inside of...
LLVM_ABI void eraseFromParent()
This method unlinks 'this' from the containing module and deletes it.
Definition Globals.cpp:158
static LLVM_ABI std::string getGlobalIdentifier(StringRef Name, GlobalValue::LinkageTypes Linkage, StringRef FileName)
Return the modified name for a global value suitable to be used as the key for a global lookup (e....
Definition Globals.cpp:234
bool isWeakForLinker() const
@ InternalLinkage
Rename collisions when linking (static functions).
Definition GlobalValue.h:60
LLVM_ABI const Function * getFunction() const
Return the function this instruction belongs to.
MDNode * getMetadata(unsigned KindID) const
Get the metadata of given kind attached to this Instruction.
LLVM_ABI void setMetadata(unsigned KindID, MDNode *Node)
Set the metadata of the specified kind to the specified node.
This is an important class for using LLVM in a threaded context.
Definition LLVMContext.h:68
Metadata node.
Definition Metadata.h:1069
const MDOperand & getOperand(unsigned I) const
Definition Metadata.h:1426
ArrayRef< MDOperand > operands() const
Definition Metadata.h:1424
unsigned getNumOperands() const
Return number of MDNode operands.
Definition Metadata.h:1432
LLVM_ABI TempMDNode clone() const
Create a (temporary) clone of this.
Definition Metadata.cpp:684
static std::enable_if_t< std::is_base_of< MDNode, T >::value, T * > replaceWithUniqued(std::unique_ptr< T, TempMDNodeDeleter > N)
Replace a temporary node with a uniqued one.
Definition Metadata.h:1301
static LLVM_ABI MDString * get(LLVMContext &Context, StringRef Str)
Definition Metadata.cpp:615
This class implements a map that also provides access to all stored values in a deterministic order.
Definition MapVector.h:38
size_type count(const KeyT &Key) const
Definition MapVector.h:152
LLVM_ABI MemProfContextDisambiguation(const ModuleSummaryIndex *Summary=nullptr, bool isSamplePGO=false)
LLVM_ABI PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
LLVM_ABI PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
static ErrorOr< std::unique_ptr< MemoryBuffer > > getFile(const Twine &Filename, bool IsText=false, bool RequiresNullTerminator=true, bool IsVolatile=false, std::optional< Align > Alignment=std::nullopt)
Open the specified file as a MemoryBuffer, returning a new MemoryBuffer if successful,...
Class to hold module path string table and global value map, and encapsulate methods for operating on...
static StringRef getOriginalNameBeforePromote(StringRef Name)
Helper to obtain the unpromoted name for a global value (or the original name if not promoted).
ValueInfo getValueInfo(const GlobalValueSummaryMapTy::value_type &R) const
Return a ValueInfo for the index value_type (convenient when iterating index).
uint64_t getStackIdAtIndex(unsigned Index) const
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:67
LLVMContext & getContext() const
Get the global data context.
Definition Module.h:327
A NodeSet contains a set of SUnit DAG nodes with additional information that assigns a priority to th...
unsigned size() const
bool insert(SUnit *SU)
The optimization diagnostic interface.
bool allowExtraAnalysis(StringRef PassName) const
Whether we allow for extra compile-time budget to perform more analysis to produce fewer false positi...
LLVM_ABI void emit(DiagnosticInfoOptimizationBase &OptDiag)
Output the remark via the diagnostic handler and to the optimization record file.
Diagnostic information for applied optimization remarks.
A discriminated union of two or more pointer types, with the discriminator in the low bits of the poi...
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
Definition Analysis.h:115
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
A class that wrap the SHA1 algorithm.
Definition SHA1.h:27
LLVM_ABI void update(ArrayRef< uint8_t > Data)
Digest more data.
Definition SHA1.cpp:208
LLVM_ABI std::array< uint8_t, 20 > result()
Return the current raw 160-bits SHA1 for the digested data since the last call to init().
Definition SHA1.cpp:288
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
Definition SmallSet.h:184
reference emplace_back(ArgTypes &&... Args)
void reserve(size_type N)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Definition Value.cpp:553
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
Definition Value.cpp:319
std::pair< iterator, bool > insert(const ValueT &V)
Definition DenseSet.h:209
bool contains(const_arg_type_t< ValueT > V) const
Check if the set contains the given element.
Definition DenseSet.h:182
bool erase(const ValueT &V)
Definition DenseSet.h:97
void insert_range(Range &&R)
Definition DenseSet.h:235
void swap(DenseSetImpl &RHS)
Definition DenseSet.h:109
size_type size() const
Definition DenseSet.h:84
size_type count(const_arg_type_t< ValueT > V) const
Return 1 if the specified key is in the set, 0 otherwise.
Definition DenseSet.h:187
void reserve(size_t Size)
Grow the DenseSet so that it can contain at least NumEntries items before resizing again.
Definition DenseSet.h:93
An efficient, type-erasing, non-owning reference to a callable.
Helper class to iterate through stack ids in both metadata (memprof MIB and callsite) and the corresp...
CallStackIterator beginAfterSharedPrefix(const CallStack &Other)
CallStackIterator end() const
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
CallInst * Call
Changed
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ Entry
Definition COFF.h:862
@ CE
Windows NT (Windows on ARM)
Definition MCAsmInfo.h:51
ValuesClass values(OptsTy... Options)
Helper to build a ValuesClass by forwarding a variable number of arguments as an initializer list to ...
initializer< Ty > init(const Ty &Val)
std::enable_if_t< detail::IsValidPointer< X, Y >::value, X * > dyn_extract(Y &&MD)
Extract a Value from Metadata, if any.
Definition Metadata.h:696
LLVM_ABI AllocationType getMIBAllocType(const MDNode *MIB)
Returns the allocation type from an MIB metadata node.
LLVM_ABI bool metadataMayIncludeContextSizeInfo()
Whether the alloc memprof metadata may include context size info for some MIBs (but possibly not all)...
LLVM_ABI bool hasSingleAllocType(uint8_t AllocTypes)
True if the AllocTypes bitmask contains just a single type.
LLVM_ABI std::string getAllocTypeAttributeString(AllocationType Type)
Returns the string to use in attributes with the given type.
LLVM_ABI MDNode * getMIBStackNode(const MDNode *MIB)
Returns the stack node from an MIB metadata node.
LLVM_ABI void removeAnyExistingAmbiguousAttribute(CallBase *CB)
Removes any existing "ambiguous" memprof attribute.
DiagnosticInfoOptimizationBase::Argument NV
LLVM_ABI CallBase & promoteIndirectCall(CallBase &CB, Function *F, uint64_t Count, uint64_t TotalCount, bool AttachProfToDirectCall, OptimizationRemarkEmitter *ORE)
uint32_t NodeId
Definition RDFGraph.h:262
NodeAddr< NodeBase * > Node
Definition RDFGraph.h:381
NodeAddr< FuncNode * > Func
Definition RDFGraph.h:393
bool empty() const
Definition BasicBlock.h:101
friend class Instruction
Iterator for Instructions in a `BasicBlock.
Definition BasicBlock.h:73
uint64_t read64le(const void *P)
Definition Endian.h:415
void write32le(void *P, uint32_t V)
Definition Endian.h:455
This is an optimization pass for GlobalISel generic memory operations.
cl::opt< unsigned > MinClonedColdBytePercent("memprof-cloning-cold-threshold", cl::init(100), cl::Hidden, cl::desc("Min percent of cold bytes to hint alloc cold during cloning"))
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
Definition STLExtras.h:315
void dump(const SparseBitVector< ElementSize > &LHS, raw_ostream &out)
LLVM_ABI void logAllUnhandledErrors(Error E, raw_ostream &OS, Twine ErrorBanner={})
Log all errors (if any) in E to OS.
Definition Error.cpp:61
void stable_sort(R &&Range)
Definition STLExtras.h:2116
cl::opt< bool > MemProfReportHintedSizes("memprof-report-hinted-sizes", cl::init(false), cl::Hidden, cl::desc("Report total allocation sizes of hinted allocations"))
LLVM_ABI bool isLegalToPromote(const CallBase &CB, Function *Callee, const char **FailureReason=nullptr)
Return true if the given indirect call site can be made to call Callee.
Printable print(const GCNRegPressure &RP, const GCNSubtarget *ST=nullptr, unsigned DynamicVGPRBlockSize=0)
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
Definition STLExtras.h:2554
void set_intersect(S1Ty &S1, const S2Ty &S2)
set_intersect(A, B) - Compute A := A ^ B Identical to set_intersection, except that it works on set<>...
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
LLVM_ABI bool mayHaveMemprofSummary(const CallBase *CB)
Returns true if the instruction could have memprof metadata, used to ensure consistency between summa...
constexpr from_range_t from_range
static cl::opt< bool > MemProfRequireDefinitionForPromotion("memprof-require-definition-for-promotion", cl::init(false), cl::Hidden, cl::desc("Require target function definition when promoting indirect calls"))
auto dyn_cast_if_present(const Y &Val)
dyn_cast_if_present<X> - Functionally identical to dyn_cast, except that a null (or none in the case ...
Definition Casting.h:732
cl::opt< unsigned > MemProfTopNImportant("memprof-top-n-important", cl::init(10), cl::Hidden, cl::desc("Number of largest cold contexts to consider important"))
bool set_is_subset(const S1Ty &S1, const S2Ty &S2)
set_is_subset(A, B) - Return true iff A in B
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
Definition STLExtras.h:2208
void set_subtract(S1Ty &S1, const S2Ty &S2)
set_subtract(A, B) - Compute A := A - B
InnerAnalysisManagerProxy< FunctionAnalysisManager, Module > FunctionAnalysisManagerModuleProxy
Provide the FunctionAnalysisManager to Module proxy.
raw_ostream & WriteGraph(raw_ostream &O, const GraphType &G, bool ShortNames=false, const Twine &Title="")
bool set_intersects(const S1Ty &S1, const S2Ty &S2)
set_intersects(A, B) - Return true iff A ^ B is non empty
detail::concat_range< ValueT, RangeTs... > concat(RangeTs &&...Ranges)
Returns a concatenated range across two or more ranges.
Definition STLExtras.h:1151
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Definition InstrProf.h:143
LLVM_ABI Expected< std::unique_ptr< ModuleSummaryIndex > > getModuleSummaryIndex(MemoryBufferRef Buffer)
Parse the specified bitcode buffer, returning the module summary index.
auto dyn_cast_or_null(const Y &Val)
Definition Casting.h:753
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1746
LLVM_ABI void annotateValueSite(Module &M, Instruction &Inst, const InstrProfRecord &InstrProfR, InstrProfValueKind ValueKind, uint32_t SiteIndx, uint32_t MaxMDCount=3)
Get the value profile data for value site SiteIdx from InstrProfR and annotate the instruction Inst w...
cl::opt< unsigned > MaxSummaryIndirectEdges("module-summary-max-indirect-edges", cl::init(0), cl::Hidden, cl::desc("Max number of summary edges added from " "indirect call profile metadata"))
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
bool none_of(R &&Range, UnaryPredicate P)
Provide wrappers to std::none_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1753
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
bool set_union(S1Ty &S1, const S2Ty &S2)
set_union(A, B) - Compute A := A u B, return whether A changed.
cl::opt< bool > SupportsHotColdNew
Indicate we are linking with an allocator that supports hot/cold operator new interfaces.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
S1Ty set_intersection(const S1Ty &S1, const S2Ty &S2)
set_intersection(A, B) - Return A ^ B
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
cl::opt< bool > EnableMemProfContextDisambiguation
Enable MemProf context disambiguation for thin link.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Count
Definition InstrProf.h:145
S1Ty set_difference(const S1Ty &S1, const S2Ty &S2)
set_difference(A, B) - Return A - B
raw_ostream & operator<<(raw_ostream &OS, const APFixedPoint &FX)
Expected< T > errorOrToExpected(ErrorOr< T > &&EO)
Convert an ErrorOr<T> to an Expected<T>.
Definition Error.h:1261
ArrayRef(const T &OneElt) -> ArrayRef< T >
std::string toString(const APInt &I, unsigned Radix, bool Signed, bool formatAsCLiteral=false, bool UpperCase=true, bool InsertSeparators=false)
ValueMap< const Value *, WeakTrackingVH > ValueToValueMapTy
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1772
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition STLExtras.h:1947
LLVM_ABI Function * CloneFunction(Function *F, ValueToValueMapTy &VMap, ClonedCodeInfo *CodeInfo=nullptr)
Return a copy of the specified function and add it to that function's module.
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
Definition MIRParser.h:39
cl::opt< bool > MemProfFixupImportant("memprof-fixup-important", cl::init(true), cl::Hidden, cl::desc("Enables edge fixup for important contexts"))
#define N
static std::string getEdgeAttributes(NodeRef, ChildIteratorType ChildIter, GraphType G)
static const ContextNode< DerivedCCG, FuncTy, CallTy > * GetCallee(const EdgePtrTy &P)
std::unique_ptr< ContextNode< DerivedCCG, FuncTy, CallTy > > NodePtrTy
mapped_iterator< typename std::vector< std::shared_ptr< ContextEdge< DerivedCCG, FuncTy, CallTy > > >::const_iterator, decltype(&GetCallee)> ChildIteratorType
mapped_iterator< typename std::vector< NodePtrTy >::const_iterator, decltype(&getNode)> nodes_iterator
std::shared_ptr< ContextEdge< DerivedCCG, FuncTy, CallTy > > EdgePtrTy
Summary of memprof metadata on allocations.
std::vector< MIBInfo > MIBs
SmallVector< unsigned > StackIdIndices
SmallVector< unsigned > Clones
DOTGraphTraits - Template class that can be specialized to customize how graphs are converted to 'dot...
DefaultDOTGraphTraits(bool simple=false)
An information struct used to provide DenseMap with the various necessary components for a given valu...
typename GraphType::UnknownGraphTypeError NodeRef
Definition GraphTraits.h:95
Struct that holds a reference to a particular GUID in a global value summary.
ArrayRef< std::unique_ptr< GlobalValueSummary > > getSummaryList() const
GlobalValue::GUID getGUID() const
PointerUnion< CallsiteInfo *, AllocInfo * > SimpleType
static SimpleType getSimplifiedValue(IndexCall &Val)
const PointerUnion< CallsiteInfo *, AllocInfo * > SimpleType
static SimpleType getSimplifiedValue(const IndexCall &Val)
Define a template that can be specialized by smart pointers to reflect the fact that they are automat...
Definition Casting.h:34