Skip to content

Commit 7ad8a3d

Browse files
[MemProf] Simplify edge iterations (NFC) (#123469)
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 5ede7b6 commit 7ad8a3d

File tree

1 file changed

+45
-71
lines changed

1 file changed

+45
-71
lines changed

llvm/lib/Transforms/IPO/MemProfContextDisambiguation.cpp

+45-71
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
@@ -2313,12 +2309,13 @@ bool CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::partitionCallsByCallee(
23132309
// Track whether we already assigned original node to a callee.
23142310
bool UsedOrigNode = false;
23152311
assert(NodeToCallingFunc[Node]);
2316-
for (auto EI = Node->CalleeEdges.begin(); EI != Node->CalleeEdges.end();) {
2317-
auto Edge = *EI;
2318-
if (!Edge->Callee->hasCall()) {
2319-
++EI;
2312+
// Iterate over a copy of Node's callee edges, since we may need to remove
2313+
// edges in moveCalleeEdgeToNewCaller, and this simplifies the handling and
2314+
// makes it less error-prone.
2315+
auto CalleeEdges = Node->CalleeEdges;
2316+
for (auto &Edge : CalleeEdges) {
2317+
if (!Edge->Callee->hasCall())
23202318
continue;
2321-
}
23222319

23232320
// Will be updated below to point to whatever (caller) node this callee edge
23242321
// should be moved to.
@@ -2361,12 +2358,10 @@ bool CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::partitionCallsByCallee(
23612358
}
23622359

23632360
// Don't need to move edge if we are using the original node;
2364-
if (CallerNodeToUse == Node) {
2365-
++EI;
2361+
if (CallerNodeToUse == Node)
23662362
continue;
2367-
}
23682363

2369-
moveCalleeEdgeToNewCaller(EI, CallerNodeToUse);
2364+
moveCalleeEdgeToNewCaller(Edge, CallerNodeToUse);
23702365
}
23712366
// Now that we are done moving edges, clean up any caller edges that ended
23722367
// up with no type or context ids. During moveCalleeEdgeToNewCaller all
@@ -3046,24 +3041,23 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::exportToDot(
30463041
template <typename DerivedCCG, typename FuncTy, typename CallTy>
30473042
typename CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::ContextNode *
30483043
CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::moveEdgeToNewCalleeClone(
3049-
const std::shared_ptr<ContextEdge> &Edge, EdgeIter *CallerEdgeI,
3044+
const std::shared_ptr<ContextEdge> &Edge,
30503045
DenseSet<uint32_t> ContextIdsToMove) {
30513046
ContextNode *Node = Edge->Callee;
30523047
assert(NodeToCallingFunc.count(Node));
30533048
ContextNode *Clone =
30543049
createNewNode(Node->IsAllocation, NodeToCallingFunc[Node], Node->Call);
30553050
Node->addClone(Clone);
30563051
Clone->MatchingCalls = Node->MatchingCalls;
3057-
moveEdgeToExistingCalleeClone(Edge, Clone, CallerEdgeI, /*NewClone=*/true,
3052+
moveEdgeToExistingCalleeClone(Edge, Clone, /*NewClone=*/true,
30583053
ContextIdsToMove);
30593054
return Clone;
30603055
}
30613056

30623057
template <typename DerivedCCG, typename FuncTy, typename CallTy>
30633058
void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::
30643059
moveEdgeToExistingCalleeClone(const std::shared_ptr<ContextEdge> &Edge,
3065-
ContextNode *NewCallee, EdgeIter *CallerEdgeI,
3066-
bool NewClone,
3060+
ContextNode *NewCallee, bool NewClone,
30673061
DenseSet<uint32_t> ContextIdsToMove) {
30683062
// NewCallee and Edge's current callee must be clones of the same original
30693063
// node (Edge's current callee may be the original node too).
@@ -3094,23 +3088,18 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::
30943088
ContextIdsToMove.end());
30953089
ExistingEdgeToNewCallee->AllocTypes |= Edge->AllocTypes;
30963090
assert(Edge->ContextIds == ContextIdsToMove);
3097-
removeEdgeFromGraph(Edge.get(), CallerEdgeI, /*CalleeIter=*/false);
3091+
removeEdgeFromGraph(Edge.get());
30983092
} else {
30993093
// Otherwise just reconnect Edge to NewCallee.
31003094
Edge->Callee = NewCallee;
31013095
NewCallee->CallerEdges.push_back(Edge);
31023096
// Remove it from callee where it was previously connected.
3103-
if (CallerEdgeI)
3104-
*CallerEdgeI = OldCallee->CallerEdges.erase(*CallerEdgeI);
3105-
else
3106-
OldCallee->eraseCallerEdge(Edge.get());
3097+
OldCallee->eraseCallerEdge(Edge.get());
31073098
// Don't need to update Edge's context ids since we are simply
31083099
// reconnecting it.
31093100
}
31103101
} else {
31113102
// Only moving a subset of Edge's ids.
3112-
if (CallerEdgeI)
3113-
++(*CallerEdgeI);
31143103
// Compute the alloc type of the subset of ids being moved.
31153104
auto CallerEdgeAllocType = computeAllocType(ContextIdsToMove);
31163105
if (ExistingEdgeToNewCallee) {
@@ -3183,16 +3172,16 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::
31833172

31843173
template <typename DerivedCCG, typename FuncTy, typename CallTy>
31853174
void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::
3186-
moveCalleeEdgeToNewCaller(EdgeIter &CalleeEdgeI, ContextNode *NewCaller) {
3187-
auto Edge = *CalleeEdgeI;
3175+
moveCalleeEdgeToNewCaller(const std::shared_ptr<ContextEdge> &Edge,
3176+
ContextNode *NewCaller) {
31883177

31893178
ContextNode *OldCaller = Edge->Caller;
3179+
OldCaller->eraseCalleeEdge(Edge.get());
31903180

31913181
// We might already have an edge to the new caller. If one exists we will
31923182
// reuse it.
31933183
auto ExistingEdgeToNewCaller = NewCaller->findEdgeFromCallee(Edge->Callee);
31943184

3195-
CalleeEdgeI = OldCaller->CalleeEdges.erase(CalleeEdgeI);
31963185
if (ExistingEdgeToNewCaller) {
31973186
// Since we already have an edge to NewCaller, simply move the ids
31983187
// onto it, and remove the existing Edge.
@@ -3417,22 +3406,20 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::identifyClones(
34173406
// Iterate until we find no more opportunities for disambiguating the alloc
34183407
// types via cloning. In most cases this loop will terminate once the Node
34193408
// has a single allocation type, in which case no more cloning is needed.
3420-
// We need to be able to remove Edge from CallerEdges, so need to adjust
3421-
// iterator inside the loop.
3422-
for (auto EI = Node->CallerEdges.begin(); EI != Node->CallerEdges.end();) {
3423-
auto CallerEdge = *EI;
3424-
3409+
// Iterate over a copy of Node's caller edges, since we may need to remove
3410+
// edges in the moveEdgeTo* methods, and this simplifies the handling and
3411+
// makes it less error-prone.
3412+
auto CallerEdges = Node->CallerEdges;
3413+
for (auto &CallerEdge : CallerEdges) {
34253414
// See if cloning the prior caller edge left this node with a single alloc
34263415
// type or a single caller. In that case no more cloning of Node is needed.
34273416
if (hasSingleAllocType(Node->AllocTypes) || Node->CallerEdges.size() <= 1)
34283417
break;
34293418

34303419
// If the caller was not successfully matched to a call in the IR/summary,
34313420
// there is no point in trying to clone for it as we can't update that call.
3432-
if (!CallerEdge->Caller->hasCall()) {
3433-
++EI;
3421+
if (!CallerEdge->Caller->hasCall())
34343422
continue;
3435-
}
34363423

34373424
// Only need to process the ids along this edge pertaining to the given
34383425
// allocation.
@@ -3441,10 +3428,9 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::identifyClones(
34413428
if (!RecursiveContextIds.empty())
34423429
CallerEdgeContextsForAlloc =
34433430
set_difference(CallerEdgeContextsForAlloc, RecursiveContextIds);
3444-
if (CallerEdgeContextsForAlloc.empty()) {
3445-
++EI;
3431+
if (CallerEdgeContextsForAlloc.empty())
34463432
continue;
3447-
}
3433+
34483434
auto CallerAllocTypeForAlloc = computeAllocType(CallerEdgeContextsForAlloc);
34493435

34503436
// Compute the node callee edge alloc types corresponding to the context ids
@@ -3471,10 +3457,8 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::identifyClones(
34713457
if (allocTypeToUse(CallerAllocTypeForAlloc) ==
34723458
allocTypeToUse(Node->AllocTypes) &&
34733459
allocTypesMatch<DerivedCCG, FuncTy, CallTy>(
3474-
CalleeEdgeAllocTypesForCallerEdge, Node->CalleeEdges)) {
3475-
++EI;
3460+
CalleeEdgeAllocTypesForCallerEdge, Node->CalleeEdges))
34763461
continue;
3477-
}
34783462

34793463
// First see if we can use an existing clone. Check each clone and its
34803464
// callee edges for matching alloc types.
@@ -3504,14 +3488,11 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::identifyClones(
35043488

35053489
// The edge iterator is adjusted when we move the CallerEdge to the clone.
35063490
if (Clone)
3507-
moveEdgeToExistingCalleeClone(CallerEdge, Clone, &EI, /*NewClone=*/false,
3491+
moveEdgeToExistingCalleeClone(CallerEdge, Clone, /*NewClone=*/false,
35083492
CallerEdgeContextsForAlloc);
35093493
else
3510-
Clone =
3511-
moveEdgeToNewCalleeClone(CallerEdge, &EI, CallerEdgeContextsForAlloc);
3494+
Clone = moveEdgeToNewCalleeClone(CallerEdge, CallerEdgeContextsForAlloc);
35123495

3513-
assert(EI == Node->CallerEdges.end() ||
3514-
Node->AllocTypes != (uint8_t)AllocationType::None);
35153496
// Sanity check that no alloc types on clone or its edges are None.
35163497
assert(Clone->AllocTypes != (uint8_t)AllocationType::None);
35173498
}
@@ -3952,16 +3933,14 @@ bool CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::assignFunctions() {
39523933
// assign this clone to.
39533934
std::map<FuncInfo, ContextNode *> FuncCloneToNewCallsiteCloneMap;
39543935
FuncInfo FuncCloneAssignedToCurCallsiteClone;
3955-
// We need to be able to remove Edge from CallerEdges, so need to adjust
3956-
// iterator in the loop.
3957-
for (auto EI = Clone->CallerEdges.begin();
3958-
EI != Clone->CallerEdges.end();) {
3959-
auto Edge = *EI;
3936+
// Iterate over a copy of Clone's caller edges, since we may need to
3937+
// remove edges in the moveEdgeTo* methods, and this simplifies the
3938+
// handling and makes it less error-prone.
3939+
auto CloneCallerEdges = Clone->CallerEdges;
3940+
for (auto &Edge : CloneCallerEdges) {
39603941
// Ignore any caller that does not have a recorded callsite Call.
3961-
if (!Edge->Caller->hasCall()) {
3962-
EI++;
3942+
if (!Edge->Caller->hasCall())
39633943
continue;
3964-
}
39653944
// If this caller already assigned to call a version of OrigFunc, need
39663945
// to ensure we can assign this callsite clone to that function clone.
39673946
if (CallsiteToCalleeFuncCloneMap.count(Edge->Caller)) {
@@ -4006,27 +3985,24 @@ bool CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::assignFunctions() {
40063985
FuncCloneCalledByCaller)) {
40073986
ContextNode *NewClone =
40083987
FuncCloneToNewCallsiteCloneMap[FuncCloneCalledByCaller];
4009-
moveEdgeToExistingCalleeClone(Edge, NewClone, &EI);
3988+
moveEdgeToExistingCalleeClone(Edge, NewClone);
40103989
// Cleanup any none type edges cloned over.
40113990
removeNoneTypeCalleeEdges(NewClone);
40123991
} else {
40133992
// Create a new callsite clone.
4014-
ContextNode *NewClone = moveEdgeToNewCalleeClone(Edge, &EI);
3993+
ContextNode *NewClone = moveEdgeToNewCalleeClone(Edge);
40153994
removeNoneTypeCalleeEdges(NewClone);
40163995
FuncCloneToNewCallsiteCloneMap[FuncCloneCalledByCaller] =
40173996
NewClone;
40183997
// Add to list of clones and process later.
40193998
ClonesWorklist.push_back(NewClone);
4020-
assert(EI == Clone->CallerEdges.end() ||
4021-
Clone->AllocTypes != (uint8_t)AllocationType::None);
40223999
assert(NewClone->AllocTypes != (uint8_t)AllocationType::None);
40234000
}
40244001
// Moving the caller edge may have resulted in some none type
40254002
// callee edges.
40264003
removeNoneTypeCalleeEdges(Clone);
40274004
// We will handle the newly created callsite clone in a subsequent
4028-
// iteration over this Node's Clones. Continue here since we
4029-
// already adjusted iterator EI while moving the edge.
4005+
// iteration over this Node's Clones.
40304006
continue;
40314007
}
40324008

@@ -4074,8 +4050,6 @@ bool CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::assignFunctions() {
40744050
RecordCalleeFuncOfCallsite(Edge->Caller,
40754051
FuncCloneAssignedToCurCallsiteClone);
40764052
}
4077-
4078-
EI++;
40794053
}
40804054
}
40814055
if (VerifyCCG) {

0 commit comments

Comments
 (0)