@@ -1377,9 +1377,12 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::
1377
1377
// Compute the last node's context ids once, as it is shared by all calls in
1378
1378
// this entry.
1379
1379
DenseSet<uint32_t > LastNodeContextIds = LastNode->getContextIds ();
1380
- assert (!LastNodeContextIds.empty ());
1381
1380
1382
- for (unsigned I = 0 ; I < Calls.size (); I++) {
1381
+ bool PrevIterCreatedNode = false ;
1382
+ bool CreatedNode = false ;
1383
+ for (unsigned I = 0 ; I < Calls.size ();
1384
+ I++, PrevIterCreatedNode = CreatedNode) {
1385
+ CreatedNode = false ;
1383
1386
auto &[Call, Ids, Func, SavedContextIds] = Calls[I];
1384
1387
// Skip any for which we didn't assign any ids, these don't get a node in
1385
1388
// the graph.
@@ -1391,7 +1394,13 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::
1391
1394
if (!CallToMatchingCall.contains (Call))
1392
1395
continue ;
1393
1396
auto MatchingCall = CallToMatchingCall[Call];
1394
- assert (NonAllocationCallToContextNodeMap.contains (MatchingCall));
1397
+ if (!NonAllocationCallToContextNodeMap.contains (MatchingCall)) {
1398
+ // This should only happen if we had a prior iteration, and it didn't
1399
+ // create a node because of the below recomputation of context ids
1400
+ // finding none remaining and continuing early.
1401
+ assert (I > 0 && !PrevIterCreatedNode);
1402
+ continue ;
1403
+ }
1395
1404
NonAllocationCallToContextNodeMap[MatchingCall]->MatchingCalls .push_back (
1396
1405
Call);
1397
1406
continue ;
@@ -1444,6 +1453,7 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::
1444
1453
ContextNode *NewNode = NodeOwner.back ().get ();
1445
1454
NodeToCallingFunc[NewNode] = Func;
1446
1455
NonAllocationCallToContextNodeMap[Call] = NewNode;
1456
+ CreatedNode = true ;
1447
1457
NewNode->AllocTypes = computeAllocType (SavedContextIds);
1448
1458
1449
1459
ContextNode *FirstNode = getNodeForStackId (Ids[0 ]);
@@ -1548,13 +1558,23 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::updateStackNodes() {
1548
1558
// of length, and within each length, lexicographically by stack id. The
1549
1559
// latter is so that we can specially handle calls that have identical stack
1550
1560
// id sequences (either due to cloning or artificially because of the MIB
1551
- // context pruning).
1552
- std::stable_sort (Calls.begin (), Calls.end (),
1553
- [](const CallContextInfo &A, const CallContextInfo &B) {
1554
- return A.StackIds .size () > B.StackIds .size () ||
1555
- (A.StackIds .size () == B.StackIds .size () &&
1556
- A.StackIds < B.StackIds );
1557
- });
1561
+ // context pruning). Those with the same Ids are then sorted by function to
1562
+ // facilitate efficiently mapping them to the same context node.
1563
+ // Because the functions are pointers, to ensure a stable sort first assign
1564
+ // each function pointer to its first index in the Calls array, and then use
1565
+ // that to sort by.
1566
+ DenseMap<const FuncTy *, unsigned > FuncToIndex;
1567
+ for (const auto &[Idx, CallCtxInfo] : enumerate(Calls))
1568
+ FuncToIndex.insert ({CallCtxInfo.Func , Idx});
1569
+ std::stable_sort (
1570
+ Calls.begin (), Calls.end (),
1571
+ [&FuncToIndex](const CallContextInfo &A, const CallContextInfo &B) {
1572
+ return A.StackIds .size () > B.StackIds .size () ||
1573
+ (A.StackIds .size () == B.StackIds .size () &&
1574
+ (A.StackIds < B.StackIds ||
1575
+ (A.StackIds == B.StackIds &&
1576
+ FuncToIndex[A.Func ] < FuncToIndex[B.Func ])));
1577
+ });
1558
1578
1559
1579
// Find the node for the last stack id, which should be the same
1560
1580
// across all calls recorded for this id, and is the id for this
@@ -1572,18 +1592,26 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::updateStackNodes() {
1572
1592
DenseSet<uint32_t > LastNodeContextIds = LastNode->getContextIds ();
1573
1593
assert (!LastNodeContextIds.empty ());
1574
1594
1575
- // Map from function to the first call from the below list (with matching
1576
- // stack ids) found in that function. Note that calls from different
1577
- // functions can have the same stack ids because this is the list of stack
1578
- // ids that had (possibly pruned) nodes after building the graph from the
1579
- // allocation MIBs.
1580
- DenseMap<const FuncTy *, CallInfo> FuncToCallMap;
1595
+ #ifndef NDEBUG
1596
+ // Save the set of functions seen for a particular set of the same stack
1597
+ // ids. This is used to ensure that they have been correctly sorted to be
1598
+ // adjacent in the Calls list, since we rely on that to efficiently place
1599
+ // all such matching calls onto the same context node.
1600
+ DenseSet<const FuncTy *> MatchingIdsFuncSet;
1601
+ #endif
1581
1602
1582
1603
for (unsigned I = 0 ; I < Calls.size (); I++) {
1583
1604
auto &[Call, Ids, Func, SavedContextIds] = Calls[I];
1584
1605
assert (SavedContextIds.empty ());
1585
1606
assert (LastId == Ids.back ());
1586
1607
1608
+ #ifndef NDEBUG
1609
+ // If this call has a different set of ids than the last one, clear the
1610
+ // set used to ensure they are sorted properly.
1611
+ if (I > 0 && Ids != Calls[I - 1 ].StackIds )
1612
+ MatchingIdsFuncSet.clear ();
1613
+ #endif
1614
+
1587
1615
// First compute the context ids for this stack id sequence (the
1588
1616
// intersection of the context ids of the corresponding nodes).
1589
1617
// Start with the remaining saved ids for the last node.
@@ -1652,23 +1680,38 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::updateStackNodes() {
1652
1680
continue ;
1653
1681
}
1654
1682
1655
- // If the prior call had the same stack ids this map would not be empty.
1683
+ #ifndef NDEBUG
1684
+ // If the prior call had the same stack ids this set would not be empty.
1656
1685
// Check if we already have a call that "matches" because it is located
1657
- // in the same function.
1658
- if (FuncToCallMap. contains (Func)) {
1659
- // Record the matching call found for this call, and skip it. We
1660
- // will subsequently combine it into the same node.
1661
- CallToMatchingCall[Call] = FuncToCallMap[Func];
1662
- continue ;
1663
- }
1686
+ // in the same function. If the Calls list was sorted properly we should
1687
+ // not encounter this situation as all such entries should be adjacent
1688
+ // and processed in bulk further below.
1689
+ assert (!MatchingIdsFuncSet. contains (Func));
1690
+
1691
+ MatchingIdsFuncSet. insert (Func) ;
1692
+ # endif
1664
1693
1665
1694
// Check if the next set of stack ids is the same (since the Calls vector
1666
1695
// of tuples is sorted by the stack ids we can just look at the next one).
1696
+ // If so, save them in the CallToMatchingCall map so that they get
1697
+ // assigned to the same context node, and skip them.
1667
1698
bool DuplicateContextIds = false ;
1668
- if ( I + 1 < Calls.size ()) {
1669
- auto &CallCtxInfo = Calls[I + 1 ];
1699
+ for ( unsigned J = I + 1 ; J < Calls.size (); J++ ) {
1700
+ auto &CallCtxInfo = Calls[J ];
1670
1701
auto &NextIds = CallCtxInfo.StackIds ;
1671
- DuplicateContextIds = Ids == NextIds;
1702
+ if (NextIds != Ids)
1703
+ break ;
1704
+ auto *NextFunc = CallCtxInfo.Func ;
1705
+ if (NextFunc != Func) {
1706
+ // We have another Call with the same ids but that cannot share this
1707
+ // node, must duplicate ids for it.
1708
+ DuplicateContextIds = true ;
1709
+ break ;
1710
+ }
1711
+ auto &NextCall = CallCtxInfo.Call ;
1712
+ CallToMatchingCall[NextCall] = Call;
1713
+ // Update I so that it gets incremented correctly to skip this call.
1714
+ I = J;
1672
1715
}
1673
1716
1674
1717
// If we don't have duplicate context ids, then we can assign all the
@@ -1692,14 +1735,7 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::updateStackNodes() {
1692
1735
set_subtract (LastNodeContextIds, StackSequenceContextIds);
1693
1736
if (LastNodeContextIds.empty ())
1694
1737
break ;
1695
- // No longer possibly in a sequence of calls with duplicate stack ids,
1696
- // clear the map.
1697
- FuncToCallMap.clear ();
1698
- } else
1699
- // Record the call with its function, so we can locate it the next time
1700
- // we find a call from this function when processing the calls with the
1701
- // same stack ids.
1702
- FuncToCallMap[Func] = Call;
1738
+ }
1703
1739
}
1704
1740
}
1705
1741
0 commit comments