Skip to content

Commit fdf39c4

Browse files
committed
[MemProf] Simplify edge iterations (NFC)
Remove edge iterator parameters from the various helpers that move edges onto other nodes, and their associated iterator update code, and instead iterate over copies of the edge lists in the caller loops. This also avoids the need to increment these iterators at every early loop continue. This simplifies the code, makes it less error prone when updating, and in particular, facilitates adding handling of recursive contexts. There were no measurable compile time and memory overhead effects for a large target.
1 parent 0c6e03e commit fdf39c4

File tree

1 file changed

+45
-71
lines changed

1 file changed

+45
-71
lines changed

llvm/lib/Transforms/IPO/MemProfContextDisambiguation.cpp

Lines changed: 45 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -692,32 +692,28 @@ class CallsiteContextGraph {
692692

693693
/// Create a clone of Edge's callee and move Edge to that new callee node,
694694
/// performing the necessary context id and allocation type updates.
695-
/// If callee's caller edge iterator is supplied, it is updated when removing
696-
/// the edge from that list. If ContextIdsToMove is non-empty, only that
697-
/// subset of Edge's ids are moved to an edge to the new callee.
695+
/// If ContextIdsToMove is non-empty, only that subset of Edge's ids are
696+
/// moved to an edge to the new callee.
698697
ContextNode *
699698
moveEdgeToNewCalleeClone(const std::shared_ptr<ContextEdge> &Edge,
700-
EdgeIter *CallerEdgeI = nullptr,
701699
DenseSet<uint32_t> ContextIdsToMove = {});
702700

703701
/// Change the callee of Edge to existing callee clone NewCallee, performing
704702
/// the necessary context id and allocation type updates.
705-
/// If callee's caller edge iterator is supplied, it is updated when removing
706-
/// the edge from that list. If ContextIdsToMove is non-empty, only that
707-
/// subset of Edge's ids are moved to an edge to the new callee.
703+
/// If ContextIdsToMove is non-empty, only that subset of Edge's ids are
704+
/// moved to an edge to the new callee.
708705
void moveEdgeToExistingCalleeClone(const std::shared_ptr<ContextEdge> &Edge,
709706
ContextNode *NewCallee,
710-
EdgeIter *CallerEdgeI = nullptr,
711707
bool NewClone = false,
712708
DenseSet<uint32_t> ContextIdsToMove = {});
713709

714710
/// Change the caller of the edge at the given callee edge iterator to be
715711
/// NewCaller, performing the necessary context id and allocation type
716-
/// updates. The iterator is updated as the edge is removed from the list of
717-
/// callee edges in the original caller. This is similar to the above
718-
/// moveEdgeToExistingCalleeClone, but a simplified version of it as we always
719-
/// move the given edge and all of its context ids.
720-
void moveCalleeEdgeToNewCaller(EdgeIter &CalleeEdgeI, ContextNode *NewCaller);
712+
/// updates. This is similar to the above moveEdgeToExistingCalleeClone, but
713+
/// a simplified version of it as we always move the given edge and all of its
714+
/// context ids.
715+
void moveCalleeEdgeToNewCaller(const std::shared_ptr<ContextEdge> &Edge,
716+
ContextNode *NewCaller);
721717

722718
/// Recursively perform cloning on the graph for the given Node and its
723719
/// callers, in order to uniquely identify the allocation behavior of an
@@ -2301,12 +2297,13 @@ bool CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::partitionCallsByCallee(
23012297
// Track whether we already assigned original node to a callee.
23022298
bool UsedOrigNode = false;
23032299
assert(NodeToCallingFunc[Node]);
2304-
for (auto EI = Node->CalleeEdges.begin(); EI != Node->CalleeEdges.end();) {
2305-
auto Edge = *EI;
2306-
if (!Edge->Callee->hasCall()) {
2307-
++EI;
2300+
// Iterate over a copy of Node's callee edges, since we may need to remove
2301+
// edges in moveCalleeEdgeToNewCaller, and this simplifies the handling and
2302+
// makes it less error-prone.
2303+
auto CalleeEdges = Node->CalleeEdges;
2304+
for (auto &Edge : CalleeEdges) {
2305+
if (!Edge->Callee->hasCall())
23082306
continue;
2309-
}
23102307

23112308
// Will be updated below to point to whatever (caller) node this callee edge
23122309
// should be moved to.
@@ -2349,12 +2346,10 @@ bool CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::partitionCallsByCallee(
23492346
}
23502347

23512348
// Don't need to move edge if we are using the original node;
2352-
if (CallerNodeToUse == Node) {
2353-
++EI;
2349+
if (CallerNodeToUse == Node)
23542350
continue;
2355-
}
23562351

2357-
moveCalleeEdgeToNewCaller(EI, CallerNodeToUse);
2352+
moveCalleeEdgeToNewCaller(Edge, CallerNodeToUse);
23582353
}
23592354
// Now that we are done moving edges, clean up any caller edges that ended
23602355
// up with no type or context ids. During moveCalleeEdgeToNewCaller all
@@ -3038,24 +3033,23 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::exportToDot(
30383033
template <typename DerivedCCG, typename FuncTy, typename CallTy>
30393034
typename CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::ContextNode *
30403035
CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::moveEdgeToNewCalleeClone(
3041-
const std::shared_ptr<ContextEdge> &Edge, EdgeIter *CallerEdgeI,
3036+
const std::shared_ptr<ContextEdge> &Edge,
30423037
DenseSet<uint32_t> ContextIdsToMove) {
30433038
ContextNode *Node = Edge->Callee;
30443039
assert(NodeToCallingFunc.count(Node));
30453040
ContextNode *Clone =
30463041
createNewNode(Node->IsAllocation, NodeToCallingFunc[Node], Node->Call);
30473042
Node->addClone(Clone);
30483043
Clone->MatchingCalls = Node->MatchingCalls;
3049-
moveEdgeToExistingCalleeClone(Edge, Clone, CallerEdgeI, /*NewClone=*/true,
3044+
moveEdgeToExistingCalleeClone(Edge, Clone, /*NewClone=*/true,
30503045
ContextIdsToMove);
30513046
return Clone;
30523047
}
30533048

30543049
template <typename DerivedCCG, typename FuncTy, typename CallTy>
30553050
void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::
30563051
moveEdgeToExistingCalleeClone(const std::shared_ptr<ContextEdge> &Edge,
3057-
ContextNode *NewCallee, EdgeIter *CallerEdgeI,
3058-
bool NewClone,
3052+
ContextNode *NewCallee, bool NewClone,
30593053
DenseSet<uint32_t> ContextIdsToMove) {
30603054
// NewCallee and Edge's current callee must be clones of the same original
30613055
// node (Edge's current callee may be the original node too).
@@ -3086,23 +3080,18 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::
30863080
ContextIdsToMove.end());
30873081
ExistingEdgeToNewCallee->AllocTypes |= Edge->AllocTypes;
30883082
assert(Edge->ContextIds == ContextIdsToMove);
3089-
removeEdgeFromGraph(Edge.get(), CallerEdgeI, /*CalleeIter=*/false);
3083+
removeEdgeFromGraph(Edge.get());
30903084
} else {
30913085
// Otherwise just reconnect Edge to NewCallee.
30923086
Edge->Callee = NewCallee;
30933087
NewCallee->CallerEdges.push_back(Edge);
30943088
// Remove it from callee where it was previously connected.
3095-
if (CallerEdgeI)
3096-
*CallerEdgeI = OldCallee->CallerEdges.erase(*CallerEdgeI);
3097-
else
3098-
OldCallee->eraseCallerEdge(Edge.get());
3089+
OldCallee->eraseCallerEdge(Edge.get());
30993090
// Don't need to update Edge's context ids since we are simply
31003091
// reconnecting it.
31013092
}
31023093
} else {
31033094
// Only moving a subset of Edge's ids.
3104-
if (CallerEdgeI)
3105-
++CallerEdgeI;
31063095
// Compute the alloc type of the subset of ids being moved.
31073096
auto CallerEdgeAllocType = computeAllocType(ContextIdsToMove);
31083097
if (ExistingEdgeToNewCallee) {
@@ -3175,16 +3164,16 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::
31753164

31763165
template <typename DerivedCCG, typename FuncTy, typename CallTy>
31773166
void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::
3178-
moveCalleeEdgeToNewCaller(EdgeIter &CalleeEdgeI, ContextNode *NewCaller) {
3179-
auto Edge = *CalleeEdgeI;
3167+
moveCalleeEdgeToNewCaller(const std::shared_ptr<ContextEdge> &Edge,
3168+
ContextNode *NewCaller) {
31803169

31813170
ContextNode *OldCaller = Edge->Caller;
3171+
OldCaller->eraseCalleeEdge(Edge.get());
31823172

31833173
// We might already have an edge to the new caller. If one exists we will
31843174
// reuse it.
31853175
auto ExistingEdgeToNewCaller = NewCaller->findEdgeFromCallee(Edge->Callee);
31863176

3187-
CalleeEdgeI = OldCaller->CalleeEdges.erase(CalleeEdgeI);
31883177
if (ExistingEdgeToNewCaller) {
31893178
// Since we already have an edge to NewCaller, simply move the ids
31903179
// onto it, and remove the existing Edge.
@@ -3409,22 +3398,20 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::identifyClones(
34093398
// Iterate until we find no more opportunities for disambiguating the alloc
34103399
// types via cloning. In most cases this loop will terminate once the Node
34113400
// has a single allocation type, in which case no more cloning is needed.
3412-
// We need to be able to remove Edge from CallerEdges, so need to adjust
3413-
// iterator inside the loop.
3414-
for (auto EI = Node->CallerEdges.begin(); EI != Node->CallerEdges.end();) {
3415-
auto CallerEdge = *EI;
3416-
3401+
// Iterate over a copy of Node's caller edges, since we may need to remove
3402+
// edges in the moveEdgeTo* methods, and this simplifies the handling and
3403+
// makes it less error-prone.
3404+
auto CallerEdges = Node->CallerEdges;
3405+
for (auto &CallerEdge : CallerEdges) {
34173406
// See if cloning the prior caller edge left this node with a single alloc
34183407
// type or a single caller. In that case no more cloning of Node is needed.
34193408
if (hasSingleAllocType(Node->AllocTypes) || Node->CallerEdges.size() <= 1)
34203409
break;
34213410

34223411
// If the caller was not successfully matched to a call in the IR/summary,
34233412
// there is no point in trying to clone for it as we can't update that call.
3424-
if (!CallerEdge->Caller->hasCall()) {
3425-
++EI;
3413+
if (!CallerEdge->Caller->hasCall())
34263414
continue;
3427-
}
34283415

34293416
// Only need to process the ids along this edge pertaining to the given
34303417
// allocation.
@@ -3433,10 +3420,9 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::identifyClones(
34333420
if (!RecursiveContextIds.empty())
34343421
CallerEdgeContextsForAlloc =
34353422
set_difference(CallerEdgeContextsForAlloc, RecursiveContextIds);
3436-
if (CallerEdgeContextsForAlloc.empty()) {
3437-
++EI;
3423+
if (CallerEdgeContextsForAlloc.empty())
34383424
continue;
3439-
}
3425+
34403426
auto CallerAllocTypeForAlloc = computeAllocType(CallerEdgeContextsForAlloc);
34413427

34423428
// Compute the node callee edge alloc types corresponding to the context ids
@@ -3463,10 +3449,8 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::identifyClones(
34633449
if (allocTypeToUse(CallerAllocTypeForAlloc) ==
34643450
allocTypeToUse(Node->AllocTypes) &&
34653451
allocTypesMatch<DerivedCCG, FuncTy, CallTy>(
3466-
CalleeEdgeAllocTypesForCallerEdge, Node->CalleeEdges)) {
3467-
++EI;
3452+
CalleeEdgeAllocTypesForCallerEdge, Node->CalleeEdges))
34683453
continue;
3469-
}
34703454

34713455
// First see if we can use an existing clone. Check each clone and its
34723456
// callee edges for matching alloc types.
@@ -3496,14 +3480,11 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::identifyClones(
34963480

34973481
// The edge iterator is adjusted when we move the CallerEdge to the clone.
34983482
if (Clone)
3499-
moveEdgeToExistingCalleeClone(CallerEdge, Clone, &EI, /*NewClone=*/false,
3483+
moveEdgeToExistingCalleeClone(CallerEdge, Clone, /*NewClone=*/false,
35003484
CallerEdgeContextsForAlloc);
35013485
else
3502-
Clone =
3503-
moveEdgeToNewCalleeClone(CallerEdge, &EI, CallerEdgeContextsForAlloc);
3486+
Clone = moveEdgeToNewCalleeClone(CallerEdge, CallerEdgeContextsForAlloc);
35043487

3505-
assert(EI == Node->CallerEdges.end() ||
3506-
Node->AllocTypes != (uint8_t)AllocationType::None);
35073488
// Sanity check that no alloc types on clone or its edges are None.
35083489
assert(Clone->AllocTypes != (uint8_t)AllocationType::None);
35093490
}
@@ -3944,16 +3925,14 @@ bool CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::assignFunctions() {
39443925
// assign this clone to.
39453926
std::map<FuncInfo, ContextNode *> FuncCloneToNewCallsiteCloneMap;
39463927
FuncInfo FuncCloneAssignedToCurCallsiteClone;
3947-
// We need to be able to remove Edge from CallerEdges, so need to adjust
3948-
// iterator in the loop.
3949-
for (auto EI = Clone->CallerEdges.begin();
3950-
EI != Clone->CallerEdges.end();) {
3951-
auto Edge = *EI;
3928+
// Iterate over a copy of Clone's caller edges, since we may need to
3929+
// remove edges in the moveEdgeTo* methods, and this simplifies the
3930+
// handling and makes it less error-prone.
3931+
auto CloneCallerEdges = Clone->CallerEdges;
3932+
for (auto &Edge : CloneCallerEdges) {
39523933
// Ignore any caller that does not have a recorded callsite Call.
3953-
if (!Edge->Caller->hasCall()) {
3954-
EI++;
3934+
if (!Edge->Caller->hasCall())
39553935
continue;
3956-
}
39573936
// If this caller already assigned to call a version of OrigFunc, need
39583937
// to ensure we can assign this callsite clone to that function clone.
39593938
if (CallsiteToCalleeFuncCloneMap.count(Edge->Caller)) {
@@ -3998,27 +3977,24 @@ bool CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::assignFunctions() {
39983977
FuncCloneCalledByCaller)) {
39993978
ContextNode *NewClone =
40003979
FuncCloneToNewCallsiteCloneMap[FuncCloneCalledByCaller];
4001-
moveEdgeToExistingCalleeClone(Edge, NewClone, &EI);
3980+
moveEdgeToExistingCalleeClone(Edge, NewClone);
40023981
// Cleanup any none type edges cloned over.
40033982
removeNoneTypeCalleeEdges(NewClone);
40043983
} else {
40053984
// Create a new callsite clone.
4006-
ContextNode *NewClone = moveEdgeToNewCalleeClone(Edge, &EI);
3985+
ContextNode *NewClone = moveEdgeToNewCalleeClone(Edge);
40073986
removeNoneTypeCalleeEdges(NewClone);
40083987
FuncCloneToNewCallsiteCloneMap[FuncCloneCalledByCaller] =
40093988
NewClone;
40103989
// Add to list of clones and process later.
40113990
ClonesWorklist.push_back(NewClone);
4012-
assert(EI == Clone->CallerEdges.end() ||
4013-
Clone->AllocTypes != (uint8_t)AllocationType::None);
40143991
assert(NewClone->AllocTypes != (uint8_t)AllocationType::None);
40153992
}
40163993
// Moving the caller edge may have resulted in some none type
40173994
// callee edges.
40183995
removeNoneTypeCalleeEdges(Clone);
40193996
// We will handle the newly created callsite clone in a subsequent
4020-
// iteration over this Node's Clones. Continue here since we
4021-
// already adjusted iterator EI while moving the edge.
3997+
// iteration over this Node's Clones.
40223998
continue;
40233999
}
40244000

@@ -4066,8 +4042,6 @@ bool CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::assignFunctions() {
40664042
RecordCalleeFuncOfCallsite(Edge->Caller,
40674043
FuncCloneAssignedToCurCallsiteClone);
40684044
}
4069-
4070-
EI++;
40714045
}
40724046
}
40734047
if (VerifyCCG) {

0 commit comments

Comments
 (0)