Skip to content

Commit 7388b6c

Browse files
authored
Merge pull request #28556 from atrick/escape-valueescapes
2 parents 0dc8e06 + b8d901b commit 7388b6c

File tree

3 files changed

+56
-38
lines changed

3 files changed

+56
-38
lines changed

include/swift/SILOptimizer/Analysis/EscapeAnalysis.h

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,19 @@ class EscapeAnalysis : public BottomUpIPAnalysis {
243243
struct CGNodeWorklist;
244244

245245
/// The int-part is an EdgeType and specifies which kind of predecessor it is.
246-
typedef llvm::PointerIntPair<CGNode *, 1> Predecessor;
246+
struct Predecessor {
247+
llvm::PointerIntPair<CGNode *, 1> predAndEdgeType;
248+
249+
Predecessor(CGNode *predNode, EdgeType ty)
250+
: predAndEdgeType(predNode, ty) {}
251+
bool operator==(const Predecessor &pred) {
252+
return predAndEdgeType == pred.predAndEdgeType;
253+
}
254+
255+
bool is(EdgeType ty) const { return predAndEdgeType.getInt() == ty; }
256+
257+
CGNode *getPredNode() const { return predAndEdgeType.getPointer(); }
258+
};
247259

248260
public:
249261

@@ -473,23 +485,36 @@ class EscapeAnalysis : public BottomUpIPAnalysis {
473485
/// Returns true if the node's value escapes within the function. This
474486
/// means that any unidentified pointer in the function may alias to
475487
/// the node's value.
488+
///
476489
/// Note that in the false-case the node's value can still escape via
477490
/// the return instruction.
478491
///
479492
/// \p nodeValue is often the same as 'this->getRepValue().getValue()', but
480493
/// is sometimes a more refined value specific to a content nodes.
481-
bool escapesInsideFunction(SILValue nodeValue) const {
494+
bool valueEscapesInsideFunction(SILValue nodeValue) const {
482495
switch (getEscapeState()) {
483496
case EscapeState::None:
484497
case EscapeState::Return:
485498
return false;
486499
case EscapeState::Arguments:
487-
return !isExclusiveArgument(nodeValue);
500+
return !nodeValue || !isExclusiveArgument(nodeValue);
488501
case EscapeState::Global:
489502
return true;
490503
}
491504
llvm_unreachable("Unhandled EscapeState in switch.");
492505
}
506+
/// Returns true if the node's value escapes within the function.
507+
///
508+
/// This is a more conservative variant of valueEscapesInsideFunction, for
509+
/// when the value being accessed is unknown. For content nodes, the node's
510+
/// value cannot be used because it arbitrarily takes on one of the values
511+
/// associated with the content. e.g. if that value is an exclusive
512+
/// argument, it would be incorrect to assume all values for that content
513+
/// are exclusive.
514+
bool escapesInsideFunction() const {
515+
SILValue nodeValue = isContent() ? SILValue() : SILValue(mappedValue);
516+
return valueEscapesInsideFunction(nodeValue);
517+
}
493518

494519
/// Returns the content node of this node if it exists in the graph.
495520
CGNode *getContentNodeOrNull() const {
@@ -598,12 +623,6 @@ class EscapeAnalysis : public BottomUpIPAnalysis {
598623
return Node;
599624
}
600625

601-
/// Adds a defer-edge and updates pointsTo of all defer-reachable nodes.
602-
/// The addition of a defer-edge may invalidate the graph invariance 4).
603-
/// If this is the case, all "mismatching" Content nodes are merged until
604-
/// invariance 4) is reached again.
605-
bool addDeferEdge(CGNode *From, CGNode *To);
606-
607626
/// Adds the node \p From (to be merged with \p To) to the ToMerge list.
608627
/// The actual merging is done in mergeAllScheduledNodes().
609628
void scheduleToMerge(CGNode *From, CGNode *To) {
@@ -837,6 +856,7 @@ class EscapeAnalysis : public BottomUpIPAnalysis {
837856
friend class EscapeAnalysis;
838857
friend struct CGNodeWorklist;
839858
};
859+
using Traversal = ConnectionGraph::Traversal;
840860

841861
private:
842862

@@ -1053,9 +1073,9 @@ class EscapeAnalysis : public BottomUpIPAnalysis {
10531073

10541074
/// Returns true if the pointers \p V1 and \p V2 can possibly point to the
10551075
/// same memory.
1076+
///
10561077
/// If at least one of the pointers refers to a local object and the
10571078
/// connection-graph-nodes of both pointers do not point to the same content
1058-
/// node, the pointers do not alias.
10591079
bool canPointToSameMemory(SILValue V1, SILValue V2);
10601080

10611081
/// Invalidate all information in this analysis.

lib/SILOptimizer/Analysis/EscapeAnalysis.cpp

Lines changed: 24 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -336,11 +336,11 @@ std::pair<const CGNode *, unsigned> EscapeAnalysis::CGNode::getRepNode(
336336
return {this, 0};
337337

338338
for (Predecessor pred : Preds) {
339-
if (pred.getInt() != EdgeType::PointsTo)
339+
if (!pred.is(EdgeType::PointsTo))
340340
continue;
341-
if (!visited.insert(pred.getPointer()).second)
341+
if (!visited.insert(pred.getPredNode()).second)
342342
continue;
343-
auto repNodeAndDepth = pred.getPointer()->getRepNode(visited);
343+
auto repNodeAndDepth = pred.getPredNode()->getRepNode(visited);
344344
if (repNodeAndDepth.first)
345345
return {repNodeAndDepth.first, repNodeAndDepth.second + 1};
346346
// If a representative node was not found on this pointsTo node, recursion
@@ -390,9 +390,9 @@ bool EscapeAnalysis::CGNode::visitSuccessors(Visitor &&visitor) const {
390390
template <typename Visitor>
391391
bool EscapeAnalysis::CGNode::visitDefers(Visitor &&visitor) const {
392392
for (Predecessor pred : Preds) {
393-
if (pred.getInt() != EdgeType::Defer)
393+
if (!pred.is(EdgeType::Defer))
394394
continue;
395-
if (!visitor(pred.getPointer(), false))
395+
if (!visitor(pred.getPredNode(), false))
396396
return false;
397397
}
398398
for (auto *deferred : defersTo) {
@@ -549,10 +549,10 @@ void EscapeAnalysis::ConnectionGraph::initializePointsTo(CGNode *initialNode,
549549
// distinguish these cases, always retry backward traversal--it just won't
550550
// revisit any edges in the later case.
551551
backwardTraverse(edgeNode, [&](Predecessor pred) {
552-
if (pred.getInt() != EdgeType::Defer)
552+
if (!pred.is(EdgeType::Defer))
553553
return Traversal::Backtrack;
554554

555-
CGNode *predNode = pred.getPointer();
555+
CGNode *predNode = pred.getPredNode();
556556
if (predNode->pointsTo) {
557557
assert(predNode->pointsTo->getMergeTarget() == newPointsTo);
558558
return Traversal::Backtrack;
@@ -608,8 +608,8 @@ void EscapeAnalysis::ConnectionGraph::mergeAllScheduledNodes() {
608608
// initializePointsTo(). By ensuring that 'From' is unreachable first, the
609609
// graph appears consistent during those operations.
610610
for (Predecessor Pred : From->Preds) {
611-
CGNode *PredNode = Pred.getPointer();
612-
if (Pred.getInt() == EdgeType::PointsTo) {
611+
CGNode *PredNode = Pred.getPredNode();
612+
if (Pred.is(EdgeType::PointsTo)) {
613613
assert(PredNode->getPointsToEdge() == From
614614
&& "Incoming pointsTo edge not set in predecessor");
615615
if (PredNode != From)
@@ -715,13 +715,13 @@ void EscapeAnalysis::ConnectionGraph::mergeAllScheduledNodes() {
715715
// pointsTo predecessors (which are now attached to 'To').
716716
for (unsigned PredIdx = 0; PredIdx < To->Preds.size(); ++PredIdx) {
717717
auto predEdge = To->Preds[PredIdx];
718-
if (predEdge.getInt() != EdgeType::PointsTo)
718+
if (!predEdge.is(EdgeType::PointsTo))
719719
continue;
720-
predEdge.getPointer()->visitDefers(
721-
[&](CGNode *deferred, bool /*isSucc*/) {
722-
mergePointsTo(deferred, To);
723-
return true;
724-
});
720+
predEdge.getPredNode()->visitDefers(
721+
[&](CGNode *deferred, bool /*isSucc*/) {
722+
mergePointsTo(deferred, To);
723+
return true;
724+
});
725725
}
726726
To->mergeEscapeState(From->State);
727727

@@ -1024,7 +1024,7 @@ bool EscapeAnalysis::ConnectionGraph::backwardTraverse(
10241024
for (Predecessor pred : reachingNode->Preds) {
10251025
switch (visitor(pred)) {
10261026
case Traversal::Follow: {
1027-
CGNode *predNode = pred.getPointer();
1027+
CGNode *predNode = pred.getPredNode();
10281028
worklist.tryPush(predNode);
10291029
break;
10301030
}
@@ -1073,7 +1073,7 @@ bool EscapeAnalysis::ConnectionGraph::mayReach(CGNode *pointer,
10731073

10741074
// This query is successful when the traversal halts and returns false.
10751075
return !backwardTraverse(pointee, [pointer](Predecessor pred) {
1076-
if (pred.getPointer() == pointer)
1076+
if (pred.getPredNode() == pointer)
10771077
return Traversal::Halt;
10781078
return Traversal::Follow;
10791079
});
@@ -1177,8 +1177,6 @@ std::string CGForDotView::getNodeLabel(const Node *Node) const {
11771177
std::string Label;
11781178
llvm::raw_string_ostream O(Label);
11791179
Node->OrigNode->getRepValue().print(O, InstToIDMap);
1180-
if (Node->OrigNode->Type == EscapeAnalysis::NodeType::Return)
1181-
O << "return";
11821180
O << '\n';
11831181
if (Node->OrigNode->mappedValue) {
11841182
std::string Inst;
@@ -1503,11 +1501,11 @@ void EscapeAnalysis::ConnectionGraph::verifyStructure(bool allowMerge) const {
15031501
}
15041502
// Check if predecessor and successor edges are linked correctly.
15051503
for (Predecessor Pred : Nd->Preds) {
1506-
CGNode *PredNode = Pred.getPointer();
1507-
if (Pred.getInt() == EdgeType::Defer) {
1504+
CGNode *PredNode = Pred.getPredNode();
1505+
if (Pred.is(EdgeType::Defer)) {
15081506
assert(PredNode->findDeferred(Nd) != PredNode->defersTo.end());
15091507
} else {
1510-
assert(Pred.getInt() == EdgeType::PointsTo);
1508+
assert(Pred.is(EdgeType::PointsTo));
15111509
assert(PredNode->getPointsToEdge() == Nd);
15121510
}
15131511
}
@@ -2349,7 +2347,7 @@ bool EscapeAnalysis::canEscapeToUsePoint(SILValue V, SILNode *UsePoint,
23492347

23502348
// First check if there are escape paths which we don't explicitly see
23512349
// in the graph.
2352-
if (Node->escapesInsideFunction(V))
2350+
if (Node->valueEscapesInsideFunction(V))
23532351
return true;
23542352

23552353
// No hidden escapes: check if the Node is reachable from the UsePoint.
@@ -2369,7 +2367,7 @@ bool EscapeAnalysis::canEscapeToUsePoint(SILValue V, SILNode *UsePoint,
23692367
// As V1's content node is the same as V's content node, we also make the
23702368
// check for the content node.
23712369
CGNode *ContentNode = getValueContent(ConGraph, V);
2372-
if (ContentNode->escapesInsideFunction(V))
2370+
if (ContentNode->valueEscapesInsideFunction(V))
23732371
return true;
23742372

23752373
if (ConGraph->isUsePoint(UsePoint, ContentNode))
@@ -2450,10 +2448,10 @@ bool EscapeAnalysis::canPointToSameMemory(SILValue V1, SILValue V2) {
24502448
return true;
24512449

24522450
// Finish the check for one value being a non-escaping local object.
2453-
if (isUniq1 && Node1->escapesInsideFunction(V1))
2451+
if (isUniq1 && Node1->valueEscapesInsideFunction(V1))
24542452
isUniq1 = false;
24552453

2456-
if (isUniq2 && Node2->escapesInsideFunction(V2))
2454+
if (isUniq2 && Node2->valueEscapesInsideFunction(V2))
24572455
isUniq2 = false;
24582456

24592457
if (!isUniq1 && !isUniq2)

test/SILOptimizer/basic-aa.sil

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,12 +110,12 @@ bb1(%1 : $*Builtin.NativeObject, %2 : $*Builtin.NativeObject):
110110

111111
// Assume that inout arguments alias to preserve memory safety.
112112
//
113-
// CHECK-LABEL: @inout_args_may_alias
113+
// CHECK-LABEL: @inout_args_may_not_alias
114114
// CHECK: PAIR #1.
115115
// CHECK-NEXT: %0 = argument of bb0
116116
// CHECK-NEXT: %1 = argument of bb0
117117
// CHECK-NEXT: NoAlias
118-
sil @inout_args_may_alias: $@convention(thin) (@inout Builtin.NativeObject, @inout Builtin.NativeObject) -> () {
118+
sil @inout_args_may_not_alias: $@convention(thin) (@inout Builtin.NativeObject, @inout Builtin.NativeObject) -> () {
119119
bb0(%0 : $*Builtin.NativeObject, %1 : $*Builtin.NativeObject):
120120
%2 = tuple()
121121
return %2 : $()

0 commit comments

Comments
 (0)