@@ -526,25 +526,30 @@ class CallsiteContextGraph {
526
526
// / Create a clone of Edge's callee and move Edge to that new callee node,
527
527
// / performing the necessary context id and allocation type updates.
528
528
// / If callee's caller edge iterator is supplied, it is updated when removing
529
- // / the edge from that list.
529
+ // / the edge from that list. If ContextIdsToMove is non-empty, only that
530
+ // / subset of Edge's ids are moved to an edge to the new callee.
530
531
ContextNode *
531
532
moveEdgeToNewCalleeClone (const std::shared_ptr<ContextEdge> &Edge,
532
- EdgeIter *CallerEdgeI = nullptr );
533
+ EdgeIter *CallerEdgeI = nullptr ,
534
+ DenseSet<uint32_t > ContextIdsToMove = {});
533
535
534
536
// / Change the callee of Edge to existing callee clone NewCallee, performing
535
537
// / the necessary context id and allocation type updates.
536
538
// / If callee's caller edge iterator is supplied, it is updated when removing
537
- // / the edge from that list.
539
+ // / the edge from that list. If ContextIdsToMove is non-empty, only that
540
+ // / subset of Edge's ids are moved to an edge to the new callee.
538
541
void moveEdgeToExistingCalleeClone (const std::shared_ptr<ContextEdge> &Edge,
539
542
ContextNode *NewCallee,
540
543
EdgeIter *CallerEdgeI = nullptr ,
541
- bool NewClone = false );
544
+ bool NewClone = false ,
545
+ DenseSet<uint32_t > ContextIdsToMove = {});
542
546
543
547
// / Recursively perform cloning on the graph for the given Node and its
544
548
// / callers, in order to uniquely identify the allocation behavior of an
545
- // / allocation given its context.
546
- void identifyClones (ContextNode *Node,
547
- DenseSet<const ContextNode *> &Visited);
549
+ // / allocation given its context. The context ids of the allocation being
550
+ // / processed are given in AllocContextIds.
551
+ void identifyClones (ContextNode *Node, DenseSet<const ContextNode *> &Visited,
552
+ const DenseSet<uint32_t > &AllocContextIds);
548
553
549
554
// / Map from each context ID to the AllocationType assigned to that context.
550
555
std::map<uint32_t , AllocationType> ContextIdToAllocationType;
@@ -2358,39 +2363,99 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::exportToDot(
2358
2363
template <typename DerivedCCG, typename FuncTy, typename CallTy>
2359
2364
typename CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::ContextNode *
2360
2365
CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::moveEdgeToNewCalleeClone(
2361
- const std::shared_ptr<ContextEdge> &Edge, EdgeIter *CallerEdgeI) {
2366
+ const std::shared_ptr<ContextEdge> &Edge, EdgeIter *CallerEdgeI,
2367
+ DenseSet<uint32_t > ContextIdsToMove) {
2362
2368
ContextNode *Node = Edge->Callee ;
2363
2369
NodeOwner.push_back (
2364
2370
std::make_unique<ContextNode>(Node->IsAllocation , Node->Call ));
2365
2371
ContextNode *Clone = NodeOwner.back ().get ();
2366
2372
Node->addClone (Clone);
2367
2373
assert (NodeToCallingFunc.count (Node));
2368
2374
NodeToCallingFunc[Clone] = NodeToCallingFunc[Node];
2369
- moveEdgeToExistingCalleeClone (Edge, Clone, CallerEdgeI, /* NewClone=*/ true );
2375
+ moveEdgeToExistingCalleeClone (Edge, Clone, CallerEdgeI, /* NewClone=*/ true ,
2376
+ ContextIdsToMove);
2370
2377
return Clone;
2371
2378
}
2372
2379
2373
2380
template <typename DerivedCCG, typename FuncTy, typename CallTy>
2374
2381
void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::
2375
2382
moveEdgeToExistingCalleeClone (const std::shared_ptr<ContextEdge> &Edge,
2376
2383
ContextNode *NewCallee, EdgeIter *CallerEdgeI,
2377
- bool NewClone) {
2384
+ bool NewClone,
2385
+ DenseSet<uint32_t > ContextIdsToMove) {
2378
2386
// NewCallee and Edge's current callee must be clones of the same original
2379
2387
// node (Edge's current callee may be the original node too).
2380
2388
assert (NewCallee->getOrigNode () == Edge->Callee ->getOrigNode ());
2381
- auto &EdgeContextIds = Edge-> getContextIds ();
2389
+
2382
2390
ContextNode *OldCallee = Edge->Callee ;
2383
- if (CallerEdgeI)
2384
- *CallerEdgeI = OldCallee->CallerEdges .erase (*CallerEdgeI);
2385
- else
2386
- OldCallee->eraseCallerEdge (Edge.get ());
2387
- Edge->Callee = NewCallee;
2388
- NewCallee->CallerEdges .push_back (Edge);
2389
- // Don't need to update Edge's context ids since we are simply reconnecting
2390
- // it.
2391
- set_subtract (OldCallee->ContextIds , EdgeContextIds);
2392
- NewCallee->ContextIds .insert (EdgeContextIds.begin (), EdgeContextIds.end ());
2393
- NewCallee->AllocTypes |= Edge->AllocTypes ;
2391
+
2392
+ // We might already have an edge to the new callee from earlier cloning for a
2393
+ // different allocation. If one exists we will reuse it.
2394
+ auto ExistingEdgeToNewCallee = NewCallee->findEdgeFromCaller (Edge->Caller );
2395
+
2396
+ // Callers will pass an empty ContextIdsToMove set when they want to move the
2397
+ // edge. Copy in Edge's ids for simplicity.
2398
+ if (ContextIdsToMove.empty ())
2399
+ ContextIdsToMove = Edge->getContextIds ();
2400
+
2401
+ // If we are moving all of Edge's ids, then just move the whole Edge.
2402
+ // Otherwise only move the specified subset, to a new edge if needed.
2403
+ if (Edge->getContextIds ().size () == ContextIdsToMove.size ()) {
2404
+ // Moving the whole Edge.
2405
+ if (CallerEdgeI)
2406
+ *CallerEdgeI = OldCallee->CallerEdges .erase (*CallerEdgeI);
2407
+ else
2408
+ OldCallee->eraseCallerEdge (Edge.get ());
2409
+ if (ExistingEdgeToNewCallee) {
2410
+ // Since we already have an edge to NewCallee, simply move the ids
2411
+ // onto it, and remove the existing Edge.
2412
+ ExistingEdgeToNewCallee->getContextIds ().insert (ContextIdsToMove.begin (),
2413
+ ContextIdsToMove.end ());
2414
+ ExistingEdgeToNewCallee->AllocTypes |= Edge->AllocTypes ;
2415
+ assert (Edge->ContextIds == ContextIdsToMove);
2416
+ Edge->ContextIds .clear ();
2417
+ Edge->AllocTypes = (uint8_t )AllocationType::None;
2418
+ Edge->Caller ->eraseCalleeEdge (Edge.get ());
2419
+ } else {
2420
+ // Otherwise just reconnect Edge to NewCallee.
2421
+ Edge->Callee = NewCallee;
2422
+ NewCallee->CallerEdges .push_back (Edge);
2423
+ // Don't need to update Edge's context ids since we are simply
2424
+ // reconnecting it.
2425
+ }
2426
+ // In either case, need to update the alloc types on New Callee.
2427
+ NewCallee->AllocTypes |= Edge->AllocTypes ;
2428
+ } else {
2429
+ // Only moving a subset of Edge's ids.
2430
+ if (CallerEdgeI)
2431
+ ++CallerEdgeI;
2432
+ // Compute the alloc type of the subset of ids being moved.
2433
+ auto CallerEdgeAllocType = computeAllocType (ContextIdsToMove);
2434
+ if (ExistingEdgeToNewCallee) {
2435
+ // Since we already have an edge to NewCallee, simply move the ids
2436
+ // onto it.
2437
+ ExistingEdgeToNewCallee->getContextIds ().insert (ContextIdsToMove.begin (),
2438
+ ContextIdsToMove.end ());
2439
+ ExistingEdgeToNewCallee->AllocTypes |= CallerEdgeAllocType;
2440
+ } else {
2441
+ // Otherwise, create a new edge to NewCallee for the ids being moved.
2442
+ auto NewEdge = std::make_shared<ContextEdge>(
2443
+ NewCallee, Edge->Caller , CallerEdgeAllocType, ContextIdsToMove);
2444
+ Edge->Caller ->CalleeEdges .push_back (NewEdge);
2445
+ NewCallee->CallerEdges .push_back (NewEdge);
2446
+ }
2447
+ // In either case, need to update the alloc types on NewCallee, and remove
2448
+ // those ids and update the alloc type on the original Edge.
2449
+ NewCallee->AllocTypes |= CallerEdgeAllocType;
2450
+ set_subtract (Edge->ContextIds , ContextIdsToMove);
2451
+ Edge->AllocTypes = computeAllocType (Edge->ContextIds );
2452
+ }
2453
+ // Now perform some updates that are common to all cases: the NewCallee gets
2454
+ // the moved ids added, and we need to remove those ids from OldCallee and
2455
+ // update its alloc type (NewCallee alloc type updates handled above).
2456
+ NewCallee->ContextIds .insert (ContextIdsToMove.begin (),
2457
+ ContextIdsToMove.end ());
2458
+ set_subtract (OldCallee->ContextIds , ContextIdsToMove);
2394
2459
OldCallee->AllocTypes = computeAllocType (OldCallee->ContextIds );
2395
2460
// OldCallee alloc type should be None iff its context id set is now empty.
2396
2461
assert ((OldCallee->AllocTypes == (uint8_t )AllocationType::None) ==
@@ -2402,7 +2467,7 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::
2402
2467
// The context ids moving to the new callee are the subset of this edge's
2403
2468
// context ids and the context ids on the caller edge being moved.
2404
2469
DenseSet<uint32_t > EdgeContextIdsToMove =
2405
- set_intersection (OldCalleeEdge->getContextIds (), EdgeContextIds );
2470
+ set_intersection (OldCalleeEdge->getContextIds (), ContextIdsToMove );
2406
2471
set_subtract (OldCalleeEdge->getContextIds (), EdgeContextIdsToMove);
2407
2472
OldCalleeEdge->AllocTypes =
2408
2473
computeAllocType (OldCalleeEdge->getContextIds ());
@@ -2468,8 +2533,10 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::
2468
2533
template <typename DerivedCCG, typename FuncTy, typename CallTy>
2469
2534
void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::identifyClones() {
2470
2535
DenseSet<const ContextNode *> Visited;
2471
- for (auto &Entry : AllocationCallToContextNodeMap)
2472
- identifyClones (Entry.second , Visited);
2536
+ for (auto &Entry : AllocationCallToContextNodeMap) {
2537
+ Visited.clear ();
2538
+ identifyClones (Entry.second , Visited, Entry.second ->ContextIds );
2539
+ }
2473
2540
Visited.clear ();
2474
2541
for (auto &Entry : AllocationCallToContextNodeMap)
2475
2542
recursivelyRemoveNoneTypeCalleeEdges (Entry.second , Visited);
@@ -2487,7 +2554,8 @@ bool checkColdOrNotCold(uint8_t AllocType) {
2487
2554
2488
2555
template <typename DerivedCCG, typename FuncTy, typename CallTy>
2489
2556
void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::identifyClones(
2490
- ContextNode *Node, DenseSet<const ContextNode *> &Visited) {
2557
+ ContextNode *Node, DenseSet<const ContextNode *> &Visited,
2558
+ const DenseSet<uint32_t > &AllocContextIds) {
2491
2559
if (VerifyNodes)
2492
2560
checkNode<DerivedCCG, FuncTy, CallTy>(Node, /* CheckEdges=*/ false );
2493
2561
assert (!Node->CloneOf );
@@ -2521,7 +2589,7 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::identifyClones(
2521
2589
}
2522
2590
// Ignore any caller we previously visited via another edge.
2523
2591
if (!Visited.count (Edge->Caller ) && !Edge->Caller ->CloneOf ) {
2524
- identifyClones (Edge->Caller , Visited);
2592
+ identifyClones (Edge->Caller , Visited, AllocContextIds );
2525
2593
}
2526
2594
}
2527
2595
}
@@ -2584,13 +2652,23 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::identifyClones(
2584
2652
if (hasSingleAllocType (Node->AllocTypes ) || Node->CallerEdges .size () <= 1 )
2585
2653
break ;
2586
2654
2655
+ // Only need to process the ids along this edge pertaining to the given
2656
+ // allocation.
2657
+ auto CallerEdgeContextsForAlloc =
2658
+ set_intersection (CallerEdge->getContextIds (), AllocContextIds);
2659
+ if (CallerEdgeContextsForAlloc.empty ()) {
2660
+ ++EI;
2661
+ continue ;
2662
+ }
2663
+ auto CallerAllocTypeForAlloc = computeAllocType (CallerEdgeContextsForAlloc);
2664
+
2587
2665
// Compute the node callee edge alloc types corresponding to the context ids
2588
2666
// for this caller edge.
2589
2667
std::vector<uint8_t > CalleeEdgeAllocTypesForCallerEdge;
2590
2668
CalleeEdgeAllocTypesForCallerEdge.reserve (Node->CalleeEdges .size ());
2591
2669
for (auto &CalleeEdge : Node->CalleeEdges )
2592
2670
CalleeEdgeAllocTypesForCallerEdge.push_back (intersectAllocTypes (
2593
- CalleeEdge->getContextIds (), CallerEdge-> getContextIds () ));
2671
+ CalleeEdge->getContextIds (), CallerEdgeContextsForAlloc ));
2594
2672
2595
2673
// Don't clone if doing so will not disambiguate any alloc types amongst
2596
2674
// caller edges (including the callee edges that would be cloned).
@@ -2605,7 +2683,7 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::identifyClones(
2605
2683
// disambiguated by splitting out different context ids.
2606
2684
assert (CallerEdge->AllocTypes != (uint8_t )AllocationType::None);
2607
2685
assert (Node->AllocTypes != (uint8_t )AllocationType::None);
2608
- if (allocTypeToUse (CallerEdge-> AllocTypes ) ==
2686
+ if (allocTypeToUse (CallerAllocTypeForAlloc ) ==
2609
2687
allocTypeToUse (Node->AllocTypes ) &&
2610
2688
allocTypesMatch<DerivedCCG, FuncTy, CallTy>(
2611
2689
CalleeEdgeAllocTypesForCallerEdge, Node->CalleeEdges )) {
@@ -2618,7 +2696,7 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::identifyClones(
2618
2696
ContextNode *Clone = nullptr ;
2619
2697
for (auto *CurClone : Node->Clones ) {
2620
2698
if (allocTypeToUse (CurClone->AllocTypes ) !=
2621
- allocTypeToUse (CallerEdge-> AllocTypes ))
2699
+ allocTypeToUse (CallerAllocTypeForAlloc ))
2622
2700
continue ;
2623
2701
2624
2702
if (!allocTypesMatch<DerivedCCG, FuncTy, CallTy>(
@@ -2630,9 +2708,11 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::identifyClones(
2630
2708
2631
2709
// The edge iterator is adjusted when we move the CallerEdge to the clone.
2632
2710
if (Clone)
2633
- moveEdgeToExistingCalleeClone (CallerEdge, Clone, &EI);
2711
+ moveEdgeToExistingCalleeClone (CallerEdge, Clone, &EI, /* NewClone=*/ false ,
2712
+ CallerEdgeContextsForAlloc);
2634
2713
else
2635
- Clone = moveEdgeToNewCalleeClone (CallerEdge, &EI);
2714
+ Clone =
2715
+ moveEdgeToNewCalleeClone (CallerEdge, &EI, CallerEdgeContextsForAlloc);
2636
2716
2637
2717
assert (EI == Node->CallerEdges .end () ||
2638
2718
Node->AllocTypes != (uint8_t )AllocationType::None);
0 commit comments