Skip to content

Commit fd566d9

Browse files
committed
EscapeAnalysis: fix a problem where a inconsistent connection graph can be generated.
rdar://problem/24686791
1 parent 069a9d5 commit fd566d9

File tree

3 files changed

+65
-13
lines changed

3 files changed

+65
-13
lines changed

include/swift/SILOptimizer/Analysis/EscapeAnalysis.h

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -501,11 +501,25 @@ class EscapeAnalysis : public BottomUpIPAnalysis {
501501
}
502502

503503
/// Creates a defer-edge between \p From and \p To.
504-
/// This may invalidate the graph invariance 4). See addDeferEdge.
505-
bool defer(CGNode *From, CGNode *To) {
506-
bool EdgeAdded = addDeferEdge(From, To);
504+
/// This may trigger node merges to keep the graph invariance 4).
505+
/// Returns the \p From node or its merge-target in case \p From was merged
506+
/// during adding the edge.
507+
/// The \p EdgeAdded is set to true if there was no defer-edge between
508+
/// \p From and \p To, yet.
509+
CGNode *defer(CGNode *From, CGNode *To, bool &EdgeAdded) {
510+
if (addDeferEdge(From, To))
511+
EdgeAdded = true;
507512
mergeAllScheduledNodes();
508-
return EdgeAdded;
513+
return From->getMergeTarget();
514+
}
515+
516+
/// Creates a defer-edge between \p From and \p To.
517+
/// This may trigger node merges to keep the graph invariance 4).
518+
/// Returns the \p From node or its merge-target in case \p From was merged
519+
/// during adding the edge.
520+
CGNode *defer(CGNode *From, CGNode *To) {
521+
bool UnusedEdgeAddedFlag = false;
522+
return defer(From, To, UnusedEdgeAddedFlag);
509523
}
510524

511525
/// Merges the \p SourceGraph into this graph. The \p Mapping contains the

lib/SILOptimizer/Analysis/EscapeAnalysis.cpp

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -502,9 +502,7 @@ bool EscapeAnalysis::ConnectionGraph::mergeFrom(ConnectionGraph *SourceGraph,
502502
// Create the edge in this graph. Note: this may trigger merging of
503503
// content nodes.
504504
if (DestReachable) {
505-
Changed |= defer(DestFrom, DestReachable);
506-
// In case DestFrom is merged during adding the defer-edge.
507-
DestFrom = DestFrom->getMergeTarget();
505+
DestFrom = defer(DestFrom, DestReachable, Changed);
508506
}
509507

510508
for (auto *Deferred : SourceReachable->defersTo) {
@@ -1080,7 +1078,7 @@ void EscapeAnalysis::buildConnectionGraph(FunctionInfo *FInfo,
10801078
for (SILValue Src : Incoming) {
10811079
CGNode *SrcArg = ConGraph->getNode(Src, this);
10821080
if (SrcArg) {
1083-
ConGraph->defer(ArgNode, SrcArg);
1081+
ArgNode = ConGraph->defer(ArgNode, SrcArg);
10841082
} else {
10851083
ConGraph->setEscapesGlobal(ArgNode);
10861084
break;
@@ -1269,7 +1267,7 @@ void EscapeAnalysis::analyzeInstruction(SILInstruction *I,
12691267
assert(ResultNode && "thick functions must have a CG node");
12701268
for (const Operand &Op : I->getAllOperands()) {
12711269
if (CGNode *ArgNode = ConGraph->getNode(Op.get(), this)) {
1272-
ConGraph->defer(ResultNode, ArgNode);
1270+
ResultNode = ConGraph->defer(ResultNode, ArgNode);
12731271
}
12741272
}
12751273
return;
@@ -1296,7 +1294,7 @@ void EscapeAnalysis::analyzeInstruction(SILInstruction *I,
12961294
ResultNode = FieldNode;
12971295
assert(isPointer(I));
12981296
} else {
1299-
ConGraph->defer(ResultNode, FieldNode);
1297+
ResultNode = ConGraph->defer(ResultNode, FieldNode);
13001298
}
13011299
}
13021300
}
@@ -1332,8 +1330,7 @@ void EscapeAnalysis::analyzeInstruction(SILInstruction *I,
13321330
case ValueKind::ReturnInst:
13331331
if (CGNode *ValueNd = ConGraph->getNode(cast<ReturnInst>(I)->getOperand(),
13341332
this)) {
1335-
ConGraph->defer(ConGraph->getReturnNode(),
1336-
ValueNd);
1333+
ConGraph->defer(ConGraph->getReturnNode(), ValueNd);
13371334
}
13381335
return;
13391336
default:
@@ -1353,7 +1350,7 @@ analyzeSelectInst(SelectInst *SI, ConnectionGraph *ConGraph) {
13531350
auto *ArgNode = ConGraph->getNode(CaseVal, this);
13541351
assert(ArgNode &&
13551352
"there should be an argument node if there is a result node");
1356-
ConGraph->defer(ResultNode, ArgNode);
1353+
ResultNode = ConGraph->defer(ResultNode, ArgNode);
13571354
}
13581355
// ... also including the default value.
13591356
auto *DefaultNode = ConGraph->getNode(SI->getDefaultResult(), this);

test/SILOptimizer/escape_analysis.sil

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,16 @@ struct MyError : ErrorType {
5656
final class ErrorClass : ErrorType {
5757
}
5858

59+
struct SomeData {
60+
let x : X
61+
}
62+
63+
struct FourFields {
64+
let a : SomeData
65+
let b : Pointer
66+
let c : Builtin.RawPointer
67+
let d : Y
68+
}
5969

6070
// Sanity check with a simple function.
6171

@@ -966,6 +976,37 @@ bb0(%0 : $Optional<Builtin.NativeObject>):
966976
return %2 : $()
967977
}
968978

979+
sil_global @global_y : $SomeData
980+
981+
// CHECK-LABEL: CG of test_node_merge_during_struct_inst
982+
// CHECK-NEXT: Arg %0 Esc: G, Succ: (%4.1)
983+
// CHECK-NEXT: Val %1 Esc: G, Succ: (%4.1)
984+
// CHECK-NEXT: Val %4 Esc: G, Succ: (%4.1)
985+
// CHECK-NEXT: Con %4.1 Esc: G, Succ: (%4.1), %0, %1, %4
986+
// CHECK-NEXT: End
987+
sil @test_node_merge_during_struct_inst : $@convention(thin) (Y) -> () {
988+
bb0(%0 : $Y):
989+
%1 = global_addr @global_y : $*SomeData
990+
%2 = address_to_pointer %1 : $*SomeData to $Builtin.RawPointer
991+
%3 = raw_pointer_to_ref %2 : $Builtin.RawPointer to $Y
992+
993+
%4 = alloc_stack $Pointer
994+
%5 = struct_element_addr %4 : $*Pointer, #Pointer.y
995+
store %3 to %5 : $*Y
996+
997+
%7 = load %1 : $*SomeData
998+
%8 = load %4 : $*Pointer
999+
%9 = address_to_pointer %4 : $*Pointer to $Builtin.RawPointer
1000+
1001+
// Analyzing this instruction causes a node merge.
1002+
// Check that we don't crash on this.
1003+
%l = struct $FourFields(%7 : $SomeData, %8 : $Pointer, %9 : $Builtin.RawPointer, %0 : $Y)
1004+
1005+
dealloc_stack %4 : $*Pointer
1006+
%r = tuple ()
1007+
return %r : $()
1008+
}
1009+
9691010
// CHECK-LABEL: CG of arraysemantics_is_native_no_typecheck
9701011
// CHECK-NEXT: Arg %0 Esc: A, Succ:
9711012
// CHECK-NEXT: End

0 commit comments

Comments
 (0)