@@ -403,17 +403,7 @@ class EscapeAnalysis : public BottomUpIPAnalysis {
403
403
404
404
// / Checks an invariant of the connection graph: The points-to nodes of
405
405
// / the defer-successors must match with the points-to of this node.
406
- bool matchPointToOfDefers () const {
407
- for (CGNode *Def : defersTo) {
408
- if (pointsTo != Def->pointsTo )
409
- return false ;
410
- }
411
- // / A defer-path in the graph must not end without the specified points-to
412
- // / node.
413
- if (pointsTo && !pointsToIsEdge && defersTo.empty ())
414
- return false ;
415
- return true ;
416
- }
406
+ bool matchPointToOfDefers (bool allowMerge = false ) const ;
417
407
418
408
friend class CGNodeMap ;
419
409
friend class ConnectionGraph ;
@@ -480,7 +470,7 @@ class EscapeAnalysis : public BottomUpIPAnalysis {
480
470
llvm_unreachable (" Unhandled EscapeState in switch." );
481
471
}
482
472
483
- // / Returns the content node if of this node if it exists in the graph.
473
+ // / Returns the content node of this node if it exists in the graph.
484
474
CGNode *getContentNodeOrNull () const {
485
475
return pointsTo;
486
476
}
@@ -603,14 +593,25 @@ class EscapeAnalysis : public BottomUpIPAnalysis {
603
593
}
604
594
}
605
595
596
+ // / Initialize the 'pointsTo' fields of all nodes in the defer web of \p
597
+ // / initialiNode.
598
+ // /
599
+ // / If \p createEdge is true, a proper pointsTo edge will be created from \p
600
+ // / initialNode to \p pointsTo.
601
+ void initializePointsTo (CGNode *initialNode, CGNode *newPointsTo,
602
+ bool createEdge = false );
603
+
604
+ void initializePointsToEdge (CGNode *initialNode, CGNode *newPointsTo) {
605
+ initializePointsTo (initialNode, newPointsTo, true );
606
+ }
607
+
606
608
// / Merges all nodes which are added to the ToMerge list.
607
609
void mergeAllScheduledNodes ();
608
610
609
- // / Transitively updates pointsTo of all nodes in the defer-edge web,
610
- // / starting at \p InitialNode.
611
- // / If a node in the web already points to another content node, the other
612
- // / content node is scheduled to be merged with \p pointsTo.
613
- void updatePointsTo (CGNode *InitialNode, CGNode *pointsTo);
611
+ // / Transitively update pointsTo of all nodes in the defer-edge web,
612
+ // / reaching and reachable from \p initialNode. All nodes in this defer web
613
+ // / must already have an initialized `pointsTo`.
614
+ void mergePointsTo (CGNode *initialNode, CGNode *pointsTo);
614
615
615
616
// / Utility function to clear the isInWorkList flags of all nodes in
616
617
// / \p WorkList.
@@ -627,12 +628,20 @@ class EscapeAnalysis : public BottomUpIPAnalysis {
627
628
// / Returns null, if V is not a "pointer".
628
629
CGNode *getNode (ValueBase *V, bool createIfNeeded = true );
629
630
630
- // / Gets or creates a content node to which \a AddrNode points to during
631
- // / initial graph construction. This may not be called after defer edges
632
- // / have been created. Doing so would break the invariant that all
633
- // / non-content nodes ultimately have a pointsTo edge to a single content
634
- // / node.
635
- CGNode *getContentNode (CGNode *AddrNode);
631
+ // / Helper to create a content node and update the pointsTo graph. \p
632
+ // / addrNode will point to the new content node. The new content node is
633
+ // / directly initialized with the remaining function arguments.
634
+ CGNode *createContentNode (CGNode *addrNode, SILValue addrVal);
635
+
636
+ // / Create a new content node based on an existing content node to support
637
+ // / graph merging.
638
+ // /
639
+ // / \p destAddrNode will point to to new content. The content's initial
640
+ // / state will be initialized based on the \p srcContent node.
641
+ CGNode *createMergedContent (CGNode *destAddrNode, CGNode *srcContent);
642
+
643
+ // / Get a node represnting the field data within the given RC node.
644
+ CGNode *getFieldContent (CGNode *rcNode);
636
645
637
646
// / Get or creates a pseudo node for the function return value.
638
647
CGNode *getReturnNode () {
@@ -679,31 +688,21 @@ class EscapeAnalysis : public BottomUpIPAnalysis {
679
688
return Idx;
680
689
}
681
690
682
- // / Specifies that the node's value escapes to global or unidentified
683
- // / memory.
684
- void setEscapesGlobal (CGNode *Node) {
685
- Node->mergeEscapeState (EscapeState::Global);
686
-
687
- // Make sure to have a content node. Otherwise we may end up not merging
688
- // the global-escape state into a caller graph (only content nodes are
689
- // merged). Either the node itself is a content node or we let the node
690
- // point to one.
691
- if (Node->Type != NodeType::Content)
692
- getContentNode (Node);
691
+ void escapeContentsOf (CGNode *Node) {
692
+ CGNode *escapedContent = Node->getContentNodeOrNull ();
693
+ if (!escapedContent) {
694
+ escapedContent = createContentNode (Node, Node->V );
695
+ }
696
+ escapedContent->markEscaping ();
693
697
}
694
698
695
699
// / Creates a defer-edge between \p From and \p To.
696
700
// / This may trigger node merges to keep the graph invariance 4).
697
701
// / Returns the \p From node or its merge-target in case \p From was merged
698
702
// / during adding the edge.
699
- // / The \p EdgeAdded is set to true if there was no defer-edge between
700
- // / \p From and \p To, yet.
701
- CGNode *defer (CGNode *From, CGNode *To, bool &EdgeAdded) {
702
- if (addDeferEdge (From, To))
703
- EdgeAdded = true ;
704
- mergeAllScheduledNodes ();
705
- return From->getMergeTarget ();
706
- }
703
+ // / \p Changed is set to true if a defer edge was added or any nodes were
704
+ // / merged.
705
+ CGNode *defer (CGNode *From, CGNode *To, bool &Changed);
707
706
708
707
// / Creates a defer-edge between \p From and \p To.
709
708
// / This may trigger node merges to keep the graph invariance 4).
@@ -802,7 +801,7 @@ class EscapeAnalysis : public BottomUpIPAnalysis {
802
801
void dumpCG () const ;
803
802
804
803
// / Checks if the graph is OK.
805
- void verify () const ;
804
+ void verify (bool allowMerge = false ) const ;
806
805
807
806
// / Just verifies the graph structure. This function can also be called
808
807
// / during the graph is modified, e.g. in mergeAllScheduledNodes().
@@ -889,9 +888,22 @@ class EscapeAnalysis : public BottomUpIPAnalysis {
889
888
SILValue getPointerRoot (SILValue value) const ;
890
889
891
890
// / If \p pointer is a pointer, set it to global escaping.
892
- void setEscapesGlobal (ConnectionGraph *ConGraph, ValueBase *pointer) {
893
- if (CGNode *Node = ConGraph->getNode (pointer))
894
- ConGraph->setEscapesGlobal (Node);
891
+ void setEscapesGlobal (ConnectionGraph *conGraph, ValueBase *pointer) {
892
+ CGNode *Node = conGraph->getNode (pointer);
893
+ if (!Node)
894
+ return ;
895
+
896
+ if (Node->isContent ()) {
897
+ Node->markEscaping ();
898
+ return ;
899
+ }
900
+ Node->mergeEscapeState (EscapeState::Global);
901
+
902
+ // Make sure to have a content node. Otherwise we may end up not merging
903
+ // the global-escape state into a caller graph (only content nodes are
904
+ // merged). Either the node itself is a content node or we let the node
905
+ // point to one.
906
+ conGraph->escapeContentsOf (Node);
895
907
}
896
908
897
909
// / Gets or creates FunctionEffects for \p F.
@@ -902,6 +914,15 @@ class EscapeAnalysis : public BottomUpIPAnalysis {
902
914
return FInfo;
903
915
}
904
916
917
+ // / Get or create the node representing the memory pointed to by \p
918
+ // / addrVal. If \p addrVal is an address, then return the content node for the
919
+ // / variable's memory. Otherwise, \p addrVal may contain a reference, so
920
+ // / return the content node for the referenced heap object.
921
+ // /
922
+ // / Note that \p addrVal cannot be an address within a heap object, such as
923
+ // / an address from ref_element_addr or project_box.
924
+ CGNode *getValueContent (ConnectionGraph *conGraph, SILValue addrVal);
925
+
905
926
// / Build a connection graph for reach callee from the callee list.
906
927
bool buildConnectionGraphForCallees (SILInstruction *Caller,
907
928
CalleeList Callees,
0 commit comments