Skip to content

Commit 81107e4

Browse files
authored
Improve handling of copy_value and destroy_value in (swiftlang#35011)
MemoryBehaviorVisitor - Also, compute use points for destroy_value - Cleanup explicit checks for refcount instructions in RLE
1 parent 529d9b2 commit 81107e4

File tree

7 files changed

+94
-11
lines changed

7 files changed

+94
-11
lines changed

include/swift/SILOptimizer/Analysis/EscapeAnalysis.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1158,6 +1158,10 @@ class EscapeAnalysis : public BottomUpIPAnalysis {
11581158
/// Note that if \p RI is a retain-instruction always false is returned.
11591159
bool canEscapeTo(SILValue V, RefCountingInst *RI);
11601160

1161+
/// Returns true if the value \p V can escape to the destroy_value instruction
1162+
/// \p DVI.
1163+
bool canEscapeTo(SILValue V, DestroyValueInst *DVI);
1164+
11611165
/// Return true if \p releasedReference deinitialization may release memory
11621166
/// pointed to by \p accessedAddress.
11631167
bool mayReleaseContent(SILValue releasedReference, SILValue accessedAddress);

lib/SILOptimizer/Analysis/EscapeAnalysis.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -870,6 +870,7 @@ void EscapeAnalysis::ConnectionGraph::computeUsePoints() {
870870
#include "swift/AST/ReferenceStorage.def"
871871
case SILInstructionKind::StrongReleaseInst:
872872
case SILInstructionKind::ReleaseValueInst:
873+
case SILInstructionKind::DestroyValueInst:
873874
case SILInstructionKind::ApplyInst:
874875
case SILInstructionKind::TryApplyInst: {
875876
/// Actually we only add instructions which may release a reference.
@@ -2589,8 +2590,9 @@ bool EscapeAnalysis::canEscapeToUsePoint(SILValue value,
25892590
SILInstruction *usePoint,
25902591
ConnectionGraph *conGraph) {
25912592

2592-
assert((FullApplySite::isa(usePoint) || isa<RefCountingInst>(usePoint))
2593-
&& "use points are only created for calls and refcount instructions");
2593+
assert((FullApplySite::isa(usePoint) || isa<RefCountingInst>(usePoint) ||
2594+
isa<DestroyValueInst>(usePoint)) &&
2595+
"use points are only created for calls and refcount instructions");
25942596

25952597
CGNode *node = conGraph->getValueContent(value);
25962598
if (!node)
@@ -2649,6 +2651,14 @@ bool EscapeAnalysis::canEscapeTo(SILValue V, RefCountingInst *RI) {
26492651
return canEscapeToUsePoint(V, RI, ConGraph);
26502652
}
26512653

2654+
bool EscapeAnalysis::canEscapeTo(SILValue V, DestroyValueInst *DVI) {
2655+
// If it's not uniquely identified we don't know anything about the value.
2656+
if (!isUniquelyIdentified(V))
2657+
return true;
2658+
auto *ConGraph = getConnectionGraph(DVI->getFunction());
2659+
return canEscapeToUsePoint(V, DVI, ConGraph);
2660+
}
2661+
26522662
/// Utility to get the function which contains both values \p V1 and \p V2.
26532663
static SILFunction *getCommonFunction(SILValue V1, SILValue V2) {
26542664
SILBasicBlock *BB1 = V1->getParentBlock();

lib/SILOptimizer/Analysis/MemoryBehavior.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ class MemoryBehaviorVisitor
182182
MemBehavior visitBuiltinInst(BuiltinInst *BI);
183183
MemBehavior visitStrongReleaseInst(StrongReleaseInst *BI);
184184
MemBehavior visitReleaseValueInst(ReleaseValueInst *BI);
185+
MemBehavior visitDestroyValueInst(DestroyValueInst *DVI);
185186
MemBehavior visitSetDeallocatingInst(SetDeallocatingInst *BI);
186187
MemBehavior visitBeginCOWMutationInst(BeginCOWMutationInst *BCMI);
187188
#define ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \
@@ -225,6 +226,7 @@ class MemoryBehaviorVisitor
225226
}
226227
REFCOUNTINC_MEMBEHAVIOR_INST(StrongRetainInst)
227228
REFCOUNTINC_MEMBEHAVIOR_INST(RetainValueInst)
229+
REFCOUNTINC_MEMBEHAVIOR_INST(CopyValueInst)
228230
#define UNCHECKED_REF_STORAGE(Name, ...) \
229231
REFCOUNTINC_MEMBEHAVIOR_INST(Name##RetainValueInst) \
230232
REFCOUNTINC_MEMBEHAVIOR_INST(StrongCopy##Name##ValueInst)
@@ -490,6 +492,13 @@ MemBehavior MemoryBehaviorVisitor::visitReleaseValueInst(ReleaseValueInst *SI) {
490492
return MemBehavior::MayHaveSideEffects;
491493
}
492494

495+
MemBehavior
496+
MemoryBehaviorVisitor::visitDestroyValueInst(DestroyValueInst *DVI) {
497+
if (!EA->canEscapeTo(V, DVI))
498+
return MemBehavior::None;
499+
return MemBehavior::MayHaveSideEffects;
500+
}
501+
493502
MemBehavior MemoryBehaviorVisitor::visitSetDeallocatingInst(SetDeallocatingInst *SDI) {
494503
return MemBehavior::None;
495504
}

lib/SILOptimizer/Transforms/RedundantLoadElimination.cpp

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -146,15 +146,6 @@ static bool inline isPerformingRLE(RLEKind Kind) {
146146
/// general sense but are inert from a load store perspective.
147147
static bool isRLEInertInstruction(SILInstruction *Inst) {
148148
switch (Inst->getKind()) {
149-
#define UNCHECKED_REF_STORAGE(Name, ...) \
150-
case SILInstructionKind::StrongCopy##Name##ValueInst:
151-
#define ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \
152-
case SILInstructionKind::Name##RetainInst: \
153-
case SILInstructionKind::StrongRetain##Name##Inst: \
154-
case SILInstructionKind::StrongCopy##Name##ValueInst:
155-
#include "swift/AST/ReferenceStorage.def"
156-
case SILInstructionKind::StrongRetainInst:
157-
case SILInstructionKind::RetainValueInst:
158149
case SILInstructionKind::DeallocStackInst:
159150
case SILInstructionKind::CondFailInst:
160151
case SILInstructionKind::IsEscapingClosureInst:

lib/SILOptimizer/UtilityPasses/EscapeAnalysisDumper.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,14 @@ class EscapeAnalysisDumper : public SILModuleTransform {
8585
<< " to " << ii;
8686
}
8787
}
88+
if (DestroyValueInst *dvi = dyn_cast<DestroyValueInst>(&ii)) {
89+
for (unsigned i = 0, e = Values.size(); i != e; ++i) {
90+
SILValue val = Values[i];
91+
bool escape = EA->canEscapeTo(val, dvi);
92+
llvm::outs() << (escape ? "May" : "No") << "Escape: " << val
93+
<< " to " << ii;
94+
}
95+
}
8896
}
8997
}
9098
}

test/SILOptimizer/escape_analysis.sil

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1962,3 +1962,22 @@ bb0(%0 : $Z):
19621962
unreachable
19631963
}
19641964

1965+
// CHECK-LABEL: CG of test_destroy_value
1966+
// CHECK: Arg %0 Esc: A, Succ: (%1)
1967+
// CHECK: Con [ref] %1 Esc: A, Succ: (%1.1)
1968+
// CHECK: Con [int] %1.1 Esc: G, Succ: (%1.2)
1969+
// CHECK: Con [ref] %1.2 Esc: G, Succ:
1970+
// CHECK-LABEL: End
1971+
// CHECK: NoEscape: %0 = argument of bb0 : $*X
1972+
// CHECK: to destroy_value %1 : $X
1973+
// CHECK: MayEscape: %1 = load [copy] %0 : $*X
1974+
// CHECK: to destroy_value %1 : $X
1975+
sil [ossa] @test_destroy_value : $@convention(thin) (@in X) -> () {
1976+
bb0 (%0 : $*X):
1977+
%1 = load [copy] %0 : $*X
1978+
destroy_value %1 : $X
1979+
destroy_addr %0 : $*X
1980+
%2 = tuple()
1981+
return %2 : $()
1982+
}
1983+

test/SILOptimizer/mem-behavior-all.sil

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,3 +244,45 @@ bb0(%0 : $*C, %1 : $*C, %2: $*C):
244244
return %6 : $()
245245
}
246246

247+
// CHECK-LABEL: @test_destroy_value
248+
// CHECK: PAIR #0.
249+
// CHECK-NEXT: %1 = load [copy] %0 : $*C
250+
// CHECK-NEXT: %0 = argument of bb0 : $*C
251+
// CHECK-NEXT: r=1,w=0
252+
// CHECK: PAIR #2.
253+
// CHECK-NEXT: destroy_value %1 : $C
254+
// CHECK-NEXT: %0 = argument of bb0 : $*C
255+
// CHECK-NEXT: r=0,w=0
256+
// CHECK: PAIR #3.
257+
// CHECK-NEXT: destroy_value %1 : $C
258+
// CHECK-NEXT: %1 = load [copy] %0 : $*C
259+
// CHECK-NEXT: r=1,w=1
260+
sil [ossa] @test_destroy_value : $@convention(thin) (@in C) -> () {
261+
bb0 (%0 : $*C):
262+
%1 = load [copy] %0 : $*C
263+
destroy_value %1 : $C
264+
destroy_addr %0 : $*C
265+
%2 = tuple()
266+
return %2 : $()
267+
}
268+
269+
// CHECK-LABEL: @test_copy_value
270+
// CHECK: PAIR #3.
271+
// CHECK-NEXT: %2 = copy_value %1 : $C
272+
// CHECK-NEXT: %0 = argument of bb0 : $*C
273+
// CHECK-NEXT: r=0,w=0
274+
// CHECK: PAIR #4.
275+
// CHECK-NEXT: %2 = copy_value %1 : $C
276+
// CHECK-NEXT: %1 = load [copy] %0 : $*C
277+
// CHECK-NEXT: r=0,w=0
278+
sil [ossa] @test_copy_value : $@convention(thin) (@in C) -> () {
279+
bb0 (%0 : $*C):
280+
%1 = load [copy] %0 : $*C
281+
%2 = copy_value %1 : $C
282+
destroy_value %1 : $C
283+
destroy_value %2 : $C
284+
destroy_addr %0 : $*C
285+
%3 = tuple()
286+
return %3 : $()
287+
}
288+

0 commit comments

Comments
 (0)