Skip to content

Commit 6c0186b

Browse files
committed
Reinstate "Improve funciton signature @owned return result to "not owned" conversion"
This enables function signature handles a case of self-recursion. With this change we convert 11 @owned return value to "not owned", while we convert 179 @owned parameter to @guanrateed. rdar://24022375
1 parent 8955cdc commit 6c0186b

File tree

4 files changed

+124
-27
lines changed

4 files changed

+124
-27
lines changed

include/swift/SILOptimizer/Analysis/ARCAnalysis.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,13 @@ class ConsumedReturnValueToEpilogueRetainMatcher {
114114
public:
115115
enum class ExitKind { Return, Throw };
116116

117-
enum class FindRetainKind { None, Found, Blocked };
117+
/// The state on how retains are found in a basic block.
118+
enum class FindRetainKind {
119+
None, ///< Did not find a retain.
120+
Found, ///< Found a retain.
121+
Recursion, ///< Found a retain and its due to self-recursion.
122+
Blocked ///< Found a blocking instructions, i.e. MayDecrement.
123+
};
118124

119125
using RetainKindValue = std::pair<FindRetainKind, SILInstruction *>;
120126

lib/SILOptimizer/Analysis/ARCAnalysis.cpp

Lines changed: 48 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626

2727
using namespace swift;
2828

29+
using BasicBlockRetainValue = std::pair<SILBasicBlock *, SILValue>;
30+
2931
//===----------------------------------------------------------------------===//
3032
// Decrement Analysis
3133
//===----------------------------------------------------------------------===//
@@ -481,7 +483,6 @@ void ConsumedReturnValueToEpilogueRetainMatcher::recompute() {
481483
findMatchingRetains(&*BB);
482484
}
483485

484-
485486
void
486487
ConsumedReturnValueToEpilogueRetainMatcher::
487488
findMatchingRetains(SILBasicBlock *BB) {
@@ -502,47 +503,71 @@ findMatchingRetains(SILBasicBlock *BB) {
502503
// OK. we've found the return value, now iterate on the CFG to find all the
503504
// post-dominating retains.
504505
constexpr unsigned WorkListMaxSize = 8;
505-
RV = RCFI->getRCIdentityRoot(RV);
506+
506507
llvm::DenseSet<SILBasicBlock *> RetainFrees;
507-
llvm::SmallVector<SILBasicBlock *, 4> WorkList;
508+
llvm::SmallVector<BasicBlockRetainValue, 4> WorkList;
508509
llvm::DenseSet<SILBasicBlock *> HandledBBs;
509-
WorkList.push_back(BB);
510+
WorkList.push_back(std::make_pair(BB, RV));
510511
HandledBBs.insert(BB);
511512
while (!WorkList.empty()) {
512-
auto *CBB = WorkList.pop_back_val();
513-
RetainKindValue Kind = findMatchingRetainsInner(CBB, RV);
514-
515513
// Too many blocks ?.
516514
if (WorkList.size() > WorkListMaxSize) {
517515
EpilogueRetainInsts.clear();
518516
return;
519517
}
520518

519+
// Try to find a retain %value in this basic block.
520+
auto BVP = WorkList.pop_back_val();
521+
RetainKindValue Kind = findMatchingRetainsInner(BVP.first, BVP.second);
522+
523+
// We've found a retain on this path.
524+
if (Kind.first == FindRetainKind::Found) {
525+
EpilogueRetainInsts.push_back(Kind.second);
526+
continue;
527+
}
528+
521529
// There is a MayDecrement instruction.
522-
if (Kind.first == FindRetainKind::Blocked)
530+
if (Kind.first == FindRetainKind::Blocked) {
531+
EpilogueRetainInsts.clear();
523532
return;
533+
}
534+
535+
// There is a self-recursion. Use the apply instruction as the retain.
536+
if (Kind.first == FindRetainKind::Recursion) {
537+
EpilogueRetainInsts.push_back(Kind.second);
538+
continue;
539+
}
524540

541+
// Did not find a retain in this block, try to go to its predecessors.
525542
if (Kind.first == FindRetainKind::None) {
526-
RetainFrees.insert(CBB);
527-
528543
// We can not find a retain in a block with no predecessors.
529-
if (CBB->getPreds().begin() == CBB->getPreds().end()) {
544+
if (BVP.first->getPreds().begin() == BVP.first->getPreds().end()) {
530545
EpilogueRetainInsts.clear();
531546
return;
532547
}
533548

534-
// Check the predecessors.
535-
for (auto X : CBB->getPreds()){
549+
// This block does not have a retain.
550+
RetainFrees.insert(BVP.first);
551+
552+
// If this is a SILArgument of current basic block, we can split it up to
553+
// values in the predecessors.
554+
SILArgument *SA = dyn_cast<SILArgument>(BVP.second);
555+
if (SA && SA->getParent() != BVP.first)
556+
SA = nullptr;
557+
558+
for (auto X : BVP.first->getPreds()){
536559
if (HandledBBs.find(X) != HandledBBs.end())
537560
continue;
538-
WorkList.push_back(X);
561+
// Try to use the predecessor edge-value.
562+
if (SA && SA->getIncomingValue(X)) {
563+
WorkList.push_back(std::make_pair(X, SA->getIncomingValue(X)));
564+
}
565+
else
566+
WorkList.push_back(std::make_pair(X, BVP.second));
567+
539568
HandledBBs.insert(X);
540569
}
541570
}
542-
543-
// We've found a retain on this path.
544-
if (Kind.first == FindRetainKind::Found)
545-
EpilogueRetainInsts.push_back(Kind.second);
546571
}
547572

548573
// For every block with retain, we need to check the transitive
@@ -573,6 +598,11 @@ ConsumedReturnValueToEpilogueRetainMatcher::RetainKindValue
573598
ConsumedReturnValueToEpilogueRetainMatcher::
574599
findMatchingRetainsInner(SILBasicBlock *BB, SILValue V) {
575600
for (auto II = BB->rbegin(), IE = BB->rend(); II != IE; ++II) {
601+
// Handle self-recursion.
602+
if (ApplyInst *AI = dyn_cast<ApplyInst>(&*II))
603+
if (AI->getCalleeFunction() == BB->getParent())
604+
return std::make_pair(FindRetainKind::Recursion, AI);
605+
576606
// If we do not have a retain_value or strong_retain...
577607
if (!isa<RetainValueInst>(*II) && !isa<StrongRetainInst>(*II)) {
578608
// we can ignore it if it can not decrement the reference count of the

lib/SILOptimizer/IPO/FunctionSignatureOpts.cpp

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ using namespace swift;
4141
STATISTIC(NumFunctionSignaturesOptimized, "Total func sig optimized");
4242
STATISTIC(NumDeadArgsEliminated, "Total dead args eliminated");
4343
STATISTIC(NumOwnedConvertedToGuaranteed, "Total owned args -> guaranteed args");
44-
STATISTIC(NumOwnedConvertedToGuaranteedReturnValue, "Total owned args -> guaranteed return value");
44+
STATISTIC(NumOwnedConvertedToNotOwnedResult, "Total owned result -> not owned result");
4545
STATISTIC(NumCallSitesOptimized, "Total call sites optimized");
4646
STATISTIC(NumSROAArguments, "Total SROA arguments optimized");
4747

@@ -75,6 +75,7 @@ static bool hasIdenticalReleases(ReleaseList LHS, ReleaseList RHS) {
7575
return true;
7676
}
7777

78+
7879
/// Returns .Some(I) if I is a release that is the only non-debug instruction
7980
/// with side-effects in the use-def graph originating from Arg. Returns
8081
/// .Some(nullptr), if all uses from the arg were either debug insts or do not
@@ -654,7 +655,7 @@ bool SignatureAnalyzer::analyze() {
654655
if (!Retains.empty()) {
655656
RI.CalleeRetain = Retains;
656657
ShouldOptimize = true;
657-
++NumOwnedConvertedToGuaranteedReturnValue;
658+
++NumOwnedConvertedToNotOwnedResult;
658659
}
659660
}
660661

@@ -781,11 +782,21 @@ SILFunction *SignatureOptimizer::createEmptyFunctionWithOptimizedSig(
781782
static void addRetainsForConvertedDirectResults(SILBuilder &Builder,
782783
SILLocation Loc,
783784
SILValue ReturnValue,
785+
SILInstruction *AI,
784786
ArrayRef<ResultDescriptor> DirectResults) {
785787
for (auto I : indices(DirectResults)) {
786788
auto &RV = DirectResults[I];
787789
if (RV.CalleeRetain.empty()) continue;
788790

791+
bool IsSelfRecursionEpilogueRetain = false;
792+
for (auto &X : RV.CalleeRetain) {
793+
IsSelfRecursionEpilogueRetain |= (AI == X);
794+
}
795+
796+
// We do not create an retain if this ApplyInst is a self-recursion.
797+
if (IsSelfRecursionEpilogueRetain)
798+
continue;
799+
789800
// Extract the return value if necessary.
790801
SILValue SpecificResultValue = ReturnValue;
791802
if (DirectResults.size() != 1)
@@ -804,6 +815,7 @@ static void addRetainsForConvertedDirectResults(SILBuilder &Builder,
804815
static void rewriteApplyInstToCallNewFunction(SignatureOptimizer &Optimizer,
805816
SILFunction *NewF,
806817
const ApplyList &CallSites) {
818+
llvm::DenseSet<SILInstruction *> ApplysToRemove;
807819
for (auto FAS : CallSites) {
808820
auto *AI = FAS.getInstruction();
809821

@@ -865,15 +877,20 @@ static void rewriteApplyInstToCallNewFunction(SignatureOptimizer &Optimizer,
865877

866878
// If we have converted the return value from @owned to @guaranteed,
867879
// insert a retain_value at the callsite.
868-
addRetainsForConvertedDirectResults(Builder, Loc, ReturnValue,
880+
addRetainsForConvertedDirectResults(Builder, Loc, ReturnValue, AI,
869881
Optimizer.getResultDescList());
870-
871-
// Erase the old apply and its callee.
872-
recursivelyDeleteTriviallyDeadInstructions(AI, true,
873-
[](SILInstruction *) {});
874882

883+
// Make sure we remove this apply in the end.
884+
ApplysToRemove.insert(AI);
875885
++NumCallSitesOptimized;
876886
}
887+
888+
// Lastly, we have rewritten all the callsites, erase the old applys and
889+
// its callee.
890+
for (auto *AI : ApplysToRemove) {
891+
recursivelyDeleteTriviallyDeadInstructions(AI, true,
892+
[](SILInstruction *) {});
893+
}
877894
}
878895

879896
static void createThunkBody(SILBasicBlock *BB, SILFunction *NewF,
@@ -937,7 +954,7 @@ static void createThunkBody(SILBasicBlock *BB, SILFunction *NewF,
937954
}
938955

939956
// Handle @owned to @unowned return value conversion.
940-
addRetainsForConvertedDirectResults(Builder, Loc, ReturnValue,
957+
addRetainsForConvertedDirectResults(Builder, Loc, ReturnValue, nullptr,
941958
Optimizer.getResultDescList());
942959

943960
// Function that are marked as @NoReturn must be followed by an 'unreachable'
@@ -1056,6 +1073,8 @@ static bool optimizeFunctionSignature(llvm::BumpPtrAllocator &BPA,
10561073
// to unowned conversion.
10571074
for (ResultDescriptor &RD : Optimizer.getResultDescList()) {
10581075
for (auto &X : RD.CalleeRetain) {
1076+
if (!isa<StrongRetainInst>(X) && !isa<RetainValueInst>(X))
1077+
continue;
10591078
X->eraseFromParent();
10601079
}
10611080
}

test/SILOptimizer/functionsigopts.sil

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,25 @@ bb0(%0 : $boo):
112112
return %0 : $boo
113113
}
114114

115+
116+
// CHECK-LABEL: sil [thunk] @single_owned_return_value_with_self_recursion
117+
// CHECK: function_ref @_TTSf4n_g_single_owned_return_value
118+
// CHECK: [[RET:%.*]] = apply
119+
// CHECK: retain_value [[RET]]
120+
sil @single_owned_return_value_with_self_recursion : $@convention(thin) (@owned boo) -> @owned boo {
121+
bb0(%0 : $boo):
122+
cond_br undef, bb1, bb2
123+
bb1:
124+
retain_value %0 : $boo
125+
br bb3(%0 : $boo)
126+
bb2:
127+
%2 = function_ref @single_owned_return_value_with_self_recursion : $@convention(thin) (@owned boo) -> @owned boo
128+
%3 = apply %2(%0) : $@convention(thin) (@owned boo) -> @owned boo
129+
br bb3 (%3 : $boo)
130+
bb3(%4 : $boo):
131+
return %4 : $boo
132+
}
133+
115134
// CHECK-LABEL: sil [thunk] @single_owned_return_value_with_interfering_release
116135
// CHECK: bb0([[INPUT_ARG0:%[0-9]+]] : $boo):
117136
// CHECK: [[IN1:%.*]] = function_ref @_TTSf4s__single_owned_return_value_with_interfering_release
@@ -245,6 +264,22 @@ bb0(%0 : $boo):
245264
return %5 : $()
246265
}
247266

267+
// Make sure we pull out the retain_value from the callee.
268+
//
269+
// The retain and release can be got rid of easily by arc this way.
270+
//
271+
// CHECK-LABEL: sil @single_owned_return_value_with_self_recursion_callsite
272+
// CHECK: [[RET:%.*]] = apply
273+
// CHECK: retain_value [[RET]]
274+
// CHECK: release_value [[RET]]
275+
sil @single_owned_return_value_with_self_recursion_callsite : $@convention(thin) (@owned boo) -> () {
276+
bb0(%0 : $boo):
277+
%2 = function_ref @single_owned_return_value_with_self_recursion : $@convention(thin) (@owned boo) -> @owned boo
278+
%4 = apply %2(%0) : $@convention(thin) (@owned boo) -> @owned boo
279+
release_value %4 : $boo
280+
%5 = tuple()
281+
return %5 : $()
282+
}
248283

249284
sil [fragile] @exploded_release_to_dead_param_callsite : $@convention(thin) (@owned boo) -> () {
250285
bb0(%0 : $boo):
@@ -648,6 +683,13 @@ bb0(%0 : $Builtin.Int32):
648683
// CHECK-NOT: retain_value
649684
// CHECK: return
650685

686+
// There should not be a single retain in this function.
687+
//
688+
// CHECK-LABEL: sil @_TTSf4n_g_single_owned_return_value_with_self_recursion : $@convention(thin) (@owned boo) -> boo
689+
// CHECK: bb0
690+
// CHECK-NOT: retain_value
691+
// CHECK: return
692+
651693
// CHECK-LABEL: sil @_TTSf4s__single_owned_return_value_with_interfering_release : $@convention(thin) (@owned foo, @owned foo, Int) -> @owned boo {
652694
// CHECK: retain_value
653695
// CHECK: release_value

0 commit comments

Comments
 (0)