Skip to content

Commit 82c5237

Browse files
committed
Merge pull request #2309 from apple/revert-2284-SFSO
Revert "Simplify function signature optimization"
2 parents 2d29c0d + 57e2bdb commit 82c5237

File tree

9 files changed

+911
-864
lines changed

9 files changed

+911
-864
lines changed

include/swift/SIL/Mangle.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,6 @@ 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; }
108107

109108
~SpecializationMangler() = default;
110109

include/swift/SIL/Projection.h

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

732732
public:
733+
enum LivenessKind : unsigned {
734+
NormalUseLiveness = 0,
735+
IgnoreEpilogueReleases = 1,
736+
};
737+
733738
class NewAggregateBuilder;
734739

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

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

799805
void createNextLevelChildren(ProjectionTree &Tree);
800806

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

811817
llvm::BumpPtrAllocator &Allocator;
812818

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

include/swift/SILOptimizer/Utils/FunctionSignatureOptUtils.h

Lines changed: 127 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,12 @@
2828

2929
namespace swift {
3030

31+
using ReleaseSet = llvm::DenseSet<SILInstruction *>;
32+
3133
/// A structure that maintains all of the information about a specific
3234
/// SILArgument that we are tracking.
3335
struct ArgumentDescriptor {
36+
3437
/// The argument that we are tracking original data for.
3538
SILArgument *Arg;
3639

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

4649
/// Should the argument be exploded ?
4750
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,13 +73,17 @@ 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)
76+
ArgumentDescriptor(llvm::BumpPtrAllocator &BPA, SILArgument *A,
77+
ReleaseSet Releases)
7778
: Arg(A), Index(A->getIndex()),
7879
Decl(A->getDecl()), IsEntirelyDead(false), Explode(false),
79-
OwnedToGuaranteed(false),
8080
IsIndirectResult(A->isIndirectResult()),
8181
CalleeRelease(), CalleeReleaseInThrowBlock(),
82-
ProjTree(A->getModule(), BPA, A->getType()) {}
82+
ProjTree(A->getModule(), BPA, A->getType(),
83+
ProjectionTreeNode::LivenessKind::IgnoreEpilogueReleases,
84+
Releases) {
85+
ProjTree.computeUsesAndLiveness(A);
86+
}
8387

8488
ArgumentDescriptor(const ArgumentDescriptor &) = delete;
8589
ArgumentDescriptor(ArgumentDescriptor &&) = default;
@@ -91,6 +95,29 @@ struct ArgumentDescriptor {
9195
return Arg->hasConvention(P);
9296
}
9397

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

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

140163
ResultDescriptor(const ResultDescriptor &) = delete;
141164
ResultDescriptor(ResultDescriptor &&) = default;
@@ -148,12 +171,100 @@ struct ResultDescriptor {
148171
}
149172
};
150173

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

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

158269
} // end namespace swift
159270

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

898899
// For all uses of V...
@@ -910,6 +911,13 @@ processUsersOfValue(ProjectionTree &Tree,
910911
if (!P.isValid()) {
911912
DEBUG(llvm::dbgs() << " Failed to create projection. Adding "
912913
"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+
}
913921
addNonProjectionUser(Op);
914922
continue;
915923
}
@@ -941,6 +949,12 @@ processUsersOfValue(ProjectionTree &Tree,
941949
// The only projection which we do not currently handle are enums since we
942950
// may not know the correct case. This can be extended in the future.
943951
// 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+
}
944958
addNonProjectionUser(Op);
945959
}
946960
}
@@ -1143,7 +1157,21 @@ class NewAggregateBuilderMap {
11431157

11441158
ProjectionTree::
11451159
ProjectionTree(SILModule &Mod, llvm::BumpPtrAllocator &BPA, SILType BaseTy)
1146-
: Mod(Mod), Allocator(BPA) {
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) {
11471175
DEBUG(llvm::dbgs() << "Constructing Projection Tree For : " << BaseTy);
11481176

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

11601188
void
11611189
ProjectionTree::initializeWithExistingTree(const ProjectionTree &PT) {
1190+
Kind = PT.Kind;
1191+
EpilogueReleases = PT.EpilogueReleases;
11621192
LiveLeafIndices = PT.LiveLeafIndices;
11631193
for (const auto &N : PT.ProjectionTreeNodes) {
11641194
ProjectionTreeNodes.push_back(new (Allocator) ProjectionTreeNode(*N));
@@ -1255,7 +1285,7 @@ computeUsesAndLiveness(SILValue Base) {
12551285
// If Value is not null, collate all users of Value the appropriate child
12561286
// nodes and add such items to the worklist.
12571287
if (Value) {
1258-
Node->processUsersOfValue(*this, UseWorklist, Value);
1288+
Node->processUsersOfValue(*this, UseWorklist, Value, Kind, EpilogueReleases);
12591289
}
12601290

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

0 commit comments

Comments
 (0)