@@ -310,8 +310,12 @@ class CallsiteContextGraph {
310
310
// True if this node was effectively removed from the graph, in which case
311
311
// its context id set, caller edges, and callee edges should all be empty.
312
312
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!" );
315
319
return ContextIds.empty ();
316
320
}
317
321
@@ -353,9 +357,12 @@ class CallsiteContextGraph {
353
357
}
354
358
};
355
359
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
357
361
// / carrying any context ids) after transformations.
358
362
void removeNoneTypeCalleeEdges (ContextNode *Node);
363
+ void
364
+ recursivelyRemoveNoneTypeCalleeEdges (ContextNode *Node,
365
+ DenseSet<const ContextNode *> &Visited);
359
366
360
367
protected:
361
368
// / Get a list of nodes corresponding to the stack ids in the given callsite
@@ -2431,11 +2438,43 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::
2431
2438
}
2432
2439
}
2433
2440
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
+
2434
2468
template <typename DerivedCCG, typename FuncTy, typename CallTy>
2435
2469
void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::identifyClones() {
2436
2470
DenseSet<const ContextNode *> Visited;
2437
2471
for (auto &Entry : AllocationCallToContextNodeMap)
2438
2472
identifyClones (Entry.second , Visited);
2473
+ Visited.clear ();
2474
+ for (auto &Entry : AllocationCallToContextNodeMap)
2475
+ recursivelyRemoveNoneTypeCalleeEdges (Entry.second , Visited);
2476
+ if (VerifyCCG)
2477
+ check ();
2439
2478
}
2440
2479
2441
2480
// helper function to check an AllocType is cold or notcold or both.
@@ -2450,7 +2489,7 @@ template <typename DerivedCCG, typename FuncTy, typename CallTy>
2450
2489
void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::identifyClones(
2451
2490
ContextNode *Node, DenseSet<const ContextNode *> &Visited) {
2452
2491
if (VerifyNodes)
2453
- checkNode<DerivedCCG, FuncTy, CallTy>(Node);
2492
+ checkNode<DerivedCCG, FuncTy, CallTy>(Node, /* CheckEdges= */ false );
2454
2493
assert (!Node->CloneOf );
2455
2494
2456
2495
// 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(
2511
2550
std::stable_sort (Node->CallerEdges .begin (), Node->CallerEdges .end (),
2512
2551
[&](const std::shared_ptr<ContextEdge> &A,
2513
2552
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 ;
2516
2563
2517
2564
if (A->AllocTypes == B->AllocTypes )
2518
2565
// Use the first context id for each edge as a
@@ -2591,39 +2638,16 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::identifyClones(
2591
2638
Node->AllocTypes != (uint8_t )AllocationType::None);
2592
2639
// Sanity check that no alloc types on clone or its edges are None.
2593
2640
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
- }));
2598
2641
}
2599
2642
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
- }
2607
2643
// We should still have some context ids on the original Node.
2608
2644
assert (!Node->ContextIds .empty ());
2609
2645
2610
- // Remove any callee edges that ended up with alloc type None after creating
2611
- // clones and updating callee edges.
2612
- removeNoneTypeCalleeEdges (Node);
2613
-
2614
2646
// Sanity check that no alloc types on node or edges are None.
2615
2647
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
- }));
2624
2648
2625
2649
if (VerifyNodes)
2626
- checkNode<DerivedCCG, FuncTy, CallTy>(Node);
2650
+ checkNode<DerivedCCG, FuncTy, CallTy>(Node, /* CheckEdges= */ false );
2627
2651
}
2628
2652
2629
2653
void ModuleCallsiteContextGraph::updateAllocationCall (
0 commit comments