Skip to content

Commit 9c04d33

Browse files
authored
Merge pull request swiftlang#28404 from atrick/fix-escape-ispointer
EscapeAnalysis: eliminate dangling pointers.
2 parents 3ff6c1c + 191f9db commit 9c04d33

File tree

4 files changed

+539
-402
lines changed

4 files changed

+539
-402
lines changed

include/swift/SILOptimizer/Analysis/EscapeAnalysis.h

Lines changed: 46 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -252,16 +252,18 @@ class EscapeAnalysis : public BottomUpIPAnalysis {
252252
/// pointer points to (see NodeType).
253253
class CGNode {
254254

255-
/// The associated value in the function. This is always valid for Argument
256-
/// and Value nodes, and always nullptr for Return nodes. For Content nodes,
257-
/// i is only used for debug printing. A Content's value 'V' is unreliable
258-
/// because it can change as a result of the order the the graph is
259-
/// constructed and summary graphs are merged. Sometimes it is derived from
260-
/// the instructions that access the content, other times, it's simply
261-
/// inherited from its parent. There may be multiple nodes associated to the
262-
/// same value, e.g. a Content node has the same V as its points-to
263-
/// predecessor.
264-
ValueBase *V;
255+
/// The associated value in the function. This is only valid for nodes that
256+
/// are mapped to a value in the graph's Values2Nodes map. Multiple values
257+
/// may be mapped to the same node, but only one value is associated with
258+
/// the node via 'mappedValue'. Setting 'mappedValue' to a valid SILValue
259+
/// for an unmapped node would result in a dangling pointer when the
260+
/// SILValue is deleted.
261+
///
262+
/// Argument and Value nodes are always initially mapped, but may become
263+
/// unmapped when their SILValue is deleted. Content nodes are conditionally
264+
/// mapped, only if they are associated with an explicit dereference in the
265+
/// code (which has not been deleted). Return nodes are never mapped.
266+
ValueBase *mappedValue;
265267

266268
/// The outgoing points-to edge (if any) to a Content node. See also:
267269
/// pointsToIsEdge.
@@ -317,7 +319,7 @@ class EscapeAnalysis : public BottomUpIPAnalysis {
317319

318320
/// The constructor.
319321
CGNode(ValueBase *V, NodeType Type, bool hasRC)
320-
: V(V), UsePoints(0), hasRC(hasRC), Type(Type) {
322+
: mappedValue(V), UsePoints(0), hasRC(hasRC), Type(Type) {
321323
switch (Type) {
322324
case NodeType::Argument:
323325
case NodeType::Value:
@@ -333,6 +335,11 @@ class EscapeAnalysis : public BottomUpIPAnalysis {
333335
}
334336
}
335337

338+
/// Get the representative node that maps to a SILValue and depth in the
339+
/// pointsTo graph.
340+
std::pair<const CGNode *, unsigned>
341+
getRepNode(SmallPtrSetImpl<const CGNode *> &visited) const;
342+
336343
/// Merges the use points from another node and returns true if there are
337344
/// any changes.
338345
bool mergeUsePoints(CGNode *RHS) {
@@ -417,24 +424,28 @@ class EscapeAnalysis : public BottomUpIPAnalysis {
417424
friend struct CGNodeWorklist;
418425

419426
public:
420-
SILValue getValue() const {
421-
assert(Type == NodeType::Argument || Type == NodeType::Value);
422-
return V;
423-
}
424-
SILValue getValueOrNull() const { return V; }
425-
426-
void updateValue(SILValue newValue) {
427-
assert(isContent());
428-
V = newValue;
429-
}
427+
struct RepValue {
428+
// May only be an invalid SILValue for Return nodes or deleted values.
429+
llvm::PointerIntPair<SILValue, 1, bool> valueAndIsReturn;
430+
unsigned depth;
431+
432+
SILValue getValue() const { return valueAndIsReturn.getPointer(); }
433+
bool isReturn() const { return valueAndIsReturn.getInt(); }
434+
void
435+
print(llvm::raw_ostream &stream,
436+
const llvm::DenseMap<const SILNode *, unsigned> &instToIDMap) const;
437+
};
438+
// Get the representative SILValue for this node its depth relative to the
439+
// node that is mapped to this value.
440+
RepValue getRepValue() const;
430441

431442
/// Return true if this node represents content.
432443
bool isContent() const { return Type == NodeType::Content; }
433444

434445
/// Return true if this node represents an entire reference counted object.
435446
bool hasRefCount() const { return hasRC; }
436447

437-
void setRefCount() { hasRC = true; }
448+
void setRefCount(bool rc) { hasRC = rc; }
438449

439450
/// Returns the escape state.
440451
EscapeState getEscapeState() const { return State; }
@@ -465,9 +476,8 @@ class EscapeAnalysis : public BottomUpIPAnalysis {
465476
/// Note that in the false-case the node's value can still escape via
466477
/// the return instruction.
467478
///
468-
/// \p nodeValue is often the same as 'this->V', but is sometimes a more
469-
/// refined value. For content nodes, 'this->V' is only a placeholder that
470-
/// does not necessarilly represent the node's memory.
479+
/// \p nodeValue is often the same as 'this->getRepValue().getValue()', but
480+
/// is sometimes a more refined value specific to a content nodes.
471481
bool escapesInsideFunction(SILValue nodeValue) const {
472482
switch (getEscapeState()) {
473483
case EscapeState::None:
@@ -478,7 +488,6 @@ class EscapeAnalysis : public BottomUpIPAnalysis {
478488
case EscapeState::Global:
479489
return true;
480490
}
481-
482491
llvm_unreachable("Unhandled EscapeState in switch.");
483492
}
484493

@@ -644,10 +653,9 @@ class EscapeAnalysis : public BottomUpIPAnalysis {
644653
/// Returns null, if V is not a "pointer".
645654
CGNode *getNode(ValueBase *V, bool createIfNeeded = true);
646655

647-
/// Helper to create a content node and update the pointsTo graph. \p
648-
/// addrNode will point to the new content node. The new content node is
649-
/// directly initialized with the remaining function arguments.
650-
CGNode *createContentNode(CGNode *addrNode, SILValue addrVal, bool hasRC);
656+
/// Helper to create and return a content node with the given \p hasRC
657+
/// flag. \p addrNode will gain a points-to edge to the new content node.
658+
CGNode *createContentNode(CGNode *addrNode, bool hasRC);
651659

652660
/// Create a new content node based on an existing content node to support
653661
/// graph merging.
@@ -687,6 +695,8 @@ class EscapeAnalysis : public BottomUpIPAnalysis {
687695
void setNode(ValueBase *V, CGNode *Node) {
688696
assert(Values2Nodes.find(V) == Values2Nodes.end());
689697
Values2Nodes[V] = Node;
698+
if (!Node->mappedValue)
699+
Node->mappedValue = V;
690700
}
691701

692702
/// Adds an argument/instruction in which the node's value is used.
@@ -707,7 +717,7 @@ class EscapeAnalysis : public BottomUpIPAnalysis {
707717
void escapeContentsOf(CGNode *Node) {
708718
CGNode *escapedContent = Node->getContentNodeOrNull();
709719
if (!escapedContent) {
710-
escapedContent = createContentNode(Node, Node->V, /*hasRC=*/false);
720+
escapedContent = createContentNode(Node, /*hasRC=*/false);
711721
}
712722
escapedContent->markEscaping();
713723
}
@@ -736,10 +746,10 @@ class EscapeAnalysis : public BottomUpIPAnalysis {
736746
/// Propagates the escape states through the graph.
737747
void propagateEscapeStates();
738748

739-
/// Removes a value from the graph.
740-
/// It does not delete its node but makes sure that the value cannot be
741-
/// lookup-up with getNode() anymore.
742-
void removeFromGraph(ValueBase *V) { Values2Nodes.erase(V); }
749+
/// Remove a value from the graph. Do not delete the mapped node, but reset
750+
/// mappedValue if it is set to this value, and make sure that the node
751+
/// cannot be looked up with getNode().
752+
void removeFromGraph(ValueBase *V);
743753

744754
enum class Traversal { Follow, Backtrack, Halt };
745755

@@ -821,7 +831,7 @@ class EscapeAnalysis : public BottomUpIPAnalysis {
821831

822832
/// Just verifies the graph structure. This function can also be called
823833
/// during the graph is modified, e.g. in mergeAllScheduledNodes().
824-
void verifyStructure() const;
834+
void verifyStructure(bool allowMerge = false) const;
825835

826836
friend struct ::CGForDotView;
827837
friend class EscapeAnalysis;

0 commit comments

Comments
 (0)