Skip to content

Commit 22aa3c5

Browse files
authored
Fix Escape Analysis for OSSA's pattern of array.uninitialized (#39789)
1 parent 2dd50bb commit 22aa3c5

File tree

3 files changed

+51
-10
lines changed

3 files changed

+51
-10
lines changed

include/swift/SILOptimizer/Analysis/EscapeAnalysis.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1059,8 +1059,8 @@ class EscapeAnalysis : public BottomUpIPAnalysis {
10591059
// returns an instantiated array struct and unsafe pointer to the elements.
10601060
struct ArrayUninitCall {
10611061
SILValue arrayStorageRef;
1062-
TupleExtractInst *arrayStruct = nullptr;
1063-
TupleExtractInst *arrayElementPtr = nullptr;
1062+
SILValue arrayStruct = nullptr;
1063+
SILValue arrayElementPtr = nullptr;
10641064

10651065
bool isValid() const {
10661066
return arrayStorageRef && arrayStruct && arrayElementPtr;
@@ -1072,9 +1072,9 @@ class EscapeAnalysis : public BottomUpIPAnalysis {
10721072
ArrayUninitCall
10731073
canOptimizeArrayUninitializedCall(ApplyInst *ai);
10741074

1075-
/// Return true of this tuple_extract is the result of an optimizable
1075+
/// Return true of this tuple_extract/destructure_tuple is the result of an optimizable
10761076
/// @_semantics("array.uninitialized") call.
1077-
bool canOptimizeArrayUninitializedResult(TupleExtractInst *tei);
1077+
bool canOptimizeArrayUninitializedResult(SILInstruction *tei);
10781078

10791079
/// Handle a call to "@_semantics(array.uninitialized") precisely by mapping
10801080
/// each call result to a separate graph node and relating them to the

lib/SILOptimizer/Analysis/EscapeAnalysis.cpp

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,14 @@ SILValue EscapeAnalysis::getPointerBase(SILValue value) {
250250
}
251251
return pointerOperand;
252252
}
253+
case ValueKind::MultipleValueInstructionResult: {
254+
if (auto *dt = dyn_cast<DestructureTupleInst>(value)) {
255+
if (canOptimizeArrayUninitializedResult(dt))
256+
return SILValue();
257+
return dt->getOperand();
258+
}
259+
return SILValue();
260+
}
253261
default:
254262
return SILValue();
255263
}
@@ -1939,6 +1947,11 @@ EscapeAnalysis::canOptimizeArrayUninitializedCall(ApplyInst *ai) {
19391947
continue;
19401948
}
19411949
}
1950+
if (auto *dt = dyn_cast<DestructureTupleInst>(use->getUser())) {
1951+
call.arrayStruct = dt->getResult(0);
1952+
call.arrayElementPtr = dt->getResult(1);
1953+
continue;
1954+
}
19421955
// If there are any other uses, such as a release_value, erase the previous
19431956
// call info and bail out.
19441957
call.arrayStruct = nullptr;
@@ -1957,8 +1970,9 @@ EscapeAnalysis::canOptimizeArrayUninitializedCall(ApplyInst *ai) {
19571970
}
19581971

19591972
bool EscapeAnalysis::canOptimizeArrayUninitializedResult(
1960-
TupleExtractInst *tei) {
1961-
ApplyInst *ai = dyn_cast<ApplyInst>(tei->getOperand());
1973+
SILInstruction *extract) {
1974+
assert(isa<TupleExtractInst>(extract) || isa<DestructureTupleInst>(extract));
1975+
ApplyInst *ai = dyn_cast<ApplyInst>(extract->getOperand(0));
19621976
if (!ai)
19631977
return false;
19641978

@@ -2362,11 +2376,17 @@ void EscapeAnalysis::analyzeInstruction(SILInstruction *I,
23622376
// This is a tuple_extract which extracts the second result of an
23632377
// array.uninitialized call (otherwise getPointerBase should have already
23642378
// looked through it).
2365-
auto *TEI = cast<TupleExtractInst>(I);
2366-
assert(canOptimizeArrayUninitializedResult(TEI)
2379+
assert(canOptimizeArrayUninitializedResult(I)
23672380
&& "tuple_extract should be handled as projection");
23682381
return;
23692382
}
2383+
case SILInstructionKind::DestructureTupleInst: {
2384+
if (canOptimizeArrayUninitializedResult(I)) {
2385+
return;
2386+
}
2387+
setAllEscaping(I, ConGraph);
2388+
return;
2389+
}
23702390
case SILInstructionKind::UncheckedRefCastAddrInst: {
23712391
auto *URCAI = cast<UncheckedRefCastAddrInst>(I);
23722392
CGNode *SrcNode = ConGraph->getNode(URCAI->getSrc());

test/SILOptimizer/escape_analysis.sil

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1331,15 +1331,15 @@ bb(%0 : $*Array<X>, %1 : $@callee_owned (@inout X) -> (@out (), @error Error)):
13311331
return %r : $()
13321332
}
13331333

1334-
// CHECK-LABEL: CG of arraysemantics_createUninitialized
1334+
// CHECK-LABEL: CG of arraysemantics_createUninitialized1
13351335
// CHECK-NEXT: Arg [ref] %0 Esc: A, Succ:
13361336
// CHECK-NEXT: Val [ref] %2 Esc: , Succ: (%6)
13371337
// CHECK-NEXT: Val [ref] %5 Esc: , Succ: %2
13381338
// CHECK-NEXT: Con [int] %6 Esc: R, Succ: (%6.1)
13391339
// CHECK-NEXT: Con %6.1 Esc: R, Succ: %0
13401340
// CHECK-NEXT: Ret [ref] return Esc: , Succ: %5
13411341
// CHECK-NEXT: End
1342-
sil @arraysemantics_createUninitialized : $@convention(thin) (@owned X) -> @owned Array<X> {
1342+
sil @arraysemantics_createUninitialized1 : $@convention(thin) (@owned X) -> @owned Array<X> {
13431343
bb0(%0 : $X):
13441344
%1 = function_ref @swift_bufferAllocate : $@convention(thin) () -> @owned AnyObject
13451345
%2 = apply %1() : $@convention(thin) () -> @owned AnyObject
@@ -1353,6 +1353,27 @@ bb0(%0 : $X):
13531353
return %5 : $Array<X>
13541354
}
13551355

1356+
// CHECK-LABEL: CG of arraysemantics_createUninitialized2
1357+
// CHECK-NEXT: Arg [ref] %0 Esc: A, Succ:
1358+
// CHECK-NEXT: Val [ref] %2 Esc: , Succ: (%6)
1359+
// CHECK-NEXT: Val [ref] %5 Esc: , Succ: %2
1360+
// CHECK-NEXT: Con [int] %6 Esc: R, Succ: (%6.1)
1361+
// CHECK-NEXT: Con %6.1 Esc: R, Succ: %0
1362+
// CHECK-NEXT: Ret [ref] return Esc: , Succ: %5
1363+
// CHECK-NEXT: End
1364+
sil [ossa] @arraysemantics_createUninitialized2 : $@convention(thin) (@owned X) -> @owned Array<X> {
1365+
bb0(%0 : @owned $X):
1366+
%1 = function_ref @swift_bufferAllocate : $@convention(thin) () -> @owned AnyObject
1367+
%2 = apply %1() : $@convention(thin) () -> @owned AnyObject
1368+
%3 = function_ref @createUninitialized : $@convention(method) (@owned AnyObject) -> (@owned Array<X>, UnsafeMutablePointer<X>)
1369+
%4 = apply %3(%2) : $@convention(method) (@owned AnyObject) -> (@owned Array<X>, UnsafeMutablePointer<X>)
1370+
(%5, %6) = destructure_tuple %4 : $(Array<X>, UnsafeMutablePointer<X>)
1371+
%7 = struct_extract %6 : $UnsafeMutablePointer<X>, #UnsafeMutablePointer._rawValue
1372+
%8 = pointer_to_address %7 : $Builtin.RawPointer to $*X
1373+
store %0 to [init] %8 : $*X
1374+
return %5 : $Array<X>
1375+
}
1376+
13561377
sil [_semantics "array.withUnsafeMutableBufferPointer"] @withUnsafeMutableBufferPointer : $@convention(method) (@owned @callee_owned (@inout X) -> (@out (), @error Error), @inout Array<X>) -> (@out (), @error Error)
13571378
sil [_semantics "array.props.isNativeTypeChecked"] @is_native_type_checked : $@convention(method) (@guaranteed Array<X>) -> Bool
13581379
sil [_semantics "array.check_subscript"] @check_subscript : $@convention(method) (Int32, Bool, @guaranteed Array<X>) -> ()

0 commit comments

Comments
 (0)