Skip to content

Commit 1654dd5

Browse files
committed
Cleanup EscapeAnalysis getNode and fix undef handling.
Consistently handle base and derived pointers. Consistently avoid creating nodes for undef, which breaks verification. Be more precise about creating the node based on the derived pointer type. Remove a few extraneous helpers. Fixes <rdar://58445744> swiftc assert during EscapeAnalysis verification: (EA->isPointer(Nd->mappedValue)), function verify
1 parent bd2bb2e commit 1654dd5

File tree

3 files changed

+87
-72
lines changed

3 files changed

+87
-72
lines changed

include/swift/SILOptimizer/Analysis/EscapeAnalysis.h

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -721,15 +721,12 @@ class EscapeAnalysis : public BottomUpIPAnalysis {
721721
}
722722
}
723723

724-
// Helper for getNode and getValueContent.
725-
CGNode *getOrCreateNode(ValueBase *V, PointerKind pointerKind);
726-
727724
/// Gets or creates a node for a value \p V.
728725
/// If V is a projection(-path) then the base of the projection(-path) is
729726
/// taken. This means the node is always created for the "outermost" value
730727
/// where V is contained.
731-
/// Returns null, if V is not a "pointer".
732-
CGNode *getNode(ValueBase *V, bool createIfNeeded = true);
728+
/// Returns null, if V (or its base value) is not a "pointer".
729+
CGNode *getNode(SILValue V);
733730

734731
// Helper for getValueContent to create and return a content node with the
735732
// given \p isInterior and \p hasReferenceOnly flags. \p addrNode
@@ -780,15 +777,6 @@ class EscapeAnalysis : public BottomUpIPAnalysis {
780777
return ReturnNode;
781778
}
782779

783-
/// Returns the node of the "exact" value \p V (no projections are skipped)
784-
/// if one exists.
785-
CGNode *lookupNode(ValueBase *V) {
786-
CGNode *Node = Values2Nodes.lookup(V);
787-
if (Node)
788-
return Node->getMergeTarget();
789-
return nullptr;
790-
}
791-
792780
/// Re-uses a node for another SIL value.
793781
void setNode(ValueBase *V, CGNode *Node) {
794782
assert(Values2Nodes.find(V) == Values2Nodes.end());
@@ -871,13 +859,6 @@ class EscapeAnalysis : public BottomUpIPAnalysis {
871859
bool forwardTraverseDefer(CGNode *startNode, CGNodeVisitor &&visitor);
872860

873861
public:
874-
/// Gets or creates a node for a value \p V.
875-
/// If V is a projection(-path) then the base of the projection(-path) is
876-
/// taken. This means the node is always created for the "outermost" value
877-
/// where V is contained.
878-
/// Returns null, if V is not a "pointer".
879-
CGNode *getNodeOrNull(ValueBase *V) { return getNode(V, false); }
880-
881862
/// Get the content node pointed to by \p ptrVal.
882863
///
883864
/// If \p ptrVal cannot be mapped to a node, return nullptr.

lib/SILOptimizer/Analysis/EscapeAnalysis.cpp

Lines changed: 55 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -389,47 +389,55 @@ void EscapeAnalysis::ConnectionGraph::clear() {
389389
assert(ToMerge.empty());
390390
}
391391

392+
// This never returns an interior node. It should never be called directly on an
393+
// address projection of a reference. To get the interior node for an address
394+
// projection, always ask for the content of the projection's base instead using
395+
// getValueContent() or getReferenceContent().
396+
//
397+
// Address phis are not allowed, so merging an unknown address with a reference
398+
// address projection is rare. If that happens, then the projection's node loses
399+
// it's interior property.
392400
EscapeAnalysis::CGNode *
393-
EscapeAnalysis::ConnectionGraph::getOrCreateNode(ValueBase *V,
394-
PointerKind pointerKind) {
395-
assert(pointerKind != EscapeAnalysis::NoPointer);
396-
401+
EscapeAnalysis::ConnectionGraph::getNode(SILValue V) {
402+
// Early filter obvious non-pointer opcodes.
397403
if (isa<FunctionRefInst>(V) || isa<DynamicFunctionRefInst>(V) ||
398404
isa<PreviousDynamicFunctionRefInst>(V))
399405
return nullptr;
400406

401-
CGNode * &Node = Values2Nodes[V];
402-
// Nodes mapped to values must have an indirect pointsTo. Nodes that don't
403-
// have an indirect pointsTo are imaginary nodes that don't directly represnt
404-
// a SIL value.
405-
bool hasReferenceOnly = canOnlyContainReferences(pointerKind);
406-
if (!Node) {
407-
if (isa<SILFunctionArgument>(V)) {
408-
Node = allocNode(V, NodeType::Argument, false, hasReferenceOnly);
409-
if (!isSummaryGraph)
410-
Node->mergeEscapeState(EscapeState::Arguments);
411-
} else {
412-
Node = allocNode(V, NodeType::Value, false, hasReferenceOnly);
413-
}
414-
}
415-
return Node->getMergeTarget();
416-
}
417-
418-
EscapeAnalysis::CGNode *
419-
EscapeAnalysis::ConnectionGraph::getNode(ValueBase *V, bool createIfNeeded) {
407+
// Create the node flags based on the derived value's kind. If the pointer
408+
// base type has non-reference pointers but they are never accessed in the
409+
// current function, then ignore them.
420410
PointerKind pointerKind = EA->getPointerKind(V);
421411
if (pointerKind == EscapeAnalysis::NoPointer)
422412
return nullptr;
423413

424414
// Look past address projections, pointer casts, and the like within the same
425415
// object. Does not look past a dereference such as ref_element_addr, or
426416
// project_box.
427-
V = EA->getPointerRoot(V);
417+
SILValue ptrBase = EA->getPointerRoot(V);
418+
// Do not create a node for undef values so we can verify that node values
419+
// have the correct pointer kind.
420+
if (!ptrBase->getFunction())
421+
return nullptr;
428422

429-
if (!createIfNeeded)
430-
return lookupNode(V);
423+
assert(EA->isPointer(ptrBase) &&
424+
"The base for derived pointer must also be a pointer type");
431425

432-
return getOrCreateNode(V, pointerKind);
426+
bool hasReferenceOnly = canOnlyContainReferences(pointerKind);
427+
// Update the value-to-node map.
428+
CGNode *&Node = Values2Nodes[ptrBase];
429+
if (Node) {
430+
CGNode *targetNode = Node->getMergeTarget();
431+
targetNode->mergeFlags(false /*isInterior*/, hasReferenceOnly);
432+
return targetNode;
433+
}
434+
if (isa<SILFunctionArgument>(ptrBase)) {
435+
Node = allocNode(ptrBase, NodeType::Argument, false, hasReferenceOnly);
436+
if (!isSummaryGraph)
437+
Node->mergeEscapeState(EscapeState::Arguments);
438+
} else
439+
Node = allocNode(ptrBase, NodeType::Value, false, hasReferenceOnly);
440+
return Node;
433441
}
434442

435443
/// Adds an argument/instruction in which the node's memory is released.
@@ -916,8 +924,8 @@ EscapeAnalysis::ConnectionGraph::getOrCreateAddressContent(SILValue addrVal,
916924

917925
bool contentHasReferenceOnly =
918926
EA->hasReferenceOnly(addrVal->getType().getObjectType(), *F);
919-
// Address content always has an indirect pointsTo (only reference content can
920-
// have a non-indirect pointsTo).
927+
// Address content is never an interior node (only reference content can
928+
// be an interior node).
921929
return getOrCreateContentNode(addrNode, false, contentHasReferenceOnly);
922930
}
923931

@@ -926,12 +934,14 @@ EscapeAnalysis::ConnectionGraph::getOrCreateAddressContent(SILValue addrVal,
926934
CGNode *
927935
EscapeAnalysis::ConnectionGraph::getOrCreateReferenceContent(SILValue refVal,
928936
CGNode *refNode) {
929-
// The object node points to internal fields. It neither has indirect pointsTo
930-
// nor reference-only pointsTo.
937+
// The object node created here points to internal fields. It neither has
938+
// indirect pointsTo nor reference-only pointsTo.
931939
CGNode *objNode = getOrCreateContentNode(refNode, true, false);
932940
if (!objNode->isInterior())
933941
return objNode;
934942

943+
// Determine whether the object that refVal refers to only contains
944+
// references.
935945
bool contentHasReferenceOnly = false;
936946
if (refVal) {
937947
SILType refType = refVal->getType();
@@ -972,24 +982,19 @@ EscapeAnalysis::ConnectionGraph::getOrCreateUnknownContent(CGNode *addrNode) {
972982
// on-the-fly.
973983
EscapeAnalysis::CGNode *
974984
EscapeAnalysis::ConnectionGraph::getValueContent(SILValue ptrVal) {
975-
// Look past address projections, pointer casts, and the like within the same
976-
// object. Does not look past a dereference such as ref_element_addr, or
977-
// project_box.
978-
SILValue ptrBase = EA->getPointerRoot(ptrVal);
979-
980-
PointerKind pointerKind = EA->getPointerKind(ptrBase);
981-
if (pointerKind == EscapeAnalysis::NoPointer)
982-
return nullptr;
983-
984-
CGNode *addrNode = getOrCreateNode(ptrBase, pointerKind);
985+
CGNode *addrNode = getNode(ptrVal);
985986
if (!addrNode)
986987
return nullptr;
987988

988-
if (ptrBase->getType().isAddress())
989-
return getOrCreateAddressContent(ptrBase, addrNode);
989+
// Create content based on the derived pointer. If the base pointer contains
990+
// other types of references, then the content node will be merged when those
991+
// references are accessed. If the other references types are never accessed
992+
// in this function, then they are ignored.
993+
if (ptrVal->getType().isAddress())
994+
return getOrCreateAddressContent(ptrVal, addrNode);
990995

991-
if (canOnlyContainReferences(pointerKind))
992-
return getOrCreateReferenceContent(ptrBase, addrNode);
996+
if (addrNode->hasReferenceOnly())
997+
return getOrCreateReferenceContent(ptrVal, addrNode);
993998

994999
// The pointer value may contain raw pointers.
9951000
return getOrCreateUnknownContent(addrNode);
@@ -2075,10 +2080,12 @@ void EscapeAnalysis::analyzeInstruction(SILInstruction *I,
20752080
// that may eventually be associated with 'fieldContent', so we must
20762081
// assume here that 'fieldContent2' could hold raw pointers. This is
20772082
// implied by passing in invalid SILValue.
2078-
CGNode *objNode2 =
2083+
CGNode *escapingNode =
20792084
ConGraph->getOrCreateReferenceContent(SILValue(), fieldNode);
2080-
CGNode *fieldNode2 = objNode2->getContentNodeOrNull();
2081-
ConGraph->getOrCreateUnknownContent(fieldNode2)->markEscaping();
2085+
if (CGNode *indirectFieldNode = escapingNode->getContentNodeOrNull())
2086+
escapingNode = indirectFieldNode;
2087+
2088+
ConGraph->getOrCreateUnknownContent(escapingNode)->markEscaping();
20822089
return;
20832090
}
20842091
case SILInstructionKind::DestroyAddrInst: {

test/SILOptimizer/escape_analysis.sil

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ bb0(%0 : $Pointer):
323323
// CHECK-NEXT: Val %1 Esc: , Succ: (%1.1)
324324
// CHECK-NEXT: Con [ref] %1.1 Esc: G, Succ: %4
325325
// CHECK-NEXT: Con [int] %3 Esc: A, Succ: (%4)
326-
// CHECK-NEXT: Con %4 Esc: G, Succ:
326+
// CHECK-NEXT: Con [ref] %4 Esc: G, Succ:
327327
// CHECK-NEXT: End
328328
sil @store_content : $@convention(thin) (@owned Pointer) -> () {
329329
bb0(%0 : $Pointer):
@@ -896,7 +896,7 @@ bb0:
896896
// CHECK-NEXT: Val [ref] %4 Esc: , Succ: %0, %1
897897
// CHECK-NEXT: Val [ref] %7 Esc: , Succ: (%7.1), %4
898898
// CHECK-NEXT: Con [int] %7.1 Esc: A, Succ: (%7.2)
899-
// CHECK-NEXT: Con %7.2 Esc: A, Succ:
899+
// CHECK-NEXT: Con [ref] %7.2 Esc: A, Succ:
900900
// CHECK-NEXT: Ret [ref] return Esc: , Succ: %7
901901
// CHECK-NEXT: End
902902
sil @pointer_types : $@convention(thin) (@owned Y, @owned Y) -> @owned Y {
@@ -1107,7 +1107,7 @@ bb0(%0 : $*X, %1 : $X):
11071107
// CHECK-LABEL: CG of test_casts
11081108
// CHECK-NEXT: Arg [ref] %0 Esc: A, Succ:
11091109
// CHECK-NEXT: Con [int] %0.1 Esc: A, Succ: (%0.2)
1110-
// CHECK-NEXT: Con %0.2 Esc: A, Succ:
1110+
// CHECK-NEXT: Con [ref] %0.2 Esc: A, Succ:
11111111
// CHECK-NEXT: Ret [ref] return Esc: , Succ: %0
11121112
// CHECK-NEXT: End
11131113
sil @test_casts : $@convention(thin) (@owned AnyObject) -> @owned X {
@@ -1817,3 +1817,30 @@ bb0(%0 : $IntWrapper):
18171817
%tuple = tuple (%bridge : $Builtin.BridgeObject, %ump : $UnsafeMutablePointer<Int64>)
18181818
return %tuple : $(Builtin.BridgeObject, UnsafeMutablePointer<Int64>)
18191819
}
1820+
1821+
// Test undef -> struct_extract -> bbarg
1822+
// CHECK-LABEL: CG of testMappedUndef
1823+
// CHECK-NEXT: Val [ref] %4 Esc: , Succ: (%4.1)
1824+
// CHECK-NEXT: Con [int] %4.1 Esc: G, Succ: (%4.2)
1825+
// CHECK-NEXT: Con %4.2 Esc: G, Succ:
1826+
// CHECK-LABEL: End
1827+
struct StructWithObject {
1828+
@_hasStorage var obj: AnyObject { get set }
1829+
init(obj: AnyObject)
1830+
}
1831+
1832+
sil @testMappedUndef : $@convention(thin) () -> () {
1833+
bb0:
1834+
cond_br undef, bb1, bb2
1835+
1836+
bb1:
1837+
br bb3(undef : $AnyObject)
1838+
1839+
bb2:
1840+
%2 = struct_extract undef : $StructWithObject, #StructWithObject.obj
1841+
br bb3(%2 : $AnyObject)
1842+
1843+
bb3(%4 : $AnyObject):
1844+
%5 = tuple ()
1845+
return %5 : $()
1846+
}

0 commit comments

Comments
 (0)