@@ -310,8 +310,12 @@ class CallsiteContextGraph {
310310 // True if this node was effectively removed from the graph, in which case
311311 // its context id set, caller edges, and callee edges should all be empty.
312312 bool isRemoved () const {
313- assert (ContextIds.empty () ==
314- (CalleeEdges.empty () && CallerEdges.empty ()));
313+ // Note that we can have non-empty context ids with empty caller and
314+ // callee edges if the graph ends up with a single node.
315+ if (ContextIds.empty ())
316+ assert (CalleeEdges.empty () && CallerEdges.empty () &&
317+ " Context ids empty but at least one of callee and caller edges "
318+ " were not!" );
315319 return ContextIds.empty ();
316320 }
317321
@@ -353,9 +357,12 @@ class CallsiteContextGraph {
353357 }
354358 };
355359
356- // / Helper to remove callee edges that have allocation type None (due to not
360+ // / Helpers to remove callee edges that have allocation type None (due to not
357361 // / carrying any context ids) after transformations.
358362 void removeNoneTypeCalleeEdges (ContextNode *Node);
363+ void
364+ recursivelyRemoveNoneTypeCalleeEdges (ContextNode *Node,
365+ DenseSet<const ContextNode *> &Visited);
359366
360367protected:
361368 // / Get a list of nodes corresponding to the stack ids in the given callsite
@@ -2431,11 +2438,43 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::
24312438 }
24322439}
24332440
2441+ template <typename DerivedCCG, typename FuncTy, typename CallTy>
2442+ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::
2443+ recursivelyRemoveNoneTypeCalleeEdges (
2444+ ContextNode *Node, DenseSet<const ContextNode *> &Visited) {
2445+ auto Inserted = Visited.insert (Node);
2446+ if (!Inserted.second )
2447+ return ;
2448+
2449+ removeNoneTypeCalleeEdges (Node);
2450+
2451+ for (auto *Clone : Node->Clones )
2452+ recursivelyRemoveNoneTypeCalleeEdges (Clone, Visited);
2453+
2454+ // The recursive call may remove some of this Node's caller edges.
2455+ // Iterate over a copy and skip any that were removed.
2456+ auto CallerEdges = Node->CallerEdges ;
2457+ for (auto &Edge : CallerEdges) {
2458+ // Skip any that have been removed by an earlier recursive call.
2459+ if (Edge->Callee == nullptr && Edge->Caller == nullptr ) {
2460+ assert (!std::count (Node->CallerEdges .begin (), Node->CallerEdges .end (),
2461+ Edge));
2462+ continue ;
2463+ }
2464+ recursivelyRemoveNoneTypeCalleeEdges (Edge->Caller , Visited);
2465+ }
2466+ }
2467+
24342468template <typename DerivedCCG, typename FuncTy, typename CallTy>
24352469void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::identifyClones() {
24362470 DenseSet<const ContextNode *> Visited;
24372471 for (auto &Entry : AllocationCallToContextNodeMap)
24382472 identifyClones (Entry.second , Visited);
2473+ Visited.clear ();
2474+ for (auto &Entry : AllocationCallToContextNodeMap)
2475+ recursivelyRemoveNoneTypeCalleeEdges (Entry.second , Visited);
2476+ if (VerifyCCG)
2477+ check ();
24392478}
24402479
24412480// helper function to check an AllocType is cold or notcold or both.
@@ -2450,7 +2489,7 @@ template <typename DerivedCCG, typename FuncTy, typename CallTy>
24502489void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::identifyClones(
24512490 ContextNode *Node, DenseSet<const ContextNode *> &Visited) {
24522491 if (VerifyNodes)
2453- checkNode<DerivedCCG, FuncTy, CallTy>(Node);
2492+ checkNode<DerivedCCG, FuncTy, CallTy>(Node, /* CheckEdges= */ false );
24542493 assert (!Node->CloneOf );
24552494
24562495 // If Node as a null call, then either it wasn't found in the module (regular
@@ -2511,8 +2550,16 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::identifyClones(
25112550 std::stable_sort (Node->CallerEdges .begin (), Node->CallerEdges .end (),
25122551 [&](const std::shared_ptr<ContextEdge> &A,
25132552 const std::shared_ptr<ContextEdge> &B) {
2514- assert (checkColdOrNotCold (A->AllocTypes ) &&
2515- checkColdOrNotCold (B->AllocTypes ));
2553+ // Nodes with non-empty context ids should be sorted before
2554+ // those with empty context ids.
2555+ if (A->ContextIds .empty ())
2556+ // Either B ContextIds are non-empty (in which case we
2557+ // should return false because B < A), or B ContextIds
2558+ // are empty, in which case they are equal, and we should
2559+ // maintain the original relative ordering.
2560+ return false ;
2561+ if (B->ContextIds .empty ())
2562+ return true ;
25162563
25172564 if (A->AllocTypes == B->AllocTypes )
25182565 // Use the first context id for each edge as a
@@ -2591,39 +2638,16 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::identifyClones(
25912638 Node->AllocTypes != (uint8_t )AllocationType::None);
25922639 // Sanity check that no alloc types on clone or its edges are None.
25932640 assert (Clone->AllocTypes != (uint8_t )AllocationType::None);
2594- assert (llvm::none_of (
2595- Clone->CallerEdges , [&](const std::shared_ptr<ContextEdge> &E) {
2596- return E->AllocTypes == (uint8_t )AllocationType::None;
2597- }));
25982641 }
25992642
2600- // Cloning may have resulted in some cloned callee edges with type None,
2601- // because they aren't carrying any contexts. Remove those edges.
2602- for (auto *Clone : Node->Clones ) {
2603- removeNoneTypeCalleeEdges (Clone);
2604- if (VerifyNodes)
2605- checkNode<DerivedCCG, FuncTy, CallTy>(Clone);
2606- }
26072643 // We should still have some context ids on the original Node.
26082644 assert (!Node->ContextIds .empty ());
26092645
2610- // Remove any callee edges that ended up with alloc type None after creating
2611- // clones and updating callee edges.
2612- removeNoneTypeCalleeEdges (Node);
2613-
26142646 // Sanity check that no alloc types on node or edges are None.
26152647 assert (Node->AllocTypes != (uint8_t )AllocationType::None);
2616- assert (llvm::none_of (Node->CalleeEdges ,
2617- [&](const std::shared_ptr<ContextEdge> &E) {
2618- return E->AllocTypes == (uint8_t )AllocationType::None;
2619- }));
2620- assert (llvm::none_of (Node->CallerEdges ,
2621- [&](const std::shared_ptr<ContextEdge> &E) {
2622- return E->AllocTypes == (uint8_t )AllocationType::None;
2623- }));
26242648
26252649 if (VerifyNodes)
2626- checkNode<DerivedCCG, FuncTy, CallTy>(Node);
2650+ checkNode<DerivedCCG, FuncTy, CallTy>(Node, /* CheckEdges= */ false );
26272651}
26282652
26292653void ModuleCallsiteContextGraph::updateAllocationCall (
0 commit comments