Skip to content

Commit 180c30b

Browse files
committed
Merge pull request #2284 from trentxintong/SFSO
Simplify function signature optimization
2 parents cbf08e4 + 633ca2e commit 180c30b

File tree

9 files changed

+864
-911
lines changed

9 files changed

+864
-911
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: 1 addition & 15 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

@@ -816,11 +810,6 @@ class ProjectionTree {
816810

817811
llvm::BumpPtrAllocator &Allocator;
818812

819-
/// The way we compute what is live and what is dead.
820-
ProjectionTreeNode::LivenessKind Kind;
821-
822-
llvm::DenseSet<SILInstruction *> EpilogueReleases;
823-
824813
// A common pattern is a 3 field struct.
825814
llvm::SmallVector<ProjectionTreeNode *, 4> ProjectionTreeNodes;
826815
llvm::SmallVector<unsigned, 3> LiveLeafIndices;
@@ -831,9 +820,6 @@ class ProjectionTree {
831820
/// Construct a projection tree from BaseTy.
832821
ProjectionTree(SILModule &Mod, llvm::BumpPtrAllocator &Allocator,
833822
SILType BaseTy);
834-
ProjectionTree(SILModule &Mod, llvm::BumpPtrAllocator &Allocator,
835-
SILType BaseTy, ProjectionTreeNode::LivenessKind Kind,
836-
llvm::DenseSet<SILInstruction*> Insts);
837823
/// Construct an uninitialized projection tree, which can then be
838824
/// initialized by initializeWithExistingTree.
839825
ProjectionTree(SILModule &Mod, llvm::BumpPtrAllocator &Allocator)

include/swift/SILOptimizer/Utils/FunctionSignatureOptUtils.h

Lines changed: 16 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,9 @@
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

@@ -48,6 +45,9 @@ struct ArgumentDescriptor {
4845

4946
/// Should the argument be exploded ?
5047
bool Explode;
48+
49+
/// This parameter is owned to guaranteed.
50+
bool OwnedToGuaranteed;
5151

5252
/// Is this parameter an indirect result?
5353
bool IsIndirectResult;
@@ -73,17 +73,13 @@ struct ArgumentDescriptor {
7373
/// to the original argument. The reason why we do this is to make sure we
7474
/// have access to the original argument's state if we modify the argument
7575
/// when optimizing.
76-
ArgumentDescriptor(llvm::BumpPtrAllocator &BPA, SILArgument *A,
77-
ReleaseSet Releases)
76+
ArgumentDescriptor(llvm::BumpPtrAllocator &BPA, SILArgument *A)
7877
: Arg(A), Index(A->getIndex()),
7978
Decl(A->getDecl()), IsEntirelyDead(false), Explode(false),
79+
OwnedToGuaranteed(false),
8080
IsIndirectResult(A->isIndirectResult()),
8181
CalleeRelease(), CalleeReleaseInThrowBlock(),
82-
ProjTree(A->getModule(), BPA, A->getType(),
83-
ProjectionTreeNode::LivenessKind::IgnoreEpilogueReleases,
84-
Releases) {
85-
ProjTree.computeUsesAndLiveness(A);
86-
}
82+
ProjTree(A->getModule(), BPA, A->getType()) {}
8783

8884
ArgumentDescriptor(const ArgumentDescriptor &) = delete;
8985
ArgumentDescriptor(ArgumentDescriptor &&) = default;
@@ -95,29 +91,6 @@ struct ArgumentDescriptor {
9591
return Arg->hasConvention(P);
9692
}
9793

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-
12194
bool canOptimizeLiveArg() const {
12295
return Arg->getType().isObject();
12396
}
@@ -150,15 +123,19 @@ struct ResultDescriptor {
150123
/// @owned or we could not find such a release in the callee, this is null.
151124
RetainList CalleeRetain;
152125

126+
/// This is owned to guaranteed.
127+
bool OwnedToGuaranteed;
128+
153129
/// Initialize this argument descriptor with all information from A that we
154130
/// use in our optimization.
155131
///
156132
/// *NOTE* We cache a lot of data from the argument and maintain a reference
157133
/// to the original argument. The reason why we do this is to make sure we
158134
/// have access to the original argument's state if we modify the argument
159135
/// when optimizing.
160-
ResultDescriptor() {};
161-
ResultDescriptor(SILResultInfo RI) : ResultInfo(RI), CalleeRetain() {}
136+
ResultDescriptor() {}
137+
ResultDescriptor(SILResultInfo RI)
138+
: ResultInfo(RI), CalleeRetain(), OwnedToGuaranteed(false) {}
162139

163140
ResultDescriptor(const ResultDescriptor &) = delete;
164141
ResultDescriptor(ResultDescriptor &&) = default;
@@ -171,100 +148,12 @@ struct ResultDescriptor {
171148
}
172149
};
173150

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-
151+
/// Returns true if F is a function which the pass know show to specialize
152+
/// function signatures for.
248153
bool canSpecializeFunction(SILFunction *F);
249154

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-
155+
/// Return true if this argument is used in a non-trivial way.
156+
bool hasNonTrivialNonDebugUse(SILArgument *Arg);
268157

269158
} // end namespace swift
270159

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

lib/SIL/Projection.cpp

Lines changed: 3 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -892,8 +892,7 @@ void
892892
ProjectionTreeNode::
893893
processUsersOfValue(ProjectionTree &Tree,
894894
llvm::SmallVectorImpl<ValueNodePair> &Worklist,
895-
SILValue Value, LivenessKind Kind,
896-
llvm::DenseSet<SILInstruction *> &Releases) {
895+
SILValue Value) {
897896
DEBUG(llvm::dbgs() << " Looking at Users:\n");
898897

899898
// For all uses of V...
@@ -911,13 +910,6 @@ processUsersOfValue(ProjectionTree &Tree,
911910
if (!P.isValid()) {
912911
DEBUG(llvm::dbgs() << " Failed to create projection. Adding "
913912
"to non projection user!\n");
914-
// Is the user an epilogue release ?
915-
if (Kind == IgnoreEpilogueReleases) {
916-
bool EpilogueReleaseUser = !Releases.empty();
917-
EpilogueReleaseUser &= Releases.find(User) != Releases.end();
918-
if (EpilogueReleaseUser)
919-
continue;
920-
}
921913
addNonProjectionUser(Op);
922914
continue;
923915
}
@@ -949,12 +941,6 @@ processUsersOfValue(ProjectionTree &Tree,
949941
// The only projection which we do not currently handle are enums since we
950942
// may not know the correct case. This can be extended in the future.
951943
// Is the user an epilogue release ?
952-
if (Kind == IgnoreEpilogueReleases) {
953-
bool EpilogueReleaseUser = !Releases.empty();
954-
EpilogueReleaseUser &= Releases.find(User) != Releases.end();
955-
if (EpilogueReleaseUser)
956-
continue;
957-
}
958944
addNonProjectionUser(Op);
959945
}
960946
}
@@ -1157,21 +1143,7 @@ class NewAggregateBuilderMap {
11571143

11581144
ProjectionTree::
11591145
ProjectionTree(SILModule &Mod, llvm::BumpPtrAllocator &BPA, SILType BaseTy)
1160-
: Mod(Mod), Allocator(BPA),
1161-
Kind(ProjectionTreeNode::LivenessKind::NormalUseLiveness) {
1162-
DEBUG(llvm::dbgs() << "Constructing Projection Tree For : " << BaseTy);
1163-
1164-
// Create the root node of the tree with our base type.
1165-
createRoot(BaseTy);
1166-
1167-
// Create the rest of the type tree lazily based on uses.
1168-
}
1169-
1170-
ProjectionTree::
1171-
ProjectionTree(SILModule &Mod, llvm::BumpPtrAllocator &BPA, SILType BaseTy,
1172-
ProjectionTreeNode::LivenessKind Kind,
1173-
llvm::DenseSet<SILInstruction *> Insts)
1174-
: Mod(Mod), Allocator(BPA), Kind(Kind), EpilogueReleases(Insts) {
1146+
: Mod(Mod), Allocator(BPA) {
11751147
DEBUG(llvm::dbgs() << "Constructing Projection Tree For : " << BaseTy);
11761148

11771149
// Create the root node of the tree with our base type.
@@ -1187,8 +1159,6 @@ ProjectionTree::~ProjectionTree() {
11871159

11881160
void
11891161
ProjectionTree::initializeWithExistingTree(const ProjectionTree &PT) {
1190-
Kind = PT.Kind;
1191-
EpilogueReleases = PT.EpilogueReleases;
11921162
LiveLeafIndices = PT.LiveLeafIndices;
11931163
for (const auto &N : PT.ProjectionTreeNodes) {
11941164
ProjectionTreeNodes.push_back(new (Allocator) ProjectionTreeNode(*N));
@@ -1285,7 +1255,7 @@ computeUsesAndLiveness(SILValue Base) {
12851255
// If Value is not null, collate all users of Value the appropriate child
12861256
// nodes and add such items to the worklist.
12871257
if (Value) {
1288-
Node->processUsersOfValue(*this, UseWorklist, Value, Kind, EpilogueReleases);
1258+
Node->processUsersOfValue(*this, UseWorklist, Value);
12891259
}
12901260

12911261
// If this node is live due to a non projection user, propagate down its

0 commit comments

Comments
 (0)