@@ -417,6 +417,29 @@ class CallsiteContextGraph {
417
417
418
418
DenseSet<uint32_t > &getContextIds () { return ContextIds; }
419
419
420
+ // Helper to clear the fields of this edge when we are removing it from the
421
+ // graph.
422
+ inline void clear () {
423
+ ContextIds.clear ();
424
+ AllocTypes = (uint8_t )AllocationType::None;
425
+ Caller = nullptr ;
426
+ Callee = nullptr ;
427
+ }
428
+
429
+ // Check if edge was removed from the graph. This is useful while iterating
430
+ // over a copy of edge lists when performing operations that mutate the
431
+ // graph in ways that might remove one of the edges.
432
+ inline bool isRemoved () const {
433
+ if (Callee || Caller)
434
+ return false ;
435
+ // Any edges that have been removed from the graph but are still in a
436
+ // shared_ptr somewhere should have all fields null'ed out by clear()
437
+ // above.
438
+ assert (AllocTypes == (uint8_t )AllocationType::None);
439
+ assert (ContextIds.empty ());
440
+ return true ;
441
+ }
442
+
420
443
void dump () const ;
421
444
void print (raw_ostream &OS) const ;
422
445
@@ -485,6 +508,15 @@ class CallsiteContextGraph {
485
508
DenseSet<uint32_t > ContextIds;
486
509
};
487
510
511
+ // / Helper to remove edge from graph, updating edge iterator if it is provided
512
+ // / (in which case CalleeIter indicates which edge list is being iterated).
513
+ // / This will also perform the necessary clearing of the ContextEdge members
514
+ // / to enable later checking if the edge has been removed (since we may have
515
+ // / other copies of the shared_ptr in existence, and in fact rely on this to
516
+ // / enable removal while iterating over a copy of a node's edge list).
517
+ void removeEdgeFromGraph (ContextEdge *Edge, EdgeIter *EI = nullptr ,
518
+ bool CalleeIter = true );
519
+
488
520
// / Assigns the given Node to calls at or inlined into the location with
489
521
// / the Node's stack id, after post order traversing and processing its
490
522
// / caller nodes. Uses the call information recorded in the given
@@ -920,15 +952,42 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::ContextNode::
920
952
Caller->CalleeEdges .push_back (Edge);
921
953
}
922
954
955
+ template <typename DerivedCCG, typename FuncTy, typename CallTy>
956
+ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::removeEdgeFromGraph(
957
+ ContextEdge *Edge, EdgeIter *EI, bool CalleeIter) {
958
+ assert (!EI || (*EI)->get () == Edge);
959
+ // Save the Caller and Callee pointers so we can erase Edge from their edge
960
+ // lists after clearing Edge below. We do the clearing first in case it is
961
+ // destructed after removing from the edge lists (if those were the last
962
+ // shared_ptr references to Edge).
963
+ auto *Callee = Edge->Callee ;
964
+ auto *Caller = Edge->Caller ;
965
+
966
+ // Make sure the edge fields are cleared out so we can properly detect
967
+ // removed edges if Edge is not destructed because there is still a shared_ptr
968
+ // reference.
969
+ Edge->clear ();
970
+
971
+ if (!EI) {
972
+ Callee->eraseCallerEdge (Edge);
973
+ Caller->eraseCalleeEdge (Edge);
974
+ } else if (CalleeIter) {
975
+ Callee->eraseCallerEdge (Edge);
976
+ *EI = Caller->CalleeEdges .erase (*EI);
977
+ } else {
978
+ Caller->eraseCalleeEdge (Edge);
979
+ *EI = Callee->CallerEdges .erase (*EI);
980
+ }
981
+ }
982
+
923
983
template <typename DerivedCCG, typename FuncTy, typename CallTy>
924
984
void CallsiteContextGraph<
925
985
DerivedCCG, FuncTy, CallTy>::removeNoneTypeCalleeEdges(ContextNode *Node) {
926
986
for (auto EI = Node->CalleeEdges .begin (); EI != Node->CalleeEdges .end ();) {
927
987
auto Edge = *EI;
928
988
if (Edge->AllocTypes == (uint8_t )AllocationType::None) {
929
989
assert (Edge->ContextIds .empty ());
930
- Edge->Callee ->eraseCallerEdge (Edge.get ());
931
- EI = Node->CalleeEdges .erase (EI);
990
+ removeEdgeFromGraph (Edge.get (), &EI, /* CalleeIter=*/ true );
932
991
} else
933
992
++EI;
934
993
}
@@ -1197,13 +1256,7 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::connectNewNode(
1197
1256
}
1198
1257
// Remove old edge if context ids empty.
1199
1258
if (Edge->getContextIds ().empty ()) {
1200
- if (TowardsCallee) {
1201
- Edge->Callee ->eraseCallerEdge (Edge.get ());
1202
- EI = OrigNode->CalleeEdges .erase (EI);
1203
- } else {
1204
- Edge->Caller ->eraseCalleeEdge (Edge.get ());
1205
- EI = OrigNode->CallerEdges .erase (EI);
1206
- }
1259
+ removeEdgeFromGraph (Edge.get (), &EI, TowardsCallee);
1207
1260
continue ;
1208
1261
}
1209
1262
++EI;
@@ -1272,8 +1325,10 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::
1272
1325
auto CallerEdges = Node->CallerEdges ;
1273
1326
for (auto &Edge : CallerEdges) {
1274
1327
// Skip any that have been removed during the recursion.
1275
- if (!Edge)
1328
+ if (Edge->isRemoved ()) {
1329
+ assert (!is_contained (Node->CallerEdges , Edge));
1276
1330
continue ;
1331
+ }
1277
1332
assignStackNodesPostOrder (Edge->Caller , Visited, StackIdToMatchingCalls,
1278
1333
CallToMatchingCall);
1279
1334
}
@@ -1402,10 +1457,8 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::
1402
1457
auto *PrevEdge = CurNode->findEdgeFromCallee (PrevNode);
1403
1458
assert (PrevEdge);
1404
1459
set_subtract (PrevEdge->getContextIds (), SavedContextIds);
1405
- if (PrevEdge->getContextIds ().empty ()) {
1406
- PrevNode->eraseCallerEdge (PrevEdge);
1407
- CurNode->eraseCalleeEdge (PrevEdge);
1408
- }
1460
+ if (PrevEdge->getContextIds ().empty ())
1461
+ removeEdgeFromGraph (PrevEdge);
1409
1462
}
1410
1463
// Since we update the edges from leaf to tail, only look at the callee
1411
1464
// edges. This isn't an alloc node, so if there are no callee edges, the
@@ -2076,15 +2129,19 @@ bool CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::calleesMatch(
2076
2129
// Hook up edge's original caller to new callee node.
2077
2130
AddEdge (Edge->Caller , CurCalleeNode);
2078
2131
2132
+ #ifndef NDEBUG
2133
+ // Save this because Edge's fields get cleared below when removed.
2134
+ auto *Caller = Edge->Caller ;
2135
+ #endif
2136
+
2079
2137
// Remove old edge
2080
- Edge->Callee ->eraseCallerEdge (Edge.get ());
2081
- EI = Edge->Caller ->CalleeEdges .erase (EI);
2138
+ removeEdgeFromGraph (Edge.get (), &EI, /* CalleeIter=*/ true );
2082
2139
2083
2140
// To simplify the increment of EI in the caller, subtract one from EI.
2084
2141
// In the final AddEdge call we would have either added a new callee edge,
2085
2142
// to Edge->Caller, or found an existing one. Either way we are guaranteed
2086
2143
// that there is at least one callee edge.
2087
- assert (!Edge-> Caller ->CalleeEdges .empty ());
2144
+ assert (!Caller->CalleeEdges .empty ());
2088
2145
--EI;
2089
2146
2090
2147
return true ;
@@ -2667,30 +2724,30 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::
2667
2724
// If we are moving all of Edge's ids, then just move the whole Edge.
2668
2725
// Otherwise only move the specified subset, to a new edge if needed.
2669
2726
if (Edge->getContextIds ().size () == ContextIdsToMove.size ()) {
2727
+ // First, update the alloc types on New Callee from Edge.
2728
+ // Do this before we potentially clear Edge's fields below!
2729
+ NewCallee->AllocTypes |= Edge->AllocTypes ;
2670
2730
// Moving the whole Edge.
2671
- if (CallerEdgeI)
2672
- *CallerEdgeI = OldCallee->CallerEdges .erase (*CallerEdgeI);
2673
- else
2674
- OldCallee->eraseCallerEdge (Edge.get ());
2675
2731
if (ExistingEdgeToNewCallee) {
2676
2732
// Since we already have an edge to NewCallee, simply move the ids
2677
2733
// onto it, and remove the existing Edge.
2678
2734
ExistingEdgeToNewCallee->getContextIds ().insert (ContextIdsToMove.begin (),
2679
2735
ContextIdsToMove.end ());
2680
2736
ExistingEdgeToNewCallee->AllocTypes |= Edge->AllocTypes ;
2681
2737
assert (Edge->ContextIds == ContextIdsToMove);
2682
- Edge->ContextIds .clear ();
2683
- Edge->AllocTypes = (uint8_t )AllocationType::None;
2684
- Edge->Caller ->eraseCalleeEdge (Edge.get ());
2738
+ removeEdgeFromGraph (Edge.get (), CallerEdgeI, /* CalleeIter=*/ false );
2685
2739
} else {
2686
2740
// Otherwise just reconnect Edge to NewCallee.
2687
2741
Edge->Callee = NewCallee;
2688
2742
NewCallee->CallerEdges .push_back (Edge);
2743
+ // Remove it from callee where it was previously connected.
2744
+ if (CallerEdgeI)
2745
+ *CallerEdgeI = OldCallee->CallerEdges .erase (*CallerEdgeI);
2746
+ else
2747
+ OldCallee->eraseCallerEdge (Edge.get ());
2689
2748
// Don't need to update Edge's context ids since we are simply
2690
2749
// reconnecting it.
2691
2750
}
2692
- // In either case, need to update the alloc types on New Callee.
2693
- NewCallee->AllocTypes |= Edge->AllocTypes ;
2694
2751
} else {
2695
2752
// Only moving a subset of Edge's ids.
2696
2753
if (CallerEdgeI)
@@ -2783,7 +2840,7 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::
2783
2840
auto CallerEdges = Node->CallerEdges ;
2784
2841
for (auto &Edge : CallerEdges) {
2785
2842
// Skip any that have been removed by an earlier recursive call.
2786
- if (Edge->Callee == nullptr && Edge-> Caller == nullptr ) {
2843
+ if (Edge->isRemoved () ) {
2787
2844
assert (!is_contained (Node->CallerEdges , Edge));
2788
2845
continue ;
2789
2846
}
@@ -2844,8 +2901,8 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::identifyClones(
2844
2901
auto CallerEdges = Node->CallerEdges ;
2845
2902
for (auto &Edge : CallerEdges) {
2846
2903
// Skip any that have been removed by an earlier recursive call.
2847
- if (Edge->Callee == nullptr && Edge-> Caller == nullptr ) {
2848
- assert (!llvm::count (Node->CallerEdges , Edge));
2904
+ if (Edge->isRemoved () ) {
2905
+ assert (!is_contained (Node->CallerEdges , Edge));
2849
2906
continue ;
2850
2907
}
2851
2908
// Ignore any caller we previously visited via another edge.
@@ -3289,10 +3346,17 @@ bool CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::assignFunctions() {
3289
3346
// Reset the CallsiteToCalleeFuncCloneMap entry for any callers
3290
3347
// that were previously assigned to call PreviousAssignedFuncClone,
3291
3348
// to record that they now call NewFuncClone.
3292
- for (auto CE : Clone->CallerEdges ) {
3349
+ // The none type edge removal may remove some of this Clone's caller
3350
+ // edges, if it is reached via another of its caller's callees.
3351
+ // Iterate over a copy and skip any that were removed.
3352
+ auto CallerEdges = Clone->CallerEdges ;
3353
+ for (auto CE : CallerEdges) {
3293
3354
// Skip any that have been removed on an earlier iteration.
3294
- if (!CE)
3355
+ if (CE->isRemoved ()) {
3356
+ assert (!is_contained (Clone->CallerEdges , CE));
3295
3357
continue ;
3358
+ }
3359
+ assert (CE);
3296
3360
// Ignore any caller that does not have a recorded callsite Call.
3297
3361
if (!CE->Caller ->hasCall ())
3298
3362
continue ;
@@ -3315,11 +3379,18 @@ bool CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::assignFunctions() {
3315
3379
// accordingly. This is important since we subsequently update the
3316
3380
// calls from the nodes in the graph and their assignments to callee
3317
3381
// functions recorded in CallsiteToCalleeFuncCloneMap.
3318
- for (auto CalleeEdge : CE->Caller ->CalleeEdges ) {
3382
+ // The none type edge removal may remove some of this caller's
3383
+ // callee edges, if it is reached via another of its callees.
3384
+ // Iterate over a copy and skip any that were removed.
3385
+ auto CalleeEdges = CE->Caller ->CalleeEdges ;
3386
+ for (auto CalleeEdge : CalleeEdges) {
3319
3387
// Skip any that have been removed on an earlier iteration when
3320
3388
// cleaning up newly None type callee edges.
3321
- if (!CalleeEdge)
3389
+ if (CalleeEdge->isRemoved ()) {
3390
+ assert (!is_contained (CE->Caller ->CalleeEdges , CalleeEdge));
3322
3391
continue ;
3392
+ }
3393
+ assert (CalleeEdge);
3323
3394
ContextNode *Callee = CalleeEdge->Callee ;
3324
3395
// Skip the current callsite, we are looking for other
3325
3396
// callsites Caller calls, as well as any that does not have a
0 commit comments