Skip to content

Commit 35471ab

Browse files
committed
Merge pull request #2310 from trentxintong/SFSO
Simplify function signature optimzation and fix a memory leak in function signature.
2 parents 7c7bc25 + db9ee7c commit 35471ab

17 files changed

+775
-913
lines changed

include/swift/SIL/Mangle.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ template <typename SubType>
104104
class SpecializationMangler : public SpecializationManglerBase {
105105
SubType *asImpl() { return static_cast<SubType *>(this); }
106106
public:
107+
Mangle::Mangler &getMangler() const { return M; }
107108

108109
~SpecializationMangler() = default;
109110

include/swift/SIL/Projection.h

Lines changed: 8 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -730,11 +730,6 @@ class ProjectionTreeNode {
730730
Initialized(false), IsLive(false) {}
731731

732732
public:
733-
enum LivenessKind : unsigned {
734-
NormalUseLiveness = 0,
735-
IgnoreEpilogueReleases = 1,
736-
};
737-
738733
class NewAggregateBuilder;
739734

740735
~ProjectionTreeNode() = default;
@@ -799,8 +794,7 @@ class ProjectionTreeNode {
799794

800795
void processUsersOfValue(ProjectionTree &Tree,
801796
llvm::SmallVectorImpl<ValueNodePair> &Worklist,
802-
SILValue Value, ProjectionTreeNode::LivenessKind Kind,
803-
llvm::DenseSet<SILInstruction *> &Releases);
797+
SILValue Value);
804798

805799
void createNextLevelChildren(ProjectionTree &Tree);
806800

@@ -814,12 +808,8 @@ class ProjectionTree {
814808

815809
SILModule &Mod;
816810

817-
llvm::BumpPtrAllocator &Allocator;
818-
819-
/// The way we compute what is live and what is dead.
820-
ProjectionTreeNode::LivenessKind Kind;
821-
822-
llvm::DenseSet<SILInstruction *> EpilogueReleases;
811+
/// The allocator we use to allocate ProjectionTreeNodes in the tree.
812+
llvm::SpecificBumpPtrAllocator<ProjectionTreeNode> Allocator;
823813

824814
// A common pattern is a 3 field struct.
825815
llvm::SmallVector<ProjectionTreeNode *, 4> ProjectionTreeNodes;
@@ -829,15 +819,10 @@ class ProjectionTree {
829819

830820
public:
831821
/// Construct a projection tree from BaseTy.
832-
ProjectionTree(SILModule &Mod, llvm::BumpPtrAllocator &Allocator,
833-
SILType BaseTy);
834-
ProjectionTree(SILModule &Mod, llvm::BumpPtrAllocator &Allocator,
835-
SILType BaseTy, ProjectionTreeNode::LivenessKind Kind,
836-
llvm::DenseSet<SILInstruction*> Insts);
822+
ProjectionTree(SILModule &Mod, SILType BaseTy);
837823
/// Construct an uninitialized projection tree, which can then be
838824
/// initialized by initializeWithExistingTree.
839-
ProjectionTree(SILModule &Mod, llvm::BumpPtrAllocator &Allocator)
840-
: Mod(Mod), Allocator(Allocator) {}
825+
ProjectionTree(SILModule &Mod) : Mod(Mod) {}
841826
~ProjectionTree();
842827
ProjectionTree(const ProjectionTree &) = delete;
843828
ProjectionTree(ProjectionTree &&) = default;
@@ -950,15 +935,16 @@ class ProjectionTree {
950935
void createRoot(SILType BaseTy) {
951936
assert(ProjectionTreeNodes.empty() &&
952937
"Should only create root when ProjectionTreeNodes is empty");
953-
auto *Node = new (Allocator) ProjectionTreeNode(BaseTy);
938+
auto *Node = new (Allocator.Allocate()) ProjectionTreeNode(BaseTy);
954939
ProjectionTreeNodes.push_back(Node);
955940
}
956941

957942
ProjectionTreeNode *createChild(ProjectionTreeNode *Parent,
958943
SILType BaseTy,
959944
const Projection &P) {
960945
unsigned Index = ProjectionTreeNodes.size();
961-
auto *Node = new (Allocator) ProjectionTreeNode(Parent, Index, BaseTy, P);
946+
auto *Node = new (Allocator.Allocate()) ProjectionTreeNode(Parent, Index,
947+
BaseTy, P);
962948
ProjectionTreeNodes.push_back(Node);
963949
return ProjectionTreeNodes[Index];
964950
}

include/swift/SILOptimizer/Analysis/ARCAnalysis.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,9 @@ class ConsumedArgToEpilogueReleaseMatcher {
189189
ExitKind Kind;
190190
llvm::SmallMapVector<SILArgument *, ReleaseList, 8> ArgInstMap;
191191

192+
/// Set to true if we found some releases but not all for the argument.
193+
llvm::DenseSet<SILArgument *> FoundSomeReleases;
194+
192195
/// Eventually this will be used in place of HasBlock.
193196
SILBasicBlock *ProcessedBlock;
194197

@@ -240,6 +243,12 @@ class ConsumedArgToEpilogueReleaseMatcher {
240243
return false;
241244
}
242245

246+
/// Return true if we've found some epilgoue releases for the argument
247+
/// but not all.
248+
bool hasSomeReleasesForArgument(SILArgument *Arg) {
249+
return FoundSomeReleases.find(Arg) != FoundSomeReleases.end();
250+
}
251+
243252
bool isSingleRelease(SILArgument *Arg) const {
244253
auto Iter = ArgInstMap.find(Arg);
245254
assert(Iter != ArgInstMap.end() && "Failed to get release list for argument");

include/swift/SILOptimizer/Utils/FunctionSignatureOptUtils.h

Lines changed: 21 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,15 @@
2828

2929
namespace swift {
3030

31-
using ReleaseSet = llvm::DenseSet<SILInstruction *>;
32-
3331
/// A structure that maintains all of the information about a specific
3432
/// SILArgument that we are tracking.
3533
struct ArgumentDescriptor {
36-
3734
/// The argument that we are tracking original data for.
3835
SILArgument *Arg;
3936

37+
/// Parameter Info.
38+
SILParameterInfo PInfo;
39+
4040
/// The original index of this argument.
4141
unsigned Index;
4242

@@ -48,6 +48,9 @@ struct ArgumentDescriptor {
4848

4949
/// Should the argument be exploded ?
5050
bool Explode;
51+
52+
/// This parameter is owned to guaranteed.
53+
bool OwnedToGuaranteed;
5154

5255
/// Is this parameter an indirect result?
5356
bool IsIndirectResult;
@@ -73,17 +76,13 @@ struct ArgumentDescriptor {
7376
/// to the original argument. The reason why we do this is to make sure we
7477
/// have access to the original argument's state if we modify the argument
7578
/// when optimizing.
76-
ArgumentDescriptor(llvm::BumpPtrAllocator &BPA, SILArgument *A,
77-
ReleaseSet Releases)
78-
: Arg(A), Index(A->getIndex()),
79+
ArgumentDescriptor(SILArgument *A)
80+
: Arg(A), PInfo(Arg->getKnownParameterInfo()), Index(A->getIndex()),
7981
Decl(A->getDecl()), IsEntirelyDead(false), Explode(false),
82+
OwnedToGuaranteed(false),
8083
IsIndirectResult(A->isIndirectResult()),
8184
CalleeRelease(), CalleeReleaseInThrowBlock(),
82-
ProjTree(A->getModule(), BPA, A->getType(),
83-
ProjectionTreeNode::LivenessKind::IgnoreEpilogueReleases,
84-
Releases) {
85-
ProjTree.computeUsesAndLiveness(A);
86-
}
85+
ProjTree(A->getModule(), A->getType()) {}
8786

8887
ArgumentDescriptor(const ArgumentDescriptor &) = delete;
8988
ArgumentDescriptor(ArgumentDescriptor &&) = default;
@@ -95,35 +94,12 @@ struct ArgumentDescriptor {
9594
return Arg->hasConvention(P);
9695
}
9796

98-
/// Convert the potentially multiple interface params associated with this
99-
/// argument.
100-
void
101-
computeOptimizedInterfaceParams(SmallVectorImpl<SILParameterInfo> &Out) const;
102-
103-
/// Add potentially multiple new arguments to NewArgs from the caller's apply
104-
/// or try_apply inst.
105-
void addCallerArgs(SILBuilder &Builder, FullApplySite FAS,
106-
SmallVectorImpl<SILValue> &NewArgs) const;
107-
108-
/// Add potentially multiple new arguments to NewArgs from the thunk's
109-
/// function arguments.
110-
void addThunkArgs(SILBuilder &Builder, SILBasicBlock *BB,
111-
SmallVectorImpl<SILValue> &NewArgs) const;
112-
113-
/// Optimize the argument at ArgOffset and return the index of the next
114-
/// argument to be optimized.
115-
///
116-
/// The return value makes it easy to SROA arguments since we can return the
117-
/// amount of SROAed arguments we created.
118-
unsigned updateOptimizedBBArgs(SILBuilder &Builder, SILBasicBlock *BB,
119-
unsigned ArgOffset);
120-
12197
bool canOptimizeLiveArg() const {
12298
return Arg->getType().isObject();
12399
}
124100

125101
/// Return true if it's both legal and a good idea to explode this argument.
126-
bool shouldExplode() const {
102+
bool shouldExplode(ConsumedArgToEpilogueReleaseMatcher &ERM) const {
127103
// We cannot optimize the argument.
128104
if (!canOptimizeLiveArg())
129105
return false;
@@ -150,15 +126,19 @@ struct ResultDescriptor {
150126
/// @owned or we could not find such a release in the callee, this is null.
151127
RetainList CalleeRetain;
152128

129+
/// This is owned to guaranteed.
130+
bool OwnedToGuaranteed;
131+
153132
/// Initialize this argument descriptor with all information from A that we
154133
/// use in our optimization.
155134
///
156135
/// *NOTE* We cache a lot of data from the argument and maintain a reference
157136
/// to the original argument. The reason why we do this is to make sure we
158137
/// have access to the original argument's state if we modify the argument
159138
/// when optimizing.
160-
ResultDescriptor() {};
161-
ResultDescriptor(SILResultInfo RI) : ResultInfo(RI), CalleeRetain() {}
139+
ResultDescriptor() {}
140+
ResultDescriptor(SILResultInfo RI)
141+
: ResultInfo(RI), CalleeRetain(), OwnedToGuaranteed(false) {}
162142

163143
ResultDescriptor(const ResultDescriptor &) = delete;
164144
ResultDescriptor(ResultDescriptor &&) = default;
@@ -171,100 +151,12 @@ struct ResultDescriptor {
171151
}
172152
};
173153

174-
class FunctionSignatureInfo {
175-
/// Should this function be optimized.
176-
bool ShouldOptimize;
177-
178-
/// Optimizing this function may lead to good performance potential.
179-
bool HighlyProfitable;
180-
181-
/// Function currently analyzing.
182-
SILFunction *F;
183-
184-
/// The allocator we are using.
185-
llvm::BumpPtrAllocator &Allocator;
186-
187-
/// The alias analysis currently using.
188-
AliasAnalysis *AA;
189-
190-
/// The rc-identity analysis currently using.
191-
RCIdentityFunctionInfo *RCFI;
192-
193-
/// Does any call inside the given function may bind dynamic 'Self' to a
194-
/// generic argument of the callee.
195-
bool MayBindDynamicSelf;
196-
197-
/// Did we decide to change the self argument? If so we need to
198-
/// change the calling convention 'method' to 'freestanding'.
199-
bool ShouldModifySelfArgument = false;
200-
201-
/// A list of structures which present a "view" of precompiled information on
202-
/// an argument that we will use during our optimization.
203-
llvm::SmallVector<ArgumentDescriptor, 8> ArgDescList;
204-
205-
/// Keep a "view" of precompiled information on the direct results
206-
/// which we will use during our optimization.
207-
llvm::SmallVector<ResultDescriptor, 4> ResultDescList;
208-
209-
210-
public:
211-
FunctionSignatureInfo(SILFunction *F, llvm::BumpPtrAllocator &BPA,
212-
AliasAnalysis *AA, RCIdentityFunctionInfo *RCFI) :
213-
ShouldOptimize(false), HighlyProfitable(false), F(F), Allocator(BPA),
214-
AA(AA), RCFI(RCFI), MayBindDynamicSelf(computeMayBindDynamicSelf(F)) {
215-
analyze();
216-
}
217-
218-
bool shouldOptimize() const { return ShouldOptimize; }
219-
bool profitableOptimize() const { return HighlyProfitable; }
220-
221-
void analyze();
222-
bool analyzeParameters();
223-
bool analyzeResult();
224-
225-
/// Returns the mangled name of the function that should be generated from
226-
/// this function analyzer.
227-
std::string getOptimizedName() const;
228-
229-
bool shouldModifySelfArgument() const { return ShouldModifySelfArgument; }
230-
ArrayRef<ArgumentDescriptor> getArgDescList() const { return ArgDescList; }
231-
ArrayRef<ResultDescriptor> getResultDescList() {return ResultDescList;}
232-
SILFunction *getAnalyzedFunction() const { return F; }
233-
234-
private:
235-
/// Is the given argument required by the ABI?
236-
///
237-
/// Metadata arguments may be required if dynamic Self is bound to any generic
238-
/// parameters within this function's call sites.
239-
bool isArgumentABIRequired(SILArgument *Arg) {
240-
// This implicitly asserts that a function binding dynamic self has a self
241-
// metadata argument or object from which self metadata can be obtained.
242-
return MayBindDynamicSelf && (F->getSelfMetadataArgument() == Arg);
243-
}
244-
};
245-
246-
247-
154+
/// Returns true if F is a function which the pass know show to specialize
155+
/// function signatures for.
248156
bool canSpecializeFunction(SILFunction *F);
249157

250-
void
251-
addReleasesForConvertedOwnedParameter(SILBuilder &Builder,
252-
SILLocation Loc,
253-
OperandValueArrayRef Parameters,
254-
ArrayRef<ArgumentDescriptor> &ArgDescs);
255-
256-
void
257-
addReleasesForConvertedOwnedParameter(SILBuilder &Builder,
258-
SILLocation Loc,
259-
ArrayRef<SILArgument*> Parameters,
260-
ArrayRef<ArgumentDescriptor> &ArgDescs);
261-
void
262-
addRetainsForConvertedDirectResults(SILBuilder &Builder,
263-
SILLocation Loc,
264-
SILValue ReturnValue,
265-
SILInstruction *AI,
266-
ArrayRef<ResultDescriptor> DirectResults);
267-
158+
/// Return true if this argument is used in a non-trivial way.
159+
bool hasNonTrivialNonDebugUse(SILArgument *Arg);
268160

269161
} // end namespace swift
270162

lib/SIL/Mangle.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ FunctionSignatureSpecializationMangler(SpecializationPass P, Mangler &M,
8181
void
8282
FunctionSignatureSpecializationMangler::
8383
setArgumentDead(unsigned ArgNo) {
84-
Args[ArgNo].first = ArgumentModifierIntBase(ArgumentModifier::Dead);
84+
Args[ArgNo].first |= ArgumentModifierIntBase(ArgumentModifier::Dead);
8585
}
8686

8787
void

0 commit comments

Comments
 (0)