Skip to content

Commit 5f7f05d

Browse files
committed
Reinstate "Moves SignatureAnalyzer and ArgumentDescriptor/ResultDescriptor into
a separate analysis pass. This pass is run on every function and the optimized signature is return'ed through the getArgDescList and getResultDescList. Next step is to split to cloning and callsite rewriting into their own function passes. rdar://24730896 "
1 parent 149fd43 commit 5f7f05d

File tree

7 files changed

+665
-535
lines changed

7 files changed

+665
-535
lines changed

include/swift/SIL/Projection.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -832,6 +832,10 @@ class ProjectionTree {
832832
ProjectionTree(SILModule &Mod, llvm::BumpPtrAllocator &Allocator,
833833
SILType BaseTy, ProjectionTreeNode::LivenessKind Kind,
834834
llvm::DenseSet<SILInstruction*> Insts);
835+
/// Construct an uninitialized projection tree, which can then be
836+
/// initialized by initializeWithExistingTree.
837+
ProjectionTree(SILModule &Mod, llvm::BumpPtrAllocator &Allocator)
838+
: Mod(Mod), Allocator(Allocator) {}
835839
~ProjectionTree();
836840
ProjectionTree(const ProjectionTree &) = delete;
837841
ProjectionTree(ProjectionTree &&) = default;
@@ -842,6 +846,10 @@ class ProjectionTree {
842846
/// All debug instructions (debug_value, debug_value_addr) are ignored.
843847
void computeUsesAndLiveness(SILValue Base);
844848

849+
/// Initialize an empty projection tree with an existing, computed projection
850+
/// tree.
851+
void initializeWithExistingTree(const ProjectionTree &PT);
852+
845853
/// Create a root SILValue iout of the given leaf node values by walking on
846854
/// the projection tree.
847855
SILValue computeExplodedArgumentValue(SILBuilder &Builder,

include/swift/SILOptimizer/Analysis/Analysis.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ ANALYSIS(ClassHierarchy)
2929
ANALYSIS(Destructor)
3030
ANALYSIS(Dominance)
3131
ANALYSIS(Escape)
32+
ANALYSIS(FunctionSignature)
3233
ANALYSIS(InductionVariable)
3334
ANALYSIS(Loop)
3435
ANALYSIS(LoopRegion)
Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
//===--- FunctionSignatureAnalysis.h ----------------------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See http://swift.org/LICENSE.txt for license information
9+
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This is an analysis that determines how a function signature should be
14+
// optimized.
15+
//===----------------------------------------------------------------------===//
16+
17+
#ifndef SWIFT_SILOPTIMIZER_ANALYSIS_FUNCTIONSIGNATUREANALYSIS_H
18+
#define SWIFT_SILOPTIMIZER_ANALYSIS_FUNCTIONSIGNATUREANALYSIS_H
19+
20+
#include "swift/SIL/Projection.h"
21+
#include "swift/SIL/SILInstruction.h"
22+
#include "swift/SIL/SILValue.h"
23+
#include "swift/SIL/SILArgument.h"
24+
#include "swift/SILOptimizer/Analysis/Analysis.h"
25+
#include "swift/SILOptimizer/Analysis/AliasAnalysis.h"
26+
#include "swift/SILOptimizer/Analysis/ARCAnalysis.h"
27+
#include "swift/SILOptimizer/Analysis/RCIdentityAnalysis.h"
28+
#include "swift/SILOptimizer/Utils/Local.h"
29+
#include "swift/SILOptimizer/PassManager/PassManager.h"
30+
31+
namespace swift {
32+
33+
using ReleaseSet = llvm::DenseSet<SILInstruction *>;
34+
35+
/// A structure that maintains all of the information about a specific
36+
/// SILArgument that we are tracking.
37+
struct ArgumentDescriptor {
38+
39+
/// The argument that we are tracking original data for.
40+
SILArgument *Arg;
41+
42+
/// The original index of this argument.
43+
unsigned Index;
44+
45+
/// The original decl of this Argument.
46+
const ValueDecl *Decl;
47+
48+
/// Was this parameter originally dead?
49+
bool IsEntirelyDead;
50+
51+
/// Should the argument be exploded ?
52+
bool Explode;
53+
54+
/// Is this parameter an indirect result?
55+
bool IsIndirectResult;
56+
57+
/// If non-null, this is the release in the return block of the callee, which
58+
/// is associated with this parameter if it is @owned. If the parameter is not
59+
/// @owned or we could not find such a release in the callee, this is null.
60+
ReleaseList CalleeRelease;
61+
62+
/// The same as CalleeRelease, but the release in the throw block, if it is a
63+
/// function which has a throw block.
64+
ReleaseList CalleeReleaseInThrowBlock;
65+
66+
/// The projection tree of this arguments.
67+
ProjectionTree ProjTree;
68+
69+
ArgumentDescriptor() = delete;
70+
71+
/// Initialize this argument descriptor with all information from A that we
72+
/// use in our optimization.
73+
///
74+
/// *NOTE* We cache a lot of data from the argument and maintain a reference
75+
/// to the original argument. The reason why we do this is to make sure we
76+
/// have access to the original argument's state if we modify the argument
77+
/// when optimizing.
78+
ArgumentDescriptor(llvm::BumpPtrAllocator &BPA, SILArgument *A,
79+
ReleaseSet Releases)
80+
: Arg(A), Index(A->getIndex()),
81+
Decl(A->getDecl()), IsEntirelyDead(false), Explode(false),
82+
IsIndirectResult(A->isIndirectResult()),
83+
CalleeRelease(), CalleeReleaseInThrowBlock(),
84+
ProjTree(A->getModule(), BPA, A->getType(),
85+
ProjectionTreeNode::LivenessKind::IgnoreEpilogueReleases,
86+
Releases) {
87+
ProjTree.computeUsesAndLiveness(A);
88+
}
89+
90+
ArgumentDescriptor(const ArgumentDescriptor &) = delete;
91+
ArgumentDescriptor(ArgumentDescriptor &&) = default;
92+
ArgumentDescriptor &operator=(const ArgumentDescriptor &) = delete;
93+
ArgumentDescriptor &operator=(ArgumentDescriptor &&) = default;
94+
95+
/// \returns true if this argument's convention is P.
96+
bool hasConvention(SILArgumentConvention P) const {
97+
return Arg->hasConvention(P);
98+
}
99+
100+
/// Convert the potentially multiple interface params associated with this
101+
/// argument.
102+
void
103+
computeOptimizedInterfaceParams(SmallVectorImpl<SILParameterInfo> &Out) const;
104+
105+
/// Add potentially multiple new arguments to NewArgs from the caller's apply
106+
/// or try_apply inst.
107+
void addCallerArgs(SILBuilder &Builder, FullApplySite FAS,
108+
SmallVectorImpl<SILValue> &NewArgs) const;
109+
110+
/// Add potentially multiple new arguments to NewArgs from the thunk's
111+
/// function arguments.
112+
void addThunkArgs(SILBuilder &Builder, SILBasicBlock *BB,
113+
SmallVectorImpl<SILValue> &NewArgs) const;
114+
115+
/// Optimize the argument at ArgOffset and return the index of the next
116+
/// argument to be optimized.
117+
///
118+
/// The return value makes it easy to SROA arguments since we can return the
119+
/// amount of SROAed arguments we created.
120+
unsigned updateOptimizedBBArgs(SILBuilder &Builder, SILBasicBlock *BB,
121+
unsigned ArgOffset);
122+
123+
bool canOptimizeLiveArg() const {
124+
return Arg->getType().isObject();
125+
}
126+
127+
/// Return true if it's both legal and a good idea to explode this argument.
128+
bool shouldExplode() const {
129+
// We cannot optimize the argument.
130+
if (!canOptimizeLiveArg())
131+
return false;
132+
133+
// See if the projection tree consists of potentially multiple levels of
134+
// structs containing one field. In such a case, there is no point in
135+
// exploding the argument.
136+
if (ProjTree.isSingleton())
137+
return false;
138+
139+
size_t explosionSize = ProjTree.liveLeafCount();
140+
return explosionSize >= 1 && explosionSize <= 3;
141+
}
142+
};
143+
144+
/// A structure that maintains all of the information about a specific
145+
/// direct result that we are tracking.
146+
struct ResultDescriptor {
147+
/// The original parameter info of this argument.
148+
SILResultInfo ResultInfo;
149+
150+
/// If non-null, this is the release in the return block of the callee, which
151+
/// is associated with this parameter if it is @owned. If the parameter is not
152+
/// @owned or we could not find such a release in the callee, this is null.
153+
RetainList CalleeRetain;
154+
155+
/// Initialize this argument descriptor with all information from A that we
156+
/// use in our optimization.
157+
///
158+
/// *NOTE* We cache a lot of data from the argument and maintain a reference
159+
/// to the original argument. The reason why we do this is to make sure we
160+
/// have access to the original argument's state if we modify the argument
161+
/// when optimizing.
162+
ResultDescriptor() {};
163+
ResultDescriptor(SILResultInfo RI) : ResultInfo(RI), CalleeRetain() {}
164+
165+
ResultDescriptor(const ResultDescriptor &) = delete;
166+
ResultDescriptor(ResultDescriptor &&) = default;
167+
ResultDescriptor &operator=(const ResultDescriptor &) = delete;
168+
ResultDescriptor &operator=(ResultDescriptor &&) = default;
169+
170+
/// \returns true if this argument's ParameterConvention is P.
171+
bool hasConvention(ResultConvention R) const {
172+
return ResultInfo.getConvention() == R;
173+
}
174+
};
175+
176+
class FunctionSignatureInfo {
177+
/// Function currently analyzing.
178+
SILFunction *F;
179+
180+
/// The allocator we are using.
181+
llvm::BumpPtrAllocator &Allocator;
182+
183+
/// The alias analysis currently using.
184+
AliasAnalysis *AA;
185+
186+
/// The rc-identity analysis currently using.
187+
RCIdentityFunctionInfo *RCFI;
188+
189+
/// Does any call inside the given function may bind dynamic 'Self' to a
190+
/// generic argument of the callee.
191+
bool MayBindDynamicSelf;
192+
193+
/// Did we decide to change the self argument? If so we need to
194+
/// change the calling convention 'method' to 'freestanding'.
195+
bool ShouldModifySelfArgument = false;
196+
197+
/// A list of structures which present a "view" of precompiled information on
198+
/// an argument that we will use during our optimization.
199+
llvm::SmallVector<ArgumentDescriptor, 8> ArgDescList;
200+
201+
/// Keep a "view" of precompiled information on the direct results
202+
/// which we will use during our optimization.
203+
llvm::SmallVector<ResultDescriptor, 4> ResultDescList;
204+
205+
206+
public:
207+
FunctionSignatureInfo(SILFunction *F, llvm::BumpPtrAllocator &BPA, AliasAnalysis *AA,
208+
RCIdentityFunctionInfo *RCFI) :
209+
F(F), Allocator(BPA), AA(AA), RCFI(RCFI), MayBindDynamicSelf(computeMayBindDynamicSelf(F)) {}
210+
211+
bool analyze();
212+
bool analyzeParameters();
213+
bool analyzeResult();
214+
215+
/// Returns the mangled name of the function that should be generated from
216+
/// this function analyzer.
217+
std::string getOptimizedName() const;
218+
219+
bool shouldModifySelfArgument() const { return ShouldModifySelfArgument; }
220+
ArrayRef<ArgumentDescriptor> getArgDescList() const { return ArgDescList; }
221+
ArrayRef<ResultDescriptor> getResultDescList() {return ResultDescList;}
222+
SILFunction *getAnalyzedFunction() const { return F; }
223+
224+
private:
225+
/// Is the given argument required by the ABI?
226+
///
227+
/// Metadata arguments may be required if dynamic Self is bound to any generic
228+
/// parameters within this function's call sites.
229+
bool isArgumentABIRequired(SILArgument *Arg) {
230+
// This implicitly asserts that a function binding dynamic self has a self
231+
// metadata argument or object from which self metadata can be obtained.
232+
return MayBindDynamicSelf && (F->getSelfMetadataArgument() == Arg);
233+
}
234+
};
235+
236+
class FunctionSignatureAnalysis : public FunctionAnalysisBase<FunctionSignatureInfo> {
237+
/// The alias analysis currently using.
238+
AliasAnalysis *AA;
239+
240+
/// The rc-identity analysis currently using.
241+
RCIdentityAnalysis *RCIA;
242+
243+
llvm::BumpPtrAllocator BPA;
244+
public:
245+
FunctionSignatureAnalysis(SILModule *)
246+
: FunctionAnalysisBase<FunctionSignatureInfo>(AnalysisKind::FunctionSignature),
247+
AA(nullptr), RCIA(nullptr) {}
248+
249+
FunctionSignatureAnalysis(const FunctionSignatureAnalysis &) = delete;
250+
FunctionSignatureAnalysis &operator=(const FunctionSignatureAnalysis &) = delete;
251+
252+
static bool classof(const SILAnalysis *S) {
253+
return S->getKind() == AnalysisKind::FunctionSignature;
254+
}
255+
256+
virtual void initialize(SILPassManager *PM) override;
257+
258+
virtual FunctionSignatureInfo *newFunctionAnalysis(SILFunction *F) override {
259+
return new FunctionSignatureInfo(F, BPA, AA, RCIA->get(F));
260+
}
261+
262+
virtual bool shouldInvalidate(SILAnalysis::InvalidationKind K) override {
263+
return true;
264+
}
265+
};
266+
} // end swift namespace
267+
268+
#endif

lib/SIL/Projection.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1168,8 +1168,18 @@ ProjectionTree(SILModule &Mod, llvm::BumpPtrAllocator &BPA, SILType BaseTy,
11681168
}
11691169

11701170
ProjectionTree::~ProjectionTree() {
1171-
for (auto *N : ProjectionTreeNodes)
1172-
N->~ProjectionTreeNode();
1171+
// Do nothing !. Eventually the all the projection tree nodes will be freed
1172+
// when the BPA allocator is free.
1173+
}
1174+
1175+
void
1176+
ProjectionTree::initializeWithExistingTree(const ProjectionTree &PT) {
1177+
Kind = PT.Kind;
1178+
EpilogueReleases = PT.EpilogueReleases;
1179+
LiveLeafIndices = PT.LiveLeafIndices;
1180+
for (const auto &N : PT.ProjectionTreeNodes) {
1181+
ProjectionTreeNodes.push_back(new (Allocator) ProjectionTreeNode(*N));
1182+
}
11731183
}
11741184

11751185
SILValue

lib/SILOptimizer/Analysis/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ set(ANALYSIS_SOURCES
1010
Analysis/DestructorAnalysis.cpp
1111
Analysis/EscapeAnalysis.cpp
1212
Analysis/FunctionOrder.cpp
13+
Analysis/FunctionSignatureAnalysis.cpp
1314
Analysis/IVAnalysis.cpp
1415
Analysis/LoopAnalysis.cpp
1516
Analysis/LoopRegionAnalysis.cpp

0 commit comments

Comments
 (0)