Skip to content

Commit bd36ce1

Browse files
authored
Merge pull request #17234 from gottesmm/pr-0e0ac4897be5b6059f2959956c708dea2e027b88
2 parents 08e8fb0 + 369b1f4 commit bd36ce1

File tree

4 files changed

+89
-77
lines changed

4 files changed

+89
-77
lines changed

include/swift/SILOptimizer/Analysis/ARCAnalysis.h

Lines changed: 63 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,17 @@
1313
#ifndef SWIFT_SILOPTIMIZER_ANALYSIS_ARCANALYSIS_H
1414
#define SWIFT_SILOPTIMIZER_ANALYSIS_ARCANALYSIS_H
1515

16+
#include "swift/Basic/LLVM.h"
1617
#include "swift/SIL/SILArgument.h"
17-
#include "swift/SIL/SILValue.h"
1818
#include "swift/SIL/SILBasicBlock.h"
19+
#include "swift/SIL/SILValue.h"
1920
#include "swift/SILOptimizer/Analysis/AliasAnalysis.h"
2021
#include "swift/SILOptimizer/Analysis/PostOrderAnalysis.h"
2122
#include "swift/SILOptimizer/Analysis/RCIdentityAnalysis.h"
2223
#include "llvm/ADT/BitVector.h"
23-
#include "llvm/ADT/SmallPtrSet.h"
2424
#include "llvm/ADT/MapVector.h"
2525
#include "llvm/ADT/SetVector.h"
26+
#include "llvm/ADT/SmallPtrSet.h"
2627
#include "llvm/ADT/TinyPtrVector.h"
2728

2829
namespace swift {
@@ -39,15 +40,13 @@ class SILFunction;
3940
} // end namespace swift
4041

4142
namespace swift {
43+
4244
/// Return true if this is a retain instruction.
4345
bool isRetainInstruction(SILInstruction *II);
4446

4547
/// Return true if this is a release instruction.
4648
bool isReleaseInstruction(SILInstruction *II);
4749

48-
using RetainList = TinyPtrVector<SILInstruction *>;
49-
using ReleaseList = TinyPtrVector<SILInstruction *>;
50-
5150
/// \returns True if the user \p User decrements the ref count of \p Ptr.
5251
bool mayDecrementRefCount(SILInstruction *User, SILValue Ptr,
5352
AliasAnalysis *AA);
@@ -141,16 +140,11 @@ class ConsumedResultToEpilogueRetainMatcher {
141140
SILFunction *F;
142141
RCIdentityFunctionInfo *RCFI;
143142
AliasAnalysis *AA;
143+
144144
// We use a list of instructions for now so that we can keep the same interface
145145
// and handle exploded retain_value later.
146-
RetainList EpilogueRetainInsts;
146+
TinyPtrVector<SILInstruction *> EpilogueRetainInsts;
147147

148-
/// Return true if all the successors of the EpilogueRetainInsts do not have
149-
/// a retain.
150-
bool isTransitiveSuccessorsRetainFree(llvm::DenseSet<SILBasicBlock *> BBs);
151-
152-
/// Finds matching releases in the provided block \p BB.
153-
RetainKindValue findMatchingRetainsInBasicBlock(SILBasicBlock *BB, SILValue V);
154148
public:
155149
/// Finds matching releases in the return block of the function \p F.
156150
ConsumedResultToEpilogueRetainMatcher(RCIdentityFunctionInfo *RCFI,
@@ -160,7 +154,9 @@ class ConsumedResultToEpilogueRetainMatcher {
160154
/// Finds matching releases in the provided block \p BB.
161155
void findMatchingRetains(SILBasicBlock *BB);
162156

163-
RetainList getEpilogueRetains() { return EpilogueRetainInsts; }
157+
ArrayRef<SILInstruction *> getEpilogueRetains() const {
158+
return EpilogueRetainInsts;
159+
}
164160

165161
/// Recompute the mapping from argument to consumed arg.
166162
void recompute();
@@ -182,6 +178,16 @@ class ConsumedResultToEpilogueRetainMatcher {
182178
unsigned size() const { return EpilogueRetainInsts.size(); }
183179

184180
iterator_range<iterator> getRange() { return swift::make_range(begin(), end()); }
181+
182+
private:
183+
/// Return true if all the successors of the EpilogueRetainInsts do not have
184+
/// a retain.
185+
bool
186+
isTransitiveSuccessorsRetainFree(const llvm::DenseSet<SILBasicBlock *> &BBs);
187+
188+
/// Finds matching releases in the provided block \p BB.
189+
RetainKindValue findMatchingRetainsInBasicBlock(SILBasicBlock *BB,
190+
SILValue V);
185191
};
186192

187193
/// A class that attempts to match owned arguments and corresponding epilogue
@@ -197,40 +203,16 @@ class ConsumedArgToEpilogueReleaseMatcher {
197203
RCIdentityFunctionInfo *RCFI;
198204
ExitKind Kind;
199205
ArrayRef<SILArgumentConvention> ArgumentConventions;
200-
llvm::SmallMapVector<SILArgument *, ReleaseList, 8> ArgInstMap;
206+
207+
using InstListTy = TinyPtrVector<SILInstruction *>;
208+
llvm::SmallMapVector<SILArgument *, InstListTy, 8> ArgInstMap;
201209

202210
/// Set to true if we found some releases but not all for the argument.
203211
llvm::DenseSet<SILArgument *> FoundSomeReleases;
204212

205213
/// Eventually this will be used in place of HasBlock.
206214
SILBasicBlock *ProcessedBlock;
207215

208-
/// Return true if we have seen releases to part or all of \p Derived in
209-
/// \p Insts.
210-
///
211-
/// NOTE: This function relies on projections to analyze the relation
212-
/// between the releases values in \p Insts and \p Derived, it also bails
213-
/// out and return true if projection path can not be formed between Base
214-
/// and any one the released values.
215-
bool isRedundantRelease(ReleaseList Insts, SILValue Base, SILValue Derived);
216-
217-
/// Return true if we have a release instruction for all the reference
218-
/// semantics part of \p Argument.
219-
bool releaseArgument(ReleaseList Insts, SILValue Argument);
220-
221-
/// Walk the basic block and find all the releases that match to function
222-
/// arguments.
223-
void collectMatchingReleases(SILBasicBlock *BB);
224-
225-
/// Walk the function and find all the destroy_addr instructions that match
226-
/// to function arguments.
227-
void collectMatchingDestroyAddresses(SILBasicBlock *BB);
228-
229-
/// For every argument in the function, check to see whether all epilogue
230-
/// releases are found. Clear all releases for the argument if not all
231-
/// epilogue releases are found.
232-
void processMatchingReleases();
233-
234216
public:
235217
/// Finds matching releases in the return block of the function \p F.
236218
ConsumedArgToEpilogueReleaseMatcher(
@@ -288,33 +270,32 @@ class ConsumedArgToEpilogueReleaseMatcher {
288270
return getSingleReleaseForArgument(Arg);
289271
}
290272

291-
ReleaseList getReleasesForArgument(SILArgument *Arg) {
292-
ReleaseList Releases;
273+
ArrayRef<SILInstruction *> getReleasesForArgument(SILArgument *Arg) {
293274
auto I = ArgInstMap.find(Arg);
294275
if (I == ArgInstMap.end())
295-
return Releases;
296-
return I->second;
276+
return {};
277+
return I->second;
297278
}
298279

299-
ReleaseList getReleasesForArgument(SILValue V) {
300-
ReleaseList Releases;
280+
ArrayRef<SILInstruction *> getReleasesForArgument(SILValue V) {
301281
auto *Arg = dyn_cast<SILArgument>(V);
302282
if (!Arg)
303-
return Releases;
283+
return {};
304284
return getReleasesForArgument(Arg);
305285
}
306286

307287
/// Recompute the mapping from argument to consumed arg.
308288
void recompute();
309289

310290
bool isSingleReleaseMatchedToArgument(SILInstruction *Inst) {
311-
auto Pred = [&Inst](const std::pair<SILArgument *,
312-
ReleaseList> &P) -> bool {
313-
if (P.second.size() > 1)
314-
return false;
315-
return *P.second.begin() == Inst;
316-
};
317-
return count_if(ArgInstMap, Pred);
291+
return count_if(
292+
ArgInstMap,
293+
[&Inst](const std::pair<SILArgument *, ArrayRef<SILInstruction *>> &P)
294+
-> bool {
295+
if (P.second.size() > 1)
296+
return false;
297+
return *P.second.begin() == Inst;
298+
});
318299
}
319300

320301
using iterator = decltype(ArgInstMap)::iterator;
@@ -334,6 +315,34 @@ class ConsumedArgToEpilogueReleaseMatcher {
334315
unsigned size() const { return ArgInstMap.size(); }
335316

336317
iterator_range<iterator> getRange() { return swift::make_range(begin(), end()); }
318+
319+
private:
320+
/// Return true if we have seen releases to part or all of \p Derived in
321+
/// \p Insts.
322+
///
323+
/// NOTE: This function relies on projections to analyze the relation
324+
/// between the releases values in \p Insts and \p Derived, it also bails
325+
/// out and return true if projection path can not be formed between Base
326+
/// and any one the released values.
327+
bool isRedundantRelease(ArrayRef<SILInstruction *> Insts, SILValue Base,
328+
SILValue Derived);
329+
330+
/// Return true if we have a release instruction for all the reference
331+
/// semantics part of \p Argument.
332+
bool releaseArgument(ArrayRef<SILInstruction *> Insts, SILValue Argument);
333+
334+
/// Walk the basic block and find all the releases that match to function
335+
/// arguments.
336+
void collectMatchingReleases(SILBasicBlock *BB);
337+
338+
/// Walk the function and find all the destroy_addr instructions that match
339+
/// to function arguments.
340+
void collectMatchingDestroyAddresses(SILBasicBlock *BB);
341+
342+
/// For every argument in the function, check to see whether all epilogue
343+
/// releases are found. Clear all releases for the argument if not all
344+
/// epilogue releases are found.
345+
void processMatchingReleases();
337346
};
338347

339348
class ReleaseTracker {

lib/SILOptimizer/Analysis/ARCAnalysis.cpp

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -498,22 +498,24 @@ void ConsumedResultToEpilogueRetainMatcher::recompute() {
498498
findMatchingRetains(&*BB);
499499
}
500500

501-
bool
502-
ConsumedResultToEpilogueRetainMatcher::
503-
isTransitiveSuccessorsRetainFree(llvm::DenseSet<SILBasicBlock *> BBs) {
501+
bool ConsumedResultToEpilogueRetainMatcher::isTransitiveSuccessorsRetainFree(
502+
const llvm::DenseSet<SILBasicBlock *> &BBs) {
504503
// For every block with retain, we need to check the transitive
505504
// closure of its successors are retain-free.
506505
for (auto &I : EpilogueRetainInsts) {
507-
auto *CBB = I->getParent();
508-
for (auto &Succ : CBB->getSuccessors()) {
509-
if (BBs.find(Succ) != BBs.end())
506+
for (auto &Succ : I->getParent()->getSuccessors()) {
507+
if (BBs.count(Succ))
510508
continue;
511509
return false;
512510
}
513511
}
512+
513+
// FIXME: We are iterating over a DenseSet. That can lead to non-determinism
514+
// and is in general pretty inefficient since we are iterating over a hash
515+
// table.
514516
for (auto CBB : BBs) {
515517
for (auto &Succ : CBB->getSuccessors()) {
516-
if (BBs.find(Succ) != BBs.end())
518+
if (BBs.count(Succ))
517519
continue;
518520
return false;
519521
}
@@ -707,9 +709,8 @@ void ConsumedArgToEpilogueReleaseMatcher::recompute() {
707709
findMatchingReleases(&*BB);
708710
}
709711

710-
bool
711-
ConsumedArgToEpilogueReleaseMatcher::
712-
isRedundantRelease(ReleaseList Insts, SILValue Base, SILValue Derived) {
712+
bool ConsumedArgToEpilogueReleaseMatcher::isRedundantRelease(
713+
ArrayRef<SILInstruction *> Insts, SILValue Base, SILValue Derived) {
713714
// We use projection path to analyze the relation.
714715
auto POp = ProjectionPath::getProjectionPath(Base, Derived);
715716
// We can not build a projection path from the base to the derived, bail out.
@@ -730,9 +731,8 @@ isRedundantRelease(ReleaseList Insts, SILValue Base, SILValue Derived) {
730731
return false;
731732
}
732733

733-
bool
734-
ConsumedArgToEpilogueReleaseMatcher::
735-
releaseArgument(ReleaseList Insts, SILValue Arg) {
734+
bool ConsumedArgToEpilogueReleaseMatcher::releaseArgument(
735+
ArrayRef<SILInstruction *> Insts, SILValue Arg) {
736736
// Reason about whether all parts are released.
737737
SILModule *Mod = &(*Insts.begin())->getModule();
738738

lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.h

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -65,14 +65,14 @@ struct ArgumentDescriptor {
6565
/// Is this parameter an indirect result?
6666
bool IsIndirectResult;
6767

68-
/// If non-null, this is the release in the return block of the callee, which
69-
/// is associated with this parameter if it is @owned. If the parameter is not
70-
/// @owned or we could not find such a release in the callee, this is null.
71-
ReleaseList CalleeRelease;
72-
73-
/// The same as CalleeRelease, but the release in the throw block, if it is a
74-
/// function which has a throw block.
75-
ReleaseList CalleeReleaseInThrowBlock;
68+
/// If non-empty, this is the set of releases in the return block of
69+
/// the callee associated with this parameter if it is @owned. If it
70+
/// is empty then we could not find any such releases.
71+
TinyPtrVector<SILInstruction *> CalleeRelease;
72+
73+
/// The same as CalleeRelease, but the releases are post-dominated
74+
/// by the throw block, if it is a function which has a throw block.
75+
TinyPtrVector<SILInstruction *> CalleeReleaseInThrowBlock;
7676

7777
/// The projection tree of this arguments.
7878
ProjectionTree ProjTree;

lib/SILOptimizer/FunctionSignatureTransforms/OwnedToGuaranteedTransform.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,11 @@ bool FunctionSignatureTransform::OwnedToGuaranteedAnalyzeParameters() {
9292
auto ReleasesInThrow =
9393
ArgToThrowReleaseMap.getReleasesForArgument(A.Arg);
9494
if (!ArgToThrowReleaseMap.hasBlock() || !ReleasesInThrow.empty()) {
95-
A.CalleeRelease = Releases;
96-
A.CalleeReleaseInThrowBlock = ReleasesInThrow;
95+
assert(A.CalleeRelease.empty());
96+
assert(A.CalleeReleaseInThrowBlock.empty());
97+
copy(Releases, std::back_inserter(A.CalleeRelease));
98+
copy(ReleasesInThrow,
99+
std::back_inserter(A.CalleeReleaseInThrowBlock));
97100
// We can convert this parameter to a @guaranteed.
98101
A.OwnedToGuaranteed = true;
99102
SignatureOptimize = true;

0 commit comments

Comments
 (0)