Skip to content

Commit 295dc96

Browse files
committed
[SILOptimizer] Introduce an eager-specializer pass.
This pass finds generic functions with @_specialized attributes and generates specialized code for the attribute's concrete types. It inserts type checks and guarded dispatch at the beginning of the generic function for each specialization. Since we don't currently expose this attribute as API and don't specialize vtables and witness tables yet, the only way to reach the specialized code is by calling the generic function which performs the guarded dispatch. In the future, we can build on this work in several ways: - cross module dispatch directly to specialized code - dynamic dispatch directly to specialized code - automated specialization based on less specific hints - partial specialization - and so on... I reorganized and refactored the optimizer's generic utilities to support direct function specialization as opposed to apply specialization.
1 parent 4c05227 commit 295dc96

File tree

9 files changed

+1234
-251
lines changed

9 files changed

+1234
-251
lines changed

include/swift/SILOptimizer/PassManager/Passes.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ PASS(DiagnoseUnreachable, "diagnose-unreachable",
8888
"Diagnose Unreachable Code")
8989
PASS(DiagnosticConstantPropagation, "diagnostic-constant-propagation",
9090
"Propagate constants and emit diagnostics")
91+
PASS(EagerSpecializer, "eager-specializer",
92+
"Specialize speculatively and insert dispatch guarded by type checks")
9193
PASS(EarlyCodeMotion, "early-codemotion",
9294
"Code motion without release hoisting")
9395
PASS(EarlyInliner, "early-inline",

include/swift/SILOptimizer/Utils/GenericCloner.h

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,24 +40,25 @@ class GenericCloner : public TypeSubstCloner<GenericCloner> {
4040
GenericCloner(SILFunction *F,
4141
const ReabstractionInfo &ReInfo,
4242
TypeSubstitutionMap &ContextSubs,
43+
ArrayRef<Substitution> ParamSubs,
4344
StringRef NewName,
44-
ArrayRef<Substitution> ApplySubs,
4545
CloneCollector::CallbackType Callback)
4646
: TypeSubstCloner(*initCloned(F, ReInfo, NewName), *F, ContextSubs,
47-
ApplySubs), ReInfo(ReInfo), Callback(Callback) {
47+
ParamSubs), ReInfo(ReInfo), Callback(Callback) {
4848
assert(F->getDebugScope()->Parent != getCloned()->getDebugScope()->Parent);
4949
}
5050
/// Clone and remap the types in \p F according to the substitution
5151
/// list in \p Subs. Parameters are re-abstracted (changed from indirect to
5252
/// direct) according to \p ReInfo.
53-
static SILFunction *cloneFunction(SILFunction *F,
54-
const ReabstractionInfo &ReInfo,
55-
TypeSubstitutionMap &ContextSubs,
56-
StringRef NewName, ApplySite Caller,
57-
CloneCollector::CallbackType Callback =nullptr) {
53+
static SILFunction *
54+
cloneFunction(SILFunction *F,
55+
const ReabstractionInfo &ReInfo,
56+
TypeSubstitutionMap &ContextSubs,
57+
ArrayRef<Substitution> ParamSubs,
58+
StringRef NewName,
59+
CloneCollector::CallbackType Callback =nullptr) {
5860
// Clone and specialize the function.
59-
GenericCloner SC(F, ReInfo, ContextSubs, NewName,
60-
Caller.getSubstitutions(), Callback);
61+
GenericCloner SC(F, ReInfo, ContextSubs, ParamSubs, NewName, Callback);
6162
SC.populateCloned();
6263
SC.cleanUp(SC.getCloned());
6364
return SC.getCloned();

include/swift/SILOptimizer/Utils/Generics.h

Lines changed: 76 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -22,24 +22,51 @@
2222
#include "swift/SIL/SILFunction.h"
2323
#include "swift/SIL/SILInstruction.h"
2424
#include "swift/SILOptimizer/Utils/Local.h"
25-
#include "llvm/ADT/BitVector.h"
25+
#include "llvm/ADT/SmallBitVector.h"
2626
#include "llvm/Support/CommandLine.h"
2727
#include "llvm/Support/Debug.h"
2828

2929
namespace swift {
3030

31+
/// Tries to specialize an \p Apply of a generic function. It can be a full
32+
/// apply site or a partial apply.
33+
/// Replaced and now dead instructions are returned in \p DeadApplies.
34+
/// New created functions, like the specialized callee and thunks, are returned
35+
/// in \p NewFunctions.
36+
///
37+
/// This is the top-level entry point for specializing an existing call site.
38+
void trySpecializeApplyOfGeneric(
39+
ApplySite Apply,
40+
llvm::SmallVectorImpl<SILInstruction *> &DeadApplies,
41+
llvm::SmallVectorImpl<SILFunction *> &NewFunctions);
42+
3143
/// Helper class to describe re-abstraction of function parameters done during
3244
/// specialization.
3345
///
3446
/// Specifically, it contains information which parameters and returns are
3547
/// changed from indirect values to direct values.
3648
class ReabstractionInfo {
49+
/// A 1-bit means that this parameter/return value is converted from indirect
50+
/// to direct.
51+
llvm::SmallBitVector Conversions;
52+
53+
/// The first NumResults bits in Conversions refer to indirect out-parameters.
54+
unsigned NumResults;
55+
56+
/// The function type after applying the substitutions of the original
57+
/// apply site.
58+
CanSILFunctionType SubstitutedType;
59+
60+
/// The function type after applying the re-abstractions on the
61+
/// SubstitutedType.
62+
CanSILFunctionType SpecializedType;
63+
3764
public:
38-
/// Constructs the ReabstractionInfo for an apply site \p AI calling the
39-
/// generic function \p Orig.
65+
/// Constructs the ReabstractionInfo for generic function \p Orig with
66+
/// substitutions \p ParamSubs.
4067
/// If specialization is not possible getSpecializedType() will return an
4168
/// invalid type.
42-
ReabstractionInfo(SILFunction *Orig, ApplySite AI);
69+
ReabstractionInfo(SILFunction *Orig, ArrayRef<Substitution> ParamSubs);
4370

4471
/// Does the \p ArgIdx refer to an indirect out-parameter?
4572
bool isResultIndex(unsigned ArgIdx) const {
@@ -88,8 +115,8 @@ class ReabstractionInfo {
88115
return Conversions.size() - numArgs;
89116
}
90117

91-
/// Get the function type after applying the substitutions of the original
92-
/// apply site.
118+
/// Get the function type after applying the substitutions to the original
119+
/// generic function.
93120
CanSILFunctionType getSubstitutedType() const { return SubstitutedType; }
94121

95122
/// Get the function type after applying the re-abstractions on the
@@ -101,41 +128,61 @@ class ReabstractionInfo {
101128
/// SubstFTy by applying the re-abstractions.
102129
CanSILFunctionType createSpecializedType(CanSILFunctionType SubstFTy,
103130
SILModule &M) const;
104-
private:
105-
/// A 1-bit means that this parameter/return value is converted from indirect
106-
/// to direct.
107-
llvm::BitVector Conversions;
108-
109-
/// The first NumResults bits in Conversions refer to indirect out-parameters.
110-
unsigned NumResults;
131+
};
111132

112-
/// The function type after applying the substitutions of the original
113-
/// apply site.
114-
CanSILFunctionType SubstitutedType;
133+
/// Helper class for specializing a generic function given a list of
134+
/// substitutions.
135+
class GenericFuncSpecializer {
136+
SILModule &M;
137+
SILFunction *GenericFunc;
138+
ArrayRef<Substitution> ParamSubs;
139+
const ReabstractionInfo &ReInfo;
115140

116-
/// The function type after applying the re-abstractions on the
117-
/// SubstitutedType.
118-
CanSILFunctionType SpecializedType;
141+
TypeSubstitutionMap ContextSubs;
142+
std::string ClonedName;
143+
public:
144+
GenericFuncSpecializer(SILFunction *GenericFunc,
145+
ArrayRef<Substitution> ParamSubs,
146+
const ReabstractionInfo &ReInfo);
147+
148+
/// If we already have this specialization, reuse it.
149+
SILFunction *lookupSpecialization();
150+
151+
/// Return a newly created specialized function.
152+
SILFunction *tryCreateSpecialization();
153+
154+
/// Try to specialize GenericFunc given a list of ParamSubs.
155+
/// Returns either a new or existing specialized function, or nullptr.
156+
SILFunction *trySpecialization() {
157+
if (!ReInfo.getSpecializedType())
158+
return nullptr;
159+
160+
SILFunction *SpecializedF = lookupSpecialization();
161+
if (!SpecializedF)
162+
SpecializedF = tryCreateSpecialization();
163+
164+
return SpecializedF;
165+
}
119166
};
120167

121-
/// Tries to specialize an \p Apply of a generic function. It can be a full
122-
/// apply site or a partial apply.
123-
/// Replaced and now dead instructions are returned in \p DeadApplies.
124-
/// New created functions, like the specialized callee and thunks, are returned
125-
/// in \p NewFunctions.
126-
void trySpecializeApplyOfGeneric(ApplySite Apply,
127-
llvm::SmallVectorImpl<SILInstruction *> &DeadApplies,
128-
llvm::SmallVectorImpl<SILFunction *> &NewFunctions);
168+
// =============================================================================
169+
// Prespecialized symbol lookup.
170+
// =============================================================================
129171

130-
/// Checks if a given mangled name could be a name of a whitelisted specialization.
172+
/// Checks if a given mangled name could be a name of a whitelisted
173+
/// specialization.
131174
bool isWhitelistedSpecialization(StringRef SpecName);
132175

133176
/// Create a new apply based on an old one, but with a different
134177
/// function being applied.
135178
ApplySite replaceWithSpecializedFunction(ApplySite AI, SILFunction *NewF,
136179
const ReabstractionInfo &ReInfo);
137180

138-
SILFunction *getExistingSpecialization(SILModule &M, StringRef FunctionName);
181+
/// Returns a SILFunction for the symbol specified by FunctioName if it is
182+
/// visible to the current SILModule. This is used to link call sites to
183+
/// externally defined specialization and should only be used when the function
184+
/// body is not required for further optimization or inlining (-Onone).
185+
SILFunction *lookupPrespecializedSymbol(SILModule &M, StringRef FunctionName);
139186

140187
} // end namespace swift
141188

lib/SILOptimizer/IPO/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ set(IPO_SOURCES
33
IPO/CapturePropagation.cpp
44
IPO/ClosureSpecializer.cpp
55
IPO/DeadFunctionElimination.cpp
6+
IPO/EagerSpecializer.cpp
67
IPO/ExternalDefsToDecls.cpp
78
IPO/FunctionSignatureOpts.cpp
89
IPO/GlobalOpt.cpp

0 commit comments

Comments
 (0)