@@ -117,10 +117,9 @@ static bool mayContainReference(SILType Ty, const SILFunction &F) {
117
117
118
118
// Returns true if the type \p Ty must be a reference or must transitively
119
119
// contain a reference. If \p Ty is itself an address, return false.
120
- // Will be used in a subsequent commit.
121
- // static bool mustContainReference(SILType Ty, const SILFunction &F) {
122
- // return findRecursiveRefType(Ty, F, true);
123
- // }
120
+ static bool mustContainReference (SILType Ty, const SILFunction &F) {
121
+ return findRecursiveRefType (Ty, F, true );
122
+ }
124
123
125
124
bool EscapeAnalysis::isPointer (ValueBase *V) const {
126
125
auto *F = V->getFunction ();
@@ -334,6 +333,15 @@ class EscapeAnalysis::CGNodeMap {
334
333
void EscapeAnalysis::CGNode::mergeProperties (CGNode *fromNode) {
335
334
if (!V)
336
335
V = fromNode->V ;
336
+
337
+ // TODO: Optimistically merge hasRC. 'this' node can only be merged with
338
+ // `fromNode` if their pointer values are compatible. If `fromNode->hasRC` is
339
+ // true, then it is guaranteed to represent the head of a heap object. Thus,
340
+ // it can only be merged with 'this' when the pointer values that access
341
+ // 'this' are also references.
342
+ //
343
+ // For now, this is pessimistic until we understand performance implications.
344
+ hasRC &= fromNode->hasRC ;
337
345
}
338
346
339
347
template <typename Visitor>
@@ -842,8 +850,9 @@ void EscapeAnalysis::ConnectionGraph::computeUsePoints() {
842
850
}
843
851
844
852
CGNode *EscapeAnalysis::ConnectionGraph::createContentNode (CGNode *addrNode,
845
- SILValue addrVal) {
846
- CGNode *newContent = allocNode (addrVal, NodeType::Content);
853
+ SILValue addrVal,
854
+ bool hasRC) {
855
+ CGNode *newContent = allocNode (addrVal, NodeType::Content, hasRC);
847
856
initializePointsToEdge (addrNode, newContent);
848
857
assert (ToMerge.empty ()
849
858
&& " Initially setting pointsTo should not require any node merges" );
@@ -860,7 +869,7 @@ EscapeAnalysis::ConnectionGraph::createMergedContent(CGNode *destAddrNode,
860
869
// on the source content.
861
870
//
862
871
// TODO: node properties will come from `srcContent` here...
863
- return createContentNode (destAddrNode, destAddrNode->V );
872
+ return createContentNode (destAddrNode, destAddrNode->V , srcContent-> hasRC );
864
873
}
865
874
866
875
// Get a node representing the field data within the given reference-counted
@@ -872,7 +881,7 @@ CGNode *EscapeAnalysis::ConnectionGraph::getFieldContent(CGNode *rcNode) {
872
881
if (rcNode->pointsTo )
873
882
return rcNode->pointsTo ;
874
883
875
- return createContentNode (rcNode, rcNode->V );
884
+ return createContentNode (rcNode, rcNode->V , /* hasRC= */ false );
876
885
}
877
886
878
887
bool EscapeAnalysis::ConnectionGraph::mergeFrom (ConnectionGraph *SourceGraph,
@@ -1140,6 +1149,8 @@ std::string CGForDotView::getNodeLabel(const Node *Node) const {
1140
1149
1141
1150
switch (Node->OrigNode ->Type ) {
1142
1151
case swift::EscapeAnalysis::NodeType::Content:
1152
+ if (Node->OrigNode ->hasRefCount ())
1153
+ O << " rc-" ;
1143
1154
O << " content" ;
1144
1155
break ;
1145
1156
case swift::EscapeAnalysis::NodeType::Return:
@@ -1177,7 +1188,11 @@ std::string CGForDotView::getNodeAttributes(const Node *Node) const {
1177
1188
std::string attr;
1178
1189
switch (Orig->Type ) {
1179
1190
case swift::EscapeAnalysis::NodeType::Content:
1180
- attr = " style=\" rounded\" " ;
1191
+ attr = " style=\" rounded" ;
1192
+ if (Orig->hasRefCount ()) {
1193
+ attr += " ,filled" ;
1194
+ }
1195
+ attr += " \" " ;
1181
1196
break ;
1182
1197
case swift::EscapeAnalysis::NodeType::Argument:
1183
1198
case swift::EscapeAnalysis::NodeType::Return:
@@ -1296,6 +1311,9 @@ void EscapeAnalysis::ConnectionGraph::dumpCG() const {
1296
1311
1297
1312
void EscapeAnalysis::CGNode::dump () const {
1298
1313
llvm::errs () << getTypeStr ();
1314
+ if (hasRefCount ())
1315
+ llvm::errs () << " [rc]" ;
1316
+
1299
1317
if (V)
1300
1318
llvm::errs () << " : " << *V;
1301
1319
else
@@ -1406,6 +1424,9 @@ void EscapeAnalysis::ConnectionGraph::print(llvm::raw_ostream &OS) const {
1406
1424
OS << Separator << NodeStr (Def);
1407
1425
Separator = " , " ;
1408
1426
}
1427
+ if (Nd->hasRefCount ())
1428
+ OS << " [rc]" ;
1429
+
1409
1430
OS << ' \n ' ;
1410
1431
}
1411
1432
OS << " End\n " ;
@@ -1439,6 +1460,10 @@ void EscapeAnalysis::ConnectionGraph::verify(bool allowMerge) const {
1439
1460
// which consist of only defer-edges and a single trailing points-to edge
1440
1461
// must lead to the same
1441
1462
assert (Nd->matchPointToOfDefers (allowMerge));
1463
+ if (Nd->isContent () && Nd->V ) {
1464
+ if (Nd->hasRefCount ())
1465
+ assert (mayContainReference (Nd->V ->getType (), *F));
1466
+ }
1442
1467
}
1443
1468
#endif
1444
1469
}
@@ -1522,15 +1547,26 @@ EscapeAnalysis::getValueContent(ConnectionGraph *conGraph, SILValue addrVal) {
1522
1547
assert (isPointer (addrNodeValue));
1523
1548
assert (addrNodeValue == getPointerRoot (addrVal));
1524
1549
}
1550
+ auto *F = addrVal->getFunction ();
1551
+ bool hasRC = mustContainReference (baseAddr->getType (), *F)
1552
+ || mustContainReference (addrVal->getType (), *F);
1553
+
1525
1554
// Have we already merged a content node?
1526
1555
if (CGNode *content = addrNode->getContentNodeOrNull ()) {
1527
- // TODO: Merge node properties here.
1556
+ // hasRC might not match if one of the values pointing to this content was
1557
+ // cast to an unknown type. If any of the types must contain a reference,
1558
+ // then the content should contain a reference.
1559
+ if (content->hasRefCount ())
1560
+ assert (mayContainReference (baseAddr->getType (), *F));
1561
+ else if (hasRC)
1562
+ content->setRefCount ();
1563
+
1528
1564
return content;
1529
1565
}
1530
1566
if (!isPointer (baseAddr))
1531
1567
return nullptr ;
1532
1568
1533
- return conGraph->createContentNode (addrNode, baseAddr);
1569
+ return conGraph->createContentNode (addrNode, baseAddr, hasRC );
1534
1570
}
1535
1571
1536
1572
void EscapeAnalysis::buildConnectionGraph (FunctionInfo *FInfo,
@@ -1737,8 +1773,11 @@ void EscapeAnalysis::analyzeInstruction(SILInstruction *I,
1737
1773
CGNode *ArrayRefNode = ArrayStructValue->getContentNodeOrNull ();
1738
1774
if (!ArrayRefNode) {
1739
1775
ArrayRefNode = ConGraph->createContentNode (
1740
- ArrayStructValue, ArrayStructValue->getValueOrNull ());
1741
- }
1776
+ ArrayStructValue, ArrayStructValue->getValueOrNull (),
1777
+ /* hasRC=*/ true );
1778
+ } else
1779
+ ArrayRefNode->setRefCount ();
1780
+
1742
1781
// Another content node for the element storage.
1743
1782
CGNode *ArrayElementStorage = ConGraph->getFieldContent (ArrayRefNode);
1744
1783
ArrayElementStorage->markEscaping ();
@@ -1868,6 +1907,9 @@ void EscapeAnalysis::analyzeInstruction(SILInstruction *I,
1868
1907
if (!rcContent)
1869
1908
return ;
1870
1909
1910
+ // rcContent->hasRefCount() may or may not be true depending on whether
1911
+ // the type could be analyzed. Either way, treat it structurally like a
1912
+ // refcounted object.
1871
1913
CGNode *fieldContent = ConGraph->getFieldContent (rcContent);
1872
1914
if (!deinitIsKnownToNotCapture (OpV)) {
1873
1915
fieldContent->markEscaping ();
0 commit comments