Skip to content

Commit 84e1d7e

Browse files
authored
Merge pull request #28273 from atrick/escape-initializePointsTo
Cleanup EscapeAnalysis::ConnectionGraph::initializePointsTo.
2 parents 9a71f23 + e66e033 commit 84e1d7e

File tree

2 files changed

+147
-51
lines changed

2 files changed

+147
-51
lines changed

lib/SILOptimizer/Analysis/EscapeAnalysis.cpp

Lines changed: 27 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -456,24 +456,18 @@ void EscapeAnalysis::ConnectionGraph::initializePointsTo(CGNode *initialNode,
456456
CGNode *newPointsTo,
457457
bool createEdge) {
458458
// Track nodes that require pointsTo edges.
459-
llvm::SmallVector<CGNode *, 4> pointsToEdges;
459+
llvm::SmallVector<CGNode *, 4> pointsToEdgeNodes;
460+
if (createEdge)
461+
pointsToEdgeNodes.push_back(initialNode);
460462

461463
// Step 1: Visit each node that reaches or is reachable via defer edges until
462464
// reaching a node with the newPointsTo or with a proper pointsTo edge.
463465

464466
// A worklist to gather updated nodes in the defer web.
465467
CGNodeWorklist updatedNodes(this);
466-
updatedNodes.push(initialNode);
467-
if (createEdge)
468-
pointsToEdges.push_back(initialNode);
469-
unsigned updateCount = 1;
470-
assert(updateCount == updatedNodes.size());
471-
// Augment the worlist with the nodes that were reached via backward
472-
// traversal. It's not as precise as DFS, but helps avoid redundant pointsTo
473-
// edges in most cases.
474-
llvm::SmallPtrSet<CGNode *, 8> backwardReachable;
475-
476-
auto visitDeferTarget = [&](CGNode *node, bool isSuccessor) {
468+
unsigned updateCount = 0;
469+
470+
auto visitDeferTarget = [&](CGNode *node, bool /*isSuccessor*/) {
477471
if (updatedNodes.contains(node))
478472
return true;
479473

@@ -484,7 +478,7 @@ void EscapeAnalysis::ConnectionGraph::initializePointsTo(CGNode *initialNode,
484478
// nodes are initialized one at a time, each time a new defer edge is
485479
// created. If this were not complete, then the backward traversal below
486480
// in Step 2 could reach uninitialized nodes not seen here in Step 1.
487-
pointsToEdges.push_back(node);
481+
pointsToEdgeNodes.push_back(node);
488482
return true;
489483
}
490484
++updateCount;
@@ -493,31 +487,29 @@ void EscapeAnalysis::ConnectionGraph::initializePointsTo(CGNode *initialNode,
493487
// edge. Create a "fake" pointsTo edge to maintain the graph invariant
494488
// (this changes the structure of the graph but adding this edge has no
495489
// effect on the process of merging nodes or creating new defer edges).
496-
pointsToEdges.push_back(node);
490+
pointsToEdgeNodes.push_back(node);
497491
}
498492
updatedNodes.push(node);
499-
if (!isSuccessor)
500-
backwardReachable.insert(node);
501-
502493
return true;
503494
};
495+
// Seed updatedNodes with initialNode.
496+
visitDeferTarget(initialNode, true);
504497
// updatedNodes may grow during this loop.
505-
unsigned nextUpdatedNodeIdx = 0;
506-
for (; nextUpdatedNodeIdx < updatedNodes.size(); ++nextUpdatedNodeIdx)
507-
updatedNodes[nextUpdatedNodeIdx]->visitDefers(visitDeferTarget);
498+
for (unsigned idx = 0; idx < updatedNodes.size(); ++idx)
499+
updatedNodes[idx]->visitDefers(visitDeferTarget);
508500
// Reset this worklist so others can be used, but updateNode.nodeVector still
509501
// holds all the nodes found by step 1.
510502
updatedNodes.reset();
511503

512504
// Step 2: Update pointsTo fields by propagating backward from nodes that
513505
// already have a pointsTo edge.
514-
assert(nextUpdatedNodeIdx == updatedNodes.size());
515-
--nextUpdatedNodeIdx;
516-
bool processBackwardReachable = false;
517506
do {
518-
while (!pointsToEdges.empty()) {
519-
CGNode *edgeNode = pointsToEdges.pop_back_val();
507+
while (!pointsToEdgeNodes.empty()) {
508+
CGNode *edgeNode = pointsToEdgeNodes.pop_back_val();
520509
if (!edgeNode->pointsTo) {
510+
// This node is either (1) a leaf node in the defer web (identified in
511+
// step 1) or (2) an arbitrary node in a defer-cycle (identified in a
512+
// previous iteration of the outer loop).
521513
edgeNode->setPointsToEdge(newPointsTo);
522514
newPointsTo->mergeUsePoints(edgeNode);
523515
assert(updateCount--);
@@ -542,35 +534,19 @@ void EscapeAnalysis::ConnectionGraph::initializePointsTo(CGNode *initialNode,
542534
return Traversal::Follow;
543535
});
544536
}
545-
// For all nodes visited in step 1, if any node was not backward-reachable
546-
// from a pointsTo edge, create an edge for it and restart traversal.
547-
//
548-
// First process all forward-reachable nodes in backward order, then process
549-
// all backwardReachable nodes in forward order.
550-
while (nextUpdatedNodeIdx != updatedNodes.size()) {
551-
CGNode *node = updatedNodes[nextUpdatedNodeIdx];
552-
// When processBackwardReachable == true, the backwardReachable set is
553-
// empty and all forward reachable nodes already have a pointsTo edge.
554-
if (!backwardReachable.count(node)) {
555-
if (!node->pointsTo) {
556-
pointsToEdges.push_back(node);
557-
break;
558-
}
559-
}
560-
if (processBackwardReachable) {
561-
++nextUpdatedNodeIdx;
562-
continue;
563-
}
564-
if (nextUpdatedNodeIdx > 0) {
565-
--nextUpdatedNodeIdx;
566-
continue;
537+
// For all nodes visited in step 1, pick a single node that was not
538+
// backward-reachable from a pointsTo edge, create an edge for it and
539+
// restart traversal. This only happens when step 1 fails to find leaves in
540+
// the defer web because of defer edge cycles.
541+
while (!updatedNodes.empty()) {
542+
CGNode *node = updatedNodes.nodeVector.pop_back_val();
543+
if (!node->pointsTo) {
544+
pointsToEdgeNodes.push_back(node);
545+
break;
567546
}
568-
// reverse direction
569-
backwardReachable.clear();
570-
processBackwardReachable = true;
571547
}
572548
// This outer loop is exceedingly unlikely to execute more than twice.
573-
} while (!pointsToEdges.empty());
549+
} while (!pointsToEdgeNodes.empty());
574550
assert(updateCount == 0);
575551
}
576552

test/SILOptimizer/escape_analysis.sil

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1535,3 +1535,123 @@ bb0:
15351535
return %7 : $()
15361536
}
15371537

1538+
// Test the absence of redundant pointsTo edges
1539+
// CHECK-LABEL: CG of testInitializePointsToLeaf
1540+
// CHECK: Arg %0 Esc: A, Succ: (%0.1)
1541+
// CHECK: Con %0.1 Esc: A, Succ: (%0.2) [rc]
1542+
// CHECK: Con %0.2 Esc: A, Succ: (%12.1)
1543+
// CHECK: Val %2 Esc: %4, Succ: %0.2
1544+
// CHECK: Val %4 Esc: %4, Succ: %2
1545+
// CHECK: Val %7 Esc: %12, Succ: (%12.1), %0.2
1546+
// CHECK: Val %12 Esc: %12, Succ: (%12.1), %7
1547+
// CHECK: Con %12.1 Esc: A, Succ: (%13) [rc]
1548+
// CHECK: Con %13 Esc: A, Succ:
1549+
// CHECK-LABEL: End
1550+
class C {
1551+
var c: C
1552+
}
1553+
1554+
sil @testInitializePointsToWrapOptional : $@convention(method) (@guaranteed LinkedNode) -> Optional<LinkedNode> {
1555+
bb0(%0: $LinkedNode):
1556+
%adr = ref_element_addr %0 : $LinkedNode, #LinkedNode.next
1557+
%val = load %adr : $*LinkedNode
1558+
%optional = enum $Optional<LinkedNode>, #Optional.some!enumelt.1, %val : $LinkedNode
1559+
return %optional : $Optional<LinkedNode>
1560+
}
1561+
1562+
sil @testInitializePointsToLeaf : $@convention(method) (@guaranteed LinkedNode) -> () {
1563+
bb0(%0 : $LinkedNode):
1564+
%f1 = function_ref @testInitializePointsToWrapOptional : $@convention(method) (@guaranteed LinkedNode) -> Optional<LinkedNode>
1565+
%call1 = apply %f1(%0) : $@convention(method) (@guaranteed LinkedNode) -> Optional<LinkedNode>
1566+
switch_enum %call1 : $Optional<LinkedNode>, case #Optional.some!enumelt.1: bb2, case #Optional.none!enumelt: bb3
1567+
1568+
bb2(%arg1 : $LinkedNode):
1569+
br bb4
1570+
1571+
bb3:
1572+
br bb4
1573+
1574+
bb4:
1575+
%call2 = apply %f1(%0) : $@convention(method) (@guaranteed LinkedNode) -> Optional<LinkedNode>
1576+
switch_enum %call2 : $Optional<LinkedNode>, case #Optional.some!enumelt.1: bb10, case #Optional.none!enumelt: bb9
1577+
1578+
bb9:
1579+
%37 = integer_literal $Builtin.Int1, -1
1580+
cond_fail %37 : $Builtin.Int1, "Unexpectedly found nil while unwrapping an Optional value"
1581+
unreachable
1582+
1583+
// %40
1584+
bb10(%arg2 : $LinkedNode):
1585+
%adr = ref_element_addr %arg2 : $LinkedNode, #LinkedNode.next
1586+
%val = load %adr : $*LinkedNode
1587+
%66 = tuple ()
1588+
return %66 : $()
1589+
}
1590+
1591+
// Another test for redundant pointsTo edges. In the original
1592+
// implementation, redundant points edges were created whenever adding
1593+
// a defer edge from a node with uninitialized pointsTo to a node with
1594+
// already-initialized pointsTo.
1595+
// CHECK-LABEL: CG of testInitializePointsToRedundant
1596+
// CHECK: Arg %0 Esc: A, Succ: (%0.1)
1597+
// CHECK: Con %0.1 Esc: A, Succ: (%2) [rc]
1598+
// CHECK: Arg %1 Esc: A, Succ: (%0.1)
1599+
// CHECK: Con %2 Esc: A, Succ:
1600+
// CHECK: Val %7 Esc: %7,%18, Succ: %0
1601+
// CHECK: Val %12 Esc: %12,%14,%18, Succ: %1
1602+
// CHECK: Val %14 Esc: %18, Succ: (%0.1), %1, %12
1603+
// CHECK: Val %18 Esc: %18, Succ: %7, %14
1604+
// CHECK-LABEL: End
1605+
sil @testInitializePointsToMerge : $@convention(method) (@guaranteed C, @guaranteed C) -> C {
1606+
bb0(%0: $C, %1 : $C):
1607+
cond_br undef, bb1, bb2
1608+
1609+
bb1:
1610+
br bb3(%0 : $C)
1611+
1612+
bb2:
1613+
br bb3(%1 : $C)
1614+
1615+
bb3(%arg : $C):
1616+
return %arg : $C
1617+
}
1618+
1619+
sil @testInitializePointsToRedundant : $@convention(method) (@guaranteed C, @guaranteed C) -> () {
1620+
bb0(%0 : $C, %1 : $C):
1621+
%adr0 = ref_element_addr %0 : $C, #C.c
1622+
%val0 = load %adr0 : $*C
1623+
cond_br undef, bb1, bb2
1624+
1625+
bb1:
1626+
br bb3(%0 : $C)
1627+
1628+
bb2:
1629+
br bb3(%0 : $C)
1630+
1631+
bb3(%arg1 : $C):
1632+
br bb4
1633+
1634+
bb4:
1635+
cond_br undef, bb5, bb6
1636+
1637+
bb5:
1638+
br bb7(%1 : $C)
1639+
1640+
bb6:
1641+
br bb7(%1 : $C)
1642+
1643+
bb7(%arg2 : $C):
1644+
%f1 = function_ref @testInitializePointsToMerge : $@convention(method) (@guaranteed C, @guaranteed C) -> C
1645+
%call1 = apply %f1(%arg2, %1) : $@convention(method) (@guaranteed C, @guaranteed C) -> C
1646+
cond_br undef, bb8, bb9
1647+
1648+
bb8:
1649+
br bb10(%call1 : $C)
1650+
1651+
bb9:
1652+
br bb10(%arg1 : $C)
1653+
1654+
bb10(%arg3 : $C):
1655+
%66 = tuple ()
1656+
return %66 : $()
1657+
}

0 commit comments

Comments
 (0)