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(FoundProfiledCalleeIndirectTailCallCount,
97 "Number of tail calls in chains to profiled callees that are "
98 "indirect (thin link)");
99STATISTIC(IndirectTailCallsRecordedForICPThinBackend,
100 "Number of indirect tail calls recorded for ICP for cloning during "
101 "ThinLTO backend");
102STATISTIC(DeferredBackedges, "Number of backedges with deferred cloning");
103STATISTIC(NewMergedNodes, "Number of new nodes created during merging");
104STATISTIC(NonNewMergedNodes, "Number of non new nodes used during merging");
105STATISTIC(MissingAllocForContextId,
106 "Number of missing alloc nodes for context ids");
107STATISTIC(SkippedCallsCloning,
108 "Number of calls skipped during cloning due to unexpected operand");
109STATISTIC(MismatchedCloneAssignments,
110 "Number of callsites assigned to call multiple non-matching clones");
111STATISTIC(TotalMergeInvokes, "Number of merge invocations for nodes");
112STATISTIC(TotalMergeIters, "Number of merge iterations for nodes");
113STATISTIC(MaxMergeIters, "Max merge iterations for nodes");
114STATISTIC(NumImportantContextIds, "Number of important context ids");
115STATISTIC(NumFixupEdgeIdsInserted, "Number of fixup edge ids inserted");
116STATISTIC(NumFixupEdgesAdded, "Number of fixup edges added");
117STATISTIC(NumFixedContexts, "Number of contexts with fixed edges");
118STATISTIC(NumImplicitCallersAssigned,
119 "Number of callsite clones without an edge to a callee's clones "
120 "assigned the callee function clone of their original node");
121STATISTIC(NumImplicitCallersSourced,
122 "Number of calls in function clones whose callee was taken from a "
123 "callsite clone an implicit caller requires");
124STATISTIC(NumTrimmedContextIds,
125 "Number of context ids with call stacks trimmed at a callsite");
126STATISTIC(NumImplicitCallersUnresolved,
127 "Number of callsite clones without an edge to a callee's clones "
128 "left in a function clone calling a conflicting callee clone");
129STATISTIC(AliaseesPrevailingInDiffModuleFromAlias,
130 "Number of aliasees prevailing in a different module than its alias");
131STATISTIC(NumClonedCalleeCallsites,
132 "Number of summary callsites assigned to call a cloned callee (thin "
133 "link)");
134STATISTIC(NumClonedCalleeIndirectCallsites,
135 "Number of summary callsites assigned to call a cloned callee with "
136 "an indirect call edge (thin link)");
137STATISTIC(NumClonedCalleeEdgesMarkedRequiresDeclImport,
138 "Number of summary indirect call edges to cloned callees marked as "
139 "requiring a declaration import (thin link)");
140
142 "memprof-dot-file-path-prefix", cl::init(""), cl::Hidden,
143 cl::value_desc("filename"),
144 cl::desc("Specify the path prefix of the MemProf dot files."));
145
146static cl::opt<bool> ExportToDot("memprof-export-to-dot", cl::init(false),
148 cl::desc("Export graph to dot files."));
149
150// TODO: Remove this option once new handling is validated more widely.
152 "memprof-merge-iteration", cl::init(true), cl::Hidden,
153 cl::desc("Iteratively apply merging on a node to catch new callers"));
154
155// How much of the graph to export to dot.
157 All, // The full CCG graph.
158 Alloc, // Only contexts for the specified allocation.
159 Context, // Only the specified context.
160};
161
163 "memprof-dot-scope", cl::desc("Scope of graph to export to dot"),
166 clEnumValN(DotScope::All, "all", "Export full callsite graph"),
168 "Export only nodes with contexts feeding given "
169 "-memprof-dot-alloc-id"),
170 clEnumValN(DotScope::Context, "context",
171 "Export only nodes with given -memprof-dot-context-id")));
172
174 AllocIdForDot("memprof-dot-alloc-id", cl::init(0), cl::Hidden,
175 cl::desc("Id of alloc to export if -memprof-dot-scope=alloc "
176 "or to highlight if -memprof-dot-scope=all"));
177
179 "memprof-dot-context-id", cl::init(0), cl::Hidden,
180 cl::desc("Id of context to export if -memprof-dot-scope=context or to "
181 "highlight otherwise"));
182
183static cl::opt<bool>
184 DumpCCG("memprof-dump-ccg", cl::init(false), cl::Hidden,
185 cl::desc("Dump CallingContextGraph to stdout after each stage."));
186
187static cl::opt<bool>
188 VerifyCCG("memprof-verify-ccg", cl::init(false), cl::Hidden,
189 cl::desc("Perform verification checks on CallingContextGraph."));
190
191static cl::opt<bool>
192 VerifyNodes("memprof-verify-nodes", cl::init(false), cl::Hidden,
193 cl::desc("Perform frequent verification checks on nodes."));
194
196 "memprof-import-summary",
197 cl::desc("Import summary to use for testing the ThinLTO backend via opt"),
198 cl::Hidden);
199
201 TailCallSearchDepth("memprof-tail-call-search-depth", cl::init(5),
203 cl::desc("Max depth to recursively search for missing "
204 "frames through tail calls."));
205
206// Whether the ThinLTO search for frames missing due to tail calls should look
207// through indirect tail calls, via the summary call edges to their profiled
208// targets.
210 "memprof-indirect-tail-call-search", cl::init(true), cl::Hidden,
211 cl::desc("Search for missing frames through indirect tail calls to their "
212 "profiled targets (ThinLTO)."));
213
214// Optionally enable cloning of callsites involved with recursive cycles
216 "memprof-allow-recursive-callsites", cl::init(true), cl::Hidden,
217 cl::desc("Allow cloning of callsites involved in recursive cycles"));
218
220 "memprof-clone-recursive-contexts", cl::init(true), cl::Hidden,
221 cl::desc("Allow cloning of contexts through recursive cycles"));
222
223// Generally this is needed for correct assignment of allocation clones to
224// function clones, however, allow it to be disabled for debugging while the
225// functionality is new and being tested more widely.
226static cl::opt<bool>
227 MergeClones("memprof-merge-clones", cl::init(true), cl::Hidden,
228 cl::desc("Merge clones before assigning functions"));
229
230// When disabled, try to detect and prevent cloning of recursive contexts.
231// This is only necessary until we support cloning through recursive cycles.
232// Leave on by default for now, as disabling requires a little bit of compile
233// time overhead and doesn't affect correctness, it will just inflate the cold
234// hinted bytes reporting a bit when -memprof-report-hinted-sizes is enabled.
236 "memprof-allow-recursive-contexts", cl::init(true), cl::Hidden,
237 cl::desc("Allow cloning of contexts having recursive cycles"));
238
239// Set the minimum absolute count threshold for allowing inlining of indirect
240// calls promoted during cloning.
242 "memprof-icp-noinline-threshold", cl::init(0), cl::Hidden,
243 cl::desc("Minimum absolute count for promoted target to be inlinable"));
244
245namespace llvm {
247 "enable-memprof-context-disambiguation", cl::Hidden,
248 cl::desc("Enable MemProf context disambiguation"));
249
250// Indicate we are linking with an allocator that supports hot/cold operator
251// new interfaces.
253 "supports-hot-cold-new", cl::init(false), cl::Hidden,
254 cl::desc("Linking with hot/cold operator new interfaces"));
255
257 "memprof-require-definition-for-promotion", cl::init(false), cl::Hidden,
258 cl::desc(
259 "Require target function definition when promoting indirect calls"));
260
261// Applying the thin link cloning decisions to indirect calls requires the
262// ThinLTO backend to perform ICP to the profiled target, which requires that
263// the target be available in the caller's module (or in any module the caller
264// is imported into). When the target is defined in a different module it must
265// be imported, but the profiled targets are often synthesized from the MemProf
266// profile with a small count, so their summary edges are not hot and large
267// targets are often not imported. Since the thin link cloning runs before the
268// function importing analysis, we can mark the indirect call edges to callees
269// of callsites that were assigned to call a cloned callee as requiring a
270// declaration import, in which case the function importer imports at least a
271// declaration of the callee into any module containing the caller that
272// doesn't define the callee. Direct calls don't require importing the callee,
273// since the ThinLTO backend can simply call a declaration of the callee clone,
274// so we only do this for edges marked as being from indirect calls in the
275// summary. Note that unlike regular ICP, which by default requires the
276// target's definition (see -icp-allow-decls), MemProf ICP can promote to a
277// declaration of the target (see -memprof-require-definition-for-promotion),
278// since the purpose is to call the assigned clone rather than to inline. This
279// is therefore not done under -memprof-require-definition-for-promotion.
281 "memprof-import-cloned-indirect-targets", cl::init(true), cl::Hidden,
282 cl::desc("Import at least a declaration of the indirect call targets of "
283 "callsites assigned to call a cloned callee (needed for MemProf "
284 "ICP in the ThinLTO backend)"));
285
288
289// Appends a per-context diagnostic suffix to each -memprof-report-hinted-sizes
290// line: the allocation function clone, how far the context matched, and the
291// post-cloning call paths from the outermost matched caller to the reached
292// allocation clone(s) and their final hints. Requires
293// -memprof-report-hinted-sizes, and adds some memory and time overhead.
295 "memprof-report-hinted-sizes-detail", cl::init(false), cl::Hidden,
296 cl::desc("Append post-cloning call path and matching details to each "
297 "-memprof-report-hinted-sizes line"));
298
299// Post-cloning call paths in the detail suffix longer than this (in functions)
300// have runs of uncloned (or cloned) functions in their middle elided to
301// "...", keeping the ends and every cloned/uncloned transition.
303 "memprof-report-hinted-sizes-detail-max-path-len", cl::init(7), cl::Hidden,
304 cl::desc("Maximum number of functions printed in full for a post-cloning "
305 "call path in the -memprof-report-hinted-sizes-detail suffix; "
306 "longer paths are elided in the middle"));
307
309 "memprof-top-n-important", cl::init(10), cl::Hidden,
310 cl::desc("Number of largest cold contexts to consider important"));
311
313 "memprof-fixup-important", cl::init(true), cl::Hidden,
314 cl::desc("Enables edge fixup for important contexts"));
315
316} // namespace llvm
317
318namespace {
319
320/// CRTP base for graphs built from either IR or ThinLTO summary index.
321///
322/// The graph represents the call contexts in all memprof metadata on allocation
323/// calls, with nodes for the allocations themselves, as well as for the calls
324/// in each context. The graph is initially built from the allocation memprof
325/// metadata (or summary) MIBs. It is then updated to match calls with callsite
326/// metadata onto the nodes, updating it to reflect any inlining performed on
327/// those calls.
328///
329/// Each MIB (representing an allocation's call context with allocation
330/// behavior) is assigned a unique context id during the graph build. The edges
331/// and nodes in the graph are decorated with the context ids they carry. This
332/// is used to correctly update the graph when cloning is performed so that we
333/// can uniquify the context for a single (possibly cloned) allocation.
334template <typename DerivedCCG, typename FuncTy, typename CallTy>
335class CallsiteContextGraph {
336public:
337 CallsiteContextGraph() = default;
338 CallsiteContextGraph(const CallsiteContextGraph &) = default;
339 CallsiteContextGraph(CallsiteContextGraph &&) = default;
340
341 /// Main entry point to perform analysis and transformations on graph.
342 bool process(function_ref<void(StringRef, StringRef, const Twine &)>
343 EmitRemark = nullptr,
344 bool AllowExtraAnalysis = false);
345
346 /// Perform cloning on the graph necessary to uniquely identify the allocation
347 /// behavior of an allocation based on its context.
348 void identifyClones();
349
350 /// Assign callsite clones to functions, cloning functions as needed to
351 /// accommodate the combinations of their callsite clones reached by callers.
352 /// For regular LTO this clones functions and callsites in the IR, but for
353 /// ThinLTO the cloning decisions are noted in the summaries and later applied
354 /// in applyImport.
355 bool assignFunctions();
356
357 void dump() const;
358 void print(raw_ostream &OS) const;
359 void printTotalSizes(raw_ostream &OS,
360 function_ref<void(StringRef, StringRef, const Twine &)>
361 EmitRemark = nullptr) const;
362
364 const CallsiteContextGraph &CCG) {
365 CCG.print(OS);
366 return OS;
367 }
368
369 friend struct GraphTraits<
370 const CallsiteContextGraph<DerivedCCG, FuncTy, CallTy> *>;
371 friend struct DOTGraphTraits<
372 const CallsiteContextGraph<DerivedCCG, FuncTy, CallTy> *>;
373
374 void exportToDot(std::string Label) const;
375
376 /// Represents a function clone via FuncTy pointer and clone number pair.
377 struct FuncInfo final
378 : public std::pair<FuncTy *, unsigned /*Clone number*/> {
379 using Base = std::pair<FuncTy *, unsigned>;
380 FuncInfo(const Base &B) : Base(B) {}
381 FuncInfo(FuncTy *F = nullptr, unsigned CloneNo = 0) : Base(F, CloneNo) {}
382 explicit operator bool() const { return this->first != nullptr; }
383 FuncTy *func() const { return this->first; }
384 unsigned cloneNo() const { return this->second; }
385 };
386
387 /// Represents a callsite clone via CallTy and clone number pair.
388 struct CallInfo final : public std::pair<CallTy, unsigned /*Clone number*/> {
389 using Base = std::pair<CallTy, unsigned>;
390 CallInfo(const Base &B) : Base(B) {}
391 CallInfo(CallTy Call = nullptr, unsigned CloneNo = 0)
392 : Base(Call, CloneNo) {}
393 explicit operator bool() const { return (bool)this->first; }
394 CallTy call() const { return this->first; }
395 unsigned cloneNo() const { return this->second; }
396 void setCloneNo(unsigned N) { this->second = N; }
397 void print(raw_ostream &OS) const {
398 if (!operator bool()) {
399 assert(!cloneNo());
400 OS << "null Call";
401 return;
402 }
403 call()->print(OS);
404 OS << "\t(clone " << cloneNo() << ")";
405 }
406 void dump() const {
407 print(dbgs());
408 dbgs() << "\n";
409 }
410 friend raw_ostream &operator<<(raw_ostream &OS, const CallInfo &Call) {
411 Call.print(OS);
412 return OS;
413 }
414 };
415
416 struct ContextEdge;
417
418 /// Node in the Callsite Context Graph
419 struct ContextNode {
420 // Assigned to nodes as they are created, useful for debugging.
421 unsigned NodeId = 0;
422
423 // Keep this for now since in the IR case where we have an Instruction* it
424 // is not as immediately discoverable. Used for printing richer information
425 // when dumping graph.
426 bool IsAllocation;
427
428 // Keeps track of when the Call was reset to null because there was
429 // recursion.
430 bool Recursive = false;
431
432 // This will be formed by ORing together the AllocationType enum values
433 // for contexts including this node.
434 uint8_t AllocTypes = 0;
435
436 // The corresponding allocation or interior call. This is the primary call
437 // for which we have created this node.
438 CallInfo Call;
439
440 // List of other calls that can be treated the same as the primary call
441 // through cloning. I.e. located in the same function and have the same
442 // (possibly trimmed) stack ids. They will be updated the same way as the
443 // primary call when assigning to function clones.
444 SmallVector<CallInfo, 0> MatchingCalls;
445
446 // For alloc nodes this is a unique id assigned when constructed, and for
447 // callsite stack nodes it is the original stack id when the node is
448 // constructed from the memprof MIB metadata on the alloc nodes. Note that
449 // this is only used when matching callsite metadata onto the stack nodes
450 // created when processing the allocation memprof MIBs, and for labeling
451 // nodes in the dot graph. Therefore we don't bother to assign a value for
452 // clones.
453 uint64_t OrigStackOrAllocId = 0;
454
455 // Edges to all callees in the profiled call stacks.
456 // TODO: Should this be a map (from Callee node) for more efficient lookup?
457 std::vector<std::shared_ptr<ContextEdge>> CalleeEdges;
458
459 // Edges to all callers in the profiled call stacks.
460 // TODO: Should this be a map (from Caller node) for more efficient lookup?
461 std::vector<std::shared_ptr<ContextEdge>> CallerEdges;
462
463 // Returns true if we need to look at the callee edges for determining the
464 // node context ids and allocation type.
465 bool useCallerEdgesForContextInfo() const {
466 // Typically if the callee edges are empty either the caller edges are
467 // also empty, or this is an allocation (leaf node). However, if we are
468 // allowing recursive callsites and contexts this will be violated for
469 // incompletely cloned recursive cycles.
470 assert(!CalleeEdges.empty() || CallerEdges.empty() || IsAllocation ||
472 // When cloning for a recursive context, during cloning we might be in the
473 // midst of cloning for a recurrence and have moved context ids off of a
474 // caller edge onto the clone but not yet off of the incoming caller
475 // (back) edge. If we don't look at those we miss the fact that this node
476 // still has context ids of interest.
477 return IsAllocation || CloneRecursiveContexts;
478 }
479
480 // Compute the context ids for this node from the union of its edge context
481 // ids.
482 DenseSet<uint32_t> getContextIds() const {
483 unsigned Count = 0;
484 // Compute the number of ids for reserve below. In general we only need to
485 // look at one set of edges, typically the callee edges, since other than
486 // allocations and in some cases during recursion cloning, all the context
487 // ids on the callers should also flow out via callee edges.
488 for (auto &Edge : CalleeEdges.empty() ? CallerEdges : CalleeEdges)
489 Count += Edge->getContextIds().size();
490 DenseSet<uint32_t> ContextIds;
491 ContextIds.reserve(Count);
493 CalleeEdges, useCallerEdgesForContextInfo()
494 ? CallerEdges
495 : std::vector<std::shared_ptr<ContextEdge>>());
496 for (const auto &Edge : Edges)
497 ContextIds.insert_range(Edge->getContextIds());
498 return ContextIds;
499 }
500
501 // Compute the allocation type for this node from the OR of its edge
502 // allocation types.
503 uint8_t computeAllocType() const {
504 uint8_t BothTypes =
505 (uint8_t)AllocationType::Cold | (uint8_t)AllocationType::NotCold;
506 uint8_t AllocType = (uint8_t)AllocationType::None;
508 CalleeEdges, useCallerEdgesForContextInfo()
509 ? CallerEdges
510 : std::vector<std::shared_ptr<ContextEdge>>());
511 for (const auto &Edge : Edges) {
512 AllocType |= Edge->AllocTypes;
513 // Bail early if alloc type reached both, no further refinement.
514 if (AllocType == BothTypes)
515 return AllocType;
516 }
517 return AllocType;
518 }
519
520 // The context ids set for this node is empty if its edge context ids are
521 // also all empty.
522 bool emptyContextIds() const {
524 CalleeEdges, useCallerEdgesForContextInfo()
525 ? CallerEdges
526 : std::vector<std::shared_ptr<ContextEdge>>());
527 for (const auto &Edge : Edges) {
528 if (!Edge->getContextIds().empty())
529 return false;
530 }
531 return true;
532 }
533
534 // Whether the given context id is among this node's context ids.
535 bool hasContextId(uint32_t Id) const {
537 CalleeEdges, useCallerEdgesForContextInfo()
538 ? CallerEdges
539 : std::vector<std::shared_ptr<ContextEdge>>());
540 for (const auto &Edge : Edges) {
541 if (Edge->getContextIds().contains(Id))
542 return true;
543 }
544 return false;
545 }
546
547 // List of clones of this ContextNode, initially empty.
548 std::vector<ContextNode *> Clones;
549
550 // If a clone, points to the original uncloned node.
551 ContextNode *CloneOf = nullptr;
552
553 ContextNode(bool IsAllocation) : IsAllocation(IsAllocation), Call() {}
554
555 ContextNode(bool IsAllocation, CallInfo C)
556 : IsAllocation(IsAllocation), Call(C) {}
557
558 void addClone(ContextNode *Clone) {
559 if (CloneOf) {
560 CloneOf->Clones.push_back(Clone);
561 Clone->CloneOf = CloneOf;
562 } else {
563 Clones.push_back(Clone);
564 assert(!Clone->CloneOf);
565 Clone->CloneOf = this;
566 }
567 }
568
569 ContextNode *getOrigNode() {
570 if (!CloneOf)
571 return this;
572 return CloneOf;
573 }
574
575 const ContextNode *getOrigNode() const {
576 if (!CloneOf)
577 return this;
578 return CloneOf;
579 }
580
581 void addOrUpdateCallerEdge(ContextNode *Caller, AllocationType AllocType,
582 unsigned int ContextId);
583
584 ContextEdge *findEdgeFromCallee(const ContextNode *Callee);
585 ContextEdge *findEdgeFromCaller(const ContextNode *Caller);
586 void eraseCalleeEdge(const ContextEdge *Edge);
587 void eraseCallerEdge(const ContextEdge *Edge);
588
589 void setCall(CallInfo C) { Call = std::move(C); }
590
591 bool hasCall() const { return (bool)Call.call(); }
592
593 void printCall(raw_ostream &OS) const { Call.print(OS); }
594
595 // True if this node was effectively removed from the graph, in which case
596 // it should have an allocation type of None and empty context ids.
597 bool isRemoved() const {
598 // Typically if the callee edges are empty either the caller edges are
599 // also empty, or this is an allocation (leaf node). However, if we are
600 // allowing recursive callsites and contexts this will be violated for
601 // incompletely cloned recursive cycles.
603 (AllocTypes == (uint8_t)AllocationType::None) ==
604 emptyContextIds());
605 return AllocTypes == (uint8_t)AllocationType::None;
606 }
607
608 void dump() const;
609 void print(raw_ostream &OS) const;
610
611 friend raw_ostream &operator<<(raw_ostream &OS, const ContextNode &Node) {
612 Node.print(OS);
613 return OS;
614 }
615 };
616
617 /// Edge in the Callsite Context Graph from a ContextNode N to a caller or
618 /// callee.
619 struct ContextEdge {
620 ContextNode *Callee;
621 ContextNode *Caller;
622
623 // This will be formed by ORing together the AllocationType enum values
624 // for contexts including this edge.
625 uint8_t AllocTypes = 0;
626
627 // Set just before initiating cloning when cloning of recursive contexts is
628 // enabled. Used to defer cloning of backedges until we have done cloning of
629 // the callee node for non-backedge caller edges. This exposes cloning
630 // opportunities through the backedge of the cycle.
631 // TODO: Note that this is not updated during cloning, and it is unclear
632 // whether that would be needed.
633 bool IsBackedge = false;
634
635 // The set of IDs for contexts including this edge.
636 DenseSet<uint32_t> ContextIds;
637
638 ContextEdge(ContextNode *Callee, ContextNode *Caller, uint8_t AllocType,
639 DenseSet<uint32_t> ContextIds)
640 : Callee(Callee), Caller(Caller), AllocTypes(AllocType),
641 ContextIds(std::move(ContextIds)) {}
642
643 DenseSet<uint32_t> &getContextIds() { return ContextIds; }
644
645 // Helper to clear the fields of this edge when we are removing it from the
646 // graph.
647 inline void clear() {
648 ContextIds.clear();
649 AllocTypes = (uint8_t)AllocationType::None;
650 Caller = nullptr;
651 Callee = nullptr;
652 }
653
654 // Check if edge was removed from the graph. This is useful while iterating
655 // over a copy of edge lists when performing operations that mutate the
656 // graph in ways that might remove one of the edges.
657 inline bool isRemoved() const {
658 if (Callee || Caller)
659 return false;
660 // Any edges that have been removed from the graph but are still in a
661 // shared_ptr somewhere should have all fields null'ed out by clear()
662 // above.
663 assert(AllocTypes == (uint8_t)AllocationType::None);
664 assert(ContextIds.empty());
665 return true;
666 }
667
668 void dump() const;
669 void print(raw_ostream &OS) const;
670
671 friend raw_ostream &operator<<(raw_ostream &OS, const ContextEdge &Edge) {
672 Edge.print(OS);
673 return OS;
674 }
675 };
676
677 /// Helpers to remove edges that have allocation type None (due to not
678 /// carrying any context ids) after transformations.
679 void removeNoneTypeCalleeEdges(ContextNode *Node);
680 void removeNoneTypeCallerEdges(ContextNode *Node);
681 void
682 recursivelyRemoveNoneTypeCalleeEdges(ContextNode *Node,
683 DenseSet<const ContextNode *> &Visited);
684
685protected:
686 /// Get a list of nodes corresponding to the stack ids in the given callsite
687 /// context.
688 template <class NodeT, class IteratorT>
689 std::vector<uint64_t>
690 getStackIdsWithContextNodes(CallStack<NodeT, IteratorT> &CallsiteContext);
691
692 /// Adds nodes for the given allocation and any stack ids on its memprof MIB
693 /// metadata (or summary).
694 ContextNode *addAllocNode(CallInfo Call, const FuncTy *F);
695
696 /// Adds nodes for the given MIB stack ids.
697 template <class NodeT, class IteratorT>
698 void addStackNodesForMIB(
699 ContextNode *AllocNode, CallStack<NodeT, IteratorT> &StackContext,
700 CallStack<NodeT, IteratorT> &CallsiteContext, AllocationType AllocType,
701 ArrayRef<ContextTotalSize> ContextSizeInfo,
702 std::map<uint64_t, uint32_t> &TotalSizeToContextIdTopNCold);
703
704 /// Matches all callsite metadata (or summary) to the nodes created for
705 /// allocation memprof MIB metadata, synthesizing new nodes to reflect any
706 /// inlining performed on those callsite instructions.
707 void updateStackNodes();
708
709 /// Optionally fixup edges for the N largest cold contexts to better enable
710 /// cloning. This is particularly helpful if the context includes recursion
711 /// as well as inlining, resulting in a single stack node for multiple stack
712 /// ids in the context. With recursion it is particularly difficult to get the
713 /// edge updates correct as in the general case we have lost the original
714 /// stack id ordering for the context. Do more expensive fixup for the largest
715 /// contexts, controlled by MemProfTopNImportant and MemProfFixupImportant.
716 void fixupImportantContexts();
717
718 /// Update graph to conservatively handle any callsite stack nodes that target
719 /// multiple different callee target functions.
720 void handleCallsitesWithMultipleTargets();
721
722 /// Mark backedges via the standard DFS based backedge algorithm.
723 void markBackedges();
724
725 /// Merge clones generated during cloning for different allocations but that
726 /// are called by the same caller node, to ensure proper function assignment.
727 void mergeClones();
728
729 // Try to partition calls on the given node (already placed into the AllCalls
730 // array) by callee function, creating new copies of Node as needed to hold
731 // calls with different callees, and moving the callee edges appropriately.
732 // Returns true if partitioning was successful.
733 bool partitionCallsByCallee(
734 ContextNode *Node, ArrayRef<CallInfo> AllCalls,
735 std::vector<std::pair<CallInfo, ContextNode *>> &NewCallToNode);
736
737 /// Save lists of calls with MemProf metadata in each function, for faster
738 /// iteration.
739 MapVector<FuncTy *, std::vector<CallInfo>> FuncToCallsWithMetadata;
740
741 /// Map from callsite node to the enclosing caller function.
742 std::map<const ContextNode *, const FuncTy *> NodeToCallingFunc;
743
744 const FuncTy *getCallingFunc(const ContextNode *N) const {
745 auto It = NodeToCallingFunc.find(N);
746 return It != NodeToCallingFunc.end() ? It->second : nullptr;
747 }
748
749 /// Functions that are referenced (called directly, or address-taken) in the
750 /// module or summary index. Only populated, at the start of reporting, when
751 /// MemProfReportHintedSizesDetail is enabled; used to distinguish allocation
752 /// functions with no references at all from those whose callers simply did
753 /// not match the profile.
754 DenseSet<const FuncTy *> FunctionsWithCallers;
755
756 // When exporting to dot, and an allocation id is specified, contains the
757 // context ids on that allocation.
758 DenseSet<uint32_t> DotAllocContextIds;
759
760private:
761 using EdgeIter = typename std::vector<std::shared_ptr<ContextEdge>>::iterator;
762
763 // Structure to keep track of information for each call as we are matching
764 // non-allocation callsites onto context nodes created from the allocation
765 // call metadata / summary contexts.
766 struct CallContextInfo {
767 // The callsite we're trying to match.
768 CallTy Call;
769 // The callsites stack ids that have a context node in the graph.
770 std::vector<uint64_t> StackIds;
771 // The function containing this callsite.
772 const FuncTy *Func;
773 // Initially empty, if needed this will be updated to contain the context
774 // ids for use in a new context node created for this callsite.
775 DenseSet<uint32_t> ContextIds;
776 };
777
778 /// Helper to remove edge from graph, updating edge iterator if it is provided
779 /// (in which case CalleeIter indicates which edge list is being iterated).
780 /// This will also perform the necessary clearing of the ContextEdge members
781 /// to enable later checking if the edge has been removed (since we may have
782 /// other copies of the shared_ptr in existence, and in fact rely on this to
783 /// enable removal while iterating over a copy of a node's edge list).
784 void removeEdgeFromGraph(ContextEdge *Edge, EdgeIter *EI = nullptr,
785 bool CalleeIter = true);
786
787 /// Assigns the given Node to calls at or inlined into the location with
788 /// the Node's stack id, after post order traversing and processing its
789 /// caller nodes. Uses the call information recorded in the given
790 /// StackIdToMatchingCalls map, and creates new nodes for inlined sequences
791 /// as needed. Called by updateStackNodes which sets up the given
792 /// StackIdToMatchingCalls map.
793 void assignStackNodesPostOrder(
794 ContextNode *Node, DenseSet<const ContextNode *> &Visited,
795 DenseMap<uint64_t, std::vector<CallContextInfo>> &StackIdToMatchingCalls,
796 DenseMap<CallInfo, CallInfo> &CallToMatchingCall,
797 const DenseSet<uint32_t> &ImportantContextIds);
798
799 /// Duplicates the given set of context ids, updating the provided
800 /// map from each original id with the newly generated context ids,
801 /// and returning the new duplicated id set.
802 DenseSet<uint32_t> duplicateContextIds(
803 const DenseSet<uint32_t> &StackSequenceContextIds,
804 DenseMap<uint32_t, DenseSet<uint32_t>> &OldToNewContextIds);
805
806 /// Propagates all duplicated context ids across the graph.
807 void propagateDuplicateContextIds(
808 const DenseMap<uint32_t, DenseSet<uint32_t>> &OldToNewContextIds);
809
810 /// Connect the NewNode to OrigNode's callees if TowardsCallee is true,
811 /// else to its callers. Also updates OrigNode's edges to remove any context
812 /// ids moved to the newly created edge.
813 void connectNewNode(ContextNode *NewNode, ContextNode *OrigNode,
814 bool TowardsCallee, const DenseSet<uint32_t> &ContextIds);
815
816 /// Get the stack id corresponding to the given Id or Index (for IR this will
817 /// return itself, for a summary index this will return the id recorded in the
818 /// index for that stack id index value).
819 uint64_t getStackId(uint64_t IdOrIndex) const {
820 return static_cast<const DerivedCCG *>(this)->getStackId(IdOrIndex);
821 }
822
823 /// Returns true if the given call targets the callee of the given edge, or if
824 /// we were able to identify the call chain through intermediate tail calls.
825 /// In the latter case new context nodes are added to the graph for the
826 /// identified tail calls, and their synthesized nodes are added to
827 /// TailCallToContextNodeMap. The EdgeIter is updated in the latter case for
828 /// the updated edges and to prepare it for an increment in the caller.
829 bool
830 calleesMatch(CallTy Call, EdgeIter &EI,
831 MapVector<CallInfo, ContextNode *> &TailCallToContextNodeMap);
832
833 // Return the callee function of the given call, or nullptr if it can't be
834 // determined
835 const FuncTy *getCalleeFunc(CallTy Call) {
836 return static_cast<DerivedCCG *>(this)->getCalleeFunc(Call);
837 }
838
839 /// Returns true if the given call targets the given function, or if we were
840 /// able to identify the call chain through intermediate tail calls (in which
841 /// case FoundCalleeChain will be populated).
842 bool calleeMatchesFunc(
843 CallTy Call, const FuncTy *Func, const FuncTy *CallerFunc,
844 std::vector<std::pair<CallTy, FuncTy *>> &FoundCalleeChain) {
845 return static_cast<DerivedCCG *>(this)->calleeMatchesFunc(
846 Call, Func, CallerFunc, FoundCalleeChain);
847 }
848
849 /// Returns true if both call instructions have the same callee.
850 bool sameCallee(CallTy Call1, CallTy Call2) {
851 return static_cast<DerivedCCG *>(this)->sameCallee(Call1, Call2);
852 }
853
854 /// Get a list of nodes corresponding to the stack ids in the given
855 /// callsite's context.
856 std::vector<uint64_t> getStackIdsWithContextNodesForCall(CallTy Call) {
857 return static_cast<DerivedCCG *>(this)->getStackIdsWithContextNodesForCall(
858 Call);
859 }
860
861 /// Get the last stack id in the context for callsite.
862 uint64_t getLastStackId(CallTy Call) {
863 return static_cast<DerivedCCG *>(this)->getLastStackId(Call);
864 }
865
866 /// Update the allocation call to record type of allocated memory.
867 void updateAllocationCall(CallInfo &Call, AllocationType AllocType) {
868 AllocType == AllocationType::Cold ? AllocTypeCold++ : AllocTypeNotCold++;
869 static_cast<DerivedCCG *>(this)->updateAllocationCall(Call, AllocType);
870 }
871
872 /// Get the AllocationType assigned to the given allocation instruction clone.
873 AllocationType getAllocationCallType(const CallInfo &Call) const {
874 return static_cast<const DerivedCCG *>(this)->getAllocationCallType(Call);
875 }
876
877 /// Update non-allocation call to invoke (possibly cloned) function
878 /// CalleeFunc.
879 void updateCall(CallInfo &CallerCall, FuncInfo CalleeFunc) {
880 static_cast<DerivedCCG *>(this)->updateCall(CallerCall, CalleeFunc);
881 }
882
883 /// Clone the given function for the given callsite, recording mapping of all
884 /// of the functions tracked calls to their new versions in the CallMap.
885 /// Assigns new clones to clone number CloneNo.
886 FuncInfo cloneFunctionForCallsite(
887 FuncInfo &Func, CallInfo &Call, DenseMap<CallInfo, CallInfo> &CallMap,
888 std::vector<CallInfo> &CallsWithMetadataInFunc, unsigned CloneNo) {
889 return static_cast<DerivedCCG *>(this)->cloneFunctionForCallsite(
890 Func, Call, CallMap, CallsWithMetadataInFunc, CloneNo);
891 }
892
893 /// Gets a label to use in the dot graph for the given call clone in the given
894 /// function.
895 std::string getLabel(const FuncTy *Func, const CallTy Call,
896 unsigned CloneNo) const {
897 return static_cast<const DerivedCCG *>(this)->getLabel(Func, Call, CloneNo);
898 }
899
900 /// Gets the function name (with optional clone suffix) for reporting.
901 std::string getFuncName(const FuncTy *Func, unsigned CloneNo = 0) const {
902 return static_cast<const DerivedCCG *>(this)->getFuncName(Func, CloneNo);
903 }
904
905 /// Returns true if the given function was marked dead by ThinLTO dead symbol
906 /// analysis.
907 bool isFuncDead(const FuncTy *Func) const {
908 return static_cast<const DerivedCCG *>(this)->isFuncDead(Func);
909 }
910
911 /// Populates FunctionsWithCallers (MemProfReportHintedSizesDetail only).
912 void populateFunctionsWithCallers() {
913 static_cast<DerivedCCG *>(this)->populateFunctionsWithCallers();
914 }
915
916 /// Records, before identifyClones(), the chain of (uncloned) nodes of every
917 /// context and how far it matched (MemProfReportHintedSizesDetail only).
918 void capturePreCloningContextInfo();
919
920 /// Formats the detail suffix for the report line of context Id, whose
921 /// (possibly cloned) allocation node is Node (MemProfReportHintedSizesDetail
922 /// only). See the option description for the format.
923 std::string formatContextReportSuffix(const ContextNode *Node,
924 uint32_t Id) const;
925
926 // Create and return a new ContextNode.
927 ContextNode *createNewNode(bool IsAllocation, const FuncTy *F = nullptr,
928 CallInfo C = CallInfo()) {
929 NodeOwner.push_back(std::make_unique<ContextNode>(IsAllocation, C));
930 auto *NewNode = NodeOwner.back().get();
931 if (F)
932 NodeToCallingFunc[NewNode] = F;
933 NewNode->NodeId = NodeOwner.size();
934 return NewNode;
935 }
936
937 /// Helpers to find the node corresponding to the given call or stackid.
938 ContextNode *getNodeForInst(const CallInfo &C);
939 ContextNode *getNodeForAlloc(const CallInfo &C);
940 ContextNode *getNodeForStackId(uint64_t StackId);
941
942 /// Computes the alloc type corresponding to the given context ids, by
943 /// unioning their recorded alloc types.
944 uint8_t computeAllocType(DenseSet<uint32_t> &ContextIds) const;
945
946 /// Returns the allocation type of the intersection of the contexts of two
947 /// nodes (based on their provided context id sets), optimized for the case
948 /// when Node1Ids is smaller than Node2Ids.
949 uint8_t intersectAllocTypesImpl(const DenseSet<uint32_t> &Node1Ids,
950 const DenseSet<uint32_t> &Node2Ids) const;
951
952 /// Returns the allocation type of the intersection of the contexts of two
953 /// nodes (based on their provided context id sets).
954 uint8_t intersectAllocTypes(const DenseSet<uint32_t> &Node1Ids,
955 const DenseSet<uint32_t> &Node2Ids) const;
956
957 /// Create a clone of Edge's callee and move Edge to that new callee node,
958 /// performing the necessary context id and allocation type updates.
959 /// If ContextIdsToMove is non-empty, only that subset of Edge's ids are
960 /// moved to an edge to the new callee.
961 ContextNode *
962 moveEdgeToNewCalleeClone(const std::shared_ptr<ContextEdge> &Edge,
963 DenseSet<uint32_t> ContextIdsToMove = {});
964
965 /// Change the callee of Edge to existing callee clone NewCallee, performing
966 /// the necessary context id and allocation type updates.
967 /// If ContextIdsToMove is non-empty, only that subset of Edge's ids are
968 /// moved to an edge to the new callee.
969 void moveEdgeToExistingCalleeClone(const std::shared_ptr<ContextEdge> &Edge,
970 ContextNode *NewCallee,
971 bool NewClone = false,
972 DenseSet<uint32_t> ContextIdsToMove = {});
973
974 /// Change the caller of the edge at the given callee edge iterator to be
975 /// NewCaller, performing the necessary context id and allocation type
976 /// updates. This is similar to the above moveEdgeToExistingCalleeClone, but
977 /// a simplified version of it as we always move the given edge and all of its
978 /// context ids.
979 void moveCalleeEdgeToNewCaller(const std::shared_ptr<ContextEdge> &Edge,
980 ContextNode *NewCaller);
981
982 /// Recursive helper for marking backedges via DFS.
983 void markBackedges(ContextNode *Node, DenseSet<const ContextNode *> &Visited,
984 DenseSet<const ContextNode *> &CurrentStack);
985
986 /// Recursive helper for merging clones.
987 void
988 mergeClones(ContextNode *Node, DenseSet<const ContextNode *> &Visited,
989 DenseMap<uint32_t, ContextNode *> &ContextIdToAllocationNode);
990 /// Main worker for merging callee clones for a given node.
991 void mergeNodeCalleeClones(
992 ContextNode *Node, DenseSet<const ContextNode *> &Visited,
993 DenseMap<uint32_t, ContextNode *> &ContextIdToAllocationNode);
994 /// Helper to find other callers of the given set of callee edges that can
995 /// share the same callee merge node.
996 void findOtherCallersToShareMerge(
997 ContextNode *Node, std::vector<std::shared_ptr<ContextEdge>> &CalleeEdges,
998 DenseMap<uint32_t, ContextNode *> &ContextIdToAllocationNode,
999 DenseSet<ContextNode *> &OtherCallersToShareMerge);
1000
1001 /// Recursively perform cloning on the graph for the given Node and its
1002 /// callers, in order to uniquely identify the allocation behavior of an
1003 /// allocation given its context. The context ids of the allocation being
1004 /// processed are given in AllocContextIds.
1005 void identifyClones(ContextNode *Node, DenseSet<const ContextNode *> &Visited,
1006 const DenseSet<uint32_t> &AllocContextIds);
1007
1008 /// Records which clone of a callsite node an implicit caller requires (see
1009 /// assignImplicitCallers). The call to that callsite in a given function
1010 /// clone (the map key below) must call the same callee version as Source.
1011 struct ImplicitSource {
1012 /// The required clone of the callsite node.
1013 const ContextNode *Source;
1014 /// One of the trimmed context ids that made Source required. If Source is
1015 /// later emptied by further cloning, this id is used to find the clone
1016 /// that now carries the trimmed contexts (see resolveImplicitSource).
1017 uint32_t ContextId;
1018 };
1019 /// Map from (original callsite node, function clone number) to the clone of
1020 /// that callsite node that the call in that function clone must follow.
1021 using ImplicitSourceMap =
1022 DenseMap<std::pair<const ContextNode *, unsigned>, ImplicitSource>;
1023
1024 /// Assign the implicit callers of the clones of Node (callsite clones without
1025 /// an edge to any clone of Node which contexts trimmed at Node's frame would
1026 /// have reached) the function clone called by the caller carrying those
1027 /// contexts, and record the clone of Node their calls must follow. See
1028 /// assignFunctions for the maps.
1029 void assignImplicitCallers(
1030 ContextNode *Node, const DenseSet<uint32_t> &TrimmedContextIds,
1031 DenseMap<ContextNode *, FuncInfo> &CallsiteToCalleeFuncCloneMap,
1032 const std::map<FuncInfo, ContextNode *> &FuncCloneToCurNodeCloneMap,
1033 ImplicitSourceMap &ImplicitSources);
1034
1035 /// Returns the clone of Node (the original callsite node) that the implicit
1036 /// source Src refers to: Src.Source unless it has since been emptied, in
1037 /// which case the clone that now carries Src.ContextId (null if none does,
1038 /// which is not expected).
1039 static const ContextNode *resolveImplicitSource(const ContextNode *Node,
1040 const ImplicitSource &Src);
1041
1042 /// Map from each context ID to the AllocationType assigned to that context.
1043 DenseMap<uint32_t, AllocationType> ContextIdToAllocationType;
1044
1045 /// Map from each contextID to the profiled full contexts and their total
1046 /// sizes (there may be more than one due to context trimming),
1047 /// optionally populated when requested (via MemProfReportHintedSizes or
1048 /// MinClonedColdBytePercent).
1049 DenseMap<uint32_t, std::vector<ContextTotalSize>> ContextIdToContextSizeInfos;
1050
1051 /// Identifies the context node created for a stack id when adding the MIB
1052 /// contexts to the graph. This is used to locate the context nodes when
1053 /// trying to assign the corresponding callsites with those stack ids to these
1054 /// nodes.
1055 DenseMap<uint64_t, ContextNode *> StackEntryIdToContextNodeMap;
1056
1057 /// Saves information for the contexts identified as important (the largest
1058 /// cold contexts up to MemProfTopNImportant).
1059 struct ImportantContextInfo {
1060 // The original list of leaf first stack ids corresponding to this context.
1061 std::vector<uint64_t> StackIds;
1062 // Max length of stack ids corresponding to a single stack ContextNode for
1063 // this context (i.e. the max length of a key in StackIdsToNode below).
1064 unsigned MaxLength = 0;
1065 // Mapping of slices of the stack ids to the corresponding ContextNode
1066 // (there can be multiple stack ids due to inlining). Populated when
1067 // updating stack nodes while matching them to the IR or summary.
1068 std::map<std::vector<uint64_t>, ContextNode *> StackIdsToNode;
1069 };
1070
1071 // Map of important full context ids to information about each.
1072 DenseMap<uint32_t, ImportantContextInfo> ImportantContextIdInfo;
1073
1074 // For each important context id found in Node (if any), records the list of
1075 // stack ids that corresponded to the given callsite Node. There can be more
1076 // than one in the case of inlining.
1077 void recordStackNode(std::vector<uint64_t> &StackIds, ContextNode *Node,
1078 // We pass in the Node's context ids to avoid the
1079 // overhead of computing them as the caller already has
1080 // them in some cases.
1081 const DenseSet<uint32_t> &NodeContextIds,
1082 const DenseSet<uint32_t> &ImportantContextIds) {
1083 if (!MemProfTopNImportant) {
1084 assert(ImportantContextIds.empty());
1085 return;
1086 }
1087 DenseSet<uint32_t> Ids =
1088 set_intersection(NodeContextIds, ImportantContextIds);
1089 if (Ids.empty())
1090 return;
1091 auto Size = StackIds.size();
1092 for (auto Id : Ids) {
1093 auto &Entry = ImportantContextIdInfo[Id];
1094 Entry.StackIdsToNode[StackIds] = Node;
1095 // Keep track of the max to simplify later analysis.
1096 if (Size > Entry.MaxLength)
1097 Entry.MaxLength = Size;
1098 }
1099 }
1100
1101 /// Maps to track the calls to their corresponding nodes in the graph.
1102 MapVector<CallInfo, ContextNode *> AllocationCallToContextNodeMap;
1103 MapVector<CallInfo, ContextNode *> NonAllocationCallToContextNodeMap;
1104
1105 /// Owner of all ContextNode unique_ptrs.
1106 std::vector<std::unique_ptr<ContextNode>> NodeOwner;
1107
1108 /// Perform sanity checks on graph when requested.
1109 void check() const;
1110
1111 /// Keeps track of the last unique context id assigned.
1112 unsigned int LastContextId = 0;
1113
1114 /// Per-context information captured before identifyClones() when
1115 /// MemProfReportHintedSizesDetail is enabled, so that the report can relate
1116 /// the final (cloned) state back to the original context. "Frames" below are
1117 /// CCG nodes, not profile stack frames: a node matched to a call covers all
1118 /// of that call's inlined stack frames, so a chain can be shorter than the
1119 /// profiled stack.
1120 struct PreCloningContextInfo {
1121 // Ordered chain of uncloned ContextNodes for this context ID from the leaf
1122 // allocation node (Chain[0]) up to the outermost node in the CCG for this
1123 // context.
1124 std::vector<const ContextNode *> Chain;
1125 // Index in Chain of the outermost matched callsite node, i.e. the
1126 // outermost node such that it and all nodes below it
1127 // (Chain[1..MaxMatchedFrame]) were matched to a call in the IR/summary
1128 // (hasCall() == true). If the whole context matched, this is the
1129 // context's outermost node (possibly where the context was trimmed);
1130 // otherwise it is the last matched node below the first unmatched one. The
1131 // function containing it (the "outermost matched caller") is where the
1132 // reported post-cloning paths start. 0 if no caller of the allocation
1133 // matched.
1134 unsigned MaxMatchedFrame = 0;
1135 // True if the outermost matched node had caller edges for other contexts,
1136 // i.e. the context was trimmed below callers that other contexts reach.
1137 bool OutermostMatchedNodeHasOtherCallers = false;
1138 // If MaxMatchedFrame + 1 < Chain.size(), why did Chain[MaxMatchedFrame + 1]
1139 // not have a call: it was a recursive cycle node, or its calling function
1140 // was found but the call there did not match the callee (mismatched
1141 // callee); otherwise the caller had no !callsite for this stack id.
1142 bool StoppedAtRecursive = false;
1143 bool StoppedAtMismatchedCallee = false;
1144 // Stack id and (when known) calling function of the first unmatched node.
1145 uint64_t UnmatchedStackId = 0;
1146 const FuncTy *UnmatchedCallingFunc = nullptr;
1147 };
1148 /// Map from context id to its pre-cloning information.
1149 DenseMap<uint32_t, PreCloningContextInfo> PreCloningContextInfoMap;
1150 /// Allocation nodes (uncloned) that had at least one matched caller before
1151 /// cloning.
1152 DenseSet<const ContextNode *> PreCloningAllocHasMatchedCaller;
1153 /// Map from function to the number of function clones assigned to it
1154 /// (including the original), recorded during assignFunctions().
1155 DenseMap<const FuncTy *, unsigned> FuncToNumClones;
1156 /// Map from (original callsite node, clone number of the function clone
1157 /// containing the call) to the clone number of the callee function the call
1158 /// was updated to in assignFunctions(). Used to follow the post-cloning call
1159 /// path from a caller clone down to the allocation clone it reaches.
1160 DenseMap<std::pair<const ContextNode *, unsigned>, unsigned>
1161 OrigNodeAndCloneToCalleeClone;
1162 /// Map from (original allocation node, clone number of the function clone
1163 /// containing the allocation) to the allocation node in that clone, whose
1164 /// call carries the final hint.
1165 DenseMap<std::pair<const ContextNode *, unsigned>, const ContextNode *>
1166 OrigAllocAndCloneToNode;
1167};
1168
1169template <typename DerivedCCG, typename FuncTy, typename CallTy>
1170using ContextNode =
1171 typename CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::ContextNode;
1172template <typename DerivedCCG, typename FuncTy, typename CallTy>
1173using ContextEdge =
1174 typename CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::ContextEdge;
1175template <typename DerivedCCG, typename FuncTy, typename CallTy>
1176using FuncInfo =
1177 typename CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::FuncInfo;
1178template <typename DerivedCCG, typename FuncTy, typename CallTy>
1179using CallInfo =
1180 typename CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::CallInfo;
1181
1182/// CRTP derived class for graphs built from IR (regular LTO).
1183class ModuleCallsiteContextGraph
1184 : public CallsiteContextGraph<ModuleCallsiteContextGraph, Function,
1185 Instruction *> {
1186public:
1187 ModuleCallsiteContextGraph(
1188 Module &M,
1189 llvm::function_ref<OptimizationRemarkEmitter &(Function *)> OREGetter);
1190
1191private:
1192 friend CallsiteContextGraph<ModuleCallsiteContextGraph, Function,
1193 Instruction *>;
1194
1195 uint64_t getStackId(uint64_t IdOrIndex) const;
1196 const Function *getCalleeFunc(Instruction *Call);
1197 bool calleeMatchesFunc(
1198 Instruction *Call, const Function *Func, const Function *CallerFunc,
1199 std::vector<std::pair<Instruction *, Function *>> &FoundCalleeChain);
1200 bool sameCallee(Instruction *Call1, Instruction *Call2);
1201 bool findProfiledCalleeThroughTailCalls(
1202 const Function *ProfiledCallee, Value *CurCallee, unsigned Depth,
1203 std::vector<std::pair<Instruction *, Function *>> &FoundCalleeChain,
1204 bool &FoundMultipleCalleeChains);
1205 uint64_t getLastStackId(Instruction *Call);
1206 std::vector<uint64_t> getStackIdsWithContextNodesForCall(Instruction *Call);
1207 void updateAllocationCall(CallInfo &Call, AllocationType AllocType);
1208 AllocationType getAllocationCallType(const CallInfo &Call) const;
1209 void updateCall(CallInfo &CallerCall, FuncInfo CalleeFunc);
1210 CallsiteContextGraph<ModuleCallsiteContextGraph, Function,
1211 Instruction *>::FuncInfo
1212 cloneFunctionForCallsite(FuncInfo &Func, CallInfo &Call,
1213 DenseMap<CallInfo, CallInfo> &CallMap,
1214 std::vector<CallInfo> &CallsWithMetadataInFunc,
1215 unsigned CloneNo);
1216 std::string getLabel(const Function *Func, const Instruction *Call,
1217 unsigned CloneNo) const;
1218 std::string getFuncName(const Function *Func, unsigned CloneNo = 0) const;
1219 bool isFuncDead(const Function *Func) const { return false; }
1220 void populateFunctionsWithCallers();
1221
1222 const Module &Mod;
1223 llvm::function_ref<OptimizationRemarkEmitter &(Function *)> OREGetter;
1224};
1225
1226/// Represents a call in the summary index graph, which can either be an
1227/// allocation or an interior callsite node in an allocation's context.
1228/// Holds a pointer to the corresponding data structure in the index.
1229struct IndexCall : public PointerUnion<CallsiteInfo *, AllocInfo *> {
1230 IndexCall() : PointerUnion() {}
1231 IndexCall(std::nullptr_t) : IndexCall() {}
1232 IndexCall(CallsiteInfo *StackNode) : PointerUnion(StackNode) {}
1233 IndexCall(AllocInfo *AllocNode) : PointerUnion(AllocNode) {}
1234 IndexCall(PointerUnion PT) : PointerUnion(PT) {}
1235
1236 IndexCall *operator->() { return this; }
1237
1238 void print(raw_ostream &OS) const {
1239 PointerUnion<CallsiteInfo *, AllocInfo *> Base = *this;
1241 OS << *AI;
1242 } else {
1244 assert(CI);
1245 OS << *CI;
1246 }
1247 }
1248};
1249} // namespace
1250
1251namespace llvm {
1252template <> struct simplify_type<IndexCall> {
1254 static SimpleType getSimplifiedValue(IndexCall &Val) { return Val; }
1255};
1256template <> struct simplify_type<const IndexCall> {
1258 static SimpleType getSimplifiedValue(const IndexCall &Val) { return Val; }
1259};
1260} // namespace llvm
1261
1262namespace {
1263/// CRTP derived class for graphs built from summary index (ThinLTO).
1264class IndexCallsiteContextGraph
1265 : public CallsiteContextGraph<IndexCallsiteContextGraph, FunctionSummary,
1266 IndexCall> {
1267public:
1268 IndexCallsiteContextGraph(
1269 ModuleSummaryIndex &Index,
1270 llvm::function_ref<bool(GlobalValue::GUID, const GlobalValueSummary *)>
1271 isPrevailing);
1272
1273 ~IndexCallsiteContextGraph() {
1274 // Now that we are done with the graph it is safe to add the new
1275 // CallsiteInfo structs to the function summary vectors. The graph nodes
1276 // point into locations within these vectors, so we don't want to add them
1277 // any earlier.
1278 for (auto &I : FunctionCalleesToSynthesizedCallsiteInfos) {
1279 auto *FS = I.first;
1280 for (auto &Callsite : I.second)
1281 FS->addCallsite(std::move(*Callsite.second));
1282 }
1283 }
1284
1285private:
1286 friend CallsiteContextGraph<IndexCallsiteContextGraph, FunctionSummary,
1287 IndexCall>;
1288
1289 uint64_t getStackId(uint64_t IdOrIndex) const;
1290 const FunctionSummary *getCalleeFunc(IndexCall &Call);
1291 bool calleeMatchesFunc(
1292 IndexCall &Call, const FunctionSummary *Func,
1293 const FunctionSummary *CallerFunc,
1294 std::vector<std::pair<IndexCall, FunctionSummary *>> &FoundCalleeChain);
1295 bool sameCallee(IndexCall &Call1, IndexCall &Call2);
1296 bool findProfiledCalleeThroughTailCalls(
1297 ValueInfo ProfiledCallee, ValueInfo CurCallee, unsigned Depth,
1298 std::vector<std::pair<IndexCall, FunctionSummary *>> &FoundCalleeChain,
1299 bool &FoundMultipleCalleeChains);
1300 uint64_t getLastStackId(IndexCall &Call);
1301 std::vector<uint64_t> getStackIdsWithContextNodesForCall(IndexCall &Call);
1302 void updateAllocationCall(CallInfo &Call, AllocationType AllocType);
1303 AllocationType getAllocationCallType(const CallInfo &Call) const;
1304 void updateCall(CallInfo &CallerCall, FuncInfo CalleeFunc);
1305 CallsiteContextGraph<IndexCallsiteContextGraph, FunctionSummary,
1306 IndexCall>::FuncInfo
1307 cloneFunctionForCallsite(FuncInfo &Func, CallInfo &Call,
1308 DenseMap<CallInfo, CallInfo> &CallMap,
1309 std::vector<CallInfo> &CallsWithMetadataInFunc,
1310 unsigned CloneNo);
1311 std::string getLabel(const FunctionSummary *Func, const IndexCall &Call,
1312 unsigned CloneNo) const;
1313 std::string getFuncName(const FunctionSummary *Func,
1314 unsigned CloneNo = 0) const;
1315 bool isFuncDead(const FunctionSummary *Func) const;
1316 void populateFunctionsWithCallers();
1317 DenseSet<GlobalValue::GUID> findAliaseeGUIDsPrevailingInDifferentModule();
1318
1319 // Saves mapping from function summaries containing memprof records back to
1320 // its VI, for use in checking and debugging.
1321 std::map<const FunctionSummary *, ValueInfo> FSToVIMap;
1322
1323 const ModuleSummaryIndex &Index;
1324 llvm::function_ref<bool(GlobalValue::GUID, const GlobalValueSummary *)>
1325 isPrevailing;
1326
1327 // Saves/owns the callsite info structures synthesized for missing tail call
1328 // frames that we discover while building the graph.
1329 // It maps from the summary of the function making the tail call, to a map
1330 // of callee ValueInfo to corresponding synthesized callsite info.
1331 DenseMap<FunctionSummary *,
1332 std::map<ValueInfo, std::unique_ptr<CallsiteInfo>>>
1333 FunctionCalleesToSynthesizedCallsiteInfos;
1334};
1335} // namespace
1336
1337template <>
1338struct llvm::DenseMapInfo<CallsiteContextGraph<
1339 ModuleCallsiteContextGraph, Function, Instruction *>::CallInfo>
1341template <>
1342struct llvm::DenseMapInfo<CallsiteContextGraph<
1343 IndexCallsiteContextGraph, FunctionSummary, IndexCall>::CallInfo>
1344 : public DenseMapInfo<std::pair<IndexCall, unsigned>> {};
1345template <>
1346struct llvm::DenseMapInfo<IndexCall>
1347 : public DenseMapInfo<PointerUnion<CallsiteInfo *, AllocInfo *>> {};
1348
1349namespace {
1350
1351// Map the uint8_t alloc types (which may contain NotCold|Cold) to the alloc
1352// type we should actually use on the corresponding allocation.
1353// If we can't clone a node that has NotCold+Cold alloc type, we will fall
1354// back to using NotCold. So don't bother cloning to distinguish NotCold+Cold
1355// from NotCold.
1356AllocationType allocTypeToUse(uint8_t AllocTypes) {
1357 assert(AllocTypes != (uint8_t)AllocationType::None);
1358 if (AllocTypes ==
1361 else
1362 return (AllocationType)AllocTypes;
1363}
1364
1365// Helper to check if the alloc types for all edges recorded in the
1366// InAllocTypes vector match the alloc types for all edges in the Edges
1367// vector.
1368template <typename DerivedCCG, typename FuncTy, typename CallTy>
1369bool allocTypesMatch(
1370 const std::vector<uint8_t> &InAllocTypes,
1371 const std::vector<std::shared_ptr<ContextEdge<DerivedCCG, FuncTy, CallTy>>>
1372 &Edges) {
1373 // This should be called only when the InAllocTypes vector was computed for
1374 // this set of Edges. Make sure the sizes are the same.
1375 assert(InAllocTypes.size() == Edges.size());
1376 return std::equal(
1377 InAllocTypes.begin(), InAllocTypes.end(), Edges.begin(), Edges.end(),
1378 [](const uint8_t &l,
1379 const std::shared_ptr<ContextEdge<DerivedCCG, FuncTy, CallTy>> &r) {
1380 // Can share if one of the edges is None type - don't
1381 // care about the type along that edge as it doesn't
1382 // exist for those context ids.
1383 if (l == (uint8_t)AllocationType::None ||
1384 r->AllocTypes == (uint8_t)AllocationType::None)
1385 return true;
1386 return allocTypeToUse(l) == allocTypeToUse(r->AllocTypes);
1387 });
1388}
1389
1390// Helper to check if the alloc types for all edges recorded in the
1391// InAllocTypes vector match the alloc types for callee edges in the given
1392// clone. Because the InAllocTypes were computed from the original node's callee
1393// edges, and other cloning could have happened after this clone was created, we
1394// need to find the matching clone callee edge, which may or may not exist.
1395template <typename DerivedCCG, typename FuncTy, typename CallTy>
1396bool allocTypesMatchClone(
1397 const std::vector<uint8_t> &InAllocTypes,
1398 const ContextNode<DerivedCCG, FuncTy, CallTy> *Clone) {
1399 const ContextNode<DerivedCCG, FuncTy, CallTy> *Node = Clone->CloneOf;
1400 assert(Node);
1401 // InAllocTypes should have been computed for the original node's callee
1402 // edges.
1403 assert(InAllocTypes.size() == Node->CalleeEdges.size());
1404 // First create a map of the clone callee edge callees to the edge alloc type.
1406 EdgeCalleeMap;
1407 for (const auto &E : Clone->CalleeEdges) {
1408 assert(!EdgeCalleeMap.contains(E->Callee));
1409 EdgeCalleeMap[E->Callee] = E->AllocTypes;
1410 }
1411 // Next, walk the original node's callees, and look for the corresponding
1412 // clone edge to that callee.
1413 for (unsigned I = 0; I < Node->CalleeEdges.size(); I++) {
1414 auto Iter = EdgeCalleeMap.find(Node->CalleeEdges[I]->Callee);
1415 // Not found is ok, we will simply add an edge if we use this clone.
1416 if (Iter == EdgeCalleeMap.end())
1417 continue;
1418 // Can share if one of the edges is None type - don't
1419 // care about the type along that edge as it doesn't
1420 // exist for those context ids.
1421 if (InAllocTypes[I] == (uint8_t)AllocationType::None ||
1422 Iter->second == (uint8_t)AllocationType::None)
1423 continue;
1424 if (allocTypeToUse(Iter->second) != allocTypeToUse(InAllocTypes[I]))
1425 return false;
1426 }
1427 return true;
1428}
1429
1430} // end anonymous namespace
1431
1432template <typename DerivedCCG, typename FuncTy, typename CallTy>
1433typename CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::ContextNode *
1434CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::getNodeForInst(
1435 const CallInfo &C) {
1436 ContextNode *Node = getNodeForAlloc(C);
1437 if (Node)
1438 return Node;
1439
1440 return NonAllocationCallToContextNodeMap.lookup(C);
1441}
1442
1443template <typename DerivedCCG, typename FuncTy, typename CallTy>
1444typename CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::ContextNode *
1445CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::getNodeForAlloc(
1446 const CallInfo &C) {
1447 return AllocationCallToContextNodeMap.lookup(C);
1448}
1449
1450template <typename DerivedCCG, typename FuncTy, typename CallTy>
1451typename CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::ContextNode *
1452CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::getNodeForStackId(
1453 uint64_t StackId) {
1454 auto StackEntryNode = StackEntryIdToContextNodeMap.find(StackId);
1455 if (StackEntryNode != StackEntryIdToContextNodeMap.end())
1456 return StackEntryNode->second;
1457 return nullptr;
1458}
1459
1460template <typename DerivedCCG, typename FuncTy, typename CallTy>
1461void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::ContextNode::
1462 addOrUpdateCallerEdge(ContextNode *Caller, AllocationType AllocType,
1463 unsigned int ContextId) {
1464 for (auto &Edge : CallerEdges) {
1465 if (Edge->Caller == Caller) {
1466 Edge->AllocTypes |= (uint8_t)AllocType;
1467 Edge->getContextIds().insert(ContextId);
1468 return;
1469 }
1470 }
1471 std::shared_ptr<ContextEdge> Edge = std::make_shared<ContextEdge>(
1472 this, Caller, (uint8_t)AllocType, DenseSet<uint32_t>({ContextId}));
1473 CallerEdges.push_back(Edge);
1474 Caller->CalleeEdges.push_back(Edge);
1475}
1476
1477template <typename DerivedCCG, typename FuncTy, typename CallTy>
1478void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::removeEdgeFromGraph(
1479 ContextEdge *Edge, EdgeIter *EI, bool CalleeIter) {
1480 assert(!EI || (*EI)->get() == Edge);
1481 assert(!Edge->isRemoved());
1482 // Save the Caller and Callee pointers so we can erase Edge from their edge
1483 // lists after clearing Edge below. We do the clearing first in case it is
1484 // destructed after removing from the edge lists (if those were the last
1485 // shared_ptr references to Edge).
1486 auto *Callee = Edge->Callee;
1487 auto *Caller = Edge->Caller;
1488
1489 // Make sure the edge fields are cleared out so we can properly detect
1490 // removed edges if Edge is not destructed because there is still a shared_ptr
1491 // reference.
1492 Edge->clear();
1493
1494#ifndef NDEBUG
1495 auto CalleeCallerCount = Callee->CallerEdges.size();
1496 auto CallerCalleeCount = Caller->CalleeEdges.size();
1497#endif
1498 if (!EI) {
1499 Callee->eraseCallerEdge(Edge);
1500 Caller->eraseCalleeEdge(Edge);
1501 } else if (CalleeIter) {
1502 Callee->eraseCallerEdge(Edge);
1503 *EI = Caller->CalleeEdges.erase(*EI);
1504 } else {
1505 Caller->eraseCalleeEdge(Edge);
1506 *EI = Callee->CallerEdges.erase(*EI);
1507 }
1508 assert(Callee->CallerEdges.size() < CalleeCallerCount);
1509 assert(Caller->CalleeEdges.size() < CallerCalleeCount);
1510}
1511
1512template <typename DerivedCCG, typename FuncTy, typename CallTy>
1513void CallsiteContextGraph<
1514 DerivedCCG, FuncTy, CallTy>::removeNoneTypeCalleeEdges(ContextNode *Node) {
1515 for (auto EI = Node->CalleeEdges.begin(); EI != Node->CalleeEdges.end();) {
1516 auto Edge = *EI;
1517 if (Edge->AllocTypes == (uint8_t)AllocationType::None) {
1518 assert(Edge->ContextIds.empty());
1519 removeEdgeFromGraph(Edge.get(), &EI, /*CalleeIter=*/true);
1520 } else
1521 ++EI;
1522 }
1523}
1524
1525template <typename DerivedCCG, typename FuncTy, typename CallTy>
1526void CallsiteContextGraph<
1527 DerivedCCG, FuncTy, CallTy>::removeNoneTypeCallerEdges(ContextNode *Node) {
1528 for (auto EI = Node->CallerEdges.begin(); EI != Node->CallerEdges.end();) {
1529 auto Edge = *EI;
1530 if (Edge->AllocTypes == (uint8_t)AllocationType::None) {
1531 assert(Edge->ContextIds.empty());
1532 Edge->Caller->eraseCalleeEdge(Edge.get());
1533 EI = Node->CallerEdges.erase(EI);
1534 } else
1535 ++EI;
1536 }
1537}
1538
1539template <typename DerivedCCG, typename FuncTy, typename CallTy>
1540typename CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::ContextEdge *
1541CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::ContextNode::
1542 findEdgeFromCallee(const ContextNode *Callee) {
1543 for (const auto &Edge : CalleeEdges)
1544 if (Edge->Callee == Callee)
1545 return Edge.get();
1546 return nullptr;
1547}
1548
1549template <typename DerivedCCG, typename FuncTy, typename CallTy>
1550typename CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::ContextEdge *
1551CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::ContextNode::
1552 findEdgeFromCaller(const ContextNode *Caller) {
1553 for (const auto &Edge : CallerEdges)
1554 if (Edge->Caller == Caller)
1555 return Edge.get();
1556 return nullptr;
1557}
1558
1559template <typename DerivedCCG, typename FuncTy, typename CallTy>
1560void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::ContextNode::
1561 eraseCalleeEdge(const ContextEdge *Edge) {
1562 auto EI = llvm::find_if(
1563 CalleeEdges, [Edge](const std::shared_ptr<ContextEdge> &CalleeEdge) {
1564 return CalleeEdge.get() == Edge;
1565 });
1566 assert(EI != CalleeEdges.end());
1567 CalleeEdges.erase(EI);
1568}
1569
1570template <typename DerivedCCG, typename FuncTy, typename CallTy>
1571void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::ContextNode::
1572 eraseCallerEdge(const ContextEdge *Edge) {
1573 auto EI = llvm::find_if(
1574 CallerEdges, [Edge](const std::shared_ptr<ContextEdge> &CallerEdge) {
1575 return CallerEdge.get() == Edge;
1576 });
1577 assert(EI != CallerEdges.end());
1578 CallerEdges.erase(EI);
1579}
1580
1581template <typename DerivedCCG, typename FuncTy, typename CallTy>
1582uint8_t CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::computeAllocType(
1583 DenseSet<uint32_t> &ContextIds) const {
1584 uint8_t BothTypes =
1585 (uint8_t)AllocationType::Cold | (uint8_t)AllocationType::NotCold;
1586 uint8_t AllocType = (uint8_t)AllocationType::None;
1587 for (auto Id : ContextIds) {
1588 AllocType |= (uint8_t)ContextIdToAllocationType.at(Id);
1589 // Bail early if alloc type reached both, no further refinement.
1590 if (AllocType == BothTypes)
1591 return AllocType;
1592 }
1593 return AllocType;
1594}
1595
1596template <typename DerivedCCG, typename FuncTy, typename CallTy>
1597uint8_t
1598CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::intersectAllocTypesImpl(
1599 const DenseSet<uint32_t> &Node1Ids,
1600 const DenseSet<uint32_t> &Node2Ids) const {
1601 uint8_t BothTypes =
1602 (uint8_t)AllocationType::Cold | (uint8_t)AllocationType::NotCold;
1603 uint8_t AllocType = (uint8_t)AllocationType::None;
1604 for (auto Id : Node1Ids) {
1605 if (!Node2Ids.count(Id))
1606 continue;
1607 AllocType |= (uint8_t)ContextIdToAllocationType.at(Id);
1608 // Bail early if alloc type reached both, no further refinement.
1609 if (AllocType == BothTypes)
1610 return AllocType;
1611 }
1612 return AllocType;
1613}
1614
1615template <typename DerivedCCG, typename FuncTy, typename CallTy>
1616uint8_t CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::intersectAllocTypes(
1617 const DenseSet<uint32_t> &Node1Ids,
1618 const DenseSet<uint32_t> &Node2Ids) const {
1619 if (Node1Ids.size() < Node2Ids.size())
1620 return intersectAllocTypesImpl(Node1Ids, Node2Ids);
1621 else
1622 return intersectAllocTypesImpl(Node2Ids, Node1Ids);
1623}
1624
1625template <typename DerivedCCG, typename FuncTy, typename CallTy>
1626typename CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::ContextNode *
1627CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::addAllocNode(
1628 CallInfo Call, const FuncTy *F) {
1629 assert(!getNodeForAlloc(Call));
1630 ContextNode *AllocNode = createNewNode(/*IsAllocation=*/true, F, Call);
1631 AllocationCallToContextNodeMap[Call] = AllocNode;
1632 // Use LastContextId as a uniq id for MIB allocation nodes.
1633 AllocNode->OrigStackOrAllocId = LastContextId;
1634 // Alloc type should be updated as we add in the MIBs. We should assert
1635 // afterwards that it is not still None.
1636 AllocNode->AllocTypes = (uint8_t)AllocationType::None;
1637
1638 return AllocNode;
1639}
1640
1641static std::string getAllocTypeString(uint8_t AllocTypes) {
1642 if (!AllocTypes)
1643 return "None";
1644 std::string Str;
1645 if (AllocTypes & (uint8_t)AllocationType::NotCold)
1646 Str += "NotCold";
1647 if (AllocTypes & (uint8_t)AllocationType::Cold)
1648 Str += "Cold";
1649 return Str;
1650}
1651
1652template <typename DerivedCCG, typename FuncTy, typename CallTy>
1653template <class NodeT, class IteratorT>
1654void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::addStackNodesForMIB(
1655 ContextNode *AllocNode, CallStack<NodeT, IteratorT> &StackContext,
1656 CallStack<NodeT, IteratorT> &CallsiteContext, AllocationType AllocType,
1657 ArrayRef<ContextTotalSize> ContextSizeInfo,
1658 std::map<uint64_t, uint32_t> &TotalSizeToContextIdTopNCold) {
1659 // Treating the hot alloc type as NotCold before the disambiguation for "hot"
1660 // is done.
1661 if (AllocType == AllocationType::Hot)
1662 AllocType = AllocationType::NotCold;
1663
1664 ContextIdToAllocationType[++LastContextId] = AllocType;
1665
1666 bool IsImportant = false;
1667 if (!ContextSizeInfo.empty()) {
1668 auto &Entry = ContextIdToContextSizeInfos[LastContextId];
1669 // If this is a cold allocation, and we are collecting non-zero largest
1670 // contexts, see if this is a candidate.
1671 if (AllocType == AllocationType::Cold && MemProfTopNImportant > 0) {
1672 uint64_t TotalCold = 0;
1673 for (auto &CSI : ContextSizeInfo)
1674 TotalCold += CSI.TotalSize;
1675 // Record this context if either we haven't found the first top-n largest
1676 // yet, or if it is larger than the smallest already recorded.
1677 if (TotalSizeToContextIdTopNCold.size() < MemProfTopNImportant ||
1678 // Since TotalSizeToContextIdTopNCold is a std::map, it is implicitly
1679 // sorted in ascending size of its key which is the size.
1680 TotalCold > TotalSizeToContextIdTopNCold.begin()->first) {
1681 if (TotalSizeToContextIdTopNCold.size() == MemProfTopNImportant) {
1682 // Remove old one and its associated entries.
1683 auto IdToRemove = TotalSizeToContextIdTopNCold.begin()->second;
1684 TotalSizeToContextIdTopNCold.erase(
1685 TotalSizeToContextIdTopNCold.begin());
1686 assert(ImportantContextIdInfo.count(IdToRemove));
1687 ImportantContextIdInfo.erase(IdToRemove);
1688 }
1689 TotalSizeToContextIdTopNCold[TotalCold] = LastContextId;
1690 IsImportant = true;
1691 }
1692 }
1693 Entry.insert(Entry.begin(), ContextSizeInfo.begin(), ContextSizeInfo.end());
1694 }
1695
1696 // Update alloc type and context ids for this MIB.
1697 AllocNode->AllocTypes |= (uint8_t)AllocType;
1698
1699 // Now add or update nodes for each stack id in alloc's context.
1700 // Later when processing the stack ids on non-alloc callsites we will adjust
1701 // for any inlining in the context.
1702 ContextNode *PrevNode = AllocNode;
1703 // Look for recursion (direct recursion should have been collapsed by
1704 // module summary analysis, here we should just be detecting mutual
1705 // recursion). Mark these nodes so we don't try to clone.
1706 SmallSet<uint64_t, 8> StackIdSet;
1707 // Skip any on the allocation call (inlining).
1708 for (auto ContextIter = StackContext.beginAfterSharedPrefix(CallsiteContext);
1709 ContextIter != StackContext.end(); ++ContextIter) {
1710 auto StackId = getStackId(*ContextIter);
1711 if (IsImportant)
1712 ImportantContextIdInfo[LastContextId].StackIds.push_back(StackId);
1713 ContextNode *StackNode = getNodeForStackId(StackId);
1714 if (!StackNode) {
1715 StackNode = createNewNode(/*IsAllocation=*/false);
1716 StackEntryIdToContextNodeMap[StackId] = StackNode;
1717 StackNode->OrigStackOrAllocId = StackId;
1718 }
1719 // Marking a node recursive will prevent its cloning completely, even for
1720 // non-recursive contexts flowing through it.
1722 auto Ins = StackIdSet.insert(StackId);
1723 if (!Ins.second)
1724 StackNode->Recursive = true;
1725 }
1726 StackNode->AllocTypes |= (uint8_t)AllocType;
1727 PrevNode->addOrUpdateCallerEdge(StackNode, AllocType, LastContextId);
1728 PrevNode = StackNode;
1729 }
1730}
1731
1732template <typename DerivedCCG, typename FuncTy, typename CallTy>
1733DenseSet<uint32_t>
1734CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::duplicateContextIds(
1735 const DenseSet<uint32_t> &StackSequenceContextIds,
1736 DenseMap<uint32_t, DenseSet<uint32_t>> &OldToNewContextIds) {
1737 DenseSet<uint32_t> NewContextIds;
1738 for (auto OldId : StackSequenceContextIds) {
1739 NewContextIds.insert(++LastContextId);
1740 OldToNewContextIds[OldId].insert(LastContextId);
1741 assert(ContextIdToAllocationType.count(OldId));
1742 // The new context has the same allocation type and size info as original.
1743 ContextIdToAllocationType[LastContextId] = ContextIdToAllocationType[OldId];
1744 auto CSI = ContextIdToContextSizeInfos.find(OldId);
1745 if (CSI != ContextIdToContextSizeInfos.end())
1746 ContextIdToContextSizeInfos[LastContextId] = CSI->second;
1747 if (DotAllocContextIds.contains(OldId))
1748 DotAllocContextIds.insert(LastContextId);
1749 }
1750 return NewContextIds;
1751}
1752
1753template <typename DerivedCCG, typename FuncTy, typename CallTy>
1754void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::
1755 propagateDuplicateContextIds(
1756 const DenseMap<uint32_t, DenseSet<uint32_t>> &OldToNewContextIds) {
1757 // Build a set of duplicated context ids corresponding to the input id set.
1758 auto GetNewIds = [&OldToNewContextIds](const DenseSet<uint32_t> &ContextIds) {
1759 DenseSet<uint32_t> NewIds;
1760 for (auto Id : ContextIds)
1761 if (auto NewId = OldToNewContextIds.find(Id);
1762 NewId != OldToNewContextIds.end())
1763 NewIds.insert_range(NewId->second);
1764 return NewIds;
1765 };
1766
1767 // Recursively update context ids sets along caller edges.
1768 auto UpdateCallers = [&](ContextNode *Node,
1769 DenseSet<const ContextEdge *> &Visited,
1770 auto &&UpdateCallers) -> void {
1771 for (const auto &Edge : Node->CallerEdges) {
1772 auto Inserted = Visited.insert(Edge.get());
1773 if (!Inserted.second)
1774 continue;
1775 ContextNode *NextNode = Edge->Caller;
1776 DenseSet<uint32_t> NewIdsToAdd = GetNewIds(Edge->getContextIds());
1777 // Only need to recursively iterate to NextNode via this caller edge if
1778 // it resulted in any added ids to NextNode.
1779 if (!NewIdsToAdd.empty()) {
1780 Edge->getContextIds().insert_range(NewIdsToAdd);
1781 UpdateCallers(NextNode, Visited, UpdateCallers);
1782 }
1783 }
1784 };
1785
1786 DenseSet<const ContextEdge *> Visited;
1787 for (auto &Entry : AllocationCallToContextNodeMap) {
1788 auto *Node = Entry.second;
1789 UpdateCallers(Node, Visited, UpdateCallers);
1790 }
1791}
1792
1793template <typename DerivedCCG, typename FuncTy, typename CallTy>
1794void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::connectNewNode(
1795 ContextNode *NewNode, ContextNode *OrigNode, bool TowardsCallee,
1796 const DenseSet<uint32_t> &ContextIds) {
1797 auto &OrigEdges =
1798 TowardsCallee ? OrigNode->CalleeEdges : OrigNode->CallerEdges;
1799 // Increment iterator in loop so that we can remove edges as needed.
1800 for (auto EI = OrigEdges.begin(); EI != OrigEdges.end();) {
1801 auto Edge = *EI;
1802 DenseSet<uint32_t> NewEdgeContextIds;
1803 // Remove any matching context ids from Edge, return set that were found and
1804 // removed, these are the new edge's context ids.
1805 set_subtract(Edge->getContextIds(), ContextIds, NewEdgeContextIds);
1806 // If no matching context ids for this edge, skip it.
1807 if (NewEdgeContextIds.empty()) {
1808 ++EI;
1809 continue;
1810 }
1811 if (TowardsCallee) {
1812 uint8_t NewAllocType = computeAllocType(NewEdgeContextIds);
1813 auto NewEdge = std::make_shared<ContextEdge>(
1814 Edge->Callee, NewNode, NewAllocType, std::move(NewEdgeContextIds));
1815 NewNode->CalleeEdges.push_back(NewEdge);
1816 NewEdge->Callee->CallerEdges.push_back(NewEdge);
1817 } else {
1818 uint8_t NewAllocType = computeAllocType(NewEdgeContextIds);
1819 auto NewEdge = std::make_shared<ContextEdge>(
1820 NewNode, Edge->Caller, NewAllocType, std::move(NewEdgeContextIds));
1821 NewNode->CallerEdges.push_back(NewEdge);
1822 NewEdge->Caller->CalleeEdges.push_back(NewEdge);
1823 }
1824 // Remove old edge if context ids empty.
1825 if (Edge->getContextIds().empty()) {
1826 removeEdgeFromGraph(Edge.get(), &EI, TowardsCallee);
1827 continue;
1828 }
1829 ++EI;
1830 }
1831}
1832
1833template <typename DerivedCCG, typename FuncTy, typename CallTy>
1834static void checkEdge(
1835 const std::shared_ptr<ContextEdge<DerivedCCG, FuncTy, CallTy>> &Edge) {
1836 // Confirm that alloc type is not None and that we have at least one context
1837 // id.
1838 assert(Edge->AllocTypes != (uint8_t)AllocationType::None);
1839 assert(!Edge->ContextIds.empty());
1840}
1841
1842template <typename DerivedCCG, typename FuncTy, typename CallTy>
1843static void checkNode(const ContextNode<DerivedCCG, FuncTy, CallTy> *Node,
1844 bool CheckEdges = true) {
1845 if (Node->isRemoved())
1846 return;
1847#ifndef NDEBUG
1848 // Compute node's context ids once for use in asserts.
1849 auto NodeContextIds = Node->getContextIds();
1850#endif
1851 // Node's context ids should be the union of both its callee and caller edge
1852 // context ids.
1853 if (Node->CallerEdges.size()) {
1854 DenseSet<uint32_t> CallerEdgeContextIds(
1855 Node->CallerEdges.front()->ContextIds);
1856 for (const auto &Edge : llvm::drop_begin(Node->CallerEdges)) {
1857 if (CheckEdges)
1859 set_union(CallerEdgeContextIds, Edge->ContextIds);
1860 }
1861 // Node can have more context ids than callers if some contexts terminate at
1862 // node and some are longer. If we are allowing recursive callsites and
1863 // contexts this will be violated for incompletely cloned recursive cycles,
1864 // so skip the checking in that case.
1866 NodeContextIds == CallerEdgeContextIds ||
1867 set_is_subset(CallerEdgeContextIds, NodeContextIds));
1868 }
1869 if (Node->CalleeEdges.size()) {
1870 DenseSet<uint32_t> CalleeEdgeContextIds(
1871 Node->CalleeEdges.front()->ContextIds);
1872 for (const auto &Edge : llvm::drop_begin(Node->CalleeEdges)) {
1873 if (CheckEdges)
1875 set_union(CalleeEdgeContextIds, Edge->getContextIds());
1876 }
1877 // If we are allowing recursive callsites and contexts this will be violated
1878 // for incompletely cloned recursive cycles, so skip the checking in that
1879 // case.
1881 NodeContextIds == CalleeEdgeContextIds);
1882 }
1883 // FIXME: Since this checking is only invoked under an option, we should
1884 // change the error checking from using assert to something that will trigger
1885 // an error on a release build.
1886#ifndef NDEBUG
1887 // Make sure we don't end up with duplicate edges between the same caller and
1888 // callee.
1890 for (const auto &E : Node->CalleeEdges)
1891 NodeSet.insert(E->Callee);
1892 assert(NodeSet.size() == Node->CalleeEdges.size());
1893#endif
1894}
1895
1896template <typename DerivedCCG, typename FuncTy, typename CallTy>
1897void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::
1898 assignStackNodesPostOrder(ContextNode *Node,
1899 DenseSet<const ContextNode *> &Visited,
1900 DenseMap<uint64_t, std::vector<CallContextInfo>>
1901 &StackIdToMatchingCalls,
1902 DenseMap<CallInfo, CallInfo> &CallToMatchingCall,
1903 const DenseSet<uint32_t> &ImportantContextIds) {
1904 auto Inserted = Visited.insert(Node);
1905 if (!Inserted.second)
1906 return;
1907 // Post order traversal. Iterate over a copy since we may add nodes and
1908 // therefore new callers during the recursive call, invalidating any
1909 // iterator over the original edge vector. We don't need to process these
1910 // new nodes as they were already processed on creation.
1911 auto CallerEdges = Node->CallerEdges;
1912 for (auto &Edge : CallerEdges) {
1913 // Skip any that have been removed during the recursion.
1914 if (Edge->isRemoved()) {
1915 assert(!is_contained(Node->CallerEdges, Edge));
1916 continue;
1917 }
1918 assignStackNodesPostOrder(Edge->Caller, Visited, StackIdToMatchingCalls,
1919 CallToMatchingCall, ImportantContextIds);
1920 }
1921
1922 // If this node's stack id is in the map, update the graph to contain new
1923 // nodes representing any inlining at interior callsites. Note we move the
1924 // associated context ids over to the new nodes.
1925
1926 // Ignore this node if it is for an allocation or we didn't record any
1927 // stack id lists ending at it.
1928 if (Node->IsAllocation ||
1929 !StackIdToMatchingCalls.count(Node->OrigStackOrAllocId))
1930 return;
1931
1932 auto &Calls = StackIdToMatchingCalls[Node->OrigStackOrAllocId];
1933 // Handle the simple case first. A single call with a single stack id.
1934 // In this case there is no need to create any new context nodes, simply
1935 // assign the context node for stack id to this Call.
1936 if (Calls.size() == 1) {
1937 auto &[Call, Ids, Func, SavedContextIds] = Calls[0];
1938 if (Ids.size() == 1) {
1939 assert(SavedContextIds.empty());
1940 // It should be this Node
1941 assert(Node == getNodeForStackId(Ids[0]));
1942 if (Node->Recursive)
1943 return;
1944 Node->setCall(Call);
1945 NonAllocationCallToContextNodeMap[Call] = Node;
1946 NodeToCallingFunc[Node] = Func;
1947 recordStackNode(Ids, Node, Node->getContextIds(), ImportantContextIds);
1948 return;
1949 }
1950 }
1951
1952#ifndef NDEBUG
1953 // Find the node for the last stack id, which should be the same
1954 // across all calls recorded for this id, and is this node's id.
1955 uint64_t LastId = Node->OrigStackOrAllocId;
1956 ContextNode *LastNode = getNodeForStackId(LastId);
1957 // We should only have kept stack ids that had nodes.
1958 assert(LastNode);
1959 assert(LastNode == Node);
1960#else
1961 ContextNode *LastNode = Node;
1962#endif
1963
1964 // Compute the last node's context ids once, as it is shared by all calls in
1965 // this entry.
1966 DenseSet<uint32_t> LastNodeContextIds = LastNode->getContextIds();
1967
1968 [[maybe_unused]] bool PrevIterCreatedNode = false;
1969 bool CreatedNode = false;
1970 for (unsigned I = 0; I < Calls.size();
1971 I++, PrevIterCreatedNode = CreatedNode) {
1972 CreatedNode = false;
1973 auto &[Call, Ids, Func, SavedContextIds] = Calls[I];
1974 // Skip any for which we didn't assign any ids, these don't get a node in
1975 // the graph.
1976 if (SavedContextIds.empty()) {
1977 // If this call has a matching call (located in the same function and
1978 // having the same stack ids), simply add it to the context node created
1979 // for its matching call earlier. These can be treated the same through
1980 // cloning and get updated at the same time.
1981 if (!CallToMatchingCall.contains(Call))
1982 continue;
1983 auto MatchingCall = CallToMatchingCall[Call];
1984 if (!NonAllocationCallToContextNodeMap.contains(MatchingCall)) {
1985 // This should only happen if we had a prior iteration, and it didn't
1986 // create a node because of the below recomputation of context ids
1987 // finding none remaining and continuing early.
1988 assert(I > 0 && !PrevIterCreatedNode);
1989 continue;
1990 }
1991 NonAllocationCallToContextNodeMap[MatchingCall]->MatchingCalls.push_back(
1992 Call);
1993 continue;
1994 }
1995
1996 assert(LastId == Ids.back());
1997
1998 // Recompute the context ids for this stack id sequence (the
1999 // intersection of the context ids of the corresponding nodes).
2000 // Start with the ids we saved in the map for this call, which could be
2001 // duplicated context ids. We have to recompute as we might have overlap
2002 // overlap between the saved context ids for different last nodes, and
2003 // removed them already during the post order traversal.
2004 set_intersect(SavedContextIds, LastNodeContextIds);
2005 ContextNode *PrevNode = LastNode;
2006 bool Skip = false;
2007 // Iterate backwards through the stack Ids, starting after the last Id
2008 // in the list, which was handled once outside for all Calls.
2009 for (auto IdIter = Ids.rbegin() + 1; IdIter != Ids.rend(); IdIter++) {
2010 auto Id = *IdIter;
2011 ContextNode *CurNode = getNodeForStackId(Id);
2012 // We should only have kept stack ids that had nodes and weren't
2013 // recursive.
2014 assert(CurNode);
2015 assert(!CurNode->Recursive);
2016
2017 auto *Edge = CurNode->findEdgeFromCaller(PrevNode);
2018 if (!Edge) {
2019 Skip = true;
2020 break;
2021 }
2022 PrevNode = CurNode;
2023
2024 // Update the context ids, which is the intersection of the ids along
2025 // all edges in the sequence.
2026 set_intersect(SavedContextIds, Edge->getContextIds());
2027
2028 // If we now have no context ids for clone, skip this call.
2029 if (SavedContextIds.empty()) {
2030 Skip = true;
2031 break;
2032 }
2033 }
2034 if (Skip)
2035 continue;
2036
2037 // Create new context node.
2038 ContextNode *NewNode = createNewNode(/*IsAllocation=*/false, Func, Call);
2039 NonAllocationCallToContextNodeMap[Call] = NewNode;
2040 CreatedNode = true;
2041 NewNode->AllocTypes = computeAllocType(SavedContextIds);
2042
2043 ContextNode *FirstNode = getNodeForStackId(Ids[0]);
2044 assert(FirstNode);
2045
2046 // Connect to callees of innermost stack frame in inlined call chain.
2047 // This updates context ids for FirstNode's callee's to reflect those
2048 // moved to NewNode.
2049 connectNewNode(NewNode, FirstNode, /*TowardsCallee=*/true, SavedContextIds);
2050
2051 // Connect to callers of outermost stack frame in inlined call chain.
2052 // This updates context ids for FirstNode's caller's to reflect those
2053 // moved to NewNode.
2054 connectNewNode(NewNode, LastNode, /*TowardsCallee=*/false, SavedContextIds);
2055
2056 // Now we need to remove context ids from edges/nodes between First and
2057 // Last Node.
2058 PrevNode = nullptr;
2059 for (auto Id : Ids) {
2060 ContextNode *CurNode = getNodeForStackId(Id);
2061 // We should only have kept stack ids that had nodes.
2062 assert(CurNode);
2063
2064 // Remove the context ids moved to NewNode from CurNode, and the
2065 // edge from the prior node.
2066 if (PrevNode) {
2067 auto *PrevEdge = CurNode->findEdgeFromCallee(PrevNode);
2068 // If the sequence contained recursion, we might have already removed
2069 // some edges during the connectNewNode calls above.
2070 if (!PrevEdge) {
2071 PrevNode = CurNode;
2072 continue;
2073 }
2074 set_subtract(PrevEdge->getContextIds(), SavedContextIds);
2075 if (PrevEdge->getContextIds().empty())
2076 removeEdgeFromGraph(PrevEdge);
2077 }
2078 // Since we update the edges from leaf to tail, only look at the callee
2079 // edges. This isn't an alloc node, so if there are no callee edges, the
2080 // alloc type is None.
2081 CurNode->AllocTypes = CurNode->CalleeEdges.empty()
2082 ? (uint8_t)AllocationType::None
2083 : CurNode->computeAllocType();
2084 PrevNode = CurNode;
2085 }
2086
2087 recordStackNode(Ids, NewNode, SavedContextIds, ImportantContextIds);
2088
2089 if (VerifyNodes) {
2090 checkNode<DerivedCCG, FuncTy, CallTy>(NewNode, /*CheckEdges=*/true);
2091 for (auto Id : Ids) {
2092 ContextNode *CurNode = getNodeForStackId(Id);
2093 // We should only have kept stack ids that had nodes.
2094 assert(CurNode);
2095 checkNode<DerivedCCG, FuncTy, CallTy>(CurNode, /*CheckEdges=*/true);
2096 }
2097 }
2098 }
2099}
2100
2101template <typename DerivedCCG, typename FuncTy, typename CallTy>
2102void CallsiteContextGraph<DerivedCCG, FuncTy,
2103 CallTy>::fixupImportantContexts() {
2104 if (ImportantContextIdInfo.empty())
2105 return;
2106
2107 // Update statistics as we are done building this map at this point.
2108 NumImportantContextIds = ImportantContextIdInfo.size();
2109
2111 return;
2112
2113 if (ExportToDot)
2114 exportToDot("beforestackfixup");
2115
2116 // For each context we identified as important, walk through the saved context
2117 // stack ids in order from leaf upwards, and make sure all edges are correct.
2118 // These can be difficult to get right when updating the graph while mapping
2119 // nodes onto summary or IR, especially when there is recursion. In
2120 // particular, when we have created new nodes to reflect inlining, it is
2121 // sometimes impossible to know exactly how to update the edges in the face of
2122 // recursion, as we have lost the original ordering of the stack ids in the
2123 // contexts.
2124 // TODO: Consider only doing this if we detect the context has recursive
2125 // cycles.
2126 //
2127 // I.e. assume we have a context with stack ids like: {A B A C A D E}
2128 // and let's say A was inlined into B, C, and D. The original graph will have
2129 // multiple recursive cycles through A. When we match the original context
2130 // nodes onto the IR or summary, we will merge {A B} into one context node,
2131 // {A C} onto another, and {A D} onto another. Looking at the stack sequence
2132 // above, we should end up with a non-cyclic set of edges like:
2133 // {AB} <- {AC} <- {AD} <- E. However, because we normally have lost the
2134 // original ordering, we won't get the edges correct initially (it's
2135 // impossible without the original ordering). Here we do the fixup (add and
2136 // removing edges where necessary) for this context. In the
2137 // ImportantContextInfo struct in this case we should have a MaxLength = 2,
2138 // and map entries for {A B}, {A C}, {A D}, and {E}.
2139 for (auto &[CurContextId, Info] : ImportantContextIdInfo) {
2140 if (Info.StackIdsToNode.empty())
2141 continue;
2142 bool Changed = false;
2143 ContextNode *PrevNode = nullptr;
2144 ContextNode *CurNode = nullptr;
2145 DenseSet<const ContextEdge *> VisitedEdges;
2146 ArrayRef<uint64_t> AllStackIds(Info.StackIds);
2147 // Try to identify what callsite ContextNode maps to which slice of the
2148 // context's ordered stack ids.
2149 for (unsigned I = 0; I < AllStackIds.size(); I++, PrevNode = CurNode) {
2150 // We will do this greedily, trying up to MaxLength stack ids in a row, to
2151 // see if we recorded a context node for that sequence.
2152 auto Len = Info.MaxLength;
2153 auto LenToEnd = AllStackIds.size() - I;
2154 if (Len > LenToEnd)
2155 Len = LenToEnd;
2156 CurNode = nullptr;
2157 // Try to find a recorded context node starting with the longest length
2158 // recorded, and on down until we check for just a single stack node.
2159 for (; Len > 0; Len--) {
2160 // Get the slice of the original stack id sequence to check.
2161 auto CheckStackIds = AllStackIds.slice(I, Len);
2162 auto EntryIt = Info.StackIdsToNode.find(CheckStackIds);
2163 if (EntryIt == Info.StackIdsToNode.end())
2164 continue;
2165 CurNode = EntryIt->second;
2166 // Skip forward so we don't try to look for the ones we just matched.
2167 // We increment by Len - 1, because the outer for loop will increment I.
2168 I += Len - 1;
2169 break;
2170 }
2171 // Give up if we couldn't find a node. Since we need to clone from the
2172 // leaf allocation upwards, no sense in doing anymore fixup further up
2173 // the context if we couldn't match part of the original stack context
2174 // onto a callsite node.
2175 if (!CurNode)
2176 break;
2177 // No edges to fix up until we have a pair of nodes that should be
2178 // adjacent in the graph.
2179 if (!PrevNode)
2180 continue;
2181 // See if we already have a call edge from CurNode to PrevNode.
2182 auto *CurEdge = PrevNode->findEdgeFromCaller(CurNode);
2183 if (CurEdge) {
2184 // We already have an edge. Make sure it contains this context id.
2185 if (CurEdge->getContextIds().insert(CurContextId).second) {
2186 NumFixupEdgeIdsInserted++;
2187 Changed = true;
2188 }
2189 } else {
2190 // No edge exists - add one.
2191 NumFixupEdgesAdded++;
2192 DenseSet<uint32_t> ContextIds({CurContextId});
2193 auto AllocType = computeAllocType(ContextIds);
2194 auto NewEdge = std::make_shared<ContextEdge>(
2195 PrevNode, CurNode, AllocType, std::move(ContextIds));
2196 PrevNode->CallerEdges.push_back(NewEdge);
2197 CurNode->CalleeEdges.push_back(NewEdge);
2198 // Save the new edge for the below handling.
2199 CurEdge = NewEdge.get();
2200 Changed = true;
2201 }
2202 VisitedEdges.insert(CurEdge);
2203 // Now remove this context id from any other caller edges calling
2204 // PrevNode.
2205 for (auto &Edge : PrevNode->CallerEdges) {
2206 // Skip the edge updating/created above and edges we have already
2207 // visited (due to recursion).
2208 if (Edge.get() != CurEdge && !VisitedEdges.contains(Edge.get()))
2209 Edge->getContextIds().erase(CurContextId);
2210 }
2211 }
2212 if (Changed)
2213 NumFixedContexts++;
2214 }
2215}
2216
2217template <typename DerivedCCG, typename FuncTy, typename CallTy>
2218void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::updateStackNodes() {
2219 // Map of stack id to all calls with that as the last (outermost caller)
2220 // callsite id that has a context node (some might not due to trimming
2221 // performed during matching of the allocation profile contexts).
2222 // The CallContextInfo contains the Call and a list of its stack ids with
2223 // ContextNodes, the function containing Call, and the set of context ids
2224 // the analysis will eventually identify for use in any new node created
2225 // for that callsite.
2226 DenseMap<uint64_t, std::vector<CallContextInfo>> StackIdToMatchingCalls;
2227 for (auto &[Func, CallsWithMetadata] : FuncToCallsWithMetadata) {
2228 for (auto &Call : CallsWithMetadata) {
2229 // Ignore allocations, already handled.
2230 if (AllocationCallToContextNodeMap.count(Call))
2231 continue;
2232 auto StackIdsWithContextNodes =
2233 getStackIdsWithContextNodesForCall(Call.call());
2234 // If there were no nodes created for MIBs on allocs (maybe this was in
2235 // the unambiguous part of the MIB stack that was trimmed), ignore.
2236 if (StackIdsWithContextNodes.empty())
2237 continue;
2238 // Otherwise, record this Call along with the list of ids for the last
2239 // (outermost caller) stack id with a node.
2240 StackIdToMatchingCalls[StackIdsWithContextNodes.back()].push_back(
2241 {Call.call(), StackIdsWithContextNodes, Func, {}});
2242 }
2243 }
2244
2245 // First make a pass through all stack ids that correspond to a call,
2246 // as identified in the above loop. Compute the context ids corresponding to
2247 // each of these calls when they correspond to multiple stack ids due to
2248 // due to inlining. Perform any duplication of context ids required when
2249 // there is more than one call with the same stack ids. Their (possibly newly
2250 // duplicated) context ids are saved in the StackIdToMatchingCalls map.
2251 DenseMap<uint32_t, DenseSet<uint32_t>> OldToNewContextIds;
2252 // Save a map from each call to any that are found to match it. I.e. located
2253 // in the same function and have the same (possibly trimmed) stack ids. We use
2254 // this to avoid creating extra graph nodes as they can be treated the same.
2255 DenseMap<CallInfo, CallInfo> CallToMatchingCall;
2256 for (auto &It : StackIdToMatchingCalls) {
2257 auto &Calls = It.getSecond();
2258 // Skip single calls with a single stack id. These don't need a new node.
2259 if (Calls.size() == 1) {
2260 auto &Ids = Calls[0].StackIds;
2261 if (Ids.size() == 1)
2262 continue;
2263 }
2264 // In order to do the best and maximal matching of inlined calls to context
2265 // node sequences we will sort the vectors of stack ids in descending order
2266 // of length, and within each length, lexicographically by stack id. The
2267 // latter is so that we can specially handle calls that have identical stack
2268 // id sequences (either due to cloning or artificially because of the MIB
2269 // context trimming). Those with the same Ids are then sorted by function to
2270 // facilitate efficiently mapping them to the same context node.
2271 // Because the functions are pointers, to ensure a stable sort first assign
2272 // each function pointer to its first index in the Calls array, and then use
2273 // that to sort by.
2274 DenseMap<const FuncTy *, unsigned> FuncToIndex;
2275 for (const auto &[Idx, CallCtxInfo] : enumerate(Calls))
2276 FuncToIndex.insert({CallCtxInfo.Func, Idx});
2278 Calls,
2279 [&FuncToIndex](const CallContextInfo &A, const CallContextInfo &B) {
2280 return A.StackIds.size() > B.StackIds.size() ||
2281 (A.StackIds.size() == B.StackIds.size() &&
2282 (A.StackIds < B.StackIds ||
2283 (A.StackIds == B.StackIds &&
2284 FuncToIndex[A.Func] < FuncToIndex[B.Func])));
2285 });
2286
2287 // Find the node for the last stack id, which should be the same
2288 // across all calls recorded for this id, and is the id for this
2289 // entry in the StackIdToMatchingCalls map.
2290 uint64_t LastId = It.getFirst();
2291 ContextNode *LastNode = getNodeForStackId(LastId);
2292 // We should only have kept stack ids that had nodes.
2293 assert(LastNode);
2294
2295 if (LastNode->Recursive)
2296 continue;
2297
2298 // Initialize the context ids with the last node's. We will subsequently
2299 // refine the context ids by computing the intersection along all edges.
2300 DenseSet<uint32_t> LastNodeContextIds = LastNode->getContextIds();
2301 assert(!LastNodeContextIds.empty());
2302
2303#ifndef NDEBUG
2304 // Save the set of functions seen for a particular set of the same stack
2305 // ids. This is used to ensure that they have been correctly sorted to be
2306 // adjacent in the Calls list, since we rely on that to efficiently place
2307 // all such matching calls onto the same context node.
2308 DenseSet<const FuncTy *> MatchingIdsFuncSet;
2309#endif
2310
2311 for (unsigned I = 0; I < Calls.size(); I++) {
2312 auto &[Call, Ids, Func, SavedContextIds] = Calls[I];
2313 assert(SavedContextIds.empty());
2314 assert(LastId == Ids.back());
2315
2316#ifndef NDEBUG
2317 // If this call has a different set of ids than the last one, clear the
2318 // set used to ensure they are sorted properly.
2319 if (I > 0 && Ids != Calls[I - 1].StackIds)
2320 MatchingIdsFuncSet.clear();
2321#endif
2322
2323 // First compute the context ids for this stack id sequence (the
2324 // intersection of the context ids of the corresponding nodes).
2325 // Start with the remaining saved ids for the last node.
2326 assert(!LastNodeContextIds.empty());
2327 DenseSet<uint32_t> StackSequenceContextIds = LastNodeContextIds;
2328
2329 ContextNode *PrevNode = LastNode;
2330 ContextNode *CurNode = LastNode;
2331 bool Skip = false;
2332
2333 // Iterate backwards through the stack Ids, starting after the last Id
2334 // in the list, which was handled once outside for all Calls.
2335 for (auto IdIter = Ids.rbegin() + 1; IdIter != Ids.rend(); IdIter++) {
2336 auto Id = *IdIter;
2337 CurNode = getNodeForStackId(Id);
2338 // We should only have kept stack ids that had nodes.
2339 assert(CurNode);
2340
2341 if (CurNode->Recursive) {
2342 Skip = true;
2343 break;
2344 }
2345
2346 auto *Edge = CurNode->findEdgeFromCaller(PrevNode);
2347 // If there is no edge then the nodes belong to different MIB contexts,
2348 // and we should skip this inlined context sequence. For example, this
2349 // particular inlined context may include stack ids A->B, and we may
2350 // indeed have nodes for both A and B, but it is possible that they were
2351 // never profiled in sequence in a single MIB for any allocation (i.e.
2352 // we might have profiled an allocation that involves the callsite A,
2353 // but through a different one of its callee callsites, and we might
2354 // have profiled an allocation that involves callsite B, but reached
2355 // from a different caller callsite).
2356 if (!Edge) {
2357 Skip = true;
2358 break;
2359 }
2360 PrevNode = CurNode;
2361
2362 // Update the context ids, which is the intersection of the ids along
2363 // all edges in the sequence.
2364 set_intersect(StackSequenceContextIds, Edge->getContextIds());
2365
2366 // If we now have no context ids for clone, skip this call.
2367 if (StackSequenceContextIds.empty()) {
2368 Skip = true;
2369 break;
2370 }
2371 }
2372 if (Skip)
2373 continue;
2374
2375 // If some of this call's stack ids did not have corresponding nodes (due
2376 // to trimming), don't include any context ids for contexts that extend
2377 // beyond these nodes. Otherwise we would be matching part of unrelated /
2378 // not fully matching stack contexts. To do this, subtract any context ids
2379 // found in caller nodes of the last node found above.
2380 if (Ids.back() != getLastStackId(Call)) {
2381 for (const auto &PE : LastNode->CallerEdges) {
2382 set_subtract(StackSequenceContextIds, PE->getContextIds());
2383 if (StackSequenceContextIds.empty())
2384 break;
2385 }
2386 // If we now have no context ids for clone, skip this call.
2387 if (StackSequenceContextIds.empty())
2388 continue;
2389 }
2390
2391#ifndef NDEBUG
2392 // If the prior call had the same stack ids this set would not be empty.
2393 // Check if we already have a call that "matches" because it is located
2394 // in the same function. If the Calls list was sorted properly we should
2395 // not encounter this situation as all such entries should be adjacent
2396 // and processed in bulk further below.
2397 assert(!MatchingIdsFuncSet.contains(Func));
2398
2399 MatchingIdsFuncSet.insert(Func);
2400#endif
2401
2402 // Check if the next set of stack ids is the same (since the Calls vector
2403 // of tuples is sorted by the stack ids we can just look at the next one).
2404 // If so, save them in the CallToMatchingCall map so that they get
2405 // assigned to the same context node, and skip them.
2406 bool DuplicateContextIds = false;
2407 for (unsigned J = I + 1; J < Calls.size(); J++) {
2408 auto &CallCtxInfo = Calls[J];
2409 auto &NextIds = CallCtxInfo.StackIds;
2410 if (NextIds != Ids)
2411 break;
2412 auto *NextFunc = CallCtxInfo.Func;
2413 if (NextFunc != Func) {
2414 // We have another Call with the same ids but that cannot share this
2415 // node, must duplicate ids for it.
2416 DuplicateContextIds = true;
2417 break;
2418 }
2419 auto &NextCall = CallCtxInfo.Call;
2420 CallToMatchingCall[NextCall] = Call;
2421 // Update I so that it gets incremented correctly to skip this call.
2422 I = J;
2423 }
2424
2425 // If we don't have duplicate context ids, then we can assign all the
2426 // context ids computed for the original node sequence to this call.
2427 // If there are duplicate calls with the same stack ids then we synthesize
2428 // new context ids that are duplicates of the originals. These are
2429 // assigned to SavedContextIds, which is a reference into the map entry
2430 // for this call, allowing us to access these ids later on.
2431 OldToNewContextIds.reserve(OldToNewContextIds.size() +
2432 StackSequenceContextIds.size());
2433 SavedContextIds =
2434 DuplicateContextIds
2435 ? duplicateContextIds(StackSequenceContextIds, OldToNewContextIds)
2436 : StackSequenceContextIds;
2437 assert(!SavedContextIds.empty());
2438
2439 if (!DuplicateContextIds) {
2440 // Update saved last node's context ids to remove those that are
2441 // assigned to other calls, so that it is ready for the next call at
2442 // this stack id.
2443 set_subtract(LastNodeContextIds, StackSequenceContextIds);
2444 if (LastNodeContextIds.empty())
2445 break;
2446 }
2447 }
2448 }
2449
2450 // Propagate the duplicate context ids over the graph.
2451 propagateDuplicateContextIds(OldToNewContextIds);
2452
2453 if (VerifyCCG)
2454 check();
2455
2456 // Now perform a post-order traversal over the graph, starting with the
2457 // allocation nodes, essentially processing nodes from callers to callees.
2458 // For any that contains an id in the map, update the graph to contain new
2459 // nodes representing any inlining at interior callsites. Note we move the
2460 // associated context ids over to the new nodes.
2461 DenseSet<const ContextNode *> Visited;
2462 DenseSet<uint32_t> ImportantContextIds(llvm::from_range,
2463 ImportantContextIdInfo.keys());
2464 for (auto &Entry : AllocationCallToContextNodeMap)
2465 assignStackNodesPostOrder(Entry.second, Visited, StackIdToMatchingCalls,
2466 CallToMatchingCall, ImportantContextIds);
2467
2468 fixupImportantContexts();
2469
2470 if (VerifyCCG)
2471 check();
2472}
2473
2474uint64_t ModuleCallsiteContextGraph::getLastStackId(Instruction *Call) {
2475 CallStack<MDNode, MDNode::op_iterator> CallsiteContext(
2476 Call->getMetadata(LLVMContext::MD_callsite));
2477 return CallsiteContext.back();
2478}
2479
2480uint64_t IndexCallsiteContextGraph::getLastStackId(IndexCall &Call) {
2482 CallStack<CallsiteInfo, SmallVector<unsigned>::const_iterator>
2483 CallsiteContext(dyn_cast_if_present<CallsiteInfo *>(Call));
2484 // Need to convert index into stack id.
2485 return Index.getStackIdAtIndex(CallsiteContext.back());
2486}
2487
2488static const std::string MemProfCloneSuffix = ".memprof.";
2489
2490static std::string getMemProfFuncName(Twine Base, unsigned CloneNo) {
2491 // We use CloneNo == 0 to refer to the original version, which doesn't get
2492 // renamed with a suffix.
2493 if (!CloneNo)
2494 return Base.str();
2495 return (Base + MemProfCloneSuffix + Twine(CloneNo)).str();
2496}
2497
2498static bool isMemProfClone(const Function &F) {
2499 return F.getName().contains(MemProfCloneSuffix);
2500}
2501
2502// Return the clone number of the given function by extracting it from the
2503// memprof suffix. Assumes the caller has already confirmed it is a memprof
2504// clone.
2505static unsigned getMemProfCloneNum(const Function &F) {
2507 auto Pos = F.getName().find_last_of('.');
2508 assert(Pos > 0);
2509 unsigned CloneNo;
2510 bool Err = F.getName().drop_front(Pos + 1).getAsInteger(10, CloneNo);
2511 assert(!Err);
2512 (void)Err;
2513 return CloneNo;
2514}
2515
2516std::string ModuleCallsiteContextGraph::getLabel(const Function *Func,
2517 const Instruction *Call,
2518 unsigned CloneNo) const {
2519 return (Twine(Call->getFunction()->getName()) + " -> " +
2520 cast<CallBase>(Call)->getCalledFunction()->getName())
2521 .str();
2522}
2523
2524std::string IndexCallsiteContextGraph::getLabel(const FunctionSummary *Func,
2525 const IndexCall &Call,
2526 unsigned CloneNo) const {
2527 auto VI = FSToVIMap.find(Func);
2528 assert(VI != FSToVIMap.end());
2529 std::string CallerName = getMemProfFuncName(VI->second.name(), CloneNo);
2531 return CallerName + " -> alloc";
2532 else {
2533 auto *Callsite = dyn_cast_if_present<CallsiteInfo *>(Call);
2534 return CallerName + " -> " +
2535 getMemProfFuncName(Callsite->Callee.name(),
2536 Callsite->Clones[CloneNo]);
2537 }
2538}
2539
2540std::string ModuleCallsiteContextGraph::getFuncName(const Function *Func,
2541 unsigned CloneNo) const {
2542 if (!Func)
2543 return "<unknown>";
2544 return getMemProfFuncName(Func->getName(), CloneNo);
2545}
2546
2547void ModuleCallsiteContextGraph::populateFunctionsWithCallers() {
2548 // Any use (direct call, address taken, alias, etc.) means the function is
2549 // referenced and may be reached by callers above the profiled context.
2550 for (const auto &F : Mod)
2551 if (!F.use_empty())
2552 FunctionsWithCallers.insert(&F);
2553}
2554
2555std::string IndexCallsiteContextGraph::getFuncName(const FunctionSummary *Func,
2556 unsigned CloneNo) const {
2557 if (!Func)
2558 return "<unknown>";
2559 auto VI = FSToVIMap.find(Func);
2560 if (VI != FSToVIMap.end()) {
2561 if (!VI->second.name().empty())
2562 return getMemProfFuncName(VI->second.name(), CloneNo);
2563 return getMemProfFuncName("GUID:" + std::to_string(VI->second.getGUID()),
2564 CloneNo);
2565 }
2566 return getMemProfFuncName("<unknown>", CloneNo);
2567}
2568
2569bool IndexCallsiteContextGraph::isFuncDead(const FunctionSummary *Func) const {
2570 return Index.withGlobalValueDeadStripping() && Func && !Func->isLive();
2571}
2572
2573void IndexCallsiteContextGraph::populateFunctionsWithCallers() {
2574 for (const auto &I : Index) {
2575 auto VI = Index.getValueInfo(I);
2576 for (const auto &S : VI.getSummaryList()) {
2577 if (!GlobalValue::isLocalLinkage(S->linkage()) &&
2578 !isPrevailing(VI.getGUID(), S.get()))
2579 continue;
2580 if (Index.withGlobalValueDeadStripping() && !S->isLive())
2581 continue;
2582 auto AddReferenced = [&](ValueInfo RefVI) {
2583 for (const auto &RefS : RefVI.getSummaryList()) {
2584 const GlobalValueSummary *Base = RefS->getBaseObject();
2585 if (const auto *RefFS = dyn_cast<FunctionSummary>(Base))
2586 FunctionsWithCallers.insert(RefFS);
2587 }
2588 };
2589 // Address-taken references (e.g. from vtables or function pointers).
2590 for (const auto &RefVI : S->refs())
2591 AddReferenced(RefVI);
2592 // Direct calls.
2593 if (const auto *FS = dyn_cast<FunctionSummary>(S.get()))
2594 for (const auto &CallEdge : FS->calls())
2595 AddReferenced(CallEdge.first);
2596 }
2597 }
2598}
2599
2600std::vector<uint64_t>
2601ModuleCallsiteContextGraph::getStackIdsWithContextNodesForCall(
2602 Instruction *Call) {
2603 CallStack<MDNode, MDNode::op_iterator> CallsiteContext(
2604 Call->getMetadata(LLVMContext::MD_callsite));
2605 return getStackIdsWithContextNodes<MDNode, MDNode::op_iterator>(
2606 CallsiteContext);
2607}
2608
2609std::vector<uint64_t>
2610IndexCallsiteContextGraph::getStackIdsWithContextNodesForCall(IndexCall &Call) {
2612 CallStack<CallsiteInfo, SmallVector<unsigned>::const_iterator>
2613 CallsiteContext(dyn_cast_if_present<CallsiteInfo *>(Call));
2614 return getStackIdsWithContextNodes<CallsiteInfo,
2615 SmallVector<unsigned>::const_iterator>(
2616 CallsiteContext);
2617}
2618
2619template <typename DerivedCCG, typename FuncTy, typename CallTy>
2620template <class NodeT, class IteratorT>
2621std::vector<uint64_t>
2622CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::getStackIdsWithContextNodes(
2623 CallStack<NodeT, IteratorT> &CallsiteContext) {
2624 std::vector<uint64_t> StackIds;
2625 for (auto IdOrIndex : CallsiteContext) {
2626 auto StackId = getStackId(IdOrIndex);
2627 ContextNode *Node = getNodeForStackId(StackId);
2628 if (!Node)
2629 break;
2630 StackIds.push_back(StackId);
2631 }
2632 return StackIds;
2633}
2634
2635ModuleCallsiteContextGraph::ModuleCallsiteContextGraph(
2636 Module &M,
2637 llvm::function_ref<OptimizationRemarkEmitter &(Function *)> OREGetter)
2638 : Mod(M), OREGetter(OREGetter) {
2639 // Map for keeping track of the largest cold contexts up to the number given
2640 // by MemProfTopNImportant. Must be a std::map (not DenseMap) because keys
2641 // must be sorted.
2642 std::map<uint64_t, uint32_t> TotalSizeToContextIdTopNCold;
2643 for (auto &F : M) {
2644 std::vector<CallInfo> CallsWithMetadata;
2645 for (auto &BB : F) {
2646 for (auto &I : BB) {
2647 if (!isa<CallBase>(I))
2648 continue;
2649 if (auto *MemProfMD = I.getMetadata(LLVMContext::MD_memprof)) {
2650 CallsWithMetadata.push_back(&I);
2651 auto *AllocNode = addAllocNode(&I, &F);
2652 auto *CallsiteMD = I.getMetadata(LLVMContext::MD_callsite);
2653 assert(CallsiteMD);
2654 CallStack<MDNode, MDNode::op_iterator> CallsiteContext(CallsiteMD);
2655 // Add all of the MIBs and their stack nodes.
2656 for (auto &MDOp : MemProfMD->operands()) {
2657 auto *MIBMD = cast<const MDNode>(MDOp);
2658 std::vector<ContextTotalSize> ContextSizeInfo;
2659 // Collect the context size information if it exists.
2660 if (MIBMD->getNumOperands() > 2) {
2661 for (unsigned I = 2; I < MIBMD->getNumOperands(); I++) {
2662 MDNode *ContextSizePair =
2663 dyn_cast<MDNode>(MIBMD->getOperand(I));
2664 assert(ContextSizePair->getNumOperands() == 2);
2666 ContextSizePair->getOperand(0))
2667 ->getZExtValue();
2669 ContextSizePair->getOperand(1))
2670 ->getZExtValue();
2671 ContextSizeInfo.push_back({FullStackId, TotalSize});
2672 }
2673 }
2677 addStackNodesForMIB<MDNode, MDNode::op_iterator>(
2678 AllocNode, StackContext, CallsiteContext,
2679 getMIBAllocType(MIBMD), ContextSizeInfo,
2680 TotalSizeToContextIdTopNCold);
2681 }
2682 // If exporting the graph to dot and an allocation id of interest was
2683 // specified, record all the context ids for this allocation node.
2684 if (ExportToDot && AllocNode->OrigStackOrAllocId == AllocIdForDot)
2685 DotAllocContextIds = AllocNode->getContextIds();
2686 assert(AllocNode->AllocTypes != (uint8_t)AllocationType::None);
2687 // Memprof and callsite metadata on memory allocations no longer
2688 // needed.
2689 I.setMetadata(LLVMContext::MD_memprof, nullptr);
2690 I.setMetadata(LLVMContext::MD_callsite, nullptr);
2691 }
2692 // For callsite metadata, add to list for this function for later use.
2693 else if (I.getMetadata(LLVMContext::MD_callsite)) {
2694 CallsWithMetadata.push_back(&I);
2695 }
2696 }
2697 }
2698 if (!CallsWithMetadata.empty())
2699 FuncToCallsWithMetadata[&F] = CallsWithMetadata;
2700 }
2701
2702 if (DumpCCG) {
2703 dbgs() << "CCG before updating call stack chains:\n";
2704 dbgs() << *this;
2705 }
2706
2707 if (ExportToDot)
2708 exportToDot("prestackupdate");
2709
2710 updateStackNodes();
2711
2712 if (ExportToDot)
2713 exportToDot("poststackupdate");
2714
2715 handleCallsitesWithMultipleTargets();
2716
2717 markBackedges();
2718
2719 // Strip off remaining callsite metadata, no longer needed.
2720 for (auto &FuncEntry : FuncToCallsWithMetadata)
2721 for (auto &Call : FuncEntry.second)
2722 Call.call()->setMetadata(LLVMContext::MD_callsite, nullptr);
2723}
2724
2725// Finds the set of GUIDs for weak aliasees that are prevailing in different
2726// modules than any of their aliases. We need to handle these specially.
2728IndexCallsiteContextGraph::findAliaseeGUIDsPrevailingInDifferentModule() {
2729 DenseSet<GlobalValue::GUID> AliaseeGUIDs;
2730 for (auto &I : Index) {
2731 auto VI = Index.getValueInfo(I);
2732 for (auto &S : VI.getSummaryList()) {
2733 // We only care about aliases to functions.
2734 auto *AS = dyn_cast<AliasSummary>(S.get());
2735 if (!AS)
2736 continue;
2737 auto *AliaseeSummary = &AS->getAliasee();
2738 auto *AliaseeFS = dyn_cast<FunctionSummary>(AliaseeSummary);
2739 if (!AliaseeFS)
2740 continue;
2741 // Skip this summary if it is not for the prevailing symbol for this GUID.
2742 // The linker doesn't resolve local linkage values so don't check whether
2743 // those are prevailing.
2744 if (!GlobalValue::isLocalLinkage(S->linkage()) &&
2745 !isPrevailing(VI.getGUID(), S.get()))
2746 continue;
2747 // Prevailing aliasee could be in a different module only if it is weak.
2748 if (!GlobalValue::isWeakForLinker(AliaseeSummary->linkage()))
2749 continue;
2750 auto AliaseeGUID = AS->getAliaseeGUID();
2751 // If the aliasee copy in this module is not prevailing, record it.
2752 if (!isPrevailing(AliaseeGUID, AliaseeSummary))
2753 AliaseeGUIDs.insert(AliaseeGUID);
2754 }
2755 }
2756 AliaseesPrevailingInDiffModuleFromAlias += AliaseeGUIDs.size();
2757 return AliaseeGUIDs;
2758}
2759
2760IndexCallsiteContextGraph::IndexCallsiteContextGraph(
2761 ModuleSummaryIndex &Index,
2762 llvm::function_ref<bool(GlobalValue::GUID, const GlobalValueSummary *)>
2763 isPrevailing)
2764 : Index(Index), isPrevailing(isPrevailing) {
2765 // Since we use the aliasee summary info to create the necessary clones for
2766 // its aliases, conservatively skip recording the aliasee function's callsites
2767 // in the CCG for any that are prevailing in a different module than one of
2768 // its aliases. We could record the necessary information to do this in the
2769 // summary, but this case should not be common.
2770 DenseSet<GlobalValue::GUID> GUIDsToSkip =
2771 findAliaseeGUIDsPrevailingInDifferentModule();
2772 // Map for keeping track of the largest cold contexts up to the number given
2773 // by MemProfTopNImportant. Must be a std::map (not DenseMap) because keys
2774 // must be sorted.
2775 std::map<uint64_t, uint32_t> TotalSizeToContextIdTopNCold;
2776 // Sort by GUID for deterministic graph construction order.
2777 // TODO: This sort has a measurable cost on the thin link when memprof is
2778 // enabled. Investigate gating it behind an option that is only enabled for
2779 // tests that check internal state.
2780 for (const auto &I : Index.sortedGlobalValueSummariesRange()) {
2781 auto VI = Index.getValueInfo(I);
2782 if (GUIDsToSkip.contains(VI.getGUID()))
2783 continue;
2784 for (auto &S : VI.getSummaryList()) {
2785 // We should only add the prevailing nodes. Otherwise we may try to clone
2786 // in a weak copy that won't be linked (and may be different than the
2787 // prevailing version).
2788 // We only keep the memprof summary on the prevailing copy now when
2789 // building the combined index, as a space optimization, however don't
2790 // rely on this optimization. The linker doesn't resolve local linkage
2791 // values so don't check whether those are prevailing.
2792 if (!GlobalValue::isLocalLinkage(S->linkage()) &&
2793 !isPrevailing(VI.getGUID(), S.get()))
2794 continue;
2795 auto *FS = dyn_cast<FunctionSummary>(S.get());
2796 if (!FS)
2797 continue;
2798 std::vector<CallInfo> CallsWithMetadata;
2799 if (!FS->allocs().empty()) {
2800 for (auto &AN : FS->mutableAllocs()) {
2801 // This can happen because of recursion elimination handling that
2802 // currently exists in ModuleSummaryAnalysis. Skip these for now.
2803 // We still added them to the summary because we need to be able to
2804 // correlate properly in applyImport in the backends.
2805 if (AN.MIBs.empty())
2806 continue;
2807 IndexCall AllocCall(&AN);
2808 CallsWithMetadata.push_back(AllocCall);
2809 auto *AllocNode = addAllocNode(AllocCall, FS);
2810 // Pass an empty CallStack to the CallsiteContext (second)
2811 // parameter, since for ThinLTO we already collapsed out the inlined
2812 // stack ids on the allocation call during ModuleSummaryAnalysis.
2814 EmptyContext;
2815 unsigned I = 0;
2817 AN.ContextSizeInfos.size() == AN.MIBs.size());
2818 // Now add all of the MIBs and their stack nodes.
2819 for (auto &MIB : AN.MIBs) {
2821 StackContext(&MIB);
2822 std::vector<ContextTotalSize> ContextSizeInfo;
2823 if (!AN.ContextSizeInfos.empty()) {
2824 for (auto [FullStackId, TotalSize] : AN.ContextSizeInfos[I])
2825 ContextSizeInfo.push_back({FullStackId, TotalSize});
2826 }
2827 addStackNodesForMIB<MIBInfo, SmallVector<unsigned>::const_iterator>(
2828 AllocNode, StackContext, EmptyContext, MIB.AllocType,
2829 ContextSizeInfo, TotalSizeToContextIdTopNCold);
2830 I++;
2831 }
2832 // If exporting the graph to dot and an allocation id of interest was
2833 // specified, record all the context ids for this allocation node.
2834 if (ExportToDot && AllocNode->OrigStackOrAllocId == AllocIdForDot)
2835 DotAllocContextIds = AllocNode->getContextIds();
2836 assert(AllocNode->AllocTypes != (uint8_t)AllocationType::None);
2837 // Initialize version 0 on the summary alloc node to the current alloc
2838 // type, unless it has both types in which case make it default, so
2839 // that in the case where we aren't able to clone the original version
2840 // always ends up with the default allocation behavior.
2841 AN.Versions[0] = (uint8_t)allocTypeToUse(AllocNode->AllocTypes);
2842 }
2843 }
2844 // For callsite metadata, add to list for this function for later use.
2845 if (!FS->callsites().empty())
2846 for (auto &SN : FS->mutableCallsites()) {
2847 IndexCall StackNodeCall(&SN);
2848 CallsWithMetadata.push_back(StackNodeCall);
2849 }
2850
2851 if (!CallsWithMetadata.empty())
2852 FuncToCallsWithMetadata[FS] = CallsWithMetadata;
2853
2854 if (!FS->allocs().empty() || !FS->callsites().empty())
2855 FSToVIMap[FS] = VI;
2856 }
2857 }
2858
2859 if (DumpCCG) {
2860 dbgs() << "CCG before updating call stack chains:\n";
2861 dbgs() << *this;
2862 }
2863
2864 if (ExportToDot)
2865 exportToDot("prestackupdate");
2866
2867 updateStackNodes();
2868
2869 if (ExportToDot)
2870 exportToDot("poststackupdate");
2871
2872 handleCallsitesWithMultipleTargets();
2873
2874 markBackedges();
2875}
2876
2877template <typename DerivedCCG, typename FuncTy, typename CallTy>
2878void CallsiteContextGraph<DerivedCCG, FuncTy,
2879 CallTy>::handleCallsitesWithMultipleTargets() {
2880 // Look for and workaround callsites that call multiple functions.
2881 // This can happen for indirect calls, which needs better handling, and in
2882 // more rare cases (e.g. macro expansion).
2883 // TODO: To fix this for indirect calls we will want to perform speculative
2884 // devirtualization using either the normal PGO info with ICP, or using the
2885 // information in the profiled MemProf contexts. We can do this prior to
2886 // this transformation for regular LTO, and for ThinLTO we can simulate that
2887 // effect in the summary and perform the actual speculative devirtualization
2888 // while cloning in the ThinLTO backend.
2889
2890 // Keep track of the new nodes synthesized for discovered tail calls missing
2891 // from the profiled contexts.
2892 MapVector<CallInfo, ContextNode *> TailCallToContextNodeMap;
2893
2894 std::vector<std::pair<CallInfo, ContextNode *>> NewCallToNode;
2895 for (auto &Entry : NonAllocationCallToContextNodeMap) {
2896 auto *Node = Entry.second;
2897 assert(Node->Clones.empty());
2898 // Check all node callees and see if in the same function.
2899 // We need to check all of the calls recorded in this Node, because in some
2900 // cases we may have had multiple calls with the same debug info calling
2901 // different callees. This can happen, for example, when an object is
2902 // constructed in the paramter list - the destructor call of the object has
2903 // the same debug info (line/col) as the call the object was passed to.
2904 // Here we will prune any that don't match all callee nodes.
2905 std::vector<CallInfo> AllCalls;
2906 AllCalls.reserve(Node->MatchingCalls.size() + 1);
2907 AllCalls.push_back(Node->Call);
2908 llvm::append_range(AllCalls, Node->MatchingCalls);
2909
2910 // First see if we can partition the calls by callee function, creating new
2911 // nodes to host each set of calls calling the same callees. This is
2912 // necessary for support indirect calls with ThinLTO, for which we
2913 // synthesized CallsiteInfo records for each target. They will all have the
2914 // same callsite stack ids and would be sharing a context node at this
2915 // point. We need to perform separate cloning for each, which will be
2916 // applied along with speculative devirtualization in the ThinLTO backends
2917 // as needed. Note this does not currently support looking through tail
2918 // calls, it is unclear if we need that for indirect call targets.
2919 // First partition calls by callee func. Map indexed by func, value is
2920 // struct with list of matching calls, assigned node.
2921 if (partitionCallsByCallee(Node, AllCalls, NewCallToNode))
2922 continue;
2923
2924 auto It = AllCalls.begin();
2925 // Iterate through the calls until we find the first that matches.
2926 for (; It != AllCalls.end(); ++It) {
2927 auto ThisCall = *It;
2928 bool Match = true;
2929 for (auto EI = Node->CalleeEdges.begin(); EI != Node->CalleeEdges.end();
2930 ++EI) {
2931 auto Edge = *EI;
2932 if (!Edge->Callee->hasCall())
2933 continue;
2934 assert(NodeToCallingFunc.count(Edge->Callee));
2935 // Check if the called function matches that of the callee node.
2936 if (!calleesMatch(ThisCall.call(), EI, TailCallToContextNodeMap)) {
2937 Match = false;
2938 break;
2939 }
2940 }
2941 // Found a call that matches the callee nodes, we can quit now.
2942 if (Match) {
2943 // If the first match is not the primary call on the Node, update it
2944 // now. We will update the list of matching calls further below.
2945 if (Node->Call != ThisCall) {
2946 Node->setCall(ThisCall);
2947 // We need to update the NonAllocationCallToContextNodeMap, but don't
2948 // want to do this during iteration over that map, so save the calls
2949 // that need updated entries.
2950 NewCallToNode.push_back({ThisCall, Node});
2951 }
2952 break;
2953 }
2954 }
2955 // We will update this list below (or leave it cleared if there was no
2956 // match found above).
2957 Node->MatchingCalls.clear();
2958 // If we hit the end of the AllCalls vector, no call matching the callee
2959 // nodes was found, clear the call information in the node.
2960 if (It == AllCalls.end()) {
2961 RemovedEdgesWithMismatchedCallees++;
2962 // Work around by setting Node to have a null call, so it gets
2963 // skipped during cloning. Otherwise assignFunctions will assert
2964 // because its data structures are not designed to handle this case.
2965 Node->setCall(CallInfo());
2966 continue;
2967 }
2968 // Now add back any matching calls that call the same function as the
2969 // matching primary call on Node.
2970 for (++It; It != AllCalls.end(); ++It) {
2971 auto ThisCall = *It;
2972 if (!sameCallee(Node->Call.call(), ThisCall.call()))
2973 continue;
2974 Node->MatchingCalls.push_back(ThisCall);
2975 }
2976 }
2977
2978 // Remove all mismatched nodes identified in the above loop from the node map
2979 // (checking whether they have a null call which is set above). For a
2980 // MapVector like NonAllocationCallToContextNodeMap it is much more efficient
2981 // to do the removal via remove_if than by individually erasing entries above.
2982 // Also remove any entries if we updated the node's primary call above.
2983 NonAllocationCallToContextNodeMap.remove_if([](const auto &it) {
2984 return !it.second->hasCall() || it.second->Call != it.first;
2985 });
2986
2987 // Add entries for any new primary calls recorded above.
2988 for (auto &[Call, Node] : NewCallToNode)
2989 NonAllocationCallToContextNodeMap[Call] = Node;
2990
2991 // Add the new nodes after the above loop so that the iteration is not
2992 // invalidated.
2993 for (auto &[Call, Node] : TailCallToContextNodeMap)
2994 NonAllocationCallToContextNodeMap[Call] = Node;
2995}
2996
2997template <typename DerivedCCG, typename FuncTy, typename CallTy>
2998bool CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::partitionCallsByCallee(
2999 ContextNode *Node, ArrayRef<CallInfo> AllCalls,
3000 std::vector<std::pair<CallInfo, ContextNode *>> &NewCallToNode) {
3001 // Struct to keep track of all the calls having the same callee function,
3002 // and the node we eventually assign to them. Eventually we will record the
3003 // context node assigned to this group of calls.
3004 struct CallsWithSameCallee {
3005 std::vector<CallInfo> Calls;
3006 ContextNode *Node = nullptr;
3007 };
3008
3009 // First partition calls by callee function. Build map from each function
3010 // to the list of matching calls.
3012 for (auto ThisCall : AllCalls) {
3013 auto *F = getCalleeFunc(ThisCall.call());
3014 if (F)
3015 CalleeFuncToCallInfo[F].Calls.push_back(ThisCall);
3016 }
3017
3018 // Next, walk through all callee edges. For each callee node, get its
3019 // containing function and see if it was recorded in the above map (meaning we
3020 // have at least one matching call). Build another map from each callee node
3021 // with a matching call to the structure instance created above containing all
3022 // the calls.
3024 for (const auto &Edge : Node->CalleeEdges) {
3025 if (!Edge->Callee->hasCall())
3026 continue;
3027 const FuncTy *ProfiledCalleeFunc = NodeToCallingFunc[Edge->Callee];
3028 if (CalleeFuncToCallInfo.contains(ProfiledCalleeFunc))
3029 CalleeNodeToCallInfo[Edge->Callee] =
3030 &CalleeFuncToCallInfo[ProfiledCalleeFunc];
3031 }
3032
3033 // If there are entries in the second map, then there were no matching
3034 // calls/callees, nothing to do here. Return so we can go to the handling that
3035 // looks through tail calls.
3036 if (CalleeNodeToCallInfo.empty())
3037 return false;
3038
3039 // Walk through all callee edges again. Any and all callee edges that didn't
3040 // match any calls (callee not in the CalleeNodeToCallInfo map) are moved to a
3041 // new caller node (UnmatchedCalleesNode) which gets a null call so that it is
3042 // ignored during cloning. If it is in the map, then we use the node recorded
3043 // in that entry (creating it if needed), and move the callee edge to it.
3044 // The first callee will use the original node instead of creating a new one.
3045 // Note that any of the original calls on this node (in AllCalls) that didn't
3046 // have a callee function automatically get dropped from the node as part of
3047 // this process.
3048 ContextNode *UnmatchedCalleesNode = nullptr;
3049 // Track whether we already assigned original node to a callee.
3050 bool UsedOrigNode = false;
3051 assert(NodeToCallingFunc[Node]);
3052 // Iterate over a copy of Node's callee edges, since we may need to remove
3053 // edges in moveCalleeEdgeToNewCaller, and this simplifies the handling and
3054 // makes it less error-prone.
3055 auto CalleeEdges = Node->CalleeEdges;
3056 for (auto &Edge : CalleeEdges) {
3057 if (!Edge->Callee->hasCall())
3058 continue;
3059
3060 // Will be updated below to point to whatever (caller) node this callee edge
3061 // should be moved to.
3062 ContextNode *CallerNodeToUse = nullptr;
3063
3064 // Handle the case where there were no matching calls first. Move this
3065 // callee edge to the UnmatchedCalleesNode, creating it if needed.
3066 if (!CalleeNodeToCallInfo.contains(Edge->Callee)) {
3067 if (!UnmatchedCalleesNode)
3068 UnmatchedCalleesNode =
3069 createNewNode(/*IsAllocation=*/false, NodeToCallingFunc[Node]);
3070 CallerNodeToUse = UnmatchedCalleesNode;
3071 } else {
3072 // Look up the information recorded for this callee node, and use the
3073 // recorded caller node (creating it if needed).
3074 auto *Info = CalleeNodeToCallInfo[Edge->Callee];
3075 if (!Info->Node) {
3076 // If we haven't assigned any callees to the original node use it.
3077 if (!UsedOrigNode) {
3078 Info->Node = Node;
3079 // Clear the set of matching calls which will be updated below.
3080 Node->MatchingCalls.clear();
3081 UsedOrigNode = true;
3082 } else
3083 Info->Node =
3084 createNewNode(/*IsAllocation=*/false, NodeToCallingFunc[Node]);
3085 assert(!Info->Calls.empty());
3086 // The first call becomes the primary call for this caller node, and the
3087 // rest go in the matching calls list.
3088 Info->Node->setCall(Info->Calls.front());
3089 llvm::append_range(Info->Node->MatchingCalls,
3090 llvm::drop_begin(Info->Calls));
3091 // Save the primary call to node correspondence so that we can update
3092 // the NonAllocationCallToContextNodeMap, which is being iterated in the
3093 // caller of this function.
3094 NewCallToNode.push_back({Info->Node->Call, Info->Node});
3095 }
3096 CallerNodeToUse = Info->Node;
3097 }
3098
3099 // Don't need to move edge if we are using the original node;
3100 if (CallerNodeToUse == Node)
3101 continue;
3102
3103 moveCalleeEdgeToNewCaller(Edge, CallerNodeToUse);
3104 }
3105 // Now that we are done moving edges, clean up any caller edges that ended
3106 // up with no type or context ids. During moveCalleeEdgeToNewCaller all
3107 // caller edges from Node are replicated onto the new callers, and it
3108 // simplifies the handling to leave them until we have moved all
3109 // edges/context ids.
3110 for (auto &I : CalleeNodeToCallInfo)
3111 removeNoneTypeCallerEdges(I.second->Node);
3112 if (UnmatchedCalleesNode)
3113 removeNoneTypeCallerEdges(UnmatchedCalleesNode);
3114 removeNoneTypeCallerEdges(Node);
3115
3116 return true;
3117}
3118
3119uint64_t ModuleCallsiteContextGraph::getStackId(uint64_t IdOrIndex) const {
3120 // In the Module (IR) case this is already the Id.
3121 return IdOrIndex;
3122}
3123
3124uint64_t IndexCallsiteContextGraph::getStackId(uint64_t IdOrIndex) const {
3125 // In the Index case this is an index into the stack id list in the summary
3126 // index, convert it to an Id.
3127 return Index.getStackIdAtIndex(IdOrIndex);
3128}
3129
3130template <typename DerivedCCG, typename FuncTy, typename CallTy>
3131bool CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::calleesMatch(
3132 CallTy Call, EdgeIter &EI,
3133 MapVector<CallInfo, ContextNode *> &TailCallToContextNodeMap) {
3134 auto Edge = *EI;
3135 const FuncTy *ProfiledCalleeFunc = NodeToCallingFunc[Edge->Callee];
3136 const FuncTy *CallerFunc = NodeToCallingFunc[Edge->Caller];
3137 // Will be populated in order of callee to caller if we find a chain of tail
3138 // calls between the profiled caller and callee.
3139 std::vector<std::pair<CallTy, FuncTy *>> FoundCalleeChain;
3140 if (!calleeMatchesFunc(Call, ProfiledCalleeFunc, CallerFunc,
3141 FoundCalleeChain))
3142 return false;
3143
3144 // The usual case where the profiled callee matches that of the IR/summary.
3145 if (FoundCalleeChain.empty())
3146 return true;
3147
3148 auto AddEdge = [Edge, &EI](ContextNode *Caller, ContextNode *Callee) {
3149 auto *CurEdge = Callee->findEdgeFromCaller(Caller);
3150 // If there is already an edge between these nodes, simply update it and
3151 // return.
3152 if (CurEdge) {
3153 CurEdge->ContextIds.insert_range(Edge->ContextIds);
3154 CurEdge->AllocTypes |= Edge->AllocTypes;
3155 return;
3156 }
3157 // Otherwise, create a new edge and insert it into the caller and callee
3158 // lists.
3159 auto NewEdge = std::make_shared<ContextEdge>(
3160 Callee, Caller, Edge->AllocTypes, Edge->ContextIds);
3161 Callee->CallerEdges.push_back(NewEdge);
3162 if (Caller == Edge->Caller) {
3163 // If we are inserting the new edge into the current edge's caller, insert
3164 // the new edge before the current iterator position, and then increment
3165 // back to the current edge.
3166 EI = Caller->CalleeEdges.insert(EI, NewEdge);
3167 ++EI;
3168 assert(*EI == Edge &&
3169 "Iterator position not restored after insert and increment");
3170 } else
3171 Caller->CalleeEdges.push_back(NewEdge);
3172 };
3173
3174 // Create new nodes for each found callee and connect in between the profiled
3175 // caller and callee.
3176 auto *CurCalleeNode = Edge->Callee;
3177 for (auto &[NewCall, Func] : FoundCalleeChain) {
3178 ContextNode *NewNode = nullptr;
3179 // First check if we have already synthesized a node for this tail call.
3180 if (TailCallToContextNodeMap.count(NewCall)) {
3181 NewNode = TailCallToContextNodeMap[NewCall];
3182 NewNode->AllocTypes |= Edge->AllocTypes;
3183 } else {
3184 FuncToCallsWithMetadata[Func].push_back({NewCall});
3185 // Create Node and record node info.
3186 NewNode = createNewNode(/*IsAllocation=*/false, Func, NewCall);
3187 TailCallToContextNodeMap[NewCall] = NewNode;
3188 NewNode->AllocTypes = Edge->AllocTypes;
3189 }
3190
3191 // Hook up node to its callee node
3192 AddEdge(NewNode, CurCalleeNode);
3193
3194 CurCalleeNode = NewNode;
3195 }
3196
3197 // Hook up edge's original caller to new callee node.
3198 AddEdge(Edge->Caller, CurCalleeNode);
3199
3200#ifndef NDEBUG
3201 // Save this because Edge's fields get cleared below when removed.
3202 auto *Caller = Edge->Caller;
3203#endif
3204
3205 // Remove old edge
3206 removeEdgeFromGraph(Edge.get(), &EI, /*CalleeIter=*/true);
3207
3208 // To simplify the increment of EI in the caller, subtract one from EI.
3209 // In the final AddEdge call we would have either added a new callee edge,
3210 // to Edge->Caller, or found an existing one. Either way we are guaranteed
3211 // that there is at least one callee edge.
3212 assert(!Caller->CalleeEdges.empty());
3213 --EI;
3214
3215 return true;
3216}
3217
3218bool ModuleCallsiteContextGraph::findProfiledCalleeThroughTailCalls(
3219 const Function *ProfiledCallee, Value *CurCallee, unsigned Depth,
3220 std::vector<std::pair<Instruction *, Function *>> &FoundCalleeChain,
3221 bool &FoundMultipleCalleeChains) {
3222 // Stop recursive search if we have already explored the maximum specified
3223 // depth.
3225 return false;
3226
3227 auto SaveCallsiteInfo = [&](Instruction *Callsite, Function *F) {
3228 FoundCalleeChain.push_back({Callsite, F});
3229 };
3230
3231 auto *CalleeFunc = dyn_cast<Function>(CurCallee);
3232 if (!CalleeFunc) {
3233 auto *Alias = dyn_cast<GlobalAlias>(CurCallee);
3234 assert(Alias);
3235 CalleeFunc = dyn_cast<Function>(Alias->getAliasee());
3236 assert(CalleeFunc);
3237 }
3238
3239 // Look for tail calls in this function, and check if they either call the
3240 // profiled callee directly, or indirectly (via a recursive search).
3241 // Only succeed if there is a single unique tail call chain found between the
3242 // profiled caller and callee, otherwise we could perform incorrect cloning.
3243 bool FoundSingleCalleeChain = false;
3244 for (auto &BB : *CalleeFunc) {
3245 for (auto &I : BB) {
3246 auto *CB = dyn_cast<CallBase>(&I);
3247 if (!CB || !CB->isTailCall())
3248 continue;
3249 auto *CalledValue = CB->getCalledOperand();
3250 auto *CalledFunction = CB->getCalledFunction();
3251 if (CalledValue && !CalledFunction) {
3252 CalledValue = CalledValue->stripPointerCasts();
3253 // Stripping pointer casts can reveal a called function.
3254 CalledFunction = dyn_cast<Function>(CalledValue);
3255 }
3256 // Check if this is an alias to a function. If so, get the
3257 // called aliasee for the checks below.
3258 if (auto *GA = dyn_cast<GlobalAlias>(CalledValue)) {
3259 assert(!CalledFunction &&
3260 "Expected null called function in callsite for alias");
3261 CalledFunction = dyn_cast<Function>(GA->getAliaseeObject());
3262 }
3263 if (!CalledFunction)
3264 continue;
3265 if (CalledFunction == ProfiledCallee) {
3266 if (FoundSingleCalleeChain) {
3267 FoundMultipleCalleeChains = true;
3268 return false;
3269 }
3270 FoundSingleCalleeChain = true;
3271 FoundProfiledCalleeCount++;
3272 FoundProfiledCalleeDepth += Depth;
3273 if (Depth > FoundProfiledCalleeMaxDepth)
3274 FoundProfiledCalleeMaxDepth = Depth;
3275 SaveCallsiteInfo(&I, CalleeFunc);
3276 } else if (findProfiledCalleeThroughTailCalls(
3277 ProfiledCallee, CalledFunction, Depth + 1,
3278 FoundCalleeChain, FoundMultipleCalleeChains)) {
3279 // findProfiledCalleeThroughTailCalls should not have returned
3280 // true if FoundMultipleCalleeChains.
3281 assert(!FoundMultipleCalleeChains);
3282 if (FoundSingleCalleeChain) {
3283 FoundMultipleCalleeChains = true;
3284 return false;
3285 }
3286 FoundSingleCalleeChain = true;
3287 SaveCallsiteInfo(&I, CalleeFunc);
3288 } else if (FoundMultipleCalleeChains)
3289 return false;
3290 }
3291 }
3292
3293 return FoundSingleCalleeChain;
3294}
3295
3296const Function *ModuleCallsiteContextGraph::getCalleeFunc(Instruction *Call) {
3297 auto *CB = dyn_cast<CallBase>(Call);
3298 if (!CB->getCalledOperand() || CB->isIndirectCall())
3299 return nullptr;
3300 auto *CalleeVal = CB->getCalledOperand()->stripPointerCasts();
3301 auto *Alias = dyn_cast<GlobalAlias>(CalleeVal);
3302 if (Alias)
3303 return dyn_cast<Function>(Alias->getAliasee());
3304 return dyn_cast<Function>(CalleeVal);
3305}
3306
3307bool ModuleCallsiteContextGraph::calleeMatchesFunc(
3308 Instruction *Call, const Function *Func, const Function *CallerFunc,
3309 std::vector<std::pair<Instruction *, Function *>> &FoundCalleeChain) {
3310 auto *CB = dyn_cast<CallBase>(Call);
3311 if (!CB->getCalledOperand() || CB->isIndirectCall())
3312 return false;
3313 auto *CalleeVal = CB->getCalledOperand()->stripPointerCasts();
3314 auto *CalleeFunc = dyn_cast<Function>(CalleeVal);
3315 if (CalleeFunc == Func)
3316 return true;
3317 auto *Alias = dyn_cast<GlobalAlias>(CalleeVal);
3318 if (Alias && Alias->getAliasee() == Func)
3319 return true;
3320
3321 // Recursively search for the profiled callee through tail calls starting with
3322 // the actual Callee. The discovered tail call chain is saved in
3323 // FoundCalleeChain, and we will fixup the graph to include these callsites
3324 // after returning.
3325 // FIXME: We will currently redo the same recursive walk if we find the same
3326 // mismatched callee from another callsite. We can improve this with more
3327 // bookkeeping of the created chain of new nodes for each mismatch.
3328 unsigned Depth = 1;
3329 bool FoundMultipleCalleeChains = false;
3330 if (!findProfiledCalleeThroughTailCalls(Func, CalleeVal, Depth,
3331 FoundCalleeChain,
3332 FoundMultipleCalleeChains)) {
3333 LLVM_DEBUG(dbgs() << "Not found through unique tail call chain: "
3334 << Func->getName() << " from " << CallerFunc->getName()
3335 << " that actually called " << CalleeVal->getName()
3336 << (FoundMultipleCalleeChains
3337 ? " (found multiple possible chains)"
3338 : "")
3339 << "\n");
3340 if (FoundMultipleCalleeChains)
3341 FoundProfiledCalleeNonUniquelyCount++;
3342 return false;
3343 }
3344
3345 return true;
3346}
3347
3348bool ModuleCallsiteContextGraph::sameCallee(Instruction *Call1,
3349 Instruction *Call2) {
3350 auto *CB1 = cast<CallBase>(Call1);
3351 if (!CB1->getCalledOperand() || CB1->isIndirectCall())
3352 return false;
3353 auto *CalleeVal1 = CB1->getCalledOperand()->stripPointerCasts();
3354 auto *CalleeFunc1 = dyn_cast<Function>(CalleeVal1);
3355 auto *CB2 = cast<CallBase>(Call2);
3356 if (!CB2->getCalledOperand() || CB2->isIndirectCall())
3357 return false;
3358 auto *CalleeVal2 = CB2->getCalledOperand()->stripPointerCasts();
3359 auto *CalleeFunc2 = dyn_cast<Function>(CalleeVal2);
3360 return CalleeFunc1 == CalleeFunc2;
3361}
3362
3363bool IndexCallsiteContextGraph::findProfiledCalleeThroughTailCalls(
3364 ValueInfo ProfiledCallee, ValueInfo CurCallee, unsigned Depth,
3365 std::vector<std::pair<IndexCall, FunctionSummary *>> &FoundCalleeChain,
3366 bool &FoundMultipleCalleeChains) {
3367 // Stop recursive search if we have already explored the maximum specified
3368 // depth.
3370 return false;
3371
3372 auto CreateAndSaveCallsiteInfo = [&](ValueInfo Callee, FunctionSummary *FS) {
3373 // Make a CallsiteInfo for each discovered callee, if one hasn't already
3374 // been synthesized.
3375 if (!FunctionCalleesToSynthesizedCallsiteInfos.count(FS) ||
3376 !FunctionCalleesToSynthesizedCallsiteInfos[FS].count(Callee))
3377 // StackIds is empty (we don't have debug info available in the index for
3378 // these callsites)
3379 FunctionCalleesToSynthesizedCallsiteInfos[FS][Callee] =
3380 std::make_unique<CallsiteInfo>(Callee, SmallVector<unsigned>());
3381 CallsiteInfo *NewCallsiteInfo =
3382 FunctionCalleesToSynthesizedCallsiteInfos[FS][Callee].get();
3383 FoundCalleeChain.push_back({NewCallsiteInfo, FS});
3384 };
3385
3386 // Look for tail calls in this function, and check if they either call the
3387 // profiled callee directly, or indirectly (via a recursive search).
3388 // Only succeed if there is a single unique tail call chain found between the
3389 // profiled caller and callee, otherwise we could perform incorrect cloning.
3390 bool FoundSingleCalleeChain = false;
3391 for (auto &S : CurCallee.getSummaryList()) {
3392 if (!GlobalValue::isLocalLinkage(S->linkage()) &&
3393 !isPrevailing(CurCallee.getGUID(), S.get()))
3394 continue;
3395 auto *FS = dyn_cast<FunctionSummary>(S->getBaseObject());
3396 if (!FS)
3397 continue;
3398 auto FSVI = CurCallee;
3399 auto *AS = dyn_cast<AliasSummary>(S.get());
3400 if (AS)
3401 FSVI = AS->getAliaseeVI();
3402 for (auto &CallEdge : FS->calls()) {
3403 if (!CallEdge.second.hasTailCall())
3404 continue;
3405 // Edges marked indirect are the profiled targets of indirect calls.
3406 // If the tail call is indirect, the ThinLTO backend will perform
3407 // ICP to the target in order to call a clone of it.
3408 if (CallEdge.second.hasIndirectCall() && !IndirectTailCallSearch)
3409 continue;
3410 if (CallEdge.first == ProfiledCallee) {
3411 if (FoundSingleCalleeChain) {
3412 FoundMultipleCalleeChains = true;
3413 return false;
3414 }
3415 FoundSingleCalleeChain = true;
3416 FoundProfiledCalleeCount++;
3417 FoundProfiledCalleeDepth += Depth;
3418 if (Depth > FoundProfiledCalleeMaxDepth)
3419 FoundProfiledCalleeMaxDepth = Depth;
3420 if (CallEdge.second.hasIndirectCall())
3421 FoundProfiledCalleeIndirectTailCallCount++;
3422 CreateAndSaveCallsiteInfo(CallEdge.first, FS);
3423 // Add FS to FSToVIMap in case it isn't already there.
3424 assert(!FSToVIMap.count(FS) || FSToVIMap[FS] == FSVI);
3425 FSToVIMap[FS] = FSVI;
3426 } else if (findProfiledCalleeThroughTailCalls(
3427 ProfiledCallee, CallEdge.first, Depth + 1,
3428 FoundCalleeChain, FoundMultipleCalleeChains)) {
3429 // findProfiledCalleeThroughTailCalls should not have returned
3430 // true if FoundMultipleCalleeChains.
3431 assert(!FoundMultipleCalleeChains);
3432 if (FoundSingleCalleeChain) {
3433 FoundMultipleCalleeChains = true;
3434 return false;
3435 }
3436 FoundSingleCalleeChain = true;
3437 if (CallEdge.second.hasIndirectCall())
3438 FoundProfiledCalleeIndirectTailCallCount++;
3439 CreateAndSaveCallsiteInfo(CallEdge.first, FS);
3440 // Add FS to FSToVIMap in case it isn't already there.
3441 assert(!FSToVIMap.count(FS) || FSToVIMap[FS] == FSVI);
3442 FSToVIMap[FS] = FSVI;
3443 } else if (FoundMultipleCalleeChains)
3444 return false;
3445 }
3446 }
3447
3448 return FoundSingleCalleeChain;
3449}
3450
3451const FunctionSummary *
3452IndexCallsiteContextGraph::getCalleeFunc(IndexCall &Call) {
3453 ValueInfo Callee = dyn_cast_if_present<CallsiteInfo *>(Call)->Callee;
3454 if (Callee.getSummaryList().empty())
3455 return nullptr;
3456 return dyn_cast<FunctionSummary>(Callee.getSummaryList()[0]->getBaseObject());
3457}
3458
3459bool IndexCallsiteContextGraph::calleeMatchesFunc(
3460 IndexCall &Call, const FunctionSummary *Func,
3461 const FunctionSummary *CallerFunc,
3462 std::vector<std::pair<IndexCall, FunctionSummary *>> &FoundCalleeChain) {
3463 ValueInfo Callee = dyn_cast_if_present<CallsiteInfo *>(Call)->Callee;
3464 // If there is no summary list then this is a call to an externally defined
3465 // symbol.
3466 AliasSummary *Alias =
3467 Callee.getSummaryList().empty()
3468 ? nullptr
3469 : dyn_cast<AliasSummary>(Callee.getSummaryList()[0].get());
3470 assert(FSToVIMap.count(Func));
3471 auto FuncVI = FSToVIMap[Func];
3472 if (Callee == FuncVI ||
3473 // If callee is an alias, check the aliasee, since only function
3474 // summary base objects will contain the stack node summaries and thus
3475 // get a context node.
3476 (Alias && Alias->getAliaseeVI() == FuncVI))
3477 return true;
3478
3479 // Recursively search for the profiled callee through tail calls starting with
3480 // the actual Callee. The discovered tail call chain is saved in
3481 // FoundCalleeChain, and we will fixup the graph to include these callsites
3482 // after returning.
3483 // FIXME: We will currently redo the same recursive walk if we find the same
3484 // mismatched callee from another callsite. We can improve this with more
3485 // bookkeeping of the created chain of new nodes for each mismatch.
3486 unsigned Depth = 1;
3487 bool FoundMultipleCalleeChains = false;
3488 if (!findProfiledCalleeThroughTailCalls(
3489 FuncVI, Callee, Depth, FoundCalleeChain, FoundMultipleCalleeChains)) {
3490 LLVM_DEBUG(dbgs() << "Not found through unique tail call chain: " << FuncVI
3491 << " from " << FSToVIMap[CallerFunc]
3492 << " that actually called " << Callee
3493 << (FoundMultipleCalleeChains
3494 ? " (found multiple possible chains)"
3495 : "")
3496 << "\n");
3497 if (FoundMultipleCalleeChains)
3498 FoundProfiledCalleeNonUniquelyCount++;
3499 return false;
3500 }
3501
3502 return true;
3503}
3504
3505bool IndexCallsiteContextGraph::sameCallee(IndexCall &Call1, IndexCall &Call2) {
3506 ValueInfo Callee1 = dyn_cast_if_present<CallsiteInfo *>(Call1)->Callee;
3507 ValueInfo Callee2 = dyn_cast_if_present<CallsiteInfo *>(Call2)->Callee;
3508 return Callee1 == Callee2;
3509}
3510
3511template <typename DerivedCCG, typename FuncTy, typename CallTy>
3512void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::ContextNode::dump()
3513 const {
3514 print(dbgs());
3515 dbgs() << "\n";
3516}
3517
3518template <typename DerivedCCG, typename FuncTy, typename CallTy>
3519void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::ContextNode::print(
3520 raw_ostream &OS) const {
3521 OS << "Node " << this << "\n";
3522 OS << "\t";
3523 printCall(OS);
3524 if (Recursive)
3525 OS << " (recursive)";
3526 OS << "\n";
3527 if (!MatchingCalls.empty()) {
3528 OS << "\tMatchingCalls:\n";
3529 for (auto &MatchingCall : MatchingCalls) {
3530 OS << "\t";
3531 MatchingCall.print(OS);
3532 OS << "\n";
3533 }
3534 }
3535 OS << "\tNodeId: " << NodeId << "\n";
3536 OS << "\tAllocTypes: " << getAllocTypeString(AllocTypes) << "\n";
3537 OS << "\tContextIds:";
3538 // Make a copy of the computed context ids that we can sort for stability.
3539 auto ContextIds = getContextIds();
3540 std::vector<uint32_t> SortedIds(ContextIds.begin(), ContextIds.end());
3541 std::sort(SortedIds.begin(), SortedIds.end());
3542 for (auto Id : SortedIds)
3543 OS << " " << Id;
3544 OS << "\n";
3545 OS << "\tCalleeEdges:\n";
3546 for (auto &Edge : CalleeEdges)
3547 OS << "\t\t" << *Edge << " (Callee NodeId: " << Edge->Callee->NodeId
3548 << ")\n";
3549 OS << "\tCallerEdges:\n";
3550 for (auto &Edge : CallerEdges)
3551 OS << "\t\t" << *Edge << " (Caller NodeId: " << Edge->Caller->NodeId
3552 << ")\n";
3553 if (!Clones.empty()) {
3554 OS << "\tClones: ";
3555 ListSeparator LS;
3556 for (auto *C : Clones)
3557 OS << LS << C << " NodeId: " << C->NodeId;
3558 OS << "\n";
3559 } else if (CloneOf) {
3560 OS << "\tClone of " << CloneOf << " NodeId: " << CloneOf->NodeId << "\n";
3561 }
3562}
3563
3564template <typename DerivedCCG, typename FuncTy, typename CallTy>
3565void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::ContextEdge::dump()
3566 const {
3567 print(dbgs());
3568 dbgs() << "\n";
3569}
3570
3571template <typename DerivedCCG, typename FuncTy, typename CallTy>
3572void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::ContextEdge::print(
3573 raw_ostream &OS) const {
3574 OS << "Edge from Callee " << Callee << " to Caller: " << Caller
3575 << (IsBackedge ? " (BE)" : "")
3576 << " AllocTypes: " << getAllocTypeString(AllocTypes);
3577 OS << " ContextIds:";
3578 std::vector<uint32_t> SortedIds(ContextIds.begin(), ContextIds.end());
3579 std::sort(SortedIds.begin(), SortedIds.end());
3580 for (auto Id : SortedIds)
3581 OS << " " << Id;
3582}
3583
3584template <typename DerivedCCG, typename FuncTy, typename CallTy>
3585void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::dump() const {
3586 print(dbgs());
3587}
3588
3589template <typename DerivedCCG, typename FuncTy, typename CallTy>
3590void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::print(
3591 raw_ostream &OS) const {
3592 OS << "Callsite Context Graph:\n";
3593 using GraphType = const CallsiteContextGraph<DerivedCCG, FuncTy, CallTy> *;
3594 for (const auto Node : nodes<GraphType>(this)) {
3595 if (Node->isRemoved())
3596 continue;
3597 Node->print(OS);
3598 OS << "\n";
3599 }
3600}
3601
3602template <typename DerivedCCG, typename FuncTy, typename CallTy>
3603void CallsiteContextGraph<DerivedCCG, FuncTy,
3604 CallTy>::capturePreCloningContextInfo() {
3605 for (const auto &Entry : AllocationCallToContextNodeMap) {
3606 const ContextNode *AllocNode = Entry.second;
3607 // Remember whether any caller of this allocation matched a call, so that
3608 // the report can distinguish "no matched callers" from an allocation whose
3609 // callers are simply not part of this context.
3610 for (const auto &Edge : AllocNode->CallerEdges) {
3611 if (!Edge->isRemoved() && Edge->Caller->hasCall()) {
3612 PreCloningAllocHasMatchedCaller.insert(AllocNode);
3613 break;
3614 }
3615 }
3616 DenseSet<uint32_t> ContextIds = AllocNode->getContextIds();
3617 for (uint32_t Id : ContextIds) {
3618 PreCloningContextInfo Info;
3619 // Walk the caller edges carrying this context id from the allocation
3620 // node outwards to build the chain of nodes for this context. Each node
3621 // is visited once; backedges (recursive cycles) are only followed when
3622 // no other caller edge carries the id, so that the chain reflects the
3623 // context's stack order rather than looping.
3624 Info.Chain.push_back(AllocNode);
3625 SmallPtrSet<const ContextNode *, 16> Visited;
3626 Visited.insert(AllocNode);
3627 const ContextNode *Cur = AllocNode;
3628 while (true) {
3629 const ContextNode *Next = nullptr;
3630 for (const auto &Edge : Cur->CallerEdges) {
3631 if (Edge->isRemoved() || Edge->IsBackedge)
3632 continue;
3633 if (Edge->getContextIds().contains(Id) &&
3634 !Visited.contains(Edge->Caller)) {
3635 Next = Edge->Caller;
3636 break;
3637 }
3638 }
3639 if (!Next) {
3640 for (const auto &Edge : Cur->CallerEdges) {
3641 if (Edge->isRemoved())
3642 continue;
3643 if (Edge->getContextIds().contains(Id) &&
3644 !Visited.contains(Edge->Caller)) {
3645 Next = Edge->Caller;
3646 break;
3647 }
3648 }
3649 }
3650 if (!Next)
3651 break;
3652 Visited.insert(Next);
3653 Info.Chain.push_back(Next);
3654 Cur = Next;
3655 }
3656
3657 // Find the outermost node (walking from the allocation) such that it
3658 // and all nodes below it matched a call, and record why the first
3659 // unmatched node (if any) did not match.
3660 Info.MaxMatchedFrame = 0;
3661 for (unsigned I = 1; I < Info.Chain.size(); ++I) {
3662 if (Info.Chain[I]->hasCall()) {
3663 Info.MaxMatchedFrame = I;
3664 } else {
3665 const ContextNode *Unmatched = Info.Chain[I];
3666 Info.UnmatchedStackId = Unmatched->OrigStackOrAllocId;
3667 Info.StoppedAtRecursive = Unmatched->Recursive;
3668 // A calling function is known for the unmatched node only when a
3669 // call in that function was considered and rejected because its
3670 // callee did not match the node's callee.
3671 if (auto It = NodeToCallingFunc.find(Unmatched);
3672 It != NodeToCallingFunc.end()) {
3673 Info.StoppedAtMismatchedCallee = true;
3674 Info.UnmatchedCallingFunc = It->second;
3675 }
3676 break;
3677 }
3678 }
3679
3680 // If the whole context matched, check whether its outermost node has
3681 // matched callers reached by other contexts: then this context was
3682 // trimmed below them, and clones of those callers can change which
3683 // allocation clone it reaches.
3684 if (Info.MaxMatchedFrame > 0 &&
3685 Info.MaxMatchedFrame + 1 == Info.Chain.size()) {
3686 const ContextNode *OutermostMatchedNode =
3687 Info.Chain[Info.MaxMatchedFrame];
3688 for (const auto &Edge : OutermostMatchedNode->CallerEdges) {
3689 if (!Edge->isRemoved() && Edge->Caller->hasCall()) {
3690 Info.OutermostMatchedNodeHasOtherCallers = true;
3691 break;
3692 }
3693 }
3694 }
3695
3696 PreCloningContextInfoMap[Id] = std::move(Info);
3697 }
3698 }
3699}
3700
3701template <typename DerivedCCG, typename FuncTy, typename CallTy>
3702std::string
3703CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::formatContextReportSuffix(
3704 const ContextNode *Node, uint32_t Id) const {
3705 auto InfoIt = PreCloningContextInfoMap.find(Id);
3706 if (InfoIt == PreCloningContextInfoMap.end())
3707 return "";
3708 const PreCloningContextInfo &Info = InfoIt->second;
3709
3710 // 1. The allocation function (clone) the context's allocation node ended up
3711 // in, with a qualifier when it is dead, or when the context has callers in
3712 // the profile but none of the allocation's callers matched (either because
3713 // nothing references the function at all, or because the references did not
3714 // match the profiled callsites).
3715 const ContextNode *OrigAlloc = Node->getOrigNode();
3716 const FuncTy *AllocFunc = getCallingFunc(OrigAlloc);
3717 unsigned AllocCloneNo = Node->Call.cloneNo();
3718 std::string AllocFuncStr = getFuncName(AllocFunc, AllocCloneNo);
3719 if (isFuncDead(AllocFunc)) {
3720 AllocFuncStr += " (dead)";
3721 } else if (!PreCloningAllocHasMatchedCaller.contains(OrigAlloc) &&
3722 Info.Chain.size() > 1) {
3723 // Distinguish a function with no references in the IR/summary (it may
3724 // still be referenced from native objects) from one whose references did
3725 // not match.
3726 AllocFuncStr += AllocFunc && !FunctionsWithCallers.contains(AllocFunc)
3727 ? " (no references in IR/summary)"
3728 : " (no matched callers)";
3729 }
3730
3731 // 2. How far the context matched: all of it ("matched N frames to F", or
3732 // "trimmed at frame N in F" when F has callers above that the context does
3733 // not cover), or up to an unmatched node (with the reason and stack id).
3734 unsigned TotalFrames = Info.Chain.size() > 0 ? Info.Chain.size() - 1 : 0;
3735 unsigned Matched = Info.MaxMatchedFrame;
3736 std::string StatusStr;
3737 if (TotalFrames == 0) {
3738 StatusStr = "inlined into leaf";
3739 } else if (Matched < TotalFrames) {
3740 // Where and why matching stopped: the first unmatched node was either a
3741 // recursive callsite (not matched when recursive callsites are disabled),
3742 // a callsite whose IR callee did not match the profiled callee, or a
3743 // callsite with no matching call at all.
3744 if (Info.StoppedAtRecursive)
3745 StatusStr = "unmatched recursive callsite";
3746 else if (Info.StoppedAtMismatchedCallee)
3747 StatusStr = "unmatched callsite (mismatched callee in " +
3748 getFuncName(Info.UnmatchedCallingFunc, 0) + ")";
3749 else
3750 StatusStr = "unmatched callsite";
3751 StatusStr += " at frame " + std::to_string(Matched + 1) + "/" +
3752 std::to_string(TotalFrames) + " (stack id " +
3753 std::to_string(Info.UnmatchedStackId) + ")";
3754 } else {
3755 const ContextNode *OutermostMatchedNode = Info.Chain[Matched];
3756 const FuncTy *OutermostMatchedFunc = getCallingFunc(OutermostMatchedNode);
3757 unsigned NumOutermostMatchedFuncClones =
3758 std::max<unsigned>(1, FuncToNumClones.lookup(OutermostMatchedFunc));
3759 bool HasCallersAbove =
3760 NumOutermostMatchedFuncClones > 1 ||
3761 Info.OutermostMatchedNodeHasOtherCallers ||
3762 (OutermostMatchedFunc &&
3763 FunctionsWithCallers.contains(OutermostMatchedFunc));
3764 if (HasCallersAbove) {
3765 StatusStr = "trimmed at frame " + std::to_string(Matched) + " in " +
3766 getFuncName(OutermostMatchedFunc, 0);
3767 } else {
3768 StatusStr = "matched " + std::to_string(Matched) + " frames to " +
3769 getFuncName(OutermostMatchedFunc, 0);
3770 }
3771 }
3772
3773 // 3. The post-cloning call paths: starting from each function clone of the
3774 // outermost matched caller, follow the callee clones assigned to the
3775 // context's callsites down to the allocation clone reached, and report the
3776 // hint that clone ended up with. Paths reaching the same allocation clone
3777 // are reported once.
3778 std::string ReachesStr;
3779 if (Matched >= 1) {
3780 const ContextNode *OutermostMatchedNode = Info.Chain[Matched];
3781 const FuncTy *OutermostMatchedFunc = getCallingFunc(OutermostMatchedNode);
3782 unsigned NumOutermostMatchedFuncClones =
3783 std::max<unsigned>(1, FuncToNumClones.lookup(OutermostMatchedFunc));
3784 ReachesStr = "; reaches ";
3785 // Allocation clones (by clone number) already reported for this context.
3786 // Different function clones of the outermost matched caller often lead to
3787 // the same allocation clone; such paths are reported only once, for the
3788 // first caller clone reaching that allocation clone.
3789 SmallSet<unsigned, 4> ReportedAllocClones;
3790 bool FirstPath = true;
3791 for (unsigned OutermostMatchedFuncClone = 0;
3792 OutermostMatchedFuncClone < NumOutermostMatchedFuncClones;
3793 ++OutermostMatchedFuncClone) {
3794 // PathFuncs/PathClones[S] is the function and clone number at step S of
3795 // the path, from the outermost matched caller (S = 0) down to the
3796 // allocation function (S = Matched).
3797 std::vector<const FuncTy *> PathFuncs(Matched + 1);
3798 std::vector<unsigned> PathClones(Matched + 1);
3799 PathFuncs[0] = OutermostMatchedFunc;
3800 PathClones[0] = OutermostMatchedFuncClone;
3801 unsigned CurClone = OutermostMatchedFuncClone;
3802 for (unsigned Step = 0; Step < Matched; ++Step) {
3803 unsigned FrameIdx = Matched - Step;
3804 const ContextNode *CallNode = Info.Chain[FrameIdx];
3805 unsigned NextClone =
3806 OrigNodeAndCloneToCalleeClone.lookup({CallNode, CurClone});
3807 const FuncTy *CalleeFunc = getCallingFunc(Info.Chain[FrameIdx - 1]);
3808 PathFuncs[Step + 1] = CalleeFunc;
3809 PathClones[Step + 1] = NextClone;
3810 CurClone = NextClone;
3811 }
3812
3813 if (!ReportedAllocClones.insert(CurClone).second)
3814 continue;
3815 if (!FirstPath)
3816 ReachesStr += ", ";
3817 FirstPath = false;
3818
3819 const ContextNode *ReachedAlloc =
3820 OrigAllocAndCloneToNode.lookup({OrigAlloc, CurClone});
3821 // Report the hint actually applied to the reached allocation clone
3822 // (which accounts for allocTypeToUse and MinClonedColdBytePercent),
3823 // rather than the graph node's (possibly ambiguous) AllocTypes.
3824 std::string ReachedTypeStr;
3825 if (ReachedAlloc)
3826 ReachedTypeStr = getAllocTypeString(
3827 (uint8_t)getAllocationCallType(ReachedAlloc->Call));
3828 else if (CurClone == 0)
3829 ReachedTypeStr =
3830 getAllocTypeString((uint8_t)getAllocationCallType(OrigAlloc->Call));
3831 else
3832 ReachedTypeStr = "None";
3833
3834 // Print the path, eliding runs of uncloned (or cloned) functions in the
3835 // middle of paths longer than MemProfReportHintedSizesDetailMaxPathLen;
3836 // the ends and every transition between cloned and uncloned functions
3837 // are kept.
3838 std::string PathStr;
3839 bool SkippedPrev = false;
3840 bool PrintFullPath =
3842 for (unsigned S = 0; S <= Matched; ++S) {
3843 bool IsCloned = PathClones[S] > 0;
3844 bool PrevCloned = S > 0 ? (PathClones[S - 1] > 0) : IsCloned;
3845 bool NextCloned = S + 1 <= Matched ? (PathClones[S + 1] > 0) : IsCloned;
3846 bool Include = PrintFullPath || (S <= 1) || (S + 1 >= Matched) ||
3847 (IsCloned != PrevCloned) || (IsCloned != NextCloned);
3848 if (!Include) {
3849 if (!SkippedPrev) {
3850 PathStr += " -> ...";
3851 SkippedPrev = true;
3852 }
3853 continue;
3854 }
3855 SkippedPrev = false;
3856 if (!PathStr.empty())
3857 PathStr += " -> ";
3858 PathStr += getFuncName(PathFuncs[S], PathClones[S]);
3859 }
3860 ReachesStr += ReachedTypeStr + " via " + PathStr;
3861 }
3862 }
3863
3864 return " [alloc in " + AllocFuncStr + "; " + StatusStr + ReachesStr + "]";
3865}
3866
3867template <typename DerivedCCG, typename FuncTy, typename CallTy>
3868void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::printTotalSizes(
3869 raw_ostream &OS,
3870 function_ref<void(StringRef, StringRef, const Twine &)> EmitRemark) const {
3871 using GraphType = const CallsiteContextGraph<DerivedCCG, FuncTy, CallTy> *;
3872 for (const auto Node : nodes<GraphType>(this)) {
3873 if (Node->isRemoved())
3874 continue;
3875 if (!Node->IsAllocation)
3876 continue;
3877 DenseSet<uint32_t> ContextIds = Node->getContextIds();
3878 auto AllocTypeFromCall = getAllocationCallType(Node->Call);
3879 std::vector<uint32_t> SortedIds(ContextIds.begin(), ContextIds.end());
3880 std::sort(SortedIds.begin(), SortedIds.end());
3881 for (auto Id : SortedIds) {
3882 auto TypeI = ContextIdToAllocationType.find(Id);
3883 assert(TypeI != ContextIdToAllocationType.end());
3884 std::string Suffix;
3885 bool ComputedSuffix = false;
3886 auto GetSuffix = [&]() -> const std::string & {
3887 if (!ComputedSuffix) {
3889 ? formatContextReportSuffix(Node, Id)
3890 : "";
3891 ComputedSuffix = true;
3892 }
3893 return Suffix;
3894 };
3895 auto CSI = ContextIdToContextSizeInfos.find(Id);
3896 if (CSI != ContextIdToContextSizeInfos.end()) {
3897 for (auto &Info : CSI->second) {
3898 std::string Msg =
3899 "MemProf hinting: " + getAllocTypeString((uint8_t)TypeI->second) +
3900 " full allocation context " + std::to_string(Info.FullStackId) +
3901 " with total size " + std::to_string(Info.TotalSize) + " is " +
3902 getAllocTypeString(Node->AllocTypes) + " after cloning";
3903 if (allocTypeToUse(Node->AllocTypes) != AllocTypeFromCall)
3904 Msg += " marked " + getAllocTypeString((uint8_t)AllocTypeFromCall) +
3905 " due to cold byte percent";
3906 // Print the internal context id to aid debugging and visualization.
3907 Msg += " (internal context id " + std::to_string(Id) + ")";
3909 OS << Msg << GetSuffix() << "\n";
3910 if (EmitRemark)
3911 EmitRemark(DEBUG_TYPE, "MemProfReport", Msg);
3912 }
3913 } else {
3914 // This is only emitted if the context size info is not present.
3915 std::string Msg =
3916 "MemProf hinting: " + getAllocTypeString((uint8_t)TypeI->second) +
3917 " context is " + getAllocTypeString(Node->AllocTypes) +
3918 " after cloning";
3919 if (allocTypeToUse(Node->AllocTypes) != AllocTypeFromCall)
3920 Msg += " marked " + getAllocTypeString((uint8_t)AllocTypeFromCall) +
3921 " due to cold byte percent";
3922 // Print the internal context id to aid debugging and visualization.
3923 Msg += " (internal context id " + std::to_string(Id) + ")";
3925 OS << Msg << GetSuffix() << "\n";
3926 if (EmitRemark)
3927 EmitRemark(DEBUG_TYPE, "MemProfReport", Msg);
3928 }
3929 }
3930 }
3931}
3932
3933template <typename DerivedCCG, typename FuncTy, typename CallTy>
3934void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::check() const {
3935 using GraphType = const CallsiteContextGraph<DerivedCCG, FuncTy, CallTy> *;
3936 for (const auto Node : nodes<GraphType>(this)) {
3937 checkNode<DerivedCCG, FuncTy, CallTy>(Node, /*CheckEdges=*/false);
3938 for (auto &Edge : Node->CallerEdges)
3940 }
3941}
3942
3943template <typename DerivedCCG, typename FuncTy, typename CallTy>
3944struct GraphTraits<const CallsiteContextGraph<DerivedCCG, FuncTy, CallTy> *> {
3945 using GraphType = const CallsiteContextGraph<DerivedCCG, FuncTy, CallTy> *;
3946 using NodeRef = const ContextNode<DerivedCCG, FuncTy, CallTy> *;
3947
3948 using NodePtrTy = std::unique_ptr<ContextNode<DerivedCCG, FuncTy, CallTy>>;
3949 static NodeRef getNode(const NodePtrTy &P) { return P.get(); }
3950
3953 decltype(&getNode)>;
3954
3956 return nodes_iterator(G->NodeOwner.begin(), &getNode);
3957 }
3958
3960 return nodes_iterator(G->NodeOwner.end(), &getNode);
3961 }
3962
3964 return G->NodeOwner.begin()->get();
3965 }
3966
3967 using EdgePtrTy = std::shared_ptr<ContextEdge<DerivedCCG, FuncTy, CallTy>>;
3968 static const ContextNode<DerivedCCG, FuncTy, CallTy> *
3970 return P->Callee;
3971 }
3972
3974 mapped_iterator<typename std::vector<std::shared_ptr<ContextEdge<
3975 DerivedCCG, FuncTy, CallTy>>>::const_iterator,
3976 decltype(&GetCallee)>;
3977
3979 return ChildIteratorType(N->CalleeEdges.begin(), &GetCallee);
3980 }
3981
3983 return ChildIteratorType(N->CalleeEdges.end(), &GetCallee);
3984 }
3985};
3986
3987template <typename DerivedCCG, typename FuncTy, typename CallTy>
3988struct DOTGraphTraits<const CallsiteContextGraph<DerivedCCG, FuncTy, CallTy> *>
3989 : public DefaultDOTGraphTraits {
3990 DOTGraphTraits(bool IsSimple = false) : DefaultDOTGraphTraits(IsSimple) {
3991 // If the user requested the full graph to be exported, but provided an
3992 // allocation id, or if the user gave a context id and requested more than
3993 // just a specific context to be exported, note that highlighting is
3994 // enabled.
3995 DoHighlight =
3996 (AllocIdForDot.getNumOccurrences() && DotGraphScope == DotScope::All) ||
3997 (ContextIdForDot.getNumOccurrences() &&
3999 }
4000
4001 using GraphType = const CallsiteContextGraph<DerivedCCG, FuncTy, CallTy> *;
4003 using NodeRef = typename GTraits::NodeRef;
4004 using ChildIteratorType = typename GTraits::ChildIteratorType;
4005
4006 static std::string getNodeLabel(NodeRef Node, GraphType G) {
4007 std::string LabelString =
4008 (Twine("OrigId: ") + (Node->IsAllocation ? "Alloc" : "") +
4009 Twine(Node->OrigStackOrAllocId) + " NodeId: " + Twine(Node->NodeId))
4010 .str();
4011 LabelString += "\n";
4012 if (Node->hasCall()) {
4013 auto Func = G->NodeToCallingFunc.find(Node);
4014 assert(Func != G->NodeToCallingFunc.end());
4015 LabelString +=
4016 G->getLabel(Func->second, Node->Call.call(), Node->Call.cloneNo());
4017 for (auto &MatchingCall : Node->MatchingCalls) {
4018 LabelString += "\n";
4019 LabelString += G->getLabel(Func->second, MatchingCall.call(),
4020 MatchingCall.cloneNo());
4021 }
4022 } else {
4023 LabelString += "null call";
4024 if (Node->Recursive)
4025 LabelString += " (recursive)";
4026 else
4027 LabelString += " (external)";
4028 }
4029 return LabelString;
4030 }
4031
4033 auto ContextIds = Node->getContextIds();
4034 // If highlighting enabled, see if this node contains any of the context ids
4035 // of interest. If so, it will use a different color and a larger fontsize
4036 // (which makes the node larger as well).
4037 bool Highlight = false;
4038 if (DoHighlight) {
4039 assert(ContextIdForDot.getNumOccurrences() ||
4040 AllocIdForDot.getNumOccurrences());
4041 if (ContextIdForDot.getNumOccurrences())
4042 Highlight = ContextIds.contains(ContextIdForDot);
4043 else
4044 Highlight = set_intersects(ContextIds, G->DotAllocContextIds);
4045 }
4046 std::string AttributeString = (Twine("tooltip=\"") + getNodeId(Node) + " " +
4047 getContextIds(ContextIds) + "\"")
4048 .str();
4049 // Default fontsize is 14
4050 if (Highlight)
4051 AttributeString += ",fontsize=\"30\"";
4052 AttributeString +=
4053 (Twine(",fillcolor=\"") + getColor(Node->AllocTypes, Highlight) + "\"")
4054 .str();
4055 if (Node->CloneOf) {
4056 AttributeString += ",color=\"blue\"";
4057 AttributeString += ",style=\"filled,bold,dashed\"";
4058 } else
4059 AttributeString += ",style=\"filled\"";
4060 return AttributeString;
4061 }
4062
4063 static std::string getEdgeAttributes(NodeRef, ChildIteratorType ChildIter,
4064 GraphType G) {
4065 auto &Edge = *(ChildIter.getCurrent());
4066 // If highlighting enabled, see if this edge contains any of the context ids
4067 // of interest. If so, it will use a different color and a heavier arrow
4068 // size and weight (the larger weight makes the highlighted path
4069 // straighter).
4070 bool Highlight = false;
4071 if (DoHighlight) {
4072 assert(ContextIdForDot.getNumOccurrences() ||
4073 AllocIdForDot.getNumOccurrences());
4074 if (ContextIdForDot.getNumOccurrences())
4075 Highlight = Edge->ContextIds.contains(ContextIdForDot);
4076 else
4077 Highlight = set_intersects(Edge->ContextIds, G->DotAllocContextIds);
4078 }
4079 auto Color = getColor(Edge->AllocTypes, Highlight);
4080 std::string AttributeString =
4081 (Twine("tooltip=\"") + getContextIds(Edge->ContextIds) + "\"" +
4082 // fillcolor is the arrow head and color is the line
4083 Twine(",fillcolor=\"") + Color + "\"" + Twine(",color=\"") + Color +
4084 "\"")
4085 .str();
4086 if (Edge->IsBackedge)
4087 AttributeString += ",style=\"dotted\"";
4088 // Default penwidth and weight are both 1.
4089 if (Highlight)
4090 AttributeString += ",penwidth=\"2.0\",weight=\"2\"";
4091 return AttributeString;
4092 }
4093
4094 // Since the NodeOwners list includes nodes that are no longer connected to
4095 // the graph, skip them here.
4097 if (Node->isRemoved())
4098 return true;
4099 // If a scope smaller than the full graph was requested, see if this node
4100 // contains any of the context ids of interest.
4102 return !set_intersects(Node->getContextIds(), G->DotAllocContextIds);
4104 return !Node->getContextIds().contains(ContextIdForDot);
4105 return false;
4106 }
4107
4108private:
4109 static std::string getContextIds(const DenseSet<uint32_t> &ContextIds) {
4110 std::string IdString = "ContextIds:";
4111 if (ContextIds.size() < 100) {
4112 std::vector<uint32_t> SortedIds(ContextIds.begin(), ContextIds.end());
4113 std::sort(SortedIds.begin(), SortedIds.end());
4114 for (auto Id : SortedIds)
4115 IdString += (" " + Twine(Id)).str();
4116 } else {
4117 IdString += (" (" + Twine(ContextIds.size()) + " ids)").str();
4118 }
4119 return IdString;
4120 }
4121
4122 static std::string getColor(uint8_t AllocTypes, bool Highlight) {
4123 // If DoHighlight is not enabled, we want to use the highlight colors for
4124 // NotCold and Cold, and the non-highlight color for NotCold+Cold. This is
4125 // both compatible with the color scheme before highlighting was supported,
4126 // and for the NotCold+Cold color the non-highlight color is a bit more
4127 // readable.
4128 if (AllocTypes == (uint8_t)AllocationType::NotCold)
4129 // Color "brown1" actually looks like a lighter red.
4130 return !DoHighlight || Highlight ? "brown1" : "lightpink";
4131 if (AllocTypes == (uint8_t)AllocationType::Cold)
4132 return !DoHighlight || Highlight ? "cyan" : "lightskyblue";
4133 if (AllocTypes ==
4134 ((uint8_t)AllocationType::NotCold | (uint8_t)AllocationType::Cold))
4135 return Highlight ? "magenta" : "mediumorchid1";
4136 return "gray";
4137 }
4138
4139 static std::string getNodeId(NodeRef Node) {
4140 std::stringstream SStream;
4141 SStream << std::hex << "N0x" << (unsigned long long)Node;
4142 std::string Result = SStream.str();
4143 return Result;
4144 }
4145
4146 // True if we should highlight a specific context or allocation's contexts in
4147 // the emitted graph.
4148 static bool DoHighlight;
4149};
4150
4151template <typename DerivedCCG, typename FuncTy, typename CallTy>
4152bool DOTGraphTraits<
4153 const CallsiteContextGraph<DerivedCCG, FuncTy, CallTy> *>::DoHighlight =
4154 false;
4155
4156template <typename DerivedCCG, typename FuncTy, typename CallTy>
4157void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::exportToDot(
4158 std::string Label) const {
4159 WriteGraph(this, "", false, Label,
4160 DotFilePathPrefix + "ccg." + Label + ".dot");
4161}
4162
4163template <typename DerivedCCG, typename FuncTy, typename CallTy>
4164typename CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::ContextNode *
4165CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::moveEdgeToNewCalleeClone(
4166 const std::shared_ptr<ContextEdge> &Edge,
4167 DenseSet<uint32_t> ContextIdsToMove) {
4168 ContextNode *Node = Edge->Callee;
4169 assert(NodeToCallingFunc.count(Node));
4170 ContextNode *Clone =
4171 createNewNode(Node->IsAllocation, NodeToCallingFunc[Node], Node->Call);
4172 Node->addClone(Clone);
4173 Clone->MatchingCalls = Node->MatchingCalls;
4174 moveEdgeToExistingCalleeClone(Edge, Clone, /*NewClone=*/true,
4175 ContextIdsToMove);
4176 return Clone;
4177}
4178
4179template <typename DerivedCCG, typename FuncTy, typename CallTy>
4180void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::
4181 moveEdgeToExistingCalleeClone(const std::shared_ptr<ContextEdge> &Edge,
4182 ContextNode *NewCallee, bool NewClone,
4183 DenseSet<uint32_t> ContextIdsToMove) {
4184 // NewCallee and Edge's current callee must be clones of the same original
4185 // node (Edge's current callee may be the original node too).
4186 assert(NewCallee->getOrigNode() == Edge->Callee->getOrigNode());
4187
4188 bool EdgeIsRecursive = Edge->Callee == Edge->Caller;
4189
4190 ContextNode *OldCallee = Edge->Callee;
4191
4192 // We might already have an edge to the new callee from earlier cloning for a
4193 // different allocation. If one exists we will reuse it.
4194 auto ExistingEdgeToNewCallee = NewCallee->findEdgeFromCaller(Edge->Caller);
4195
4196 // Callers will pass an empty ContextIdsToMove set when they want to move the
4197 // edge. Copy in Edge's ids for simplicity.
4198 if (ContextIdsToMove.empty())
4199 ContextIdsToMove = Edge->getContextIds();
4200
4201 // If we are moving all of Edge's ids, then just move the whole Edge.
4202 // Otherwise only move the specified subset, to a new edge if needed.
4203 if (Edge->getContextIds().size() == ContextIdsToMove.size()) {
4204 // First, update the alloc types on New Callee from Edge.
4205 // Do this before we potentially clear Edge's fields below!
4206 NewCallee->AllocTypes |= Edge->AllocTypes;
4207 // Moving the whole Edge.
4208 if (ExistingEdgeToNewCallee) {
4209 // Since we already have an edge to NewCallee, simply move the ids
4210 // onto it, and remove the existing Edge.
4211 ExistingEdgeToNewCallee->getContextIds().insert_range(ContextIdsToMove);
4212 ExistingEdgeToNewCallee->AllocTypes |= Edge->AllocTypes;
4213 assert(Edge->ContextIds == ContextIdsToMove);
4214 removeEdgeFromGraph(Edge.get());
4215 } else {
4216 // Otherwise just reconnect Edge to NewCallee.
4217 Edge->Callee = NewCallee;
4218 NewCallee->CallerEdges.push_back(Edge);
4219 // Remove it from callee where it was previously connected.
4220 OldCallee->eraseCallerEdge(Edge.get());
4221 // Don't need to update Edge's context ids since we are simply
4222 // reconnecting it.
4223 }
4224 } else {
4225 // Only moving a subset of Edge's ids.
4226 // Compute the alloc type of the subset of ids being moved.
4227 auto CallerEdgeAllocType = computeAllocType(ContextIdsToMove);
4228 if (ExistingEdgeToNewCallee) {
4229 // Since we already have an edge to NewCallee, simply move the ids
4230 // onto it.
4231 ExistingEdgeToNewCallee->getContextIds().insert_range(ContextIdsToMove);
4232 ExistingEdgeToNewCallee->AllocTypes |= CallerEdgeAllocType;
4233 } else {
4234 // Otherwise, create a new edge to NewCallee for the ids being moved.
4235 auto NewEdge = std::make_shared<ContextEdge>(
4236 NewCallee, Edge->Caller, CallerEdgeAllocType, ContextIdsToMove);
4237 Edge->Caller->CalleeEdges.push_back(NewEdge);
4238 NewCallee->CallerEdges.push_back(NewEdge);
4239 }
4240 // In either case, need to update the alloc types on NewCallee, and remove
4241 // those ids and update the alloc type on the original Edge.
4242 NewCallee->AllocTypes |= CallerEdgeAllocType;
4243 set_subtract(Edge->ContextIds, ContextIdsToMove);
4244 Edge->AllocTypes = computeAllocType(Edge->ContextIds);
4245 }
4246 // Now walk the old callee node's callee edges and move Edge's context ids
4247 // over to the corresponding edge into the clone (which is created here if
4248 // this is a newly created clone).
4249 for (auto &OldCalleeEdge : OldCallee->CalleeEdges) {
4250 ContextNode *CalleeToUse = OldCalleeEdge->Callee;
4251 // If this is a direct recursion edge, use NewCallee (the clone) as the
4252 // callee as well, so that any edge updated/created here is also direct
4253 // recursive.
4254 if (CalleeToUse == OldCallee) {
4255 // If this is a recursive edge, see if we already moved a recursive edge
4256 // (which would have to have been this one) - if we were only moving a
4257 // subset of context ids it would still be on OldCallee.
4258 if (EdgeIsRecursive) {
4259 assert(OldCalleeEdge == Edge);
4260 continue;
4261 }
4262 CalleeToUse = NewCallee;
4263 }
4264 // The context ids moving to the new callee are the subset of this edge's
4265 // context ids and the context ids on the caller edge being moved.
4266 DenseSet<uint32_t> EdgeContextIdsToMove =
4267 set_intersection(OldCalleeEdge->getContextIds(), ContextIdsToMove);
4268 set_subtract(OldCalleeEdge->getContextIds(), EdgeContextIdsToMove);
4269 OldCalleeEdge->AllocTypes =
4270 computeAllocType(OldCalleeEdge->getContextIds());
4271 if (!NewClone) {
4272 // Update context ids / alloc type on corresponding edge to NewCallee.
4273 // There is a chance this may not exist if we are reusing an existing
4274 // clone, specifically during function assignment, where we would have
4275 // removed none type edges after creating the clone. If we can't find
4276 // a corresponding edge there, fall through to the cloning below.
4277 if (auto *NewCalleeEdge = NewCallee->findEdgeFromCallee(CalleeToUse)) {
4278 NewCalleeEdge->getContextIds().insert_range(EdgeContextIdsToMove);
4279 NewCalleeEdge->AllocTypes |= computeAllocType(EdgeContextIdsToMove);
4280 continue;
4281 }
4282 }
4283 auto NewEdge = std::make_shared<ContextEdge>(
4284 CalleeToUse, NewCallee, computeAllocType(EdgeContextIdsToMove),
4285 EdgeContextIdsToMove);
4286 NewCallee->CalleeEdges.push_back(NewEdge);
4287 NewEdge->Callee->CallerEdges.push_back(NewEdge);
4288 }
4289 // Recompute the node alloc type now that its callee edges have been
4290 // updated (since we will compute from those edges).
4291 OldCallee->AllocTypes = OldCallee->computeAllocType();
4292 // OldCallee alloc type should be None iff its context id set is now empty.
4293 assert((OldCallee->AllocTypes == (uint8_t)AllocationType::None) ==
4294 OldCallee->emptyContextIds());
4295 if (VerifyCCG) {
4296 checkNode<DerivedCCG, FuncTy, CallTy>(OldCallee, /*CheckEdges=*/false);
4297 checkNode<DerivedCCG, FuncTy, CallTy>(NewCallee, /*CheckEdges=*/false);
4298 for (const auto &OldCalleeEdge : OldCallee->CalleeEdges)
4299 checkNode<DerivedCCG, FuncTy, CallTy>(OldCalleeEdge->Callee,
4300 /*CheckEdges=*/false);
4301 for (const auto &NewCalleeEdge : NewCallee->CalleeEdges)
4302 checkNode<DerivedCCG, FuncTy, CallTy>(NewCalleeEdge->Callee,
4303 /*CheckEdges=*/false);
4304 }
4305}
4306
4307template <typename DerivedCCG, typename FuncTy, typename CallTy>
4308void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::
4309 moveCalleeEdgeToNewCaller(const std::shared_ptr<ContextEdge> &Edge,
4310 ContextNode *NewCaller) {
4311 auto *OldCallee = Edge->Callee;
4312 auto *NewCallee = OldCallee;
4313 // If this edge was direct recursive, make any new/updated edge also direct
4314 // recursive to NewCaller.
4315 bool Recursive = Edge->Caller == Edge->Callee;
4316 if (Recursive)
4317 NewCallee = NewCaller;
4318
4319 ContextNode *OldCaller = Edge->Caller;
4320 OldCaller->eraseCalleeEdge(Edge.get());
4321
4322 // We might already have an edge to the new caller. If one exists we will
4323 // reuse it.
4324 auto ExistingEdgeToNewCaller = NewCaller->findEdgeFromCallee(NewCallee);
4325
4326 if (ExistingEdgeToNewCaller) {
4327 // Since we already have an edge to NewCaller, simply move the ids
4328 // onto it, and remove the existing Edge.
4329 ExistingEdgeToNewCaller->getContextIds().insert_range(
4330 Edge->getContextIds());
4331 ExistingEdgeToNewCaller->AllocTypes |= Edge->AllocTypes;
4332 Edge->ContextIds.clear();
4333 Edge->AllocTypes = (uint8_t)AllocationType::None;
4334 OldCallee->eraseCallerEdge(Edge.get());
4335 } else {
4336 // Otherwise just reconnect Edge to NewCaller.
4337 Edge->Caller = NewCaller;
4338 NewCaller->CalleeEdges.push_back(Edge);
4339 if (Recursive) {
4340 assert(NewCallee == NewCaller);
4341 // In the case of (direct) recursive edges, we update the callee as well
4342 // so that it becomes recursive on the new caller.
4343 Edge->Callee = NewCallee;
4344 NewCallee->CallerEdges.push_back(Edge);
4345 OldCallee->eraseCallerEdge(Edge.get());
4346 }
4347 // Don't need to update Edge's context ids since we are simply
4348 // reconnecting it.
4349 }
4350 // In either case, need to update the alloc types on New Caller.
4351 NewCaller->AllocTypes |= Edge->AllocTypes;
4352
4353 // Now walk the old caller node's caller edges and move Edge's context ids
4354 // over to the corresponding edge into the node (which is created here if
4355 // this is a newly created node). We can tell whether this is a newly created
4356 // node by seeing if it has any caller edges yet.
4357#ifndef NDEBUG
4358 bool IsNewNode = NewCaller->CallerEdges.empty();
4359#endif
4360 // If we just moved a direct recursive edge, presumably its context ids should
4361 // also flow out of OldCaller via some other non-recursive callee edge. We
4362 // don't want to remove the recursive context ids from other caller edges yet,
4363 // otherwise the context ids get into an inconsistent state on OldCaller.
4364 // We will update these context ids on the non-recursive caller edge when and
4365 // if they are updated on the non-recursive callee.
4366 if (!Recursive) {
4367 for (auto &OldCallerEdge : OldCaller->CallerEdges) {
4368 auto OldCallerCaller = OldCallerEdge->Caller;
4369 // The context ids moving to the new caller are the subset of this edge's
4370 // context ids and the context ids on the callee edge being moved.
4371 DenseSet<uint32_t> EdgeContextIdsToMove = set_intersection(
4372 OldCallerEdge->getContextIds(), Edge->getContextIds());
4373 if (OldCaller == OldCallerCaller) {
4374 OldCallerCaller = NewCaller;
4375 // Don't actually move this one. The caller will move it directly via a
4376 // call to this function with this as the Edge if it is appropriate to
4377 // move to a diff node that has a matching callee (itself).
4378 continue;
4379 }
4380 set_subtract(OldCallerEdge->getContextIds(), EdgeContextIdsToMove);
4381 OldCallerEdge->AllocTypes =
4382 computeAllocType(OldCallerEdge->getContextIds());
4383 // In this function we expect that any pre-existing node already has edges
4384 // from the same callers as the old node. That should be true in the
4385 // current use case, where we will remove None-type edges after copying
4386 // over all caller edges from the callee.
4387 auto *ExistingCallerEdge = NewCaller->findEdgeFromCaller(OldCallerCaller);
4388 // Since we would have skipped caller edges when moving a direct recursive
4389 // edge, this may not hold true when recursive handling enabled.
4390 assert(IsNewNode || ExistingCallerEdge || AllowRecursiveCallsites);
4391 if (ExistingCallerEdge) {
4392 ExistingCallerEdge->getContextIds().insert_range(EdgeContextIdsToMove);
4393 ExistingCallerEdge->AllocTypes |=
4394 computeAllocType(EdgeContextIdsToMove);
4395 continue;
4396 }
4397 auto NewEdge = std::make_shared<ContextEdge>(
4398 NewCaller, OldCallerCaller, computeAllocType(EdgeContextIdsToMove),
4399 EdgeContextIdsToMove);
4400 NewCaller->CallerEdges.push_back(NewEdge);
4401 NewEdge->Caller->CalleeEdges.push_back(NewEdge);
4402 }
4403 }
4404 // Recompute the node alloc type now that its caller edges have been
4405 // updated (since we will compute from those edges).
4406 OldCaller->AllocTypes = OldCaller->computeAllocType();
4407 // OldCaller alloc type should be None iff its context id set is now empty.
4408 assert((OldCaller->AllocTypes == (uint8_t)AllocationType::None) ==
4409 OldCaller->emptyContextIds());
4410 if (VerifyCCG) {
4411 checkNode<DerivedCCG, FuncTy, CallTy>(OldCaller, /*CheckEdges=*/false);
4412 checkNode<DerivedCCG, FuncTy, CallTy>(NewCaller, /*CheckEdges=*/false);
4413 for (const auto &OldCallerEdge : OldCaller->CallerEdges)
4414 checkNode<DerivedCCG, FuncTy, CallTy>(OldCallerEdge->Caller,
4415 /*CheckEdges=*/false);
4416 for (const auto &NewCallerEdge : NewCaller->CallerEdges)
4417 checkNode<DerivedCCG, FuncTy, CallTy>(NewCallerEdge->Caller,
4418 /*CheckEdges=*/false);
4419 }
4420}
4421
4422template <typename DerivedCCG, typename FuncTy, typename CallTy>
4423void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::
4424 recursivelyRemoveNoneTypeCalleeEdges(
4425 ContextNode *Node, DenseSet<const ContextNode *> &Visited) {
4426 auto Inserted = Visited.insert(Node);
4427 if (!Inserted.second)
4428 return;
4429
4430 removeNoneTypeCalleeEdges(Node);
4431
4432 for (auto *Clone : Node->Clones)
4433 recursivelyRemoveNoneTypeCalleeEdges(Clone, Visited);
4434
4435 // The recursive call may remove some of this Node's caller edges.
4436 // Iterate over a copy and skip any that were removed.
4437 auto CallerEdges = Node->CallerEdges;
4438 for (auto &Edge : CallerEdges) {
4439 // Skip any that have been removed by an earlier recursive call.
4440 if (Edge->isRemoved()) {
4441 assert(!is_contained(Node->CallerEdges, Edge));
4442 continue;
4443 }
4444 recursivelyRemoveNoneTypeCalleeEdges(Edge->Caller, Visited);
4445 }
4446}
4447
4448// This is the standard DFS based backedge discovery algorithm.
4449template <typename DerivedCCG, typename FuncTy, typename CallTy>
4450void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::markBackedges() {
4451 // If we are cloning recursive contexts, find and mark backedges from all root
4452 // callers, using the typical DFS based backedge analysis.
4454 return;
4455 DenseSet<const ContextNode *> Visited;
4456 DenseSet<const ContextNode *> CurrentStack;
4457 for (auto &Entry : NonAllocationCallToContextNodeMap) {
4458 auto *Node = Entry.second;
4459 if (Node->isRemoved())
4460 continue;
4461 // It is a root if it doesn't have callers.
4462 if (!Node->CallerEdges.empty())
4463 continue;
4464 markBackedges(Node, Visited, CurrentStack);
4465 assert(CurrentStack.empty());
4466 }
4467}
4468
4469// Recursive helper for above markBackedges method.
4470template <typename DerivedCCG, typename FuncTy, typename CallTy>
4471void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::markBackedges(
4472 ContextNode *Node, DenseSet<const ContextNode *> &Visited,
4473 DenseSet<const ContextNode *> &CurrentStack) {
4474 auto I = Visited.insert(Node);
4475 // We should only call this for unvisited nodes.
4476 assert(I.second);
4477 (void)I;
4478 for (auto &CalleeEdge : Node->CalleeEdges) {
4479 auto *Callee = CalleeEdge->Callee;
4480 if (Visited.count(Callee)) {
4481 // Since this was already visited we need to check if it is currently on
4482 // the recursive stack in which case it is a backedge.
4483 if (CurrentStack.count(Callee))
4484 CalleeEdge->IsBackedge = true;
4485 continue;
4486 }
4487 CurrentStack.insert(Callee);
4488 markBackedges(Callee, Visited, CurrentStack);
4489 CurrentStack.erase(Callee);
4490 }
4491}
4492
4493template <typename DerivedCCG, typename FuncTy, typename CallTy>
4494void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::identifyClones() {
4495 DenseSet<const ContextNode *> Visited;
4496 for (auto &Entry : AllocationCallToContextNodeMap) {
4497 Visited.clear();
4498 identifyClones(Entry.second, Visited, Entry.second->getContextIds());
4499 }
4500 Visited.clear();
4501 for (auto &Entry : AllocationCallToContextNodeMap)
4502 recursivelyRemoveNoneTypeCalleeEdges(Entry.second, Visited);
4503 if (VerifyCCG)
4504 check();
4505}
4506
4507// helper function to check an AllocType is cold or notcold or both.
4514
4515template <typename DerivedCCG, typename FuncTy, typename CallTy>
4516void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::identifyClones(
4517 ContextNode *Node, DenseSet<const ContextNode *> &Visited,
4518 const DenseSet<uint32_t> &AllocContextIds) {
4519 if (VerifyNodes)
4520 checkNode<DerivedCCG, FuncTy, CallTy>(Node, /*CheckEdges=*/false);
4521 assert(!Node->CloneOf);
4522
4523 // If Node as a null call, then either it wasn't found in the module (regular
4524 // LTO) or summary index (ThinLTO), or there were other conditions blocking
4525 // cloning (e.g. recursion, calls multiple targets, etc).
4526 // Do this here so that we don't try to recursively clone callers below, which
4527 // isn't useful at least for this node.
4528 if (!Node->hasCall())
4529 return;
4530
4531 // No need to look at any callers if allocation type already unambiguous.
4532 if (hasSingleAllocType(Node->AllocTypes))
4533 return;
4534
4535#ifndef NDEBUG
4536 auto Insert =
4537#endif
4538 Visited.insert(Node);
4539 // We should not have visited this node yet.
4540 assert(Insert.second);
4541 // The recursive call to identifyClones may delete the current edge from the
4542 // CallerEdges vector. Make a copy and iterate on that, simpler than passing
4543 // in an iterator and having recursive call erase from it. Other edges may
4544 // also get removed during the recursion, which will have null Callee and
4545 // Caller pointers (and are deleted later), so we skip those below.
4546 {
4547 auto CallerEdges = Node->CallerEdges;
4548 for (auto &Edge : CallerEdges) {
4549 // Skip any that have been removed by an earlier recursive call.
4550 if (Edge->isRemoved()) {
4551 assert(!is_contained(Node->CallerEdges, Edge));
4552 continue;
4553 }
4554 // Defer backedges. See comments further below where these edges are
4555 // handled during the cloning of this Node.
4556 if (Edge->IsBackedge) {
4557 // We should only mark these if cloning recursive contexts, where we
4558 // need to do this deferral.
4560 continue;
4561 }
4562 // Ignore any caller we previously visited via another edge.
4563 if (!Visited.count(Edge->Caller) && !Edge->Caller->CloneOf) {
4564 identifyClones(Edge->Caller, Visited, AllocContextIds);
4565 }
4566 }
4567 }
4568
4569 // Check if we reached an unambiguous call or have have only a single caller.
4570 if (hasSingleAllocType(Node->AllocTypes) || Node->CallerEdges.size() <= 1)
4571 return;
4572
4573 // We need to clone.
4574
4575 // Try to keep the original version as alloc type NotCold. This will make
4576 // cases with indirect calls or any other situation with an unknown call to
4577 // the original function get the default behavior. We do this by sorting the
4578 // CallerEdges of the Node we will clone by alloc type.
4579 //
4580 // Give NotCold edge the lowest sort priority so those edges are at the end of
4581 // the caller edges vector, and stay on the original version (since the below
4582 // code clones greedily until it finds all remaining edges have the same type
4583 // and leaves the remaining ones on the original Node).
4584 //
4585 // We shouldn't actually have any None type edges, so the sorting priority for
4586 // that is arbitrary, and we assert in that case below.
4587 const unsigned AllocTypeCloningPriority[] = {/*None*/ 3, /*NotCold*/ 4,
4588 /*Cold*/ 1,
4589 /*NotColdCold*/ 2};
4590 llvm::stable_sort(Node->CallerEdges,
4591 [&](const std::shared_ptr<ContextEdge> &A,
4592 const std::shared_ptr<ContextEdge> &B) {
4593 // Nodes with non-empty context ids should be sorted
4594 // before those with empty context ids.
4595 if (A->ContextIds.empty())
4596 // Either B ContextIds are non-empty (in which case we
4597 // should return false because B < A), or B ContextIds
4598 // are empty, in which case they are equal, and we
4599 // should maintain the original relative ordering.
4600 return false;
4601 if (B->ContextIds.empty())
4602 return true;
4603
4604 if (A->AllocTypes == B->AllocTypes)
4605 // Use the caller node id as a deterministic
4606 // tie-breaker.
4607 return A->Caller->NodeId < B->Caller->NodeId;
4608 return AllocTypeCloningPriority[A->AllocTypes] <
4609 AllocTypeCloningPriority[B->AllocTypes];
4610 });
4611
4612 assert(Node->AllocTypes != (uint8_t)AllocationType::None);
4613
4614 DenseSet<uint32_t> RecursiveContextIds;
4616 // If we are allowing recursive callsites, but have also disabled recursive
4617 // contexts, look for context ids that show up in multiple caller edges.
4619 DenseSet<uint32_t> AllCallerContextIds;
4620 for (auto &CE : Node->CallerEdges) {
4621 // Resize to the largest set of caller context ids, since we know the
4622 // final set will be at least that large.
4623 AllCallerContextIds.reserve(CE->getContextIds().size());
4624 for (auto Id : CE->getContextIds())
4625 if (!AllCallerContextIds.insert(Id).second)
4626 RecursiveContextIds.insert(Id);
4627 }
4628 }
4629
4630 // Iterate until we find no more opportunities for disambiguating the alloc
4631 // types via cloning. In most cases this loop will terminate once the Node
4632 // has a single allocation type, in which case no more cloning is needed.
4633 // Iterate over a copy of Node's caller edges, since we may need to remove
4634 // edges in the moveEdgeTo* methods, and this simplifies the handling and
4635 // makes it less error-prone.
4636 auto CallerEdges = Node->CallerEdges;
4637 for (auto &CallerEdge : CallerEdges) {
4638 // Skip any that have been removed by an earlier recursive call.
4639 if (CallerEdge->isRemoved()) {
4640 assert(!is_contained(Node->CallerEdges, CallerEdge));
4641 continue;
4642 }
4643 assert(CallerEdge->Callee == Node);
4644
4645 // See if cloning the prior caller edge left this node with a single alloc
4646 // type or a single caller. In that case no more cloning of Node is needed.
4647 if (hasSingleAllocType(Node->AllocTypes) || Node->CallerEdges.size() <= 1)
4648 break;
4649
4650 // If the caller was not successfully matched to a call in the IR/summary,
4651 // there is no point in trying to clone for it as we can't update that call.
4652 if (!CallerEdge->Caller->hasCall())
4653 continue;
4654
4655 // Only need to process the ids along this edge pertaining to the given
4656 // allocation.
4657 auto CallerEdgeContextsForAlloc =
4658 set_intersection(CallerEdge->getContextIds(), AllocContextIds);
4659 if (!RecursiveContextIds.empty())
4660 CallerEdgeContextsForAlloc =
4661 set_difference(CallerEdgeContextsForAlloc, RecursiveContextIds);
4662 if (CallerEdgeContextsForAlloc.empty())
4663 continue;
4664
4665 auto CallerAllocTypeForAlloc = computeAllocType(CallerEdgeContextsForAlloc);
4666
4667 // Compute the node callee edge alloc types corresponding to the context ids
4668 // for this caller edge.
4669 std::vector<uint8_t> CalleeEdgeAllocTypesForCallerEdge;
4670 CalleeEdgeAllocTypesForCallerEdge.reserve(Node->CalleeEdges.size());
4671 for (auto &CalleeEdge : Node->CalleeEdges)
4672 CalleeEdgeAllocTypesForCallerEdge.push_back(intersectAllocTypes(
4673 CalleeEdge->getContextIds(), CallerEdgeContextsForAlloc));
4674
4675 // Don't clone if doing so will not disambiguate any alloc types amongst
4676 // caller edges (including the callee edges that would be cloned).
4677 // Otherwise we will simply move all edges to the clone.
4678 //
4679 // First check if by cloning we will disambiguate the caller allocation
4680 // type from node's allocation type. Query allocTypeToUse so that we don't
4681 // bother cloning to distinguish NotCold+Cold from NotCold. Note that
4682 // neither of these should be None type.
4683 //
4684 // Then check if by cloning node at least one of the callee edges will be
4685 // disambiguated by splitting out different context ids.
4686 //
4687 // However, always do the cloning if this is a backedge, in which case we
4688 // have not yet cloned along this caller edge.
4689 assert(CallerEdge->AllocTypes != (uint8_t)AllocationType::None);
4690 assert(Node->AllocTypes != (uint8_t)AllocationType::None);
4691 if (!CallerEdge->IsBackedge &&
4692 allocTypeToUse(CallerAllocTypeForAlloc) ==
4693 allocTypeToUse(Node->AllocTypes) &&
4694 allocTypesMatch<DerivedCCG, FuncTy, CallTy>(
4695 CalleeEdgeAllocTypesForCallerEdge, Node->CalleeEdges)) {
4696 continue;
4697 }
4698
4699 if (CallerEdge->IsBackedge) {
4700 // We should only mark these if cloning recursive contexts, where we
4701 // need to do this deferral.
4703 DeferredBackedges++;
4704 }
4705
4706 // If this is a backedge, we now do recursive cloning starting from its
4707 // caller since we may have moved unambiguous caller contexts to a clone
4708 // of this Node in a previous iteration of the current loop, giving more
4709 // opportunity for cloning through the backedge. Because we sorted the
4710 // caller edges earlier so that cold caller edges are first, we would have
4711 // visited and cloned this node for any unamibiguously cold non-recursive
4712 // callers before any ambiguous backedge callers. Note that we don't do this
4713 // if the caller is already cloned or visited during cloning (e.g. via a
4714 // different context path from the allocation).
4715 // TODO: Can we do better in the case where the caller was already visited?
4716 if (CallerEdge->IsBackedge && !CallerEdge->Caller->CloneOf &&
4717 !Visited.count(CallerEdge->Caller)) {
4718 const auto OrigIdCount = CallerEdge->getContextIds().size();
4719 // Now do the recursive cloning of this backedge's caller, which was
4720 // deferred earlier.
4721 identifyClones(CallerEdge->Caller, Visited, CallerEdgeContextsForAlloc);
4722 removeNoneTypeCalleeEdges(CallerEdge->Caller);
4723 // See if the recursive call to identifyClones moved the context ids to a
4724 // new edge from this node to a clone of caller, and switch to looking at
4725 // that new edge so that we clone Node for the new caller clone.
4726 bool UpdatedEdge = false;
4727 if (OrigIdCount > CallerEdge->getContextIds().size()) {
4728 for (auto E : Node->CallerEdges) {
4729 // Only interested in clones of the current edges caller.
4730 if (E->Caller->CloneOf != CallerEdge->Caller)
4731 continue;
4732 // See if this edge contains any of the context ids originally on the
4733 // current caller edge.
4734 auto CallerEdgeContextsForAllocNew =
4735 set_intersection(CallerEdgeContextsForAlloc, E->getContextIds());
4736 if (CallerEdgeContextsForAllocNew.empty())
4737 continue;
4738 // Make sure we don't pick a previously existing caller edge of this
4739 // Node, which would be processed on a different iteration of the
4740 // outer loop over the saved CallerEdges.
4741 if (llvm::is_contained(CallerEdges, E))
4742 continue;
4743 // The CallerAllocTypeForAlloc and CalleeEdgeAllocTypesForCallerEdge
4744 // are updated further below for all cases where we just invoked
4745 // identifyClones recursively.
4746 CallerEdgeContextsForAlloc.swap(CallerEdgeContextsForAllocNew);
4747 CallerEdge = E;
4748 UpdatedEdge = true;
4749 break;
4750 }
4751 }
4752 // If cloning removed this edge (and we didn't update it to a new edge
4753 // above), we're done with this edge. It's possible we moved all of the
4754 // context ids to an existing clone, in which case there's no need to do
4755 // further processing for them.
4756 if (CallerEdge->isRemoved())
4757 continue;
4758
4759 // Now we need to update the information used for the cloning decisions
4760 // further below, as we may have modified edges and their context ids.
4761
4762 // Note if we changed the CallerEdge above we would have already updated
4763 // the context ids.
4764 if (!UpdatedEdge) {
4765 CallerEdgeContextsForAlloc = set_intersection(
4766 CallerEdgeContextsForAlloc, CallerEdge->getContextIds());
4767 if (CallerEdgeContextsForAlloc.empty())
4768 continue;
4769 }
4770 // Update the other information that depends on the edges and on the now
4771 // updated CallerEdgeContextsForAlloc.
4772 CallerAllocTypeForAlloc = computeAllocType(CallerEdgeContextsForAlloc);
4773 CalleeEdgeAllocTypesForCallerEdge.clear();
4774 for (auto &CalleeEdge : Node->CalleeEdges) {
4775 CalleeEdgeAllocTypesForCallerEdge.push_back(intersectAllocTypes(
4776 CalleeEdge->getContextIds(), CallerEdgeContextsForAlloc));
4777 }
4778 }
4779
4780 // First see if we can use an existing clone. Check each clone and its
4781 // callee edges for matching alloc types.
4782 ContextNode *Clone = nullptr;
4783 for (auto *CurClone : Node->Clones) {
4784 if (allocTypeToUse(CurClone->AllocTypes) !=
4785 allocTypeToUse(CallerAllocTypeForAlloc))
4786 continue;
4787
4788 bool BothSingleAlloc = hasSingleAllocType(CurClone->AllocTypes) &&
4789 hasSingleAllocType(CallerAllocTypeForAlloc);
4790 // The above check should mean that if both have single alloc types that
4791 // they should be equal.
4792 assert(!BothSingleAlloc ||
4793 CurClone->AllocTypes == CallerAllocTypeForAlloc);
4794
4795 // If either both have a single alloc type (which are the same), or if the
4796 // clone's callee edges have the same alloc types as those for the current
4797 // allocation on Node's callee edges (CalleeEdgeAllocTypesForCallerEdge),
4798 // then we can reuse this clone.
4799 if (BothSingleAlloc || allocTypesMatchClone<DerivedCCG, FuncTy, CallTy>(
4800 CalleeEdgeAllocTypesForCallerEdge, CurClone)) {
4801 Clone = CurClone;
4802 break;
4803 }
4804 }
4805
4806 // The edge iterator is adjusted when we move the CallerEdge to the clone.
4807 if (Clone)
4808 moveEdgeToExistingCalleeClone(CallerEdge, Clone, /*NewClone=*/false,
4809 CallerEdgeContextsForAlloc);
4810 else
4811 Clone = moveEdgeToNewCalleeClone(CallerEdge, CallerEdgeContextsForAlloc);
4812
4813 // Sanity check that no alloc types on clone or its edges are None.
4814 assert(Clone->AllocTypes != (uint8_t)AllocationType::None);
4815 }
4816
4817 // We should still have some context ids on the original Node.
4818 assert(!Node->emptyContextIds());
4819
4820 // Sanity check that no alloc types on node or edges are None.
4821 assert(Node->AllocTypes != (uint8_t)AllocationType::None);
4822
4823 if (VerifyNodes)
4824 checkNode<DerivedCCG, FuncTy, CallTy>(Node, /*CheckEdges=*/false);
4825}
4826
4827void ModuleCallsiteContextGraph::updateAllocationCall(
4828 CallInfo &Call, AllocationType AllocType) {
4829 std::string AllocTypeString = getAllocTypeAttributeString(AllocType);
4831 auto A = llvm::Attribute::get(Call.call()->getFunction()->getContext(),
4832 "memprof", AllocTypeString);
4833 cast<CallBase>(Call.call())->addFnAttr(A);
4834 OREGetter(Call.call()->getFunction())
4835 .emit(OptimizationRemark(DEBUG_TYPE, "MemprofAttribute", Call.call())
4836 << ore::NV("AllocationCall", Call.call()) << " in clone "
4837 << ore::NV("Caller", Call.call()->getFunction())
4838 << " marked with memprof allocation attribute "
4839 << ore::NV("Attribute", AllocTypeString));
4840}
4841
4842void IndexCallsiteContextGraph::updateAllocationCall(CallInfo &Call,
4844 auto *AI = cast<AllocInfo *>(Call.call());
4845 assert(AI);
4846 assert(AI->Versions.size() > Call.cloneNo());
4847 AI->Versions[Call.cloneNo()] = (uint8_t)AllocType;
4848}
4849
4851ModuleCallsiteContextGraph::getAllocationCallType(const CallInfo &Call) const {
4852 const auto *CB = cast<CallBase>(Call.call());
4853 if (!CB->getAttributes().hasFnAttr("memprof"))
4854 return AllocationType::None;
4855 return CB->getAttributes().getFnAttr("memprof").getValueAsString() == "cold"
4856 ? AllocationType::Cold
4857 : AllocationType::NotCold;
4858}
4859
4861IndexCallsiteContextGraph::getAllocationCallType(const CallInfo &Call) const {
4862 const auto *AI = cast<AllocInfo *>(Call.call());
4863 assert(AI->Versions.size() > Call.cloneNo());
4864 return (AllocationType)AI->Versions[Call.cloneNo()];
4865}
4866
4867void ModuleCallsiteContextGraph::updateCall(CallInfo &CallerCall,
4868 FuncInfo CalleeFunc) {
4869 auto *CurF = getCalleeFunc(CallerCall.call());
4870 auto NewCalleeCloneNo = CalleeFunc.cloneNo();
4871 if (isMemProfClone(*CurF)) {
4872 // If we already assigned this callsite to call a specific non-default
4873 // clone (i.e. not the original function which is clone 0), ensure that we
4874 // aren't trying to now update it to call a different clone, which is
4875 // indicative of a bug in the graph or function assignment.
4876 auto CurCalleeCloneNo = getMemProfCloneNum(*CurF);
4877 if (CurCalleeCloneNo != NewCalleeCloneNo) {
4878 LLVM_DEBUG(dbgs() << "Mismatch in call clone assignment: was "
4879 << CurCalleeCloneNo << " now " << NewCalleeCloneNo
4880 << "\n");
4881 MismatchedCloneAssignments++;
4882 }
4883 }
4884 if (NewCalleeCloneNo > 0)
4885 cast<CallBase>(CallerCall.call())->setCalledFunction(CalleeFunc.func());
4886 OREGetter(CallerCall.call()->getFunction())
4887 .emit(OptimizationRemark(DEBUG_TYPE, "MemprofCall", CallerCall.call())
4888 << ore::NV("Call", CallerCall.call()) << " in clone "
4889 << ore::NV("Caller", CallerCall.call()->getFunction())
4890 << " assigned to call function clone "
4891 << ore::NV("Callee", CalleeFunc.func()));
4892}
4893
4894void IndexCallsiteContextGraph::updateCall(CallInfo &CallerCall,
4895 FuncInfo CalleeFunc) {
4896 auto *CI = cast<CallsiteInfo *>(CallerCall.call());
4897 assert(CI &&
4898 "Caller cannot be an allocation which should not have profiled calls");
4899 assert(CI->Clones.size() > CallerCall.cloneNo());
4900 auto NewCalleeCloneNo = CalleeFunc.cloneNo();
4901 auto &CurCalleeCloneNo = CI->Clones[CallerCall.cloneNo()];
4902 // If we already assigned this callsite to call a specific non-default
4903 // clone (i.e. not the original function which is clone 0), ensure that we
4904 // aren't trying to now update it to call a different clone, which is
4905 // indicative of a bug in the graph or function assignment.
4906 if (CurCalleeCloneNo != 0 && CurCalleeCloneNo != NewCalleeCloneNo) {
4907 LLVM_DEBUG(dbgs() << "Mismatch in call clone assignment: was "
4908 << CurCalleeCloneNo << " now " << NewCalleeCloneNo
4909 << "\n");
4910 MismatchedCloneAssignments++;
4911 }
4912 CurCalleeCloneNo = NewCalleeCloneNo;
4913}
4914
4915// Update the debug information attached to NewFunc to use the clone Name. Note
4916// this needs to be done for both any existing DISubprogram for the definition,
4917// as well as any separate declaration DISubprogram.
4919 assert(Name == NewFunc->getName());
4920 auto *SP = NewFunc->getSubprogram();
4921 if (!SP)
4922 return;
4923 auto *MDName = MDString::get(NewFunc->getParent()->getContext(), Name);
4924 SP->replaceLinkageName(MDName);
4925 DISubprogram *Decl = SP->getDeclaration();
4926 if (!Decl)
4927 return;
4928 TempDISubprogram NewDecl = Decl->clone();
4929 NewDecl->replaceLinkageName(MDName);
4930 SP->replaceDeclaration(MDNode::replaceWithUniqued(std::move(NewDecl)));
4931}
4932
4933CallsiteContextGraph<ModuleCallsiteContextGraph, Function,
4934 Instruction *>::FuncInfo
4935ModuleCallsiteContextGraph::cloneFunctionForCallsite(
4936 FuncInfo &Func, CallInfo &Call, DenseMap<CallInfo, CallInfo> &CallMap,
4937 std::vector<CallInfo> &CallsWithMetadataInFunc, unsigned CloneNo) {
4938 // Use existing LLVM facilities for cloning and obtaining Call in clone
4939 ValueToValueMapTy VMap;
4940 auto *NewFunc = CloneFunction(Func.func(), VMap);
4941 std::string Name = getMemProfFuncName(Func.func()->getName(), CloneNo);
4942 assert(!Func.func()->getParent()->getFunction(Name));
4943 NewFunc->setName(Name);
4944 updateSubprogramLinkageName(NewFunc, Name);
4945 for (auto &Inst : CallsWithMetadataInFunc) {
4946 // This map always has the initial version in it.
4947 assert(Inst.cloneNo() == 0);
4948 CallMap[Inst] = {cast<Instruction>(VMap[Inst.call()]), CloneNo};
4949 }
4950 OREGetter(Func.func())
4951 .emit(OptimizationRemark(DEBUG_TYPE, "MemprofClone", Func.func())
4952 << "created clone " << ore::NV("NewFunction", NewFunc));
4953 return {NewFunc, CloneNo};
4954}
4955
4956CallsiteContextGraph<IndexCallsiteContextGraph, FunctionSummary,
4957 IndexCall>::FuncInfo
4958IndexCallsiteContextGraph::cloneFunctionForCallsite(
4959 FuncInfo &Func, CallInfo &Call, DenseMap<CallInfo, CallInfo> &CallMap,
4960 std::vector<CallInfo> &CallsWithMetadataInFunc, unsigned CloneNo) {
4961 // Check how many clones we have of Call (and therefore function).
4962 // The next clone number is the current size of versions array.
4963 // Confirm this matches the CloneNo provided by the caller, which is based on
4964 // the number of function clones we have.
4965 assert(CloneNo == (isa<AllocInfo *>(Call.call())
4966 ? cast<AllocInfo *>(Call.call())->Versions.size()
4967 : cast<CallsiteInfo *>(Call.call())->Clones.size()));
4968 // Walk all the instructions in this function. Create a new version for
4969 // each (by adding an entry to the Versions/Clones summary array), and copy
4970 // over the version being called for the function clone being cloned here.
4971 // Additionally, add an entry to the CallMap for the new function clone,
4972 // mapping the original call (clone 0, what is in CallsWithMetadataInFunc)
4973 // to the new call clone.
4974 for (auto &Inst : CallsWithMetadataInFunc) {
4975 // This map always has the initial version in it.
4976 assert(Inst.cloneNo() == 0);
4977 if (auto *AI = dyn_cast<AllocInfo *>(Inst.call())) {
4978 assert(AI->Versions.size() == CloneNo);
4979 // We assign the allocation type later (in updateAllocationCall), just add
4980 // an entry for it here.
4981 AI->Versions.push_back(0);
4982 } else {
4983 auto *CI = cast<CallsiteInfo *>(Inst.call());
4984 assert(CI && CI->Clones.size() == CloneNo);
4985 // We assign the clone number later (in updateCall), just add an entry for
4986 // it here.
4987 CI->Clones.push_back(0);
4988 }
4989 CallMap[Inst] = {Inst.call(), CloneNo};
4990 }
4991 return {Func.func(), CloneNo};
4992}
4993
4994// We perform cloning for each allocation node separately. However, this
4995// sometimes results in a situation where the same node calls multiple
4996// clones of the same callee, created for different allocations. This
4997// causes issues when assigning functions to these clones, as each node can
4998// in reality only call a single callee clone.
4999//
5000// To address this, before assigning functions, merge callee clone nodes as
5001// needed using a post order traversal from the allocations. We attempt to
5002// use existing clones as the merge node when legal, and to share them
5003// among callers with the same properties (callers calling the same set of
5004// callee clone nodes for the same allocations).
5005//
5006// Without this fix, in some cases incorrect function assignment will lead
5007// to calling the wrong allocation clone.
5008template <typename DerivedCCG, typename FuncTy, typename CallTy>
5009void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::mergeClones() {
5010 if (!MergeClones)
5011 return;
5012
5013 // Generate a map from context id to the associated allocation node for use
5014 // when merging clones.
5015 DenseMap<uint32_t, ContextNode *> ContextIdToAllocationNode;
5016 for (auto &Entry : AllocationCallToContextNodeMap) {
5017 auto *Node = Entry.second;
5018 for (auto Id : Node->getContextIds())
5019 ContextIdToAllocationNode[Id] = Node->getOrigNode();
5020 for (auto *Clone : Node->Clones) {
5021 for (auto Id : Clone->getContextIds())
5022 ContextIdToAllocationNode[Id] = Clone->getOrigNode();
5023 }
5024 }
5025
5026 // Post order traversal starting from allocations to ensure each callsite
5027 // calls a single clone of its callee. Callee nodes that are clones of each
5028 // other are merged (via new merge nodes if needed) to achieve this.
5029 DenseSet<const ContextNode *> Visited;
5030 for (auto &Entry : AllocationCallToContextNodeMap) {
5031 auto *Node = Entry.second;
5032
5033 mergeClones(Node, Visited, ContextIdToAllocationNode);
5034
5035 // Make a copy so the recursive post order traversal that may create new
5036 // clones doesn't mess up iteration. Note that the recursive traversal
5037 // itself does not call mergeClones on any of these nodes, which are all
5038 // (clones of) allocations.
5039 auto Clones = Node->Clones;
5040 for (auto *Clone : Clones)
5041 mergeClones(Clone, Visited, ContextIdToAllocationNode);
5042 }
5043
5044 if (DumpCCG) {
5045 dbgs() << "CCG after merging:\n";
5046 dbgs() << *this;
5047 }
5048 if (ExportToDot)
5049 exportToDot("aftermerge");
5050
5051 if (VerifyCCG) {
5052 check();
5053 }
5054}
5055
5056// Recursive helper for above mergeClones method.
5057template <typename DerivedCCG, typename FuncTy, typename CallTy>
5058void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::mergeClones(
5059 ContextNode *Node, DenseSet<const ContextNode *> &Visited,
5060 DenseMap<uint32_t, ContextNode *> &ContextIdToAllocationNode) {
5061 auto Inserted = Visited.insert(Node);
5062 if (!Inserted.second)
5063 return;
5064
5065 // Iteratively perform merging on this node to handle new caller nodes created
5066 // during the recursive traversal. We could do something more elegant such as
5067 // maintain a worklist, but this is a simple approach that doesn't cause a
5068 // measureable compile time effect, as most nodes don't have many caller
5069 // edges to check.
5070 bool FoundUnvisited = true;
5071 unsigned Iters = 0;
5072 while (FoundUnvisited) {
5073 Iters++;
5074 FoundUnvisited = false;
5075 // Make a copy since the recursive call may move a caller edge to a new
5076 // callee, messing up the iterator.
5077 auto CallerEdges = Node->CallerEdges;
5078 for (auto CallerEdge : CallerEdges) {
5079 // Skip any caller edge moved onto a different callee during recursion.
5080 if (CallerEdge->Callee != Node)
5081 continue;
5082 // If we found an unvisited caller, note that we should check the caller
5083 // edges again as mergeClones may add or change caller nodes.
5084 if (DoMergeIteration && !Visited.contains(CallerEdge->Caller))
5085 FoundUnvisited = true;
5086 mergeClones(CallerEdge->Caller, Visited, ContextIdToAllocationNode);
5087 }
5088 }
5089
5090 TotalMergeInvokes++;
5091 TotalMergeIters += Iters;
5092 if (Iters > MaxMergeIters)
5093 MaxMergeIters = Iters;
5094
5095 // Merge for this node after we handle its callers.
5096 mergeNodeCalleeClones(Node, Visited, ContextIdToAllocationNode);
5097}
5098
5099template <typename DerivedCCG, typename FuncTy, typename CallTy>
5100void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::mergeNodeCalleeClones(
5101 ContextNode *Node, DenseSet<const ContextNode *> &Visited,
5102 DenseMap<uint32_t, ContextNode *> &ContextIdToAllocationNode) {
5103 // Ignore Node if we moved all of its contexts to clones.
5104 if (Node->emptyContextIds())
5105 return;
5106
5107 // First identify groups of clones among Node's callee edges, by building
5108 // a map from each callee base node to the associated callee edges from Node.
5109 MapVector<ContextNode *, std::vector<std::shared_ptr<ContextEdge>>>
5110 OrigNodeToCloneEdges;
5111 for (const auto &E : Node->CalleeEdges) {
5112 auto *Callee = E->Callee;
5113 if (!Callee->CloneOf && Callee->Clones.empty())
5114 continue;
5115 ContextNode *Base = Callee->getOrigNode();
5116 OrigNodeToCloneEdges[Base].push_back(E);
5117 }
5118
5119 // Helper for callee edge sorting below. Return true if A's callee has fewer
5120 // caller edges than B, or if A is a clone and B is not, or if A's callee
5121 // node id is smaller than B's.
5122 auto CalleeCallerEdgeLessThan = [](const std::shared_ptr<ContextEdge> &A,
5123 const std::shared_ptr<ContextEdge> &B) {
5124 if (A->Callee->CallerEdges.size() != B->Callee->CallerEdges.size())
5125 return A->Callee->CallerEdges.size() < B->Callee->CallerEdges.size();
5126 if (A->Callee->CloneOf && !B->Callee->CloneOf)
5127 return true;
5128 else if (!A->Callee->CloneOf && B->Callee->CloneOf)
5129 return false;
5130 // Use the callee node id as a deterministic tie-breaker.
5131 return A->Callee->NodeId < B->Callee->NodeId;
5132 };
5133
5134 // Process each set of callee clones called by Node, performing the needed
5135 // merging.
5136 for (auto Entry : OrigNodeToCloneEdges) {
5137 // CalleeEdges is the set of edges from Node reaching callees that are
5138 // mutual clones of each other.
5139 auto &CalleeEdges = Entry.second;
5140 auto NumCalleeClones = CalleeEdges.size();
5141 // A single edge means there is no merging needed.
5142 if (NumCalleeClones == 1)
5143 continue;
5144 // Sort the CalleeEdges calling this group of clones in ascending order of
5145 // their caller edge counts, putting the original non-clone node first in
5146 // cases of a tie. This simplifies finding an existing node to use as the
5147 // merge node.
5148 llvm::stable_sort(CalleeEdges, CalleeCallerEdgeLessThan);
5149
5150 /// Find other callers of the given set of callee edges that can
5151 /// share the same callee merge node. See the comments at this method
5152 /// definition for details.
5153 DenseSet<ContextNode *> OtherCallersToShareMerge;
5154 findOtherCallersToShareMerge(Node, CalleeEdges, ContextIdToAllocationNode,
5155 OtherCallersToShareMerge);
5156
5157 // Now do the actual merging. Identify existing or create a new MergeNode
5158 // during the first iteration. Move each callee over, along with edges from
5159 // other callers we've determined above can share the same merge node.
5160 ContextNode *MergeNode = nullptr;
5161 DenseMap<ContextNode *, unsigned> CallerToMoveCount;
5162 for (auto CalleeEdge : CalleeEdges) {
5163 auto *OrigCallee = CalleeEdge->Callee;
5164 // If we don't have a MergeNode yet (only happens on the first iteration,
5165 // as a new one will be created when we go to move the first callee edge
5166 // over as needed), see if we can use this callee.
5167 if (!MergeNode) {
5168 // If there are no other callers, simply use this callee.
5169 if (CalleeEdge->Callee->CallerEdges.size() == 1) {
5170 MergeNode = OrigCallee;
5171 NonNewMergedNodes++;
5172 continue;
5173 }
5174 // Otherwise, if we have identified other caller nodes that can share
5175 // the merge node with Node, see if all of OrigCallee's callers are
5176 // going to share the same merge node. In that case we can use callee
5177 // (since all of its callers would move to the new merge node).
5178 if (!OtherCallersToShareMerge.empty()) {
5179 bool MoveAllCallerEdges = true;
5180 for (auto CalleeCallerE : OrigCallee->CallerEdges) {
5181 if (CalleeCallerE == CalleeEdge)
5182 continue;
5183 if (!OtherCallersToShareMerge.contains(CalleeCallerE->Caller)) {
5184 MoveAllCallerEdges = false;
5185 break;
5186 }
5187 }
5188 // If we are going to move all callers over, we can use this callee as
5189 // the MergeNode.
5190 if (MoveAllCallerEdges) {
5191 MergeNode = OrigCallee;
5192 NonNewMergedNodes++;
5193 continue;
5194 }
5195 }
5196 }
5197 // Move this callee edge, creating a new merge node if necessary.
5198 if (MergeNode) {
5199 assert(MergeNode != OrigCallee);
5200 moveEdgeToExistingCalleeClone(CalleeEdge, MergeNode,
5201 /*NewClone*/ false);
5202 } else {
5203 MergeNode = moveEdgeToNewCalleeClone(CalleeEdge);
5204 NewMergedNodes++;
5205 }
5206 // Now move all identified edges from other callers over to the merge node
5207 // as well.
5208 if (!OtherCallersToShareMerge.empty()) {
5209 // Make and iterate over a copy of OrigCallee's caller edges because
5210 // some of these will be moved off of the OrigCallee and that would mess
5211 // up the iteration from OrigCallee.
5212 auto OrigCalleeCallerEdges = OrigCallee->CallerEdges;
5213 for (auto &CalleeCallerE : OrigCalleeCallerEdges) {
5214 if (CalleeCallerE == CalleeEdge)
5215 continue;
5216 if (!OtherCallersToShareMerge.contains(CalleeCallerE->Caller))
5217 continue;
5218 CallerToMoveCount[CalleeCallerE->Caller]++;
5219 moveEdgeToExistingCalleeClone(CalleeCallerE, MergeNode,
5220 /*NewClone*/ false);
5221 }
5222 }
5223 removeNoneTypeCalleeEdges(OrigCallee);
5224 removeNoneTypeCalleeEdges(MergeNode);
5225 }
5226 }
5227}
5228
5229// Look for other nodes that have edges to the same set of callee
5230// clones as the current Node. Those can share the eventual merge node
5231// (reducing cloning and binary size overhead) iff:
5232// - they have edges to the same set of callee clones
5233// - each callee edge reaches a subset of the same allocations as Node's
5234// corresponding edge to the same callee clone.
5235// The second requirement is to ensure that we don't undo any of the
5236// necessary cloning to distinguish contexts with different allocation
5237// behavior.
5238// FIXME: This is somewhat conservative, as we really just need to ensure
5239// that they don't reach the same allocations as contexts on edges from Node
5240// going to any of the *other* callee clones being merged. However, that
5241// requires more tracking and checking to get right.
5242template <typename DerivedCCG, typename FuncTy, typename CallTy>
5243void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::
5244 findOtherCallersToShareMerge(
5245 ContextNode *Node,
5246 std::vector<std::shared_ptr<ContextEdge>> &CalleeEdges,
5247 DenseMap<uint32_t, ContextNode *> &ContextIdToAllocationNode,
5248 DenseSet<ContextNode *> &OtherCallersToShareMerge) {
5249 auto NumCalleeClones = CalleeEdges.size();
5250 // This map counts how many edges to the same callee clone exist for other
5251 // caller nodes of each callee clone.
5252 DenseMap<ContextNode *, unsigned> OtherCallersToSharedCalleeEdgeCount;
5253 // Counts the number of other caller nodes that have edges to all callee
5254 // clones that don't violate the allocation context checking.
5255 unsigned PossibleOtherCallerNodes = 0;
5256
5257 // We only need to look at other Caller nodes if the first callee edge has
5258 // multiple callers (recall they are sorted in ascending order above).
5259 if (CalleeEdges[0]->Callee->CallerEdges.size() < 2)
5260 return;
5261
5262 // For each callee edge:
5263 // - Collect the count of other caller nodes calling the same callees.
5264 // - Collect the alloc nodes reached by contexts on each callee edge.
5265 DenseMap<ContextEdge *, DenseSet<ContextNode *>> CalleeEdgeToAllocNodes;
5266 for (auto CalleeEdge : CalleeEdges) {
5267 assert(CalleeEdge->Callee->CallerEdges.size() > 1);
5268 // For each other caller of the same callee, increment the count of
5269 // edges reaching the same callee clone.
5270 for (auto CalleeCallerEdges : CalleeEdge->Callee->CallerEdges) {
5271 if (CalleeCallerEdges->Caller == Node) {
5272 assert(CalleeCallerEdges == CalleeEdge);
5273 continue;
5274 }
5275 OtherCallersToSharedCalleeEdgeCount[CalleeCallerEdges->Caller]++;
5276 // If this caller edge now reaches all of the same callee clones,
5277 // increment the count of candidate other caller nodes.
5278 if (OtherCallersToSharedCalleeEdgeCount[CalleeCallerEdges->Caller] ==
5279 NumCalleeClones)
5280 PossibleOtherCallerNodes++;
5281 }
5282 // Collect the alloc nodes reached by contexts on each callee edge, for
5283 // later analysis.
5284 for (auto Id : CalleeEdge->getContextIds()) {
5285 auto *Alloc = ContextIdToAllocationNode.lookup(Id);
5286 if (!Alloc) {
5287 // FIXME: unclear why this happens occasionally, presumably
5288 // imperfect graph updates possibly with recursion.
5289 MissingAllocForContextId++;
5290 continue;
5291 }
5292 CalleeEdgeToAllocNodes[CalleeEdge.get()].insert(Alloc);
5293 }
5294 }
5295
5296 // Now walk the callee edges again, and make sure that for each candidate
5297 // caller node all of its edges to the callees reach the same allocs (or
5298 // a subset) as those along the corresponding callee edge from Node.
5299 for (auto CalleeEdge : CalleeEdges) {
5300 assert(CalleeEdge->Callee->CallerEdges.size() > 1);
5301 // Stop if we do not have any (more) candidate other caller nodes.
5302 if (!PossibleOtherCallerNodes)
5303 break;
5304 auto &CurCalleeAllocNodes = CalleeEdgeToAllocNodes[CalleeEdge.get()];
5305 // Check each other caller of this callee clone.
5306 for (auto &CalleeCallerE : CalleeEdge->Callee->CallerEdges) {
5307 // Not interested in the callee edge from Node itself.
5308 if (CalleeCallerE == CalleeEdge)
5309 continue;
5310 // Skip any callers that didn't have callee edges to all the same
5311 // callee clones.
5312 if (OtherCallersToSharedCalleeEdgeCount[CalleeCallerE->Caller] !=
5313 NumCalleeClones)
5314 continue;
5315 // Make sure that each context along edge from candidate caller node
5316 // reaches an allocation also reached by this callee edge from Node.
5317 for (auto Id : CalleeCallerE->getContextIds()) {
5318 auto *Alloc = ContextIdToAllocationNode.lookup(Id);
5319 if (!Alloc)
5320 continue;
5321 // If not, simply reset the map entry to 0 so caller is ignored, and
5322 // reduce the count of candidate other caller nodes.
5323 if (!CurCalleeAllocNodes.contains(Alloc)) {
5324 OtherCallersToSharedCalleeEdgeCount[CalleeCallerE->Caller] = 0;
5325 PossibleOtherCallerNodes--;
5326 break;
5327 }
5328 }
5329 }
5330 }
5331
5332 if (!PossibleOtherCallerNodes)
5333 return;
5334
5335 // Build the set of other caller nodes that can use the same callee merge
5336 // node.
5337 for (auto &[OtherCaller, Count] : OtherCallersToSharedCalleeEdgeCount) {
5338 if (Count != NumCalleeClones)
5339 continue;
5340 OtherCallersToShareMerge.insert(OtherCaller);
5341 }
5342}
5343
5344template <typename DerivedCCG, typename FuncTy, typename CallTy>
5345const typename CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::ContextNode *
5346CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::resolveImplicitSource(
5347 const ContextNode *Node, const ImplicitSource &Src) {
5348 if (!Src.Source->emptyContextIds())
5349 return Src.Source;
5350 // Src.Source lost its contexts to another clone (e.g. its last caller was
5351 // moved to a new clone when specializing a function clone further). The
5352 // trimmed contexts stay together, so the clone carrying one of them is the
5353 // version the implicit caller requires.
5354 if (Node->hasContextId(Src.ContextId))
5355 return Node;
5356 for (const ContextNode *C : Node->Clones)
5357 if (C->hasContextId(Src.ContextId))
5358 return C;
5359 // Context ids only move between the clones of a node during function
5360 // assignment, so the id should still be on one of them. Return null, which
5361 // makes the call follow the original node, rather than an emptied clone.
5362 assert(false && "trimmed context id on no clone of its callsite node");
5363 return nullptr;
5364}
5365
5366// Contexts whose call stacks were trimmed at a callsite node's frame are on
5367// its callee edges but on none of its caller edges. When that node, or one
5368// below it on the path of such a context, is cloned for the contexts of
5369// another allocation reaching it through a caller edge, the trimmed contexts
5370// stay with the node that was cloned, and the clone gets no edge to the callee
5371// nodes the trimmed contexts flow through. The clone is therefore not a caller
5372// of any clone of such a callee node, and would otherwise be assigned a
5373// function clone of the callee without regard to it, possibly one calling the
5374// wrong version of the callee for the trimmed contexts, which are agnostic to
5375// the callers of the node they were trimmed at and apply to the clone equally.
5376//
5377// This is called once the clones of callsite Node have been assigned to
5378// function clones. For each caller Y of a clone of Node whose edge carries
5379// trimmed contexts, each clone K of Y's original node that has no edge to any
5380// clone of Node, and which some of those trimmed contexts would reach (see
5381// ImpliesContextIds), is an implicit caller of Node. For example, with a
5382// context t trimmed at the frame of Y's callsite:
5383//
5384// (callers of Y) (callers of K)
5385// | |
5386// Y K clones of the same callsite node
5387// | \
5388// t | \ K has no edge to any clone of Node
5389// v v
5390// Required (other callsites in Node's function)
5391// (clone of Node called
5392// by Y, assigned to
5393// Y's function clone)
5394//
5395// Had t not been trimmed, it would also be on an edge from K, so K should get
5396// the same version of Node's function as Y:
5397// - If K was not yet assigned a function clone, assign it Y's, so that the
5398// assignment of the callsites it does have edges to takes it into account
5399// (creating further function clones derived from it if needed).
5400// - If K was already assigned to a function clone without a clone of Node,
5401// record that the Node call in that function clone should follow Required.
5402// - Otherwise K's function clone calls a conflicting clone of Node, which is
5403// left as is (and counted).
5404template <typename DerivedCCG, typename FuncTy, typename CallTy>
5405void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::assignImplicitCallers(
5406 ContextNode *Node, const DenseSet<uint32_t> &TrimmedContextIds,
5407 DenseMap<ContextNode *, FuncInfo> &CallsiteToCalleeFuncCloneMap,
5408 const std::map<FuncInfo, ContextNode *> &FuncCloneToCurNodeCloneMap,
5409 ImplicitSourceMap &ImplicitSources) {
5410 auto HasEdgeToNodeFamily = [&](const ContextNode *N) {
5411 return llvm::any_of(N->CalleeEdges,
5412 [&](const std::shared_ptr<ContextEdge> &E) {
5413 return E->Callee->getOrigNode() == Node;
5414 });
5415 };
5416 // Returns true if any of the trimmed context ids Ids, which are on (the
5417 // clone) Y but not on K, a clone of the same callsite node, would reach K had
5418 // they not been trimmed:
5419 // - An id terminating at Y applies to all clones of Y's original node (see
5420 // the example above assignImplicitCallers).
5421 // - An id reaching Y from a caller Z applies to K only if it would equally
5422 // apply to some caller C of K that is a clone of Z's original node, i.e.
5423 // it is not on C (if it were, C explicitly directs it to a callee other
5424 // than K) and, recursively, it applies to C the way it applies to Z (e.g.
5425 // because it terminates at Z, so it applies to all clones of Z's original
5426 // node). The id would then flow from C to K just as it flows from Z to Y,
5427 // had it not been trimmed:
5428 //
5429 // ... ... t terminates at Z or one of its callers
5430 // |
5431 // Z C clones of the same callsite node
5432 // | :
5433 // t | : (t) t is not on C or K; it applies to them
5434 // v v because it was trimmed above
5435 // Y K clones of the same callsite node
5436 // |
5437 // t v
5438 // Required
5439 //
5440 // This is checked recursively on (C, Z) with the ids not on C. If C == Z,
5441 // Z explicitly directs the ids to Y rather than K, so they don't apply to
5442 // K.
5443 //
5444 // Visited records the ids already examined for each (K, Y) pair, which
5445 // guards against cycles from recursion while still examining ids first seen
5446 // for the pair on a reconverging caller chain.
5447 auto ImpliesContextIds =
5448 [&](ContextNode *K, ContextNode *Y, const DenseSet<uint32_t> &Ids,
5449 DenseMap<std::pair<ContextNode *, ContextNode *>, DenseSet<uint32_t>>
5450 &Visited,
5451 auto &&ImpliesContextIds) -> bool {
5452 assert(K->getOrigNode() == Y->getOrigNode());
5453 DenseSet<uint32_t> &VisitedIds = Visited[{K, Y}];
5454 DenseSet<uint32_t> NewIds;
5455 for (auto Id : Ids)
5456 if (VisitedIds.insert(Id).second)
5457 NewIds.insert(Id);
5458 if (NewIds.empty())
5459 return false;
5460 // The ids found on each caller edge of Y, with that edge's caller Z, and
5461 // their union (a set rather than a count, as a recursive context can put
5462 // the same id on several caller edges).
5464 DenseSet<uint32_t> IdsOnCallerEdges;
5465 for (auto &YEdge : Y->CallerEdges) {
5466 DenseSet<uint32_t> IdsFromZ =
5467 set_intersection(NewIds, YEdge->getContextIds());
5468 if (IdsFromZ.empty())
5469 continue;
5470 set_union(IdsOnCallerEdges, IdsFromZ);
5471 IdsFromCallers.push_back({YEdge->Caller, std::move(IdsFromZ)});
5472 }
5473 // Any ids on none of Y's caller edges terminate at Y, and so apply to all
5474 // clones of Y's original node, including K.
5475 if (IdsOnCallerEdges.size() < NewIds.size())
5476 return true;
5477 // Otherwise check whether the ids reaching Y from a caller Z also apply to
5478 // K through a caller C of K that is a clone of Z's original node.
5479 for (auto &[Z, IdsFromZ] : IdsFromCallers) {
5480 for (auto &KEdge : K->CallerEdges) {
5481 ContextNode *C = KEdge->Caller;
5482 if (C == Z || C->getOrigNode() != Z->getOrigNode())
5483 continue;
5484 // Only the ids not on C can apply to C implicitly (C directs the ones
5485 // it has elsewhere); recursively check whether they do.
5486 DenseSet<uint32_t> IdsNotOnC;
5487 for (auto Id : IdsFromZ)
5488 if (!C->hasContextId(Id))
5489 IdsNotOnC.insert(Id);
5490 if (!IdsNotOnC.empty() &&
5491 ImpliesContextIds(C, Z, IdsNotOnC, Visited, ImpliesContextIds))
5492 return true;
5493 }
5494 }
5495 return false;
5496 };
5497 // Returns true if the given clones of Node are interchangeable for an
5498 // implicit caller: the same clone, allocations with the same hint, or
5499 // callsites already assigned to call the same function clone.
5500 auto SameVersion = [&](const ContextNode *A, const ContextNode *B) {
5501 if (A == B)
5502 return true;
5503 if (Node->IsAllocation)
5504 return allocTypeToUse(A->AllocTypes) == allocTypeToUse(B->AllocTypes);
5505 auto AIt = CallsiteToCalleeFuncCloneMap.find(A);
5506 auto BIt = CallsiteToCalleeFuncCloneMap.find(B);
5507 return AIt != CallsiteToCalleeFuncCloneMap.end() &&
5508 BIt != CallsiteToCalleeFuncCloneMap.end() &&
5509 AIt->second == BIt->second;
5510 };
5511 // The clones already identified as implicit callers of Node, so that each is
5512 // handled once (for the first caller edge whose trimmed contexts reach it).
5513 DenseSet<const ContextNode *> ImplicitCallers;
5514 // Handles the caller edge Edge of a clone of Node (or of Node itself): finds
5515 // the implicit callers among the clones of its caller Y's original node, and
5516 // assigns them, or records the clone of Node their calls must follow, as
5517 // described above.
5518 auto ProcessCaller = [&](const std::shared_ptr<ContextEdge> &Edge) {
5519 ContextNode *Y = Edge->Caller;
5520 ContextNode *Orig = Y->getOrigNode();
5521 if (!Y->hasCall() || Orig->Clones.empty())
5522 return;
5523 DenseSet<uint32_t> TrimmedIds =
5524 set_intersection(Edge->getContextIds(), TrimmedContextIds);
5525 if (TrimmedIds.empty())
5526 return;
5527 auto YIt = CallsiteToCalleeFuncCloneMap.find(Y);
5528 if (YIt == CallsiteToCalleeFuncCloneMap.end())
5529 return;
5530 // Copy, as recording assignments below may grow the map.
5531 const FuncInfo YFuncClone = YIt->second;
5532 // The clone of Node called by Y, which must be assigned to the same
5533 // function clone.
5534 auto RequiredIt = FuncCloneToCurNodeCloneMap.find(YFuncClone);
5535 assert(RequiredIt != FuncCloneToCurNodeCloneMap.end());
5536 const ContextNode *Required = RequiredIt->second;
5537 // Record in ImplicitSources that the Node call in function clone F must
5538 // follow the callsite clone Src. This is consulted when the calls in
5539 // function clones without their own clone of Node are collected (see
5540 // UnassignedCallClones in assignFunctions), and makes the requirement
5541 // survive if Src is later moved to another function clone derived from F
5542 // (when one of its callers conflicts at another callsite), after which the
5543 // call in F would otherwise follow the function clone F was derived from.
5544 auto RecordImplicitSource = [&](const FuncInfo &F, const ContextNode *Src) {
5545 // The calls in the original function (clone 0) are not collected there,
5546 // so nothing can be recorded for it.
5547 if (F.cloneNo() != 0)
5548 ImplicitSources.try_emplace({Node, F.cloneNo()},
5549 ImplicitSource{Src, *TrimmedIds.begin()});
5550 };
5551 // Check each clone of Y's original node (and the original itself) without
5552 // an edge to any clone of Node.
5553 for (ContextNode *K : llvm::concat<ContextNode *const>(
5554 Orig->Clones, ArrayRef<ContextNode *>(Orig))) {
5555 if (K == Y || !K->hasCall() || K->emptyContextIds() ||
5556 HasEdgeToNodeFamily(K) || ImplicitCallers.contains(K))
5557 continue;
5558 DenseMap<std::pair<ContextNode *, ContextNode *>, DenseSet<uint32_t>>
5559 Visited;
5560 if (!ImpliesContextIds(K, Y, TrimmedIds, Visited, ImpliesContextIds))
5561 continue;
5562 // K is an implicit caller of Node.
5563 ImplicitCallers.insert(K);
5564 auto KIt = CallsiteToCalleeFuncCloneMap.find(K);
5565 if (KIt == CallsiteToCalleeFuncCloneMap.end()) {
5566 // Not yet assigned: give it Y's function clone, in which the Node call
5567 // then follows Required.
5568 CallsiteToCalleeFuncCloneMap[K] = YFuncClone;
5569 RecordImplicitSource(YFuncClone, Required);
5570 NumImplicitCallersAssigned++;
5571 continue;
5572 }
5573 const FuncInfo KFuncClone = KIt->second;
5574 if (KFuncClone == YFuncClone) {
5575 // Already in Y's function clone.
5576 RecordImplicitSource(YFuncClone, Required);
5577 continue;
5578 }
5579 unsigned KCloneNo = KFuncClone.cloneNo();
5580 auto KNodeCloneIt = FuncCloneToCurNodeCloneMap.find(KFuncClone);
5581 if (KNodeCloneIt == FuncCloneToCurNodeCloneMap.end()) {
5582 // K's function clone has no clone of Node.
5583 if (KCloneNo == 0) {
5584 // The call in the original function keeps calling the original
5585 // callee function, or stays unhinted for an allocation. That
5586 // satisfies the requirement only if Required is that version.
5587 if (Node->IsAllocation) {
5588 if (allocTypeToUse(Required->AllocTypes) == AllocationType::NotCold)
5589 continue;
5590 } else if (auto It = CallsiteToCalleeFuncCloneMap.find(Required);
5591 It != CallsiteToCalleeFuncCloneMap.end() &&
5592 It->second.cloneNo() == 0)
5593 continue;
5594 } else {
5595 // Record that the Node call in K's function clone must follow
5596 // Required, unless an earlier implicit caller already recorded a
5597 // conflicting clone.
5598 auto [It, Inserted] = ImplicitSources.try_emplace(
5599 {Node, KCloneNo}, ImplicitSource{Required, *TrimmedIds.begin()});
5600 if (Inserted)
5601 NumImplicitCallersSourced++;
5602 if (SameVersion(It->second.Source, Required))
5603 continue;
5604 }
5605 } else if (SameVersion(KNodeCloneIt->second, Required)) {
5606 // K's function clone has a clone of Node interchangeable with
5607 // Required.
5608 RecordImplicitSource(KFuncClone, KNodeCloneIt->second);
5609 continue;
5610 }
5611 // K's function clone calls a conflicting clone of Node.
5612 NumImplicitCallersUnresolved++;
5613 }
5614 };
5615 // Process the caller edges of Node itself and of each of its clones: any of
5616 // them may carry trimmed contexts (a trimmed context stays with the clone
5617 // that was cloned, which may be Node or a clone made earlier).
5618 for (auto &Edge : Node->CallerEdges)
5619 ProcessCaller(Edge);
5620 for (auto *Clone : Node->Clones)
5621 for (auto &Edge : Clone->CallerEdges)
5622 ProcessCaller(Edge);
5623}
5624
5625// This method assigns cloned callsites to functions, cloning the functions as
5626// needed. The assignment is greedy and proceeds roughly as follows:
5627//
5628// For each function Func:
5629// For each call with graph Node having clones:
5630// Initialize ClonesWorklist to Node and its clones
5631// Initialize NodeCloneCount to 0
5632// While ClonesWorklist is not empty:
5633// Clone = pop front ClonesWorklist
5634// NodeCloneCount++
5635// If Func has been cloned less than NodeCloneCount times:
5636// If NodeCloneCount is 1:
5637// Assign Clone to original Func
5638// Continue
5639// Create a new function clone
5640// If other callers not assigned to call a function clone yet:
5641// Assign them to call new function clone
5642// Continue
5643// Assign any other caller calling the cloned version to new clone
5644//
5645// For each caller of Clone:
5646// If caller is assigned to call a specific function clone:
5647// If we cannot assign Clone to that function clone:
5648// Create new callsite Clone NewClone
5649// Add NewClone to ClonesWorklist
5650// Continue
5651// Assign Clone to existing caller's called function clone
5652// Else:
5653// If Clone not already assigned to a function clone:
5654// Assign to first function clone without assignment
5655// Assign caller to selected function clone
5656// For each call with graph Node having clones:
5657// If number func clones > number call's callsite Node clones:
5658// Record func CallInfo clones without Node clone in UnassignedCallClones
5659// For callsite Nodes in DFS order from allocations:
5660// If IsAllocation:
5661// Update allocation with alloc type
5662// Else:
5663// For Call, all MatchingCalls, and associated UnnassignedCallClones:
5664// Update call to call recorded callee clone
5665//
5666template <typename DerivedCCG, typename FuncTy, typename CallTy>
5667bool CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::assignFunctions() {
5668 bool Changed = false;
5669
5670 mergeClones();
5671
5672 // Context ids terminating at a non-allocation node which has or had callers
5673 // (i.e. is not a root), meaning their call stacks were trimmed there. Used
5674 // to identify implicit callers (see assignImplicitCallers).
5675 DenseSet<uint32_t> TrimmedContextIds;
5676 for (auto &NodePtr : NodeOwner) {
5677 ContextNode *N = NodePtr.get();
5678 if (N->IsAllocation || N->CalleeEdges.empty() ||
5679 (N->CallerEdges.empty() && N->Clones.empty() && !N->CloneOf))
5680 continue;
5681 // A context id trimmed at N is on a callee edge but on no caller edge.
5682 // Compare distinct ids rather than edge sizes: a recursive context can put
5683 // the same id on several callee and caller edges of N.
5684 DenseSet<uint32_t> CallerIds;
5685 for (auto &E : N->CallerEdges)
5686 set_union(CallerIds, E->getContextIds());
5687 for (auto &CalleeEdge : N->CalleeEdges)
5688 for (auto Id : CalleeEdge->getContextIds())
5689 if (!CallerIds.contains(Id))
5690 TrimmedContextIds.insert(Id);
5691 }
5692 NumTrimmedContextIds += TrimmedContextIds.size();
5693
5694 // Keep track of the assignment of nodes (callsites) to function clones they
5695 // call.
5696 DenseMap<ContextNode *, FuncInfo> CallsiteToCalleeFuncCloneMap;
5697
5698 // Update caller node to call function version CalleeFunc, by recording the
5699 // assignment in CallsiteToCalleeFuncCloneMap.
5700 auto RecordCalleeFuncOfCallsite = [&](ContextNode *Caller,
5701 const FuncInfo &CalleeFunc) {
5702 assert(Caller->hasCall());
5703 CallsiteToCalleeFuncCloneMap[Caller] = CalleeFunc;
5704 };
5705
5706 // Information for a single clone of this Func.
5707 struct FuncCloneInfo {
5708 // The function clone.
5709 FuncInfo FuncClone;
5710 // Remappings of each call of interest (from original uncloned call to the
5711 // corresponding cloned call in this function clone).
5712 DenseMap<CallInfo, CallInfo> CallMap;
5713 };
5714
5715 // Map to keep track of information needed to update calls in function clones
5716 // when their corresponding callsite node was not itself cloned for that
5717 // function clone. Because of call context trimming (i.e. we only keep as much
5718 // caller information as needed to distinguish hot vs cold), we may not have
5719 // caller edges coming to each callsite node from all possible function
5720 // callers. A function clone may get created for other callsites in the
5721 // function for which there are caller edges that were not trimmed. Any other
5722 // callsites in that function clone, which were not themselved cloned for
5723 // that function clone, should get updated the same way as the corresponding
5724 // callsite in the original function (which may call a clone of its callee).
5725 //
5726 // We build this map after completing function cloning for each function, so
5727 // that we can record the information from its call maps before they are
5728 // destructed. The map will be used as we update calls to update any still
5729 // unassigned call clones. Note that we may create new node clones as we clone
5730 // other functions, so later on we check which node clones were still not
5731 // created. To this end, the inner map is a map from function clone number to
5732 // the list of calls cloned for that function (can be more than one due to the
5733 // Node's MatchingCalls array).
5734 //
5735 // The alternative is creating new callsite clone nodes below as we clone the
5736 // function, but that is tricker to get right and likely more overhead.
5737 //
5738 // Each entry also records the callsite node whose callee assignment the
5739 // calls should follow (Source). By default that is the callsite clone (if
5740 // any) in the function clone the function clone was derived from, following
5741 // the chain of derivations to the original function, since a function clone
5742 // created to specialize another one should otherwise behave like it. It can
5743 // also be the callsite clone required by an implicit caller (see
5744 // assignImplicitCallers). A null Source means the original node.
5745 //
5746 // Inner map is a std::map so sorted by key (clone number), in order to get
5747 // ordered remarks in the full LTO case.
5748 struct UnassignedCallCloneInfo {
5750 const ContextNode *Source = nullptr;
5751 };
5752 DenseMap<const ContextNode *, std::map<unsigned, UnassignedCallCloneInfo>>
5753 UnassignedCallClones;
5754
5755 // Walk all functions for which we saw calls with memprof metadata, and handle
5756 // cloning for each of its calls.
5757 for (auto &[Func, CallsWithMetadata] : FuncToCallsWithMetadata) {
5758 FuncInfo OrigFunc(Func);
5759 // Map from each clone number of OrigFunc to information about that function
5760 // clone (the function clone FuncInfo and call remappings). The index into
5761 // the vector is the clone number, as function clones are created and
5762 // numbered sequentially.
5763 std::vector<FuncCloneInfo> FuncCloneInfos;
5764 // For each function clone number, the clone number of the function clone
5765 // it was derived from (created to further specialize, when a caller
5766 // already assigned to it needed a different clone of some callsite), or 0
5767 // for clones created from the original function. Used to decide which
5768 // callsite clone the calls not themselves cloned for a function clone
5769 // should follow (see UnassignedCallClones).
5770 std::vector<unsigned> FuncCloneParent;
5771 // Callsite clones required for calls in specific function clones by
5772 // implicit callers (see assignImplicitCallers).
5773 ImplicitSourceMap ImplicitSources;
5774 // Map from each original callsite node in this function to its original
5775 // call and matching calls (clone 0). The calls recorded on an original node
5776 // are updated to the calls in a function clone if that node is assigned to
5777 // a function clone, after which they can no longer be used to index the
5778 // function clone CallMaps (which are keyed by the original calls). No node
5779 // in this function has been assigned yet at this point.
5780 struct OrigCallsInfo {
5781 CallInfo Call;
5782 SmallVector<CallInfo, 0> MatchingCalls;
5783 };
5784 DenseMap<const ContextNode *, OrigCallsInfo> OrigNodeToOrigCalls;
5785 for (auto &Call : CallsWithMetadata) {
5786 ContextNode *Node = getNodeForInst(Call);
5787 if (Node && Node->Call == Call)
5788 OrigNodeToOrigCalls[Node] = {Call, Node->MatchingCalls};
5789 }
5790 for (auto &Call : CallsWithMetadata) {
5791 ContextNode *Node = getNodeForInst(Call);
5792 // Skip call if we do not have a node for it (all uses of its stack ids
5793 // were either on inlined chains or trimmed from the MIBs), or if we did
5794 // not create any clones for it.
5795 if (!Node || Node->Clones.empty())
5796 continue;
5797 assert(Node->hasCall() &&
5798 "Not having a call should have prevented cloning");
5799
5800 // Track the assignment of function clones to clones of the current
5801 // callsite Node being handled.
5802 std::map<FuncInfo, ContextNode *> FuncCloneToCurNodeCloneMap;
5803
5804 // Assign callsite version CallsiteClone to function version FuncClone,
5805 // and also assign (possibly cloned) Call to CallsiteClone.
5806 auto AssignCallsiteCloneToFuncClone = [&](const FuncInfo &FuncClone,
5807 CallInfo &Call,
5808 ContextNode *CallsiteClone,
5809 bool IsAlloc) {
5810 // Record the clone of callsite node assigned to this function clone.
5811 FuncCloneToCurNodeCloneMap[FuncClone] = CallsiteClone;
5812
5813 assert(FuncCloneInfos.size() > FuncClone.cloneNo());
5814 DenseMap<CallInfo, CallInfo> &CallMap =
5815 FuncCloneInfos[FuncClone.cloneNo()].CallMap;
5816 CallInfo CallClone(Call);
5817 if (auto It = CallMap.find(Call); It != CallMap.end())
5818 CallClone = It->second;
5819 CallsiteClone->setCall(CallClone);
5820 // Need to do the same for all matching calls. Rebuild the list of
5821 // CallsiteClone from the original matching calls (it may have been
5822 // copied from a node whose calls were already remapped), using the
5823 // same mapping as for Call.
5824 assert(OrigNodeToOrigCalls.count(Node));
5825 CallsiteClone->MatchingCalls.clear();
5826 for (const CallInfo &OrigMatchingCall :
5827 OrigNodeToOrigCalls[Node].MatchingCalls) {
5828 CallInfo CallClone(OrigMatchingCall);
5829 if (auto It = CallMap.find(OrigMatchingCall); It != CallMap.end())
5830 CallClone = It->second;
5831 CallsiteClone->MatchingCalls.push_back(CallClone);
5832 }
5833 };
5834
5835 // Invokes moveEdgeToNewCalleeClone which creates a new clone, and then
5836 // performs the necessary fixups (removing none type edges, and
5837 // importantly, propagating any function call assignment of the original
5838 // node to the new clone).
5839 auto MoveEdgeToNewCalleeCloneAndSetUp =
5840 [&](const std::shared_ptr<ContextEdge> &Edge) {
5841 ContextNode *OrigCallee = Edge->Callee;
5842 ContextNode *NewClone = moveEdgeToNewCalleeClone(Edge);
5843 removeNoneTypeCalleeEdges(NewClone);
5844 assert(NewClone->AllocTypes != (uint8_t)AllocationType::None);
5845 // If the original Callee was already assigned to call a specific
5846 // function version, make sure its new clone is assigned to call
5847 // that same function clone.
5848 if (CallsiteToCalleeFuncCloneMap.count(OrigCallee))
5849 RecordCalleeFuncOfCallsite(
5850 NewClone, CallsiteToCalleeFuncCloneMap[OrigCallee]);
5851 return NewClone;
5852 };
5853
5854 // Keep track of the clones of callsite Node that need to be assigned to
5855 // function clones. This list may be expanded in the loop body below if we
5856 // find additional cloning is required.
5857 std::deque<ContextNode *> ClonesWorklist;
5858 // Ignore original Node if we moved all of its contexts to clones.
5859 if (!Node->emptyContextIds())
5860 ClonesWorklist.push_back(Node);
5861 llvm::append_range(ClonesWorklist, Node->Clones);
5862
5863 // Now walk through all of the clones of this callsite Node that we need,
5864 // and determine the assignment to a corresponding clone of the current
5865 // function (creating new function clones as needed).
5866 unsigned NodeCloneCount = 0;
5867 while (!ClonesWorklist.empty()) {
5868 ContextNode *Clone = ClonesWorklist.front();
5869 ClonesWorklist.pop_front();
5870 NodeCloneCount++;
5871 if (VerifyNodes)
5873
5874 // Need to create a new function clone if we have more callsite clones
5875 // than existing function clones, which would have been assigned to an
5876 // earlier clone in the list (we assign callsite clones to function
5877 // clones greedily).
5878 if (FuncCloneInfos.size() < NodeCloneCount) {
5879 // If this is the first callsite copy, assign to original function.
5880 if (NodeCloneCount == 1) {
5881 // Since FuncCloneInfos is empty in this case, no clones have
5882 // been created for this function yet, and no callers should have
5883 // been assigned a function clone for this callee node yet.
5885 Clone->CallerEdges, [&](const std::shared_ptr<ContextEdge> &E) {
5886 return CallsiteToCalleeFuncCloneMap.count(E->Caller);
5887 }));
5888 // Initialize with empty call map, assign Clone to original function
5889 // and its callers, and skip to the next clone.
5890 FuncCloneInfos.push_back(
5891 {OrigFunc, DenseMap<CallInfo, CallInfo>()});
5892 FuncCloneParent.push_back(0);
5893 AssignCallsiteCloneToFuncClone(
5894 OrigFunc, Call, Clone,
5895 AllocationCallToContextNodeMap.count(Call));
5896 for (auto &CE : Clone->CallerEdges) {
5897 // Ignore any caller that does not have a recorded callsite Call.
5898 if (!CE->Caller->hasCall())
5899 continue;
5900 RecordCalleeFuncOfCallsite(CE->Caller, OrigFunc);
5901 }
5902 continue;
5903 }
5904
5905 // First locate which copy of OrigFunc to clone again. If a caller
5906 // of this callsite clone was already assigned to call a particular
5907 // function clone, we need to redirect all of those callers to the
5908 // new function clone, and update their other callees within this
5909 // function.
5910 FuncInfo PreviousAssignedFuncClone;
5911 auto EI = llvm::find_if(
5912 Clone->CallerEdges, [&](const std::shared_ptr<ContextEdge> &E) {
5913 return CallsiteToCalleeFuncCloneMap.count(E->Caller);
5914 });
5915 bool CallerAssignedToCloneOfFunc = false;
5916 if (EI != Clone->CallerEdges.end()) {
5917 const std::shared_ptr<ContextEdge> &Edge = *EI;
5918 PreviousAssignedFuncClone =
5919 CallsiteToCalleeFuncCloneMap[Edge->Caller];
5920 CallerAssignedToCloneOfFunc = true;
5921 }
5922
5923 // Clone function and save it along with the CallInfo map created
5924 // during cloning in the FuncCloneInfos.
5925 DenseMap<CallInfo, CallInfo> NewCallMap;
5926 unsigned CloneNo = FuncCloneInfos.size();
5927 assert(CloneNo > 0 && "Clone 0 is the original function, which "
5928 "should already exist in the map");
5929 FuncInfo NewFuncClone = cloneFunctionForCallsite(
5930 OrigFunc, Call, NewCallMap, CallsWithMetadata, CloneNo);
5931 FuncCloneInfos.push_back({NewFuncClone, std::move(NewCallMap)});
5932 // Record the function clone it is derived from (if any), whose
5933 // callers it will take over below.
5934 FuncCloneParent.push_back(CallerAssignedToCloneOfFunc
5935 ? PreviousAssignedFuncClone.cloneNo()
5936 : 0);
5937 FunctionClonesAnalysis++;
5938 Changed = true;
5939
5940 // If no caller callsites were already assigned to a clone of this
5941 // function, we can simply assign this clone to the new func clone
5942 // and update all callers to it, then skip to the next clone.
5943 if (!CallerAssignedToCloneOfFunc) {
5944 AssignCallsiteCloneToFuncClone(
5945 NewFuncClone, Call, Clone,
5946 AllocationCallToContextNodeMap.count(Call));
5947 for (auto &CE : Clone->CallerEdges) {
5948 // Ignore any caller that does not have a recorded callsite Call.
5949 if (!CE->Caller->hasCall())
5950 continue;
5951 RecordCalleeFuncOfCallsite(CE->Caller, NewFuncClone);
5952 }
5953 continue;
5954 }
5955
5956 // We may need to do additional node cloning in this case.
5957 // Reset the CallsiteToCalleeFuncCloneMap entry for any callers
5958 // that were previously assigned to call PreviousAssignedFuncClone,
5959 // to record that they now call NewFuncClone.
5960 // The none type edge removal may remove some of this Clone's caller
5961 // edges, if it is reached via another of its caller's callees.
5962 // Iterate over a copy and skip any that were removed.
5963 auto CallerEdges = Clone->CallerEdges;
5964 for (auto CE : CallerEdges) {
5965 // Skip any that have been removed on an earlier iteration.
5966 if (CE->isRemoved()) {
5967 assert(!is_contained(Clone->CallerEdges, CE));
5968 continue;
5969 }
5970 assert(CE);
5971 // Ignore any caller that does not have a recorded callsite Call.
5972 if (!CE->Caller->hasCall())
5973 continue;
5974
5975 if (!CallsiteToCalleeFuncCloneMap.count(CE->Caller) ||
5976 // We subsequently fall through to later handling that
5977 // will perform any additional cloning required for
5978 // callers that were calling other function clones.
5979 CallsiteToCalleeFuncCloneMap[CE->Caller] !=
5980 PreviousAssignedFuncClone)
5981 continue;
5982
5983 RecordCalleeFuncOfCallsite(CE->Caller, NewFuncClone);
5984
5985 // If we are cloning a function that was already assigned to some
5986 // callers, then essentially we are creating new callsite clones
5987 // of the other callsites in that function that are reached by those
5988 // callers. Clone the other callees of the current callsite's caller
5989 // that were already assigned to PreviousAssignedFuncClone
5990 // accordingly. This is important since we subsequently update the
5991 // calls from the nodes in the graph and their assignments to callee
5992 // functions recorded in CallsiteToCalleeFuncCloneMap.
5993 // The none type edge removal may remove some of this caller's
5994 // callee edges, if it is reached via another of its callees.
5995 // Iterate over a copy and skip any that were removed.
5996 auto CalleeEdges = CE->Caller->CalleeEdges;
5997 for (auto CalleeEdge : CalleeEdges) {
5998 // Skip any that have been removed on an earlier iteration when
5999 // cleaning up newly None type callee edges.
6000 if (CalleeEdge->isRemoved()) {
6001 assert(!is_contained(CE->Caller->CalleeEdges, CalleeEdge));
6002 continue;
6003 }
6004 assert(CalleeEdge);
6005 ContextNode *Callee = CalleeEdge->Callee;
6006 // Skip the current callsite, we are looking for other
6007 // callsites Caller calls, as well as any that does not have a
6008 // recorded callsite Call.
6009 if (Callee == Clone || !Callee->hasCall())
6010 continue;
6011 // Skip direct recursive calls. We don't need/want to clone the
6012 // caller node again, and this loop will not behave as expected if
6013 // we tried.
6014 if (Callee == CalleeEdge->Caller)
6015 continue;
6016 ContextNode *NewClone =
6017 MoveEdgeToNewCalleeCloneAndSetUp(CalleeEdge);
6018 // Moving the edge may have resulted in some none type
6019 // callee edges on the original Callee.
6020 removeNoneTypeCalleeEdges(Callee);
6021 // Update NewClone with the new Call clone of this callsite's Call
6022 // created for the new function clone created earlier.
6023 // Recall that we have already ensured when building the graph
6024 // that each caller can only call callsites within the same
6025 // function, so we are guaranteed that Callee Call is in the
6026 // current OrigFunc.
6027 // CallMap is set up as indexed by original calls at clone 0. Note
6028 // that we cannot simply use the calls recorded on Callee's
6029 // original node, as those are updated to the calls in a function
6030 // clone if the original node was itself assigned to a function
6031 // clone.
6032 assert(OrigNodeToOrigCalls.count(Callee->getOrigNode()));
6033 auto &OrigCalls = OrigNodeToOrigCalls[Callee->getOrigNode()];
6034 DenseMap<CallInfo, CallInfo> &CallMap =
6035 FuncCloneInfos[NewFuncClone.cloneNo()].CallMap;
6036 assert(CallMap.count(OrigCalls.Call));
6037 CallInfo NewCall(CallMap[OrigCalls.Call]);
6038 assert(NewCall);
6039 NewClone->setCall(NewCall);
6040 // Need to do the same for all matching calls.
6041 NewClone->MatchingCalls.clear();
6042 for (auto &OrigMatchingCall : OrigCalls.MatchingCalls) {
6043 assert(CallMap.count(OrigMatchingCall));
6044 CallInfo NewCall(CallMap[OrigMatchingCall]);
6045 assert(NewCall);
6046 NewClone->MatchingCalls.push_back(NewCall);
6047 }
6048 }
6049 }
6050 // Fall through to handling below to perform the recording of the
6051 // function for this callsite clone. This enables handling of cases
6052 // where the callers were assigned to different clones of a function.
6053 }
6054
6055 auto FindFirstAvailFuncClone = [&]() {
6056 // Find first function in FuncCloneInfos without an assigned
6057 // clone of this callsite Node. We should always have one
6058 // available at this point due to the earlier cloning when the
6059 // FuncCloneInfos size was smaller than the clone number.
6060 for (auto &CF : FuncCloneInfos) {
6061 if (!FuncCloneToCurNodeCloneMap.count(CF.FuncClone))
6062 return CF.FuncClone;
6063 }
6065 "Expected an available func clone for this callsite clone");
6066 };
6067
6068 // See if we can use existing function clone. Walk through
6069 // all caller edges to see if any have already been assigned to
6070 // a clone of this callsite's function. If we can use it, do so. If not,
6071 // because that function clone is already assigned to a different clone
6072 // of this callsite, then we need to clone again.
6073 // Basically, this checking is needed to handle the case where different
6074 // caller functions/callsites may need versions of this function
6075 // containing different mixes of callsite clones across the different
6076 // callsites within the function. If that happens, we need to create
6077 // additional function clones to handle the various combinations.
6078 //
6079 // Keep track of any new clones of this callsite created by the
6080 // following loop, as well as any existing clone that we decided to
6081 // assign this clone to.
6082 std::map<FuncInfo, ContextNode *> FuncCloneToNewCallsiteCloneMap;
6083 FuncInfo FuncCloneAssignedToCurCallsiteClone;
6084 // Iterate over a copy of Clone's caller edges, since we may need to
6085 // remove edges in the moveEdgeTo* methods, and this simplifies the
6086 // handling and makes it less error-prone.
6087 auto CloneCallerEdges = Clone->CallerEdges;
6088 for (auto &Edge : CloneCallerEdges) {
6089 // Skip removed edges (due to direct recursive edges updated when
6090 // updating callee edges when moving an edge and subsequently
6091 // removed by call to removeNoneTypeCalleeEdges on the Clone).
6092 if (Edge->isRemoved())
6093 continue;
6094 // Ignore any caller that does not have a recorded callsite Call.
6095 if (!Edge->Caller->hasCall())
6096 continue;
6097 // If this caller already assigned to call a version of OrigFunc, need
6098 // to ensure we can assign this callsite clone to that function clone.
6099 if (CallsiteToCalleeFuncCloneMap.count(Edge->Caller)) {
6100 FuncInfo FuncCloneCalledByCaller =
6101 CallsiteToCalleeFuncCloneMap[Edge->Caller];
6102 // First we need to confirm that this function clone is available
6103 // for use by this callsite node clone.
6104 //
6105 // While FuncCloneToCurNodeCloneMap is built only for this Node and
6106 // its callsite clones, one of those callsite clones X could have
6107 // been assigned to the same function clone called by Edge's caller
6108 // - if Edge's caller calls another callsite within Node's original
6109 // function, and that callsite has another caller reaching clone X.
6110 // We need to clone Node again in this case.
6111 if ((FuncCloneToCurNodeCloneMap.count(FuncCloneCalledByCaller) &&
6112 FuncCloneToCurNodeCloneMap[FuncCloneCalledByCaller] !=
6113 Clone) ||
6114 // Detect when we have multiple callers of this callsite that
6115 // have already been assigned to specific, and different, clones
6116 // of OrigFunc (due to other unrelated callsites in Func they
6117 // reach via call contexts). Is this Clone of callsite Node
6118 // assigned to a different clone of OrigFunc? If so, clone Node
6119 // again.
6120 (FuncCloneAssignedToCurCallsiteClone &&
6121 FuncCloneAssignedToCurCallsiteClone !=
6122 FuncCloneCalledByCaller)) {
6123 // We need to use a different newly created callsite clone, in
6124 // order to assign it to another new function clone on a
6125 // subsequent iteration over the Clones array (adjusted below).
6126 // Note we specifically do not reset the
6127 // CallsiteToCalleeFuncCloneMap entry for this caller, so that
6128 // when this new clone is processed later we know which version of
6129 // the function to copy (so that other callsite clones we have
6130 // assigned to that function clone are properly cloned over). See
6131 // comments in the function cloning handling earlier.
6132
6133 // Check if we already have cloned this callsite again while
6134 // walking through caller edges, for a caller calling the same
6135 // function clone. If so, we can move this edge to that new clone
6136 // rather than creating yet another new clone.
6137 if (FuncCloneToNewCallsiteCloneMap.count(
6138 FuncCloneCalledByCaller)) {
6139 ContextNode *NewClone =
6140 FuncCloneToNewCallsiteCloneMap[FuncCloneCalledByCaller];
6141 moveEdgeToExistingCalleeClone(Edge, NewClone);
6142 // Cleanup any none type edges cloned over.
6143 removeNoneTypeCalleeEdges(NewClone);
6144 } else {
6145 // Create a new callsite clone.
6146 ContextNode *NewClone = MoveEdgeToNewCalleeCloneAndSetUp(Edge);
6147 FuncCloneToNewCallsiteCloneMap[FuncCloneCalledByCaller] =
6148 NewClone;
6149 // Add to list of clones and process later.
6150 ClonesWorklist.push_back(NewClone);
6151 }
6152 // Moving the caller edge may have resulted in some none type
6153 // callee edges.
6154 removeNoneTypeCalleeEdges(Clone);
6155 // We will handle the newly created callsite clone in a subsequent
6156 // iteration over this Node's Clones.
6157 continue;
6158 }
6159
6160 // Otherwise, we can use the function clone already assigned to this
6161 // caller.
6162 if (!FuncCloneAssignedToCurCallsiteClone) {
6163 FuncCloneAssignedToCurCallsiteClone = FuncCloneCalledByCaller;
6164 // Assign Clone to FuncCloneCalledByCaller
6165 AssignCallsiteCloneToFuncClone(
6166 FuncCloneCalledByCaller, Call, Clone,
6167 AllocationCallToContextNodeMap.count(Call));
6168 } else
6169 // Don't need to do anything - callsite is already calling this
6170 // function clone.
6171 assert(FuncCloneAssignedToCurCallsiteClone ==
6172 FuncCloneCalledByCaller);
6173
6174 } else {
6175 // We have not already assigned this caller to a version of
6176 // OrigFunc. Do the assignment now.
6177
6178 // First check if we have already assigned this callsite clone to a
6179 // clone of OrigFunc for another caller during this iteration over
6180 // its caller edges.
6181 if (!FuncCloneAssignedToCurCallsiteClone) {
6182 FuncCloneAssignedToCurCallsiteClone = FindFirstAvailFuncClone();
6183 assert(FuncCloneAssignedToCurCallsiteClone);
6184 // Assign Clone to FuncCloneAssignedToCurCallsiteClone
6185 AssignCallsiteCloneToFuncClone(
6186 FuncCloneAssignedToCurCallsiteClone, Call, Clone,
6187 AllocationCallToContextNodeMap.count(Call));
6188 } else
6189 assert(FuncCloneToCurNodeCloneMap
6190 [FuncCloneAssignedToCurCallsiteClone] == Clone);
6191 // Update callers to record function version called.
6192 RecordCalleeFuncOfCallsite(Edge->Caller,
6193 FuncCloneAssignedToCurCallsiteClone);
6194 }
6195 }
6196 // If we didn't assign a function clone to this callsite clone yet, e.g.
6197 // none of its callers has a non-null call, do the assignment here.
6198 // We want to ensure that every callsite clone is assigned to some
6199 // function clone, so that the call updates below work as expected.
6200 // In particular if this is the original callsite, we want to ensure it
6201 // is assigned to the original function, otherwise the original function
6202 // will appear available for assignment to other callsite clones,
6203 // leading to unintended effects. For one, the unknown and not updated
6204 // callers will call into cloned paths leading to the wrong hints,
6205 // because they still call the original function (clone 0). Also,
6206 // because all callsites start out as being clone 0 by default, we can't
6207 // easily distinguish between callsites explicitly assigned to clone 0
6208 // vs those never assigned, which can lead to multiple updates of the
6209 // calls when invoking updateCall below, with mismatched clone values.
6210 // TODO: Add a flag to the callsite nodes or some other mechanism to
6211 // better distinguish and identify callsite clones that are not getting
6212 // assigned to function clones as expected.
6213 if (!FuncCloneAssignedToCurCallsiteClone) {
6214 FuncCloneAssignedToCurCallsiteClone = FindFirstAvailFuncClone();
6215 assert(FuncCloneAssignedToCurCallsiteClone &&
6216 "No available func clone for this callsite clone");
6217 AssignCallsiteCloneToFuncClone(
6218 FuncCloneAssignedToCurCallsiteClone, Call, Clone,
6219 /*IsAlloc=*/AllocationCallToContextNodeMap.contains(Call));
6220 }
6221 }
6222 assignImplicitCallers(Node, TrimmedContextIds,
6223 CallsiteToCalleeFuncCloneMap,
6224 FuncCloneToCurNodeCloneMap, ImplicitSources);
6225 if (VerifyCCG) {
6227 for (const auto &PE : Node->CalleeEdges)
6229 for (const auto &CE : Node->CallerEdges)
6231 for (auto *Clone : Node->Clones) {
6233 for (const auto &PE : Clone->CalleeEdges)
6235 for (const auto &CE : Clone->CallerEdges)
6237 }
6238 }
6239 }
6240
6242 FuncToNumClones[Func] = std::max<unsigned>(1, FuncCloneInfos.size());
6243 if (FuncCloneInfos.size() < 2)
6244 continue;
6245
6246 // In this case there is more than just the original function copy.
6247 // Record call clones of any callsite nodes in the function that did not
6248 // themselves get cloned for all of the function clones.
6249 for (auto &Call : CallsWithMetadata) {
6250 ContextNode *Node = getNodeForInst(Call);
6251 if (!Node || !Node->hasCall() || Node->emptyContextIds())
6252 continue;
6253 // First collect the function clones that have a clone of this callsite
6254 // node (or the node itself). They may not be sequential due to empty
6255 // clones e.g.
6256 DenseMap<unsigned, const ContextNode *> FuncCloneToNodeClone;
6257 FuncCloneToNodeClone[Node->Call.cloneNo()] = Node;
6258 // A clone left without context ids (its callers were all moved to other
6259 // clones while assigning function clones) has no edges and is not
6260 // reached by the call updates below, so the call in its function clone
6261 // keeps the original callee. If an implicit caller recorded the callsite
6262 // clone that call must follow, treat the function clone as having no
6263 // clone of this node, so that the call follows the recorded source like
6264 // any other call not cloned for its function clone.
6265 for (auto *C : Node->Clones)
6266 if (!C->emptyContextIds() ||
6267 !ImplicitSources.contains({Node, C->Call.cloneNo()}))
6268 FuncCloneToNodeClone[C->Call.cloneNo()] = C;
6269 // If Node has enough clones already to cover all function clones, we can
6270 // skip it.
6271 if (FuncCloneToNodeClone.size() >= FuncCloneInfos.size())
6272 continue;
6273 // Now check all the function clones.
6274 for (auto &FC : FuncCloneInfos) {
6275 unsigned I = FC.FuncClone.cloneNo();
6276 // Skip the first clone which got the original call.
6277 // Also skip any other clones created for this Node.
6278 if (I == 0 || FuncCloneToNodeClone.contains(I)) {
6279 continue;
6280 }
6281 // Record the call clones created for this callsite in this function
6282 // clone, and the callsite node whose callee they should follow: the
6283 // one required by an implicit caller, if any, else the clone of this
6284 // callsite node in the nearest function clone in the chain of function
6285 // clones this one was derived from (null for the original node).
6286 auto &Info = UnassignedCallClones[Node][I];
6287 auto &CallVector = Info.Calls;
6288 for (unsigned P = I;; P = FuncCloneParent[P]) {
6289 if (auto It = ImplicitSources.find({Node, P});
6290 It != ImplicitSources.end()) {
6291 Info.Source = resolveImplicitSource(Node, It->second);
6292 break;
6293 }
6294 if (auto It = FuncCloneToNodeClone.find(P);
6295 It != FuncCloneToNodeClone.end()) {
6296 Info.Source = It->second;
6297 break;
6298 }
6299 if (P == 0)
6300 break;
6301 }
6302 DenseMap<CallInfo, CallInfo> &CallMap = FC.CallMap;
6303 if (auto It = CallMap.find(Call); It != CallMap.end()) {
6304 CallInfo CallClone = It->second;
6305 CallVector.push_back(CallClone);
6306 } else {
6307 // All but the original clone (skipped earlier) should have an entry
6308 // for all calls.
6309 assert(false && "Expected to find call in CallMap");
6310 }
6311 // Need to do the same for all matching calls. Use the original
6312 // matching calls, as those on Node may have been remapped to the calls
6313 // of a function clone if Node was assigned to one.
6314 assert(OrigNodeToOrigCalls.count(Node));
6315 for (const CallInfo &OrigMatchingCall :
6316 OrigNodeToOrigCalls[Node].MatchingCalls) {
6317 if (auto It = CallMap.find(OrigMatchingCall); It != CallMap.end()) {
6318 CallInfo CallClone = It->second;
6319 CallVector.push_back(CallClone);
6320 } else {
6321 // All but the original clone (skipped earlier) should have an entry
6322 // for all calls.
6323 assert(false && "Expected to find call in CallMap");
6324 }
6325 }
6326 }
6327 }
6328 }
6329
6330 uint8_t BothTypes =
6331 (uint8_t)AllocationType::Cold | (uint8_t)AllocationType::NotCold;
6332
6333 auto UpdateCalls = [&](ContextNode *Node,
6334 DenseSet<const ContextNode *> &Visited,
6335 auto &&UpdateCalls) {
6336 auto Inserted = Visited.insert(Node);
6337 if (!Inserted.second)
6338 return;
6339
6340 for (auto *Clone : Node->Clones)
6341 UpdateCalls(Clone, Visited, UpdateCalls);
6342
6343 for (auto &Edge : Node->CallerEdges)
6344 UpdateCalls(Edge->Caller, Visited, UpdateCalls);
6345
6346 // Skip if either no call to update, or if we ended up with no context ids
6347 // (we moved all edges onto other clones).
6348 if (!Node->hasCall() || Node->emptyContextIds())
6349 return;
6350
6351 // Returns the recorded call clones in function clones which don't have a
6352 // clone of this callsite node, along with the node whose decision each
6353 // should follow (the Source recorded earlier, falling back to Node).
6354 auto GetUnassignedCallClones = [&](ContextNode *Node) {
6356 Unassigned;
6357 auto UnassignedIt = UnassignedCallClones.find(Node);
6358 if (UnassignedIt == UnassignedCallClones.end())
6359 return Unassigned;
6360 DenseSet<unsigned> NodeCallClones;
6361 for (auto *C : Node->Clones)
6362 if (!C->emptyContextIds())
6363 NodeCallClones.insert(C->Call.cloneNo());
6364 for (auto &[CloneNo, Info] : UnassignedIt->second) {
6365 // Should start at 1 as we never create an entry for original node.
6366 assert(CloneNo > 0);
6367 // If we subsequently created a clone, skip this one.
6368 if (NodeCallClones.contains(CloneNo))
6369 continue;
6370 Unassigned.push_back({Info.Source ? Info.Source : Node, Info.Calls});
6371 }
6372 return Unassigned;
6373 };
6374
6375 if (Node->IsAllocation) {
6376 auto GetAllocTypeToUse = [&](const ContextNode *Node) {
6377 auto AT = allocTypeToUse(Node->AllocTypes);
6378 // If the allocation type is ambiguous, and more aggressive hinting
6379 // has been enabled via the MinClonedColdBytePercent flag, see if this
6380 // allocation should be hinted cold anyway because its fraction cold
6381 // bytes allocated is at least the given threshold.
6382 if (Node->AllocTypes == BothTypes && MinClonedColdBytePercent < 100 &&
6383 !ContextIdToContextSizeInfos.empty()) {
6384 uint64_t TotalCold = 0;
6385 uint64_t Total = 0;
6386 for (auto Id : Node->getContextIds()) {
6387 auto TypeI = ContextIdToAllocationType.find(Id);
6388 assert(TypeI != ContextIdToAllocationType.end());
6389 auto CSI = ContextIdToContextSizeInfos.find(Id);
6390 if (CSI != ContextIdToContextSizeInfos.end()) {
6391 for (auto &Info : CSI->second) {
6392 Total += Info.TotalSize;
6393 if (TypeI->second == AllocationType::Cold)
6394 TotalCold += Info.TotalSize;
6395 }
6396 }
6397 }
6398 if (TotalCold * 100 >= Total * MinClonedColdBytePercent)
6399 AT = AllocationType::Cold;
6400 }
6401 return AT;
6402 };
6403 updateAllocationCall(Node->Call, GetAllocTypeToUse(Node));
6405 OrigAllocAndCloneToNode[{Node->getOrigNode(), Node->Call.cloneNo()}] =
6406 Node;
6407 assert(Node->MatchingCalls.empty());
6408 // Update the allocation calls in function clones without a clone of this
6409 // node the same way as the node they should follow.
6410 for (auto &[Source, Calls] : GetUnassignedCallClones(Node)) {
6411 auto AT = GetAllocTypeToUse(Source);
6412 for (auto &Call : Calls) {
6413 updateAllocationCall(Call, AT);
6414 // For the report, such an allocation clone follows Source's hint.
6416 OrigAllocAndCloneToNode[{Node->getOrigNode(), Call.cloneNo()}] =
6417 Source;
6418 }
6419 }
6420 return;
6421 }
6422
6423 auto CalleeFuncIt = CallsiteToCalleeFuncCloneMap.find(Node);
6424 if (CalleeFuncIt != CallsiteToCalleeFuncCloneMap.end()) {
6425 auto &CalleeFunc = CalleeFuncIt->second;
6426 updateCall(Node->Call, CalleeFunc);
6428 OrigNodeAndCloneToCalleeClone[{
6429 Node->getOrigNode(), Node->Call.cloneNo()}] = CalleeFunc.cloneNo();
6430 // Update all the matching calls as well.
6431 for (auto &Call : Node->MatchingCalls)
6432 updateCall(Call, CalleeFunc);
6433 }
6434
6435 // Now update all calls recorded earlier that are still in function clones
6436 // which don't have a clone of this callsite node, the same way as the
6437 // node they should follow.
6438 for (auto &[Source, Calls] : GetUnassignedCallClones(Node)) {
6439 auto It = CallsiteToCalleeFuncCloneMap.find(Source);
6440 // Fall back to the original Node's callee function.
6441 if (It == CallsiteToCalleeFuncCloneMap.end())
6442 It = CalleeFuncIt;
6443 if (It == CallsiteToCalleeFuncCloneMap.end())
6444 continue;
6445 for (auto &Call : Calls) {
6446 updateCall(Call, It->second);
6448 OrigNodeAndCloneToCalleeClone[{Node->getOrigNode(), Call.cloneNo()}] =
6449 It->second.cloneNo();
6450 }
6451 }
6452 };
6453
6454 // Performs DFS traversal starting from allocation nodes to update calls to
6455 // reflect cloning decisions recorded earlier. For regular LTO this will
6456 // update the actual calls in the IR to call the appropriate function clone
6457 // (and add attributes to allocation calls), whereas for ThinLTO the decisions
6458 // are recorded in the summary entries.
6459 DenseSet<const ContextNode *> Visited;
6460 for (auto &Entry : AllocationCallToContextNodeMap)
6461 UpdateCalls(Entry.second, Visited, UpdateCalls);
6462
6463 return Changed;
6464}
6465
6466// Compute a SHA1 hash of the callsite and alloc version information of clone I
6467// in the summary, to use in detection of duplicate clones.
6469 SHA1 Hasher;
6470 // Add a record for the callsite or alloc at the given index in the summary,
6471 // with the given version. The index must be included, since two clones that
6472 // assign the same versions to different callsites or allocs are not
6473 // duplicates.
6474 auto AddRecord = [&](char Kind, uint32_t Index, uint32_t Version) {
6475 uint8_t Data[1 + 2 * sizeof(uint32_t)];
6476 Data[0] = Kind;
6477 support::endian::write32le(&Data[1], Index);
6478 support::endian::write32le(&Data[1 + sizeof(uint32_t)], Version);
6479 Hasher.update(Data);
6480 };
6481 // Update hash with any callsites that call non-default (non-zero) callee
6482 // versions.
6483 for (auto [Index, SN] : enumerate(FS->callsites())) {
6484 // In theory all callsites and allocs in this function should have the same
6485 // number of clone entries, but handle any discrepancies gracefully below
6486 // for NDEBUG builds.
6487 assert(
6488 SN.Clones.size() > I &&
6489 "Callsite summary has fewer entries than other summaries in function");
6490 if (SN.Clones.size() <= I || !SN.Clones[I])
6491 continue;
6492 AddRecord('c', Index, SN.Clones[I]);
6493 }
6494 // Update hash with any allocs that have non-default (non-None) hints.
6495 for (auto [Index, AN] : enumerate(FS->allocs())) {
6496 // In theory all callsites and allocs in this function should have the same
6497 // number of clone entries, but handle any discrepancies gracefully below
6498 // for NDEBUG builds.
6499 assert(AN.Versions.size() > I &&
6500 "Alloc summary has fewer entries than other summaries in function");
6501 if (AN.Versions.size() <= I ||
6502 (AllocationType)AN.Versions[I] == AllocationType::None)
6503 continue;
6504 AddRecord('a', Index, AN.Versions[I]);
6505 }
6506 return support::endian::read64le(Hasher.result().data());
6507}
6508
6509#ifndef NDEBUG
6510// Check that clones I and J of FS have identical callsite and alloc versions.
6511static bool clonesHaveSameVersions(const FunctionSummary *FS, unsigned I,
6512 unsigned J) {
6513 for (auto &SN : FS->callsites()) {
6514 assert(SN.Clones.size() > I && SN.Clones.size() > J &&
6515 "Callsite summary has fewer entries than other summaries in "
6516 "function");
6517 if (SN.Clones[I] != SN.Clones[J])
6518 return false;
6519 }
6520 for (auto &AN : FS->allocs()) {
6521 assert(AN.Versions.size() > I && AN.Versions.size() > J &&
6522 "Alloc summary has fewer entries than other summaries in function");
6523 if (AN.Versions[I] != AN.Versions[J])
6524 return false;
6525 }
6526 return true;
6527}
6528#endif
6529
6531 Function &F, unsigned NumClones, Module &M, OptimizationRemarkEmitter &ORE,
6533 &FuncToAliasMap,
6534 FunctionSummary *FS) {
6535 auto TakeDeclNameAndReplace = [](GlobalValue *DeclGV, GlobalValue *NewGV) {
6536 // We might have created this when adjusting callsite in another
6537 // function. It should be a declaration.
6538 assert(DeclGV->isDeclaration());
6539 NewGV->takeName(DeclGV);
6540 DeclGV->replaceAllUsesWith(NewGV);
6541 DeclGV->eraseFromParent();
6542 };
6543
6544 // Handle aliases to this function, and create analogous alias clones to the
6545 // provided clone of this function.
6546 auto CloneFuncAliases = [&](Function *NewF, unsigned I) {
6547 if (!FuncToAliasMap.count(&F))
6548 return;
6549 for (auto *A : FuncToAliasMap[&F]) {
6550 std::string AliasName = getMemProfFuncName(A->getName(), I);
6551 auto *PrevA = M.getNamedAlias(AliasName);
6552 auto *NewA = GlobalAlias::create(A->getValueType(),
6553 A->getType()->getPointerAddressSpace(),
6554 A->getLinkage(), AliasName, NewF);
6555 NewA->copyAttributesFrom(A);
6556 if (PrevA)
6557 TakeDeclNameAndReplace(PrevA, NewA);
6558 }
6559 };
6560
6561 // The first "clone" is the original copy, we should only call this if we
6562 // needed to create new clones.
6563 assert(NumClones > 1);
6565 VMaps.reserve(NumClones - 1);
6566 FunctionsClonedThinBackend++;
6567
6568 // Map of hash of callsite/alloc versions to the instantiated function clone
6569 // (possibly the original) implementing those calls and its clone number. Used
6570 // to avoid instantiating duplicate function clones.
6571 // FIXME: Ideally the thin link would not generate such duplicate clones to
6572 // start with, but right now it happens due to phase ordering in the function
6573 // assignment and possible new clones that produces. We simply make each
6574 // duplicate an alias to the matching instantiated clone recorded in the map
6575 // (except for available_externally which are made declarations as they would
6576 // be aliases in the prevailing module, and available_externally aliases are
6577 // not well supported right now).
6579
6580 // Save the hash of the original function version.
6581 HashToFunc[ComputeHash(FS, 0)] = {&F, 0};
6582
6583 for (unsigned I = 1; I < NumClones; I++) {
6584 VMaps.emplace_back(std::make_unique<ValueToValueMapTy>());
6585 std::string Name = getMemProfFuncName(F.getName(), I);
6586 auto Hash = ComputeHash(FS, I);
6587 // If this clone would duplicate a previously seen clone, don't generate the
6588 // duplicate clone body, just make an alias to satisfy any (potentially
6589 // cross-module) references.
6590 if (auto It = HashToFunc.find(Hash); It != HashToFunc.end()) {
6591 FunctionCloneDuplicatesThinBackend++;
6592 auto [Func, OrigI] = It->second;
6593 assert(clonesHaveSameVersions(FS, I, OrigI) &&
6594 "Duplicate clone hash collision");
6595 if (Func->hasAvailableExternallyLinkage()) {
6596 // Skip these as EliminateAvailableExternallyPass does not handle
6597 // available_externally aliases correctly and we end up with an
6598 // available_externally alias to a declaration. Just create a
6599 // declaration for now as we know we will have a definition in another
6600 // module.
6601 auto Decl = M.getOrInsertFunction(Name, Func->getFunctionType());
6602 ORE.emit(OptimizationRemark(DEBUG_TYPE, "MemprofClone", &F)
6603 << "created clone decl " << ore::NV("Decl", Decl.getCallee()));
6604 continue;
6605 }
6606 auto *PrevF = M.getFunction(Name);
6607 auto *Alias = GlobalAlias::create(Name, Func);
6608 if (PrevF)
6609 TakeDeclNameAndReplace(PrevF, Alias);
6610 ORE.emit(OptimizationRemark(DEBUG_TYPE, "MemprofClone", &F)
6611 << "created clone alias " << ore::NV("Alias", Alias));
6612
6613 // Now handle aliases to this function, and clone those as well.
6614 CloneFuncAliases(Func, I);
6615 continue;
6616 }
6617 auto *NewF = CloneFunction(&F, *VMaps.back());
6618 HashToFunc[Hash] = {NewF, I};
6619 FunctionClonesThinBackend++;
6620 // Strip memprof and callsite metadata from clone as they are no longer
6621 // needed.
6622 for (auto &BB : *NewF) {
6623 for (auto &Inst : BB) {
6624 Inst.setMetadata(LLVMContext::MD_memprof, nullptr);
6625 Inst.setMetadata(LLVMContext::MD_callsite, nullptr);
6626 }
6627 }
6628 auto *PrevF = M.getFunction(Name);
6629 if (PrevF)
6630 TakeDeclNameAndReplace(PrevF, NewF);
6631 else
6632 NewF->setName(Name);
6633 updateSubprogramLinkageName(NewF, Name);
6634 ORE.emit(OptimizationRemark(DEBUG_TYPE, "MemprofClone", &F)
6635 << "created clone " << ore::NV("NewFunction", NewF));
6636
6637 // Now handle aliases to this function, and clone those as well.
6638 CloneFuncAliases(NewF, I);
6639 }
6640 return VMaps;
6641}
6642
6643// Locate the summary for F. This is complicated by the fact that it might
6644// have been internalized or promoted.
6646 const ModuleSummaryIndex *ImportSummary,
6647 const Function *CallingFunc = nullptr) {
6648 // FIXME: Ideally we would retain the original GUID in some fashion on the
6649 // function (e.g. as metadata), but for now do our best to locate the
6650 // summary without that information.
6651 ValueInfo TheFnVI = ImportSummary->getValueInfo(F.getGUID());
6652 if (!TheFnVI)
6653 // See if theFn was internalized, by checking index directly with
6654 // original name (this avoids the name adjustment done by getGUID() for
6655 // internal symbols).
6656 TheFnVI = ImportSummary->getValueInfo(
6658 if (TheFnVI)
6659 return TheFnVI;
6660 // Now query with the original name before any promotion was performed.
6661 StringRef OrigName =
6663 // When this pass is enabled, we always add thinlto_src_file provenance
6664 // metadata to imported function definitions, which allows us to recreate the
6665 // original internal symbol's GUID.
6666 auto SrcFileMD = F.getMetadata("thinlto_src_file");
6667 // If this is a call to an imported/promoted local for which we didn't import
6668 // the definition, the metadata will not exist on the declaration. However,
6669 // since we are doing this early, before any inlining in the LTO backend, we
6670 // can simply look at the metadata on the calling function which must have
6671 // been from the same module if F was an internal symbol originally.
6672 if (!SrcFileMD && F.isDeclaration()) {
6673 // We would only call this for a declaration for a direct callsite, in which
6674 // case the caller would have provided the calling function pointer.
6675 assert(CallingFunc);
6676 SrcFileMD = CallingFunc->getMetadata("thinlto_src_file");
6677 // If this is a promoted local (OrigName != F.getName()), since this is a
6678 // declaration, it must be imported from a different module and therefore we
6679 // should always find the metadata on its calling function. Any call to a
6680 // promoted local that came from this module should still be a definition.
6681 assert(SrcFileMD || OrigName == F.getName());
6682 }
6683 StringRef SrcFile = M.getSourceFileName();
6684 if (SrcFileMD)
6685 SrcFile = dyn_cast<MDString>(SrcFileMD->getOperand(0))->getString();
6686 std::string OrigId = GlobalValue::getGlobalIdentifier(
6687 OrigName, GlobalValue::InternalLinkage, SrcFile);
6688 TheFnVI = ImportSummary->getValueInfo(
6690 // Internal func in original module may have gotten a numbered suffix if we
6691 // imported an external function with the same name. This happens
6692 // automatically during IR linking for naming conflicts. It would have to
6693 // still be internal in that case (otherwise it would have been renamed on
6694 // promotion in which case we wouldn't have a naming conflict).
6695 if (!TheFnVI && OrigName == F.getName() && F.hasLocalLinkage() &&
6696 F.getName().contains('.')) {
6697 OrigName = F.getName().rsplit('.').first;
6699 OrigName, GlobalValue::InternalLinkage, SrcFile);
6700 TheFnVI = ImportSummary->getValueInfo(
6702 }
6703 // The only way we may not have a VI is if this is a declaration created for
6704 // an imported reference. For distributed ThinLTO we may not have a VI for
6705 // such declarations in the distributed summary.
6706 assert(TheFnVI || F.isDeclaration());
6707 return TheFnVI;
6708}
6709
6710// Find the CallsiteInfo record synthesized by the thin link for profiled target
6711// CandidateGUID of an indirect tail call, in MapTailCallCalleeVIToCallsite
6712// (which maps each synthesized record's callee to the record). Returns null if
6713// there is none. OrigNameGUIDToTailCallCallsite caches a map from the original
6714// name GUID of each record's callee to the record, and is built on first use.
6716 uint64_t CandidateGUID,
6717 const DenseMap<ValueInfo, CallsiteInfo> &MapTailCallCalleeVIToCallsite,
6719 &OrigNameGUIDToTailCallCallsite,
6720 const ModuleSummaryIndex *ImportSummary, InstrProfSymtab &Symtab) {
6721 auto End = MapTailCallCalleeVIToCallsite.end();
6722 // The callee of the synthesized record is normally the VP metadata GUID, so
6723 // check that first.
6724 if (ValueInfo VI = ImportSummary->getValueInfo(CandidateGUID)) {
6725 auto It = MapTailCallCalleeVIToCallsite.find(VI);
6726 if (It != End)
6727 return &It->second;
6728 }
6729 // For local targets the VP metadata may contain the GUID of the original
6730 // name without the source file prefix, which the thin link translates to the
6731 // actual GUID of the local function (see updateValueInfoForIndirectCalls).
6732 if (auto LocalGUID = ImportSummary->getGUIDFromOriginalID(CandidateGUID)) {
6733 if (ValueInfo LocalVI = ImportSummary->getValueInfo(LocalGUID)) {
6734 auto It = MapTailCallCalleeVIToCallsite.find(LocalVI);
6735 if (It != End)
6736 return &It->second;
6737 }
6738 }
6739 // The index for a distributed ThinLTO backend does not record the original
6740 // names of local functions, in which case the above lookup via
6741 // getGUIDFromOriginalID fails. Instead, compute the original name GUID of
6742 // each record's callee from its function in this module, located via its
6743 // GUID (which is recorded in the function's !guid metadata), using its name
6744 // before any promotion.
6745 if (!OrigNameGUIDToTailCallCallsite) {
6746 // Construct the (initially empty) map so that it is marked as built, even
6747 // if no entries are added below, to avoid rebuilding it on later calls.
6748 OrigNameGUIDToTailCallCallsite.emplace();
6749 for (const auto &[CalleeVI, Callsite] : MapTailCallCalleeVIToCallsite) {
6750 Function *Callee = Symtab.getFunction(CalleeVI.getGUID());
6751 if (!Callee)
6752 continue;
6753 StringRef OrigName =
6755 auto [It, Inserted] = OrigNameGUIDToTailCallCallsite->try_emplace(
6756 GlobalValue::getGUIDAssumingExternalLinkage(OrigName), &Callsite);
6757 // If multiple callees have the same original name, we can't tell which
6758 // corresponds to the profiled target.
6759 if (!Inserted && It->second != &Callsite)
6760 It->second = nullptr;
6761 }
6762 }
6763 return OrigNameGUIDToTailCallCallsite->lookup(CandidateGUID);
6764}
6765
6766bool MemProfContextDisambiguation::initializeIndirectCallPromotionInfo(
6767 Module &M) {
6768 ICallAnalysis = std::make_unique<ICallPromotionAnalysis>();
6769 Symtab = std::make_unique<InstrProfSymtab>();
6770 // Don't add canonical names, to avoid multiple functions to the symtab
6771 // when they both have the same root name with "." suffixes stripped.
6772 // If we pick the wrong one then this could lead to incorrect ICP and calling
6773 // a memprof clone that we don't actually create (resulting in linker unsats).
6774 // What this means is that the GUID of the function *must* match that in the
6775 // VP metadata to allow promotion. In practice this should not be a
6776 // limitation, since local functions have a GUID from before they were
6777 // promoted and global function names shouldn't need any special handling
6778 // (they should not get the ".llvm.*" suffix that the canonicalization
6779 // handling is attempting to strip).
6780 if (Error E = Symtab->create(M, /*InLTO=*/true, /*AddCanonical=*/false)) {
6781 std::string SymtabFailure = toString(std::move(E));
6782 M.getContext().emitError("Failed to create symtab: " + SymtabFailure);
6783 return false;
6784 }
6785 return true;
6786}
6787
6788#ifndef NDEBUG
6789// Sanity check that the MIB stack ids match between the summary and
6790// instruction metadata.
6792 const AllocInfo &AllocNode, const MDNode *MemProfMD,
6793 const CallStack<MDNode, MDNode::op_iterator> &CallsiteContext,
6794 const ModuleSummaryIndex *ImportSummary) {
6795 auto MIBIter = AllocNode.MIBs.begin();
6796 for (auto &MDOp : MemProfMD->operands()) {
6797 assert(MIBIter != AllocNode.MIBs.end());
6798 // The combined index may have been written without the MIB contexts (see
6799 // -combined-index-memprof-context, which defaults to false in NDEBUG
6800 // builds), e.g. if the thin link was performed by a release build while
6801 // this backend has assertions enabled. Since the MIB context in the summary
6802 // can never be empty after trimming the allocation's callsite context, an
6803 // empty list means the context was not serialized, and there is nothing to
6804 // check.
6805 if (MIBIter->StackIdIndices.empty()) {
6806 MIBIter++;
6807 continue;
6808 }
6809 auto StackIdIndexIter = MIBIter->StackIdIndices.begin();
6810 auto *MIBMD = cast<const MDNode>(MDOp);
6811 MDNode *StackMDNode = getMIBStackNode(MIBMD);
6812 assert(StackMDNode);
6813 CallStack<MDNode, MDNode::op_iterator> StackContext(StackMDNode);
6814 auto ContextIterBegin =
6815 StackContext.beginAfterSharedPrefix(CallsiteContext);
6816 // Skip the checking on the first iteration.
6817 uint64_t LastStackContextId =
6818 (ContextIterBegin != StackContext.end() && *ContextIterBegin == 0) ? 1
6819 : 0;
6820 for (auto ContextIter = ContextIterBegin; ContextIter != StackContext.end();
6821 ++ContextIter) {
6822 // If this is a direct recursion, simply skip the duplicate
6823 // entries, to be consistent with how the summary ids were
6824 // generated during ModuleSummaryAnalysis.
6825 if (LastStackContextId == *ContextIter)
6826 continue;
6827 LastStackContextId = *ContextIter;
6828 assert(StackIdIndexIter != MIBIter->StackIdIndices.end());
6829 assert(ImportSummary->getStackIdAtIndex(*StackIdIndexIter) ==
6830 *ContextIter);
6831 StackIdIndexIter++;
6832 }
6833 MIBIter++;
6834 }
6835}
6836#endif
6837
6838bool MemProfContextDisambiguation::applyImport(Module &M) {
6839 assert(ImportSummary);
6840 bool Changed = false;
6841
6842 // We also need to clone any aliases that reference cloned functions, because
6843 // the modified callsites may invoke via the alias. Keep track of the aliases
6844 // for each function.
6845 std::map<const Function *, SmallPtrSet<const GlobalAlias *, 1>>
6846 FuncToAliasMap;
6847 for (auto &A : M.aliases()) {
6848 auto *Aliasee = A.getAliaseeObject();
6849 if (auto *F = dyn_cast<Function>(Aliasee))
6850 FuncToAliasMap[F].insert(&A);
6851 }
6852
6853 if (!initializeIndirectCallPromotionInfo(M))
6854 return false;
6855
6856 for (auto &F : M) {
6857 if (F.isDeclaration() || isMemProfClone(F))
6858 continue;
6859
6860 OptimizationRemarkEmitter ORE(&F);
6861
6863 bool ClonesCreated = false;
6864 unsigned NumClonesCreated = 0;
6865 auto CloneFuncIfNeeded = [&](unsigned NumClones, FunctionSummary *FS) {
6866 // We should at least have version 0 which is the original copy.
6867 assert(NumClones > 0);
6868 // If only one copy needed use original.
6869 if (NumClones == 1)
6870 return;
6871 // If we already performed cloning of this function, confirm that the
6872 // requested number of clones matches (the thin link should ensure the
6873 // number of clones for each constituent callsite is consistent within
6874 // each function), before returning.
6875 if (ClonesCreated) {
6876 assert(NumClonesCreated == NumClones);
6877 return;
6878 }
6879 VMaps = createFunctionClones(F, NumClones, M, ORE, FuncToAliasMap, FS);
6880 // The first "clone" is the original copy, which doesn't have a VMap.
6881 assert(VMaps.size() == NumClones - 1);
6882 Changed = true;
6883 ClonesCreated = true;
6884 NumClonesCreated = NumClones;
6885 };
6886
6887 auto CloneCallsite = [&](const CallsiteInfo &StackNode, CallBase *CB,
6888 Function *CalledFunction, FunctionSummary *FS) {
6889 // Perform cloning if not yet done.
6890 CloneFuncIfNeeded(/*NumClones=*/StackNode.Clones.size(), FS);
6891
6892 assert(!isMemProfClone(*CalledFunction));
6893
6894 // Because we update the cloned calls by calling setCalledOperand (see
6895 // comment below), out of an abundance of caution make sure the called
6896 // function was actually the called operand (or its aliasee). We also
6897 // strip pointer casts when looking for calls (to match behavior during
6898 // summary generation), however, with opaque pointers in theory this
6899 // should not be an issue. Note we still clone the current function
6900 // (containing this call) above, as that could be needed for its callers.
6901 auto *GA = dyn_cast_or_null<GlobalAlias>(CB->getCalledOperand());
6902 if (CalledFunction != CB->getCalledOperand() &&
6903 (!GA || CalledFunction != GA->getAliaseeObject())) {
6904 SkippedCallsCloning++;
6905 return;
6906 }
6907 // Update the calls per the summary info.
6908 // Save orig name since it gets updated in the first iteration
6909 // below.
6910 auto CalleeOrigName = CalledFunction->getName();
6911 for (unsigned J = 0; J < StackNode.Clones.size(); J++) {
6912 // If the VMap is empty, this clone was a duplicate of another and was
6913 // created as an alias or a declaration.
6914 if (J > 0 && VMaps[J - 1]->empty())
6915 continue;
6916 // Do nothing if this version calls the original version of its
6917 // callee.
6918 if (!StackNode.Clones[J])
6919 continue;
6920 auto NewF = M.getOrInsertFunction(
6921 getMemProfFuncName(CalleeOrigName, StackNode.Clones[J]),
6922 CalledFunction->getFunctionType());
6923 CallBase *CBClone;
6924 // Copy 0 is the original function.
6925 if (!J)
6926 CBClone = CB;
6927 else
6928 CBClone = cast<CallBase>((*VMaps[J - 1])[CB]);
6929 // Set the called operand directly instead of calling setCalledFunction,
6930 // as the latter mutates the function type on the call. In rare cases
6931 // we may have a slightly different type on a callee function
6932 // declaration due to it being imported from a different module with
6933 // incomplete types. We really just want to change the name of the
6934 // function to the clone, and not make any type changes.
6935 CBClone->setCalledOperand(NewF.getCallee());
6936 ORE.emit(OptimizationRemark(DEBUG_TYPE, "MemprofCall", CBClone)
6937 << ore::NV("Call", CBClone) << " in clone "
6938 << ore::NV("Caller", CBClone->getFunction())
6939 << " assigned to call function clone "
6940 << ore::NV("Callee", NewF.getCallee()));
6941 }
6942 };
6943
6944 // Locate the summary for F.
6945 ValueInfo TheFnVI = findValueInfoForFunc(F, M, ImportSummary);
6946 // If not found, this could be an imported local (see comment in
6947 // findValueInfoForFunc). Skip for now as it will be cloned in its original
6948 // module (where it would have been promoted to global scope so should
6949 // satisfy any reference in this module).
6950 if (!TheFnVI)
6951 continue;
6952
6953 auto *GVSummary =
6954 ImportSummary->findSummaryInModule(TheFnVI, M.getModuleIdentifier());
6955 if (!GVSummary) {
6956 // Must have been imported, use the summary which matches the definition。
6957 // (might be multiple if this was a linkonce_odr).
6958 auto SrcModuleMD = F.getMetadata("thinlto_src_module");
6959 assert(SrcModuleMD &&
6960 "enable-import-metadata is needed to emit thinlto_src_module");
6961 StringRef SrcModule =
6962 dyn_cast<MDString>(SrcModuleMD->getOperand(0))->getString();
6963 for (auto &GVS : TheFnVI.getSummaryList()) {
6964 if (GVS->modulePath() == SrcModule) {
6965 GVSummary = GVS.get();
6966 break;
6967 }
6968 }
6969 // TODO: Put back the assert once we have metadata on imported copies of
6970 // aliases linking them back to the original alias GUID, which would allow
6971 // us to locate the alias summary here.
6972 // assert(GVSummary && GVSummary->modulePath() == SrcModule);
6973 }
6974
6975 // GVSummary can be null if this is a function imported as a copy of an
6976 // alias, and we don't have the aliasee's summary in our distributed index.
6977 // TODO: Once we can locate the original GUID for imported aliases (e.g. via
6978 // TBD additional metadata), we should find the alias summary instead, and
6979 // we can remove this check and fall back to the original check below.
6980 if (!GVSummary)
6981 continue;
6982
6983 // If this was an imported alias skip it as we won't have the function
6984 // summary, and it should be cloned in the original module.
6985 if (isa<AliasSummary>(GVSummary))
6986 continue;
6987
6988 auto *FS = cast<FunctionSummary>(GVSummary->getBaseObject());
6989
6990 if (FS->allocs().empty() && FS->callsites().empty())
6991 continue;
6992
6993 auto SI = FS->callsites().begin();
6994 auto AI = FS->allocs().begin();
6995
6996 // To handle callsite infos synthesized for tail calls which have missing
6997 // frames in the profiled context, map callee VI to the synthesized callsite
6998 // info.
6999 DenseMap<ValueInfo, CallsiteInfo> MapTailCallCalleeVIToCallsite;
7000 // Iterate the callsites for this function in reverse, since we place all
7001 // those synthesized for tail calls at the end.
7002 for (auto CallsiteIt = FS->callsites().rbegin();
7003 CallsiteIt != FS->callsites().rend(); CallsiteIt++) {
7004 auto &Callsite = *CallsiteIt;
7005 // Stop as soon as we see a non-synthesized callsite info (see comment
7006 // above loop). All the entries added for discovered tail calls have empty
7007 // stack ids.
7008 if (!Callsite.StackIdIndices.empty())
7009 break;
7010 MapTailCallCalleeVIToCallsite.insert({Callsite.Callee, Callsite});
7011 }
7012 // Maps the original name GUID of each synthesized callsite info's callee to
7013 // the callsite info, built on first use by findIndirectTailCallCallsite.
7014 std::optional<DenseMap<uint64_t, const CallsiteInfo *>>
7015 OrigNameGUIDToTailCallCallsite;
7016
7017 // Keeps track of needed ICP for the function.
7018 SmallVector<ICallAnalysisData> ICallAnalysisInfo;
7019
7020 // Assume for now that the instructions are in the exact same order
7021 // as when the summary was created, but confirm this is correct by
7022 // matching the stack ids.
7023 for (auto &BB : F) {
7024 for (auto &I : BB) {
7025 auto *CB = dyn_cast<CallBase>(&I);
7026 // Same handling as when creating module summary.
7027 if (!mayHaveMemprofSummary(CB))
7028 continue;
7029
7030 auto *CalledValue = CB->getCalledOperand();
7031 auto *CalledFunction = CB->getCalledFunction();
7032 if (CalledValue && !CalledFunction) {
7033 CalledValue = CalledValue->stripPointerCasts();
7034 // Stripping pointer casts can reveal a called function.
7035 CalledFunction = dyn_cast<Function>(CalledValue);
7036 }
7037 // Check if this is an alias to a function. If so, get the
7038 // called aliasee for the checks below.
7039 if (auto *GA = dyn_cast<GlobalAlias>(CalledValue)) {
7040 assert(!CalledFunction &&
7041 "Expected null called function in callsite for alias");
7042 CalledFunction = dyn_cast<Function>(GA->getAliaseeObject());
7043 }
7044
7045 CallStack<MDNode, MDNode::op_iterator> CallsiteContext(
7046 I.getMetadata(LLVMContext::MD_callsite));
7047 auto *MemProfMD = I.getMetadata(LLVMContext::MD_memprof);
7048
7049 // Include allocs that were already assigned a memprof function
7050 // attribute in the statistics. Only do this for those that do not have
7051 // memprof metadata, since we add an "ambiguous" memprof attribute by
7052 // default.
7053 if (CB->getAttributes().hasFnAttr("memprof") && !MemProfMD) {
7054 CB->getAttributes().getFnAttr("memprof").getValueAsString() == "cold"
7055 ? AllocTypeColdThinBackend++
7056 : AllocTypeNotColdThinBackend++;
7057 OrigAllocsThinBackend++;
7058 AllocVersionsThinBackend++;
7059 if (!MaxAllocVersionsThinBackend)
7060 MaxAllocVersionsThinBackend = 1;
7061 continue;
7062 }
7063
7064 if (MemProfMD) {
7065 // Consult the next alloc node.
7066 assert(AI != FS->allocs().end());
7067 auto &AllocNode = *(AI++);
7068
7069#ifndef NDEBUG
7070 checkAllocContextIds(AllocNode, MemProfMD, CallsiteContext,
7071 ImportSummary);
7072#endif
7073
7074 // Perform cloning if not yet done.
7075 CloneFuncIfNeeded(/*NumClones=*/AllocNode.Versions.size(), FS);
7076
7077 OrigAllocsThinBackend++;
7078 AllocVersionsThinBackend += AllocNode.Versions.size();
7079 if (MaxAllocVersionsThinBackend < AllocNode.Versions.size())
7080 MaxAllocVersionsThinBackend = AllocNode.Versions.size();
7081
7082 // If there is only one version that means we didn't end up
7083 // considering this function for cloning, and in that case the alloc
7084 // will still be none type or should have gotten the default NotCold.
7085 // Skip that after calling clone helper since that does some sanity
7086 // checks that confirm we haven't decided yet that we need cloning.
7087 // We might have a single version that is cold due to the
7088 // MinClonedColdBytePercent heuristic, make sure we don't skip in that
7089 // case.
7090 if (AllocNode.Versions.size() == 1 &&
7091 (AllocationType)AllocNode.Versions[0] != AllocationType::Cold) {
7092 assert((AllocationType)AllocNode.Versions[0] ==
7093 AllocationType::NotCold ||
7094 (AllocationType)AllocNode.Versions[0] ==
7095 AllocationType::None);
7096 UnclonableAllocsThinBackend++;
7097 continue;
7098 }
7099
7100 // All versions should have a singular allocation type.
7101 assert(llvm::none_of(AllocNode.Versions, [](uint8_t Type) {
7102 return Type == ((uint8_t)AllocationType::NotCold |
7103 (uint8_t)AllocationType::Cold);
7104 }));
7105
7106 // Update the allocation types per the summary info.
7107 for (unsigned J = 0; J < AllocNode.Versions.size(); J++) {
7108 // If the VMap is empty, this clone was a duplicate of another and
7109 // was created as an alias or a declaration.
7110 if (J > 0 && VMaps[J - 1]->empty())
7111 continue;
7112 // Ignore any that didn't get an assigned allocation type.
7113 if (AllocNode.Versions[J] == (uint8_t)AllocationType::None)
7114 continue;
7115 AllocationType AllocTy = (AllocationType)AllocNode.Versions[J];
7116 AllocTy == AllocationType::Cold ? AllocTypeColdThinBackend++
7117 : AllocTypeNotColdThinBackend++;
7118 std::string AllocTypeString = getAllocTypeAttributeString(AllocTy);
7119 auto A = llvm::Attribute::get(F.getContext(), "memprof",
7120 AllocTypeString);
7121 CallBase *CBClone;
7122 // Copy 0 is the original function.
7123 if (!J)
7124 CBClone = CB;
7125 else
7126 // Since VMaps are only created for new clones, we index with
7127 // clone J-1 (J==0 is the original clone and does not have a VMaps
7128 // entry).
7129 CBClone = cast<CallBase>((*VMaps[J - 1])[CB]);
7131 CBClone->addFnAttr(A);
7132 ORE.emit(OptimizationRemark(DEBUG_TYPE, "MemprofAttribute", CBClone)
7133 << ore::NV("AllocationCall", CBClone) << " in clone "
7134 << ore::NV("Caller", CBClone->getFunction())
7135 << " marked with memprof allocation attribute "
7136 << ore::NV("Attribute", AllocTypeString));
7137 }
7138 } else if (!CallsiteContext.empty()) {
7139 if (!CalledFunction) {
7140#ifndef NDEBUG
7141 // We should have skipped inline assembly calls.
7142 auto *CI = dyn_cast<CallInst>(CB);
7143 assert(!CI || !CI->isInlineAsm());
7144#endif
7145 // We should have skipped direct calls via a Constant.
7146 assert(CalledValue && !isa<Constant>(CalledValue));
7147
7148 // This is an indirect call, see if we have profile information and
7149 // whether any clones were recorded for the profiled targets (that
7150 // we synthesized CallsiteInfo summary records for when building the
7151 // index). These records are the next ones in the function's
7152 // callsites, one per profiled target.
7153 auto NumClones = recordICPInfo(
7154 CB,
7155 [&](const InstrProfValueData &Candidate) {
7156 assert(SI != FS->callsites().end());
7157#ifndef NDEBUG
7158 auto CalleeValueInfo =
7159 ImportSummary->getValueInfo(Candidate.Value);
7160 auto LocalGUID =
7161 ImportSummary->getGUIDFromOriginalID(Candidate.Value);
7162#endif
7163 // We might not have a ValueInfo if this is a distributed
7164 // ThinLTO backend and decided not to import that function.
7165 // The thin link may also have updated the callee from the
7166 // original name GUID recorded in the VP metadata to the GUID
7167 // of the local target function (see
7168 // updateValueInfoForIndirectCalls).
7169 assert(!CalleeValueInfo || SI->Callee == CalleeValueInfo ||
7170 (SI->Callee && SI->Callee.getGUID() == LocalGUID));
7171 return &*(SI++);
7172 },
7173 ICallAnalysisInfo);
7174
7175 // Perform cloning if not yet done. This is done here in case
7176 // we don't need to do ICP, but might need to clone this
7177 // function as it is the target of other cloned calls.
7178 if (NumClones)
7179 CloneFuncIfNeeded(NumClones, FS);
7180 }
7181
7182 else {
7183 // Consult the next callsite node.
7184 assert(SI != FS->callsites().end());
7185 auto &StackNode = *(SI++);
7186
7187#ifndef NDEBUG
7188 // Sanity check that the stack ids match between the summary and
7189 // instruction metadata.
7190 auto StackIdIndexIter = StackNode.StackIdIndices.begin();
7191 for (auto StackId : CallsiteContext) {
7192 assert(StackIdIndexIter != StackNode.StackIdIndices.end());
7193 assert(ImportSummary->getStackIdAtIndex(*StackIdIndexIter) ==
7194 StackId);
7195 StackIdIndexIter++;
7196 }
7197#endif
7198
7199 CloneCallsite(StackNode, CB, CalledFunction, FS);
7200 }
7201 } else if (CB->isTailCall() && CalledFunction) {
7202 // Locate the synthesized callsite info for the callee VI, if any was
7203 // created, and use that for cloning.
7204 ValueInfo CalleeVI =
7205 findValueInfoForFunc(*CalledFunction, M, ImportSummary, &F);
7206 if (CalleeVI && MapTailCallCalleeVIToCallsite.count(CalleeVI)) {
7207 auto Callsite = MapTailCallCalleeVIToCallsite.find(CalleeVI);
7208 assert(Callsite != MapTailCallCalleeVIToCallsite.end());
7209 CloneCallsite(Callsite->second, CB, CalledFunction, FS);
7210 }
7211 } else if (CB->isTailCall() && !CalledFunction &&
7212 !MapTailCallCalleeVIToCallsite.empty()) {
7213 // An indirect tail call, which the thin link may have identified as
7214 // being on profiled contexts with a missing frame, via the profiled
7215 // targets in its VP metadata. If so, the callsite infos synthesized
7216 // for those targets are used to perform ICP so that each clone of
7217 // this function calls the assigned clone of the target.
7218 auto PrevNumICallAnalysisInfo = ICallAnalysisInfo.size();
7219 auto NumClones = recordICPInfo(
7220 CB,
7221 [&](const InstrProfValueData &Candidate) {
7223 Candidate.Value, MapTailCallCalleeVIToCallsite,
7224 OrigNameGUIDToTailCallCallsite, ImportSummary, *Symtab);
7225 },
7226 ICallAnalysisInfo);
7227 if (ICallAnalysisInfo.size() > PrevNumICallAnalysisInfo)
7228 IndirectTailCallsRecordedForICPThinBackend++;
7229 if (NumClones)
7230 CloneFuncIfNeeded(NumClones, FS);
7231 }
7232 }
7233 }
7234
7235 // Now do any promotion required for cloning.
7236 performICP(M, VMaps, ICallAnalysisInfo, ORE);
7237 }
7238
7239 // We skip some of the functions and instructions above, so remove all the
7240 // metadata in a single sweep here.
7241 for (auto &F : M) {
7242 // We can skip memprof clones because createFunctionClones already strips
7243 // the metadata from the newly created clones.
7244 if (F.isDeclaration() || isMemProfClone(F))
7245 continue;
7246 for (auto &BB : F) {
7247 for (auto &I : BB) {
7248 if (!isa<CallBase>(I))
7249 continue;
7250 I.setMetadata(LLVMContext::MD_memprof, nullptr);
7251 I.setMetadata(LLVMContext::MD_callsite, nullptr);
7252 }
7253 }
7254 }
7255
7256 return Changed;
7257}
7258
7259unsigned MemProfContextDisambiguation::recordICPInfo(
7260 CallBase *CB,
7261 function_ref<const CallsiteInfo *(const InstrProfValueData &)> GetCallsite,
7262 SmallVector<ICallAnalysisData> &ICallAnalysisInfo) {
7263 // First see if we have profile information for this indirect call.
7264 uint32_t NumCandidates;
7265 uint64_t TotalCount;
7266 auto CandidateProfileData =
7267 ICallAnalysis->getPromotionCandidatesForInstruction(
7268 CB, TotalCount, NumCandidates,
7270 if (CandidateProfileData.empty())
7271 return 0;
7272
7273 // Iterate through all of the candidate profiled targets along with the
7274 // CallsiteInfo summary records synthesized for them, and see if any are
7275 // cloned and/or refer to clones.
7276 bool ICPNeeded = false;
7277 unsigned NumClones = 0;
7279 for (const auto &Candidate : CandidateProfileData) {
7280 const CallsiteInfo *Callsite = GetCallsite(Candidate);
7281 Callsites.push_back(Callsite);
7282 if (!Callsite)
7283 continue;
7284 // See if any of the clones of the indirect callsite for this
7285 // profiled target should call a cloned version of the profiled
7286 // target. We only need to do the ICP here if so.
7287 ICPNeeded |= llvm::any_of(Callsite->Clones,
7288 [](unsigned CloneNo) { return CloneNo != 0; });
7289 // Every callsite in the same function should have been cloned the same
7290 // number of times.
7291 assert(!NumClones || NumClones == Callsite->Clones.size());
7292 NumClones = Callsite->Clones.size();
7293 }
7294 if (!ICPNeeded)
7295 return NumClones;
7296 // Save information for ICP, which is performed later to avoid messing up the
7297 // current function traversal.
7298 ICallAnalysisInfo.push_back({CB, CandidateProfileData.vec(), NumCandidates,
7299 TotalCount, NumClones, std::move(Callsites)});
7300 return NumClones;
7301}
7302
7303void MemProfContextDisambiguation::performICP(
7304 Module &M, ArrayRef<std::unique_ptr<ValueToValueMapTy>> VMaps,
7305 ArrayRef<ICallAnalysisData> ICallAnalysisInfo,
7306 OptimizationRemarkEmitter &ORE) {
7307 // Now do any promotion required for cloning. Specifically, for each
7308 // recorded ICP candidate (which was only recorded because one clone of that
7309 // candidate should call a cloned target), we perform ICP (speculative
7310 // devirtualization) for each clone of the callsite, and update its callee
7311 // to the appropriate clone. Note that the ICP compares against the original
7312 // version of the target, which is what is in the vtable.
7313 for (auto &Info : ICallAnalysisInfo) {
7314 auto *CB = Info.CB;
7315 auto TotalCount = Info.TotalCount;
7316 unsigned NumClones = Info.NumClones;
7317 SmallVector<InstrProfValueData, 8> RemainingCandidates;
7318
7319 assert(Info.CandidateProfileData.size() == Info.Callsites.size());
7320 for (unsigned I = 0; I < Info.CandidateProfileData.size(); I++) {
7321 auto &Candidate = Info.CandidateProfileData[I];
7322 const CallsiteInfo *StackNode = Info.Callsites[I];
7323 // All calls in the same function must have the same number of clones.
7324 assert(!StackNode || NumClones == StackNode->Clones.size());
7325
7326 // See if the target is in the module. If it wasn't imported, it is
7327 // possible that this profile could have been collected on a different
7328 // target (or version of the code), and we need to be conservative
7329 // (similar to what is done in the ICP pass).
7330 Function *TargetFunction = Symtab->getFunction(Candidate.Value);
7331 // If not found, try the GUID of the callee recorded in the summary. For
7332 // local targets the VP metadata may contain the GUID of the original
7333 // name without the source file prefix (e.g. if it was synthesized from
7334 // the MemProf profile's callee GUIDs or from a SamplePGO profile), which
7335 // the thin link translates to the actual GUID of the local function
7336 // (see updateValueInfoForIndirectCalls). The latter is recorded in the
7337 // function's !guid metadata, which is preserved across promotion and
7338 // importing, and is added to the Symtab. If there is no summary record,
7339 // the target was not cloned, so we conservatively only promote it if
7340 // found directly via the VP metadata GUID.
7341 if (!TargetFunction && StackNode && StackNode->Callee &&
7342 StackNode->Callee.getGUID() != Candidate.Value)
7343 TargetFunction = Symtab->getFunction(StackNode->Callee.getGUID());
7344 if (TargetFunction == nullptr ||
7345 // Any ThinLTO global dead symbol removal should have already
7346 // occurred, so it should be safe to promote when the target is a
7347 // declaration.
7348 // TODO: Remove internal option once more fully tested.
7350 TargetFunction->isDeclaration())) {
7351 ORE.emit([&]() {
7352 return OptimizationRemarkMissed(DEBUG_TYPE, "UnableToFindTarget", CB)
7353 << "Memprof cannot promote indirect call: target with md5sum "
7354 << ore::NV("target md5sum", Candidate.Value) << " not found";
7355 });
7356 // FIXME: See if we can use the new declaration importing support to
7357 // at least get the declarations imported for this case. Hot indirect
7358 // targets should have been imported normally, however.
7359 RemainingCandidates.push_back(Candidate);
7360 continue;
7361 }
7362
7363 // Check if legal to promote
7364 const char *Reason = nullptr;
7365 if (!isLegalToPromote(*CB, TargetFunction, &Reason)) {
7366 ORE.emit([&]() {
7367 return OptimizationRemarkMissed(DEBUG_TYPE, "UnableToPromote", CB)
7368 << "Memprof cannot promote indirect call to "
7369 << ore::NV("TargetFunction", TargetFunction)
7370 << " with count of " << ore::NV("TotalCount", TotalCount)
7371 << ": " << Reason;
7372 });
7373 RemainingCandidates.push_back(Candidate);
7374 continue;
7375 }
7376
7377 assert(!isMemProfClone(*TargetFunction));
7378
7379 // Handle each call clone, applying ICP so that each clone directly
7380 // calls the specified callee clone, guarded by the appropriate ICP
7381 // check.
7382 CallBase *CBClone = CB;
7383 for (unsigned J = 0; J < NumClones; J++) {
7384 // If the VMap is empty, this clone was a duplicate of another and was
7385 // created as an alias or a declaration.
7386 if (J > 0 && VMaps[J - 1]->empty())
7387 continue;
7388 // Copy 0 is the original function.
7389 if (J > 0)
7390 CBClone = cast<CallBase>((*VMaps[J - 1])[CB]);
7391 // We do the promotion using the original name, so that the comparison
7392 // is against the name in the vtable. Then just below, change the new
7393 // direct call to call the cloned function.
7394 auto &DirectCall =
7395 pgo::promoteIndirectCall(*CBClone, TargetFunction, Candidate.Count,
7396 TotalCount, isSamplePGO, &ORE);
7397 auto *TargetToUse = TargetFunction;
7398 // Call original if this version calls the original version of its
7399 // callee (always the case if there is no summary record).
7400 if (StackNode && StackNode->Clones[J]) {
7401 TargetToUse =
7402 cast<Function>(M.getOrInsertFunction(
7403 getMemProfFuncName(TargetFunction->getName(),
7404 StackNode->Clones[J]),
7405 TargetFunction->getFunctionType())
7406 .getCallee());
7407 }
7408 DirectCall.setCalledFunction(TargetToUse);
7409 // During matching we generate synthetic VP metadata for indirect calls
7410 // not already having any, from the memprof profile's callee GUIDs. If
7411 // we subsequently promote and inline those callees, we currently lose
7412 // the ability to generate this synthetic VP metadata. Optionally apply
7413 // a noinline attribute to promoted direct calls, where the threshold is
7414 // set to capture synthetic VP metadata targets which get a count of 1.
7416 Candidate.Count < MemProfICPNoInlineThreshold)
7417 DirectCall.setIsNoInline();
7418 ORE.emit(OptimizationRemark(DEBUG_TYPE, "MemprofCall", CBClone)
7419 << ore::NV("Call", CBClone) << " in clone "
7420 << ore::NV("Caller", CBClone->getFunction())
7421 << " promoted and assigned to call function clone "
7422 << ore::NV("Callee", TargetToUse));
7423 }
7424
7425 // Update TotalCount (all clones should get same count above)
7426 TotalCount -= Candidate.Count;
7427 }
7428 // Adjust the MD.prof metadata for all clones, now that we have the new
7429 // TotalCount and the remaining candidates.
7430 CallBase *CBClone = CB;
7431 for (unsigned J = 0; J < NumClones; J++) {
7432 // If the VMap is empty, this clone was a duplicate of another and was
7433 // created as an alias or a declaration.
7434 if (J > 0 && VMaps[J - 1]->empty())
7435 continue;
7436 // Copy 0 is the original function.
7437 if (J > 0)
7438 CBClone = cast<CallBase>((*VMaps[J - 1])[CB]);
7439 // First delete the old one.
7440 CBClone->setMetadata(LLVMContext::MD_prof, nullptr);
7441 // If all promoted, we don't need the MD.prof metadata.
7442 // Otherwise we need update with the un-promoted records back.
7443 if (TotalCount != 0)
7444 annotateValueSite(M, *CBClone, RemainingCandidates, TotalCount,
7445 IPVK_IndirectCallTarget, Info.NumCandidates);
7446 }
7447 }
7448}
7449
7450template <typename DerivedCCG, typename FuncTy, typename CallTy>
7451bool CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::process(
7452 function_ref<void(StringRef, StringRef, const Twine &)> EmitRemark,
7453 bool AllowExtraAnalysis) {
7454 if (DumpCCG) {
7455 dbgs() << "CCG before cloning:\n";
7456 dbgs() << *this;
7457 }
7458 if (ExportToDot)
7459 exportToDot("postbuild");
7460
7461 if (VerifyCCG) {
7462 check();
7463 }
7464
7465 // The detail suffix needs the pre-cloning state of each context; only
7466 // capture it (extra memory and time) when it will be printed.
7468 capturePreCloningContextInfo();
7469
7470 identifyClones();
7471
7472 if (VerifyCCG) {
7473 check();
7474 }
7475
7476 if (DumpCCG) {
7477 dbgs() << "CCG after cloning:\n";
7478 dbgs() << *this;
7479 }
7480 if (ExportToDot)
7481 exportToDot("cloned");
7482
7483 bool Changed = assignFunctions();
7484
7485 if (DumpCCG) {
7486 dbgs() << "CCG after assigning function clones:\n";
7487 dbgs() << *this;
7488 }
7489 if (ExportToDot)
7490 exportToDot("clonefuncassign");
7491
7492 // AllowExtraAnalysis is set when the hinted size messages were enabled via
7493 // remarks (-pass-remarks=memprof-context-disambiguation).
7494 // TODO: Consider also supporting the detail suffix for the remark output.
7495 if (MemProfReportHintedSizes || AllowExtraAnalysis) {
7496 // The referenced-function set can be large; build it only now, when it is
7497 // used by the detail suffix, rather than keeping it across cloning.
7499 populateFunctionsWithCallers();
7500 printTotalSizes(errs(), EmitRemark);
7501 }
7502
7503 return Changed;
7504}
7505
7506bool MemProfContextDisambiguation::processModule(
7507 Module &M,
7508 llvm::function_ref<OptimizationRemarkEmitter &(Function *)> OREGetter) {
7509
7510 // If we have an import summary, then the cloning decisions were made during
7511 // the thin link on the index. Apply them and return.
7512 if (ImportSummary)
7513 return applyImport(M);
7514
7515 // TODO: If/when other types of memprof cloning are enabled beyond just for
7516 // hot and cold, we will need to change this to individually control the
7517 // AllocationType passed to addStackNodesForMIB during CCG construction.
7518 // Note that we specifically check this after applying imports above, so that
7519 // the option isn't needed to be passed to distributed ThinLTO backend
7520 // clang processes, which won't necessarily have visibility into the linker
7521 // dependences. Instead the information is communicated from the LTO link to
7522 // the backends via the combined summary index.
7523 if (!SupportsHotColdNew)
7524 return false;
7525
7526 ModuleCallsiteContextGraph CCG(M, OREGetter);
7527 // TODO: Set up remarks for regular LTO. We need to decide what function to
7528 // use in the callback.
7529 return CCG.process();
7530}
7531
7533 const ModuleSummaryIndex *Summary, bool isSamplePGO)
7534 : ImportSummary(Summary), isSamplePGO(isSamplePGO) {
7535 // Check the dot graph printing options once here, to make sure we have valid
7536 // and expected combinations.
7537 if (DotGraphScope == DotScope::Alloc && !AllocIdForDot.getNumOccurrences())
7539 "-memprof-dot-scope=alloc requires -memprof-dot-alloc-id");
7541 !ContextIdForDot.getNumOccurrences())
7543 "-memprof-dot-scope=context requires -memprof-dot-context-id");
7544 if (DotGraphScope == DotScope::All && AllocIdForDot.getNumOccurrences() &&
7545 ContextIdForDot.getNumOccurrences())
7547 "-memprof-dot-scope=all can't have both -memprof-dot-alloc-id and "
7548 "-memprof-dot-context-id");
7549 if (ImportSummary) {
7550 // The MemProfImportSummary should only be used for testing ThinLTO
7551 // distributed backend handling via opt, in which case we don't have a
7552 // summary from the pass pipeline.
7554 return;
7555 }
7556 if (MemProfImportSummary.empty())
7557 return;
7558
7559 auto ReadSummaryFile =
7561 if (!ReadSummaryFile) {
7562 logAllUnhandledErrors(ReadSummaryFile.takeError(), errs(),
7563 "Error loading file '" + MemProfImportSummary +
7564 "': ");
7565 return;
7566 }
7567 auto ImportSummaryForTestingOrErr = getModuleSummaryIndex(**ReadSummaryFile);
7568 if (!ImportSummaryForTestingOrErr) {
7569 logAllUnhandledErrors(ImportSummaryForTestingOrErr.takeError(), errs(),
7570 "Error parsing file '" + MemProfImportSummary +
7571 "': ");
7572 return;
7573 }
7574 ImportSummaryForTesting = std::move(*ImportSummaryForTestingOrErr);
7575 ImportSummary = ImportSummaryForTesting.get();
7576}
7577
7580 auto &FAM = AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
7581 auto OREGetter = [&](Function *F) -> OptimizationRemarkEmitter & {
7582 return FAM.getResult<OptimizationRemarkEmitterAnalysis>(*F);
7583 };
7584 if (!processModule(M, OREGetter))
7585 return PreservedAnalyses::all();
7586 return PreservedAnalyses::none();
7587}
7588
7589// After the thin link cloning decisions have been recorded in the summary
7590// callsite records, mark the summary indirect call edges to any callee that a
7591// callsite was assigned to call a (non-original) clone of as requiring a
7592// declaration import.
7593// See the comments for the MemProfImportClonedIndirectTargets option.
7595 ModuleSummaryIndex &Index,
7597 isPrevailing) {
7598 // Map from callee to the corresponding call edge in the current function
7599 // summary, so that we don't need to walk the function's call edges for each
7600 // callsite assigned to call a cloned callee. Note that there is a single call
7601 // edge per callee. The map is built lazily, the first time we encounter such
7602 // a callsite in a given function summary, since most functions have none
7603 // (the map is cleared before processing each function summary). The
7604 // pointers into the call edge vector remain valid since it isn't modified
7605 // while the map is in use.
7607 for (auto &I : Index) {
7608 auto VI = Index.getValueInfo(I);
7609 for (auto &S : VI.getSummaryList()) {
7610 // Only the prevailing copies were added to the CCG (see the
7611 // IndexCallsiteContextGraph constructor).
7612 if (!GlobalValue::isLocalLinkage(S->linkage()) &&
7613 !isPrevailing(VI.getGUID(), S.get()))
7614 continue;
7615 auto *FS = dyn_cast<FunctionSummary>(S.get());
7616 if (!FS || FS->callsites().empty())
7617 continue;
7618 CalleeToEdge.clear();
7619 for (auto &CI : FS->callsites()) {
7620 if (!CI.Callee || llvm::all_of(CI.Clones, [](unsigned CloneNo) {
7621 return CloneNo == 0;
7622 }))
7623 continue;
7624 // Note that we mark the edge even if the callee is defined in the
7625 // same module as the caller, since the caller may be imported into
7626 // other modules. The function importer will skip importing the callee
7627 // into any module that already defines it.
7628 NumClonedCalleeCallsites++;
7629 // Lazily build the map on the first such callsite in this function.
7630 if (CalleeToEdge.empty())
7631 for (auto &[CalleeVI, Edge] : FS->mutableCalls())
7632 CalleeToEdge[CalleeVI] = &Edge;
7633 auto It = CalleeToEdge.find(CI.Callee);
7634 if (It == CalleeToEdge.end())
7635 continue;
7636 CalleeInfo *Edge = It->second;
7637 // Direct calls don't require importing the callee. Note that the
7638 // edge is marked indirect if any call to the callee in this function
7639 // is indirect, in which case we can't distinguish whether this
7640 // callsite is direct and conservatively treat it as indirect.
7641 if (!Edge->hasIndirectCall())
7642 continue;
7643 NumClonedCalleeIndirectCallsites++;
7644 if (!Edge->requiresDeclImport()) {
7645 Edge->setRequiresDeclImport(true);
7646 NumClonedCalleeEdgesMarkedRequiresDeclImport++;
7647 }
7648 }
7649 }
7650 }
7651}
7652
7654 ModuleSummaryIndex &Index,
7656 isPrevailing,
7657 LLVMContext &Ctx,
7658 function_ref<void(StringRef, StringRef, const Twine &)> EmitRemark) {
7659 // TODO: If/when other types of memprof cloning are enabled beyond just for
7660 // hot and cold, we will need to change this to individually control the
7661 // AllocationType passed to addStackNodesForMIB during CCG construction.
7662 // The index was set from the option, so these should be in sync.
7663 assert(Index.withSupportsHotColdNew() == SupportsHotColdNew);
7664 if (!SupportsHotColdNew)
7665 return;
7666
7667 bool AllowExtraAnalysis =
7669
7670 bool Changed = false;
7671 {
7672 IndexCallsiteContextGraph CCG(Index, isPrevailing);
7673 Changed = CCG.process(EmitRemark, AllowExtraAnalysis);
7674 }
7675 // Note this must be done after the CCG is destroyed, which is when the
7676 // callsite records synthesized for missing tail call frames are added to the
7677 // function summaries. Importing declarations is only useful if MemProf ICP
7678 // is allowed to promote to a declaration of the target.
7681 updateClonedCalleeEdgesForImport(Index, isPrevailing);
7682}
7683
7684// Strips MemProf attributes and metadata. Can be invoked by the pass pipeline
7685// when we don't have an index that has recorded that we are linking with
7686// allocation libraries containing the necessary APIs for downstream
7687// transformations.
7689 // The profile matcher applies hotness attributes directly for allocations,
7690 // and those will cause us to generate calls to the hot/cold interfaces
7691 // unconditionally. If supports-hot-cold-new was not enabled in the LTO
7692 // link then assume we don't want these calls (e.g. not linking with
7693 // the appropriate library, or otherwise trying to disable this behavior).
7694 bool Changed = false;
7695 for (auto &F : M) {
7696 for (auto &BB : F) {
7697 for (auto &I : BB) {
7698 auto *CI = dyn_cast<CallBase>(&I);
7699 if (!CI)
7700 continue;
7701 if (CI->hasFnAttr("memprof")) {
7702 CI->removeFnAttr("memprof");
7703 Changed = true;
7704 }
7705 if (!CI->hasMetadata(LLVMContext::MD_callsite)) {
7706 assert(!CI->hasMetadata(LLVMContext::MD_memprof));
7707 continue;
7708 }
7709 // Strip off all memprof metadata as it is no longer needed.
7710 // Importantly, this avoids the addition of new memprof attributes
7711 // after inlining propagation.
7712 CI->setMetadata(LLVMContext::MD_memprof, nullptr);
7713 CI->setMetadata(LLVMContext::MD_callsite, nullptr);
7714 Changed = true;
7715 }
7716 }
7717 }
7718 if (!Changed)
7719 return PreservedAnalyses::all();
7720 return PreservedAnalyses::none();
7721}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
aarch64 promote const
uint64_t 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 const CallsiteInfo * findIndirectTailCallCallsite(uint64_t CandidateGUID, const DenseMap< ValueInfo, CallsiteInfo > &MapTailCallCalleeVIToCallsite, std::optional< DenseMap< uint64_t, const CallsiteInfo * > > &OrigNameGUIDToTailCallCallsite, const ModuleSummaryIndex *ImportSummary, InstrProfSymtab &Symtab)
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 bool clonesHaveSameVersions(const FunctionSummary *FS, unsigned I, unsigned J)
static void updateClonedCalleeEdgesForImport(ModuleSummaryIndex &Index, llvm::function_ref< bool(GlobalValue::GUID, const GlobalValueSummary *)> isPrevailing)
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)
static cl::opt< bool > IndirectTailCallSearch("memprof-indirect-tail-call-search", cl::init(true), cl::Hidden, cl::desc("Search for missing frames through indirect tail calls to their " "profiled targets (ThinLTO)."))
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
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
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
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.
bool contains(const_arg_type_t< KeyT > Val) const
Return true if the specified key is in the map, false otherwise.
Definition DenseMap.h:757
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:762
bool empty() const
Definition DenseMap.h:716
iterator find(const_arg_type_t< KeyT > Val)
Definition DenseMap.h:766
ValueT & at(const_arg_type_t< KeyT > Val)
Return the entry for the specified key, or abort if no such entry exists.
Definition DenseMap.h:811
void reserve(size_type NumEntries)
Grow the DenseMap so that it can contain at least NumEntries items before resizing again.
Definition DenseMap.h:721
iterator end()
Definition DenseMap.h:686
unsigned size() const
Definition DenseMap.h:717
bool erase(const KeyT &Val)
Definition DenseMap.h:930
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:793
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Definition DenseMap.h:827
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:212
DISubprogram * getSubprogram() const
Get the attached subprogram.
const Function & getFunction() const
Definition Function.h:167
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition Function.cpp:352
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
A symbol table used for function [IR]PGO name look-up with keys (such as pointers,...
Definition InstrProf.h:500
Function * getFunction(uint64_t FuncMD5Hash) const
Return function from the name's md5 hash. Return nullptr if not found.
Definition InstrProf.h:786
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:76
Metadata node.
Definition Metadata.h:1081
const MDOperand & getOperand(unsigned I) const
Definition Metadata.h:1437
ArrayRef< MDOperand > operands() const
Definition Metadata.h:1435
unsigned getNumOperands() const
Return number of MDNode operands.
Definition Metadata.h:1443
LLVM_ABI TempMDNode clone() const
Create a (temporary) clone of this.
Definition Metadata.cpp:670
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:1312
static LLVM_ABI MDString * get(LLVMContext &Context, StringRef Str)
Definition Metadata.cpp:597
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
GlobalValue::GUID getGUIDFromOriginalID(GlobalValue::GUID OriginalID) const
Return the GUID for OriginalId in the OidGuidMap.
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:68
LLVMContext & getContext() const
Get the global data context.
Definition Module.h:332
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
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
bool contains(ConstPtrType Ptr) const
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 print(raw_ostream &O, bool IsForDebug=false) const
Implement operator<< on Value.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Definition Value.cpp:549
LLVMContext & getContext() const
All values hold a context through their type.
Definition Value.h:260
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
Definition Value.cpp:315
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
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
#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:707
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:316
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:2132
cl::opt< bool > MemProfReportHintedSizes("memprof-report-hinted-sizes", cl::init(false), cl::Hidden, cl::desc("Report total allocation sizes of hinted allocations"))
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1755
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:2570
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:2224
static cl::opt< bool > MemProfImportClonedIndirectTargets("memprof-import-cloned-indirect-targets", cl::init(true), cl::Hidden, cl::desc("Import at least a declaration of the indirect call targets of " "callsites assigned to call a cloned callee (needed for MemProf " "ICP in the ThinLTO backend)"))
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:1167
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:1762
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...
static cl::opt< bool > MemProfReportHintedSizesDetail("memprof-report-hinted-sizes-detail", cl::init(false), cl::Hidden, cl::desc("Append post-cloning call path and matching details to each " "-memprof-report-hinted-sizes line"))
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:1769
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.
static cl::opt< unsigned > MemProfReportHintedSizesDetailMaxPathLen("memprof-report-hinted-sizes-detail-max-path-len", cl::init(7), cl::Hidden, cl::desc("Maximum number of functions printed in full for a post-cloning " "call path in the -memprof-report-hinted-sizes-detail suffix; " "longer paths are elided in the middle"))
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.
LLVM_ABI unsigned getMaxSummaryIndirectEdges(const LLVMContext &C)
Return -module-summary-max-indirect-edges.
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
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1933
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:1788
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition STLExtras.h:1963
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Next
Definition InstrProf.h:147
@ End
Run the machine verifier once, at the end of the pipeline.
Definition CodeGen.h:320
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
Class to accumulate and hold information about a callee.
Summary of memprof callsite metadata.
SmallVector< unsigned > StackIdIndices
SmallVector< unsigned > Clones
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:94
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