24
24
#include " swift/SILOptimizer/Utils/Local.h"
25
25
#include " swift/SILOptimizer/PassManager/Transforms.h"
26
26
#include " llvm/ADT/SmallVector.h"
27
+ #include " llvm/ADT/Statistic.h"
27
28
28
29
using namespace swift ;
29
30
31
+ STATISTIC (NumFunctionsWithProtocolArgsDevirtualized, " Number of functions with protocol args devirtualized" );
32
+ using ArgIndexList = llvm::SmallVector<unsigned , 8 >;
33
+
30
34
namespace {
31
35
32
36
class GenericSpecializer : public SILFunctionTransform {
@@ -45,6 +49,93 @@ class GenericSpecializer : public SILFunctionTransform {
45
49
46
50
};
47
51
52
+ // / ProtocolDevirtualizer class.
53
+ class ProtocolDevirtualizer : public SILFunctionTransform {
54
+
55
+ // / determine if the current function is a target for protocol devirtualizer.
56
+ bool canDevirtualizeProtocolInFunction (ProtocolDevirtualizerAnalysis *PDA,
57
+ llvm::SmallDenseMap<int , std::pair<ProtocolDecl*, ClassDecl *>> &Arg2DeclMap);
58
+
59
+ public:
60
+
61
+ void run () override {
62
+ auto *F = getFunction ();
63
+
64
+ // / Don't run protocol devirtualizer at -Os.
65
+ if (F->optimizeForSize ())
66
+ return ;
67
+
68
+ // / Don't optimize functions that should not be optimized.
69
+ if (F->empty () || (!F->shouldOptimize ())) {
70
+ return ;
71
+ }
72
+
73
+ // / This is the function to optimize for protocol devirtualize.
74
+ DEBUG (llvm::dbgs () << " *** ProtocolDevirtualization Pass on function: " << F->getName () << " ***\n " );
75
+
76
+ // / Use FunctionSignature Specialization to determine if this function
77
+ // / can be specialized, without call graph information.
78
+ if ( !canSpecializeFunction (F, nullptr , false )) {
79
+ DEBUG (llvm::dbgs () << " cannot specialize function -> abort\n " );
80
+ return ;
81
+ }
82
+
83
+ CallerAnalysis *CA = PM->getAnalysis <CallerAnalysis>();
84
+ const CallerAnalysis::FunctionInfo &FuncInfo = CA->getCallerInfo (F);
85
+
86
+ // / Use FunctionSignature Specialization to determine if this function
87
+ // / can be specialized, based on call graph.
88
+ // / canSpecializeFunction does not consider generic methods -- TODO in future.
89
+ if (!canSpecializeFunction (F, &FuncInfo, true )) {
90
+ DEBUG (llvm::dbgs () << " cannot specialize function -> abort\n " );
91
+ return ;
92
+ }
93
+
94
+ // / Get the protocol devirtualizer pass that contains which protocols can be devirtualized.
95
+ ProtocolDevirtualizerAnalysis *PDA = getAnalysis<ProtocolDevirtualizerAnalysis>();
96
+
97
+ // / Determine the arguments that can be devirtualized.
98
+ llvm::SmallDenseMap<int , std::pair<ProtocolDecl *, ClassDecl *>> Arg2DeclMap;
99
+ if (!canDevirtualizeProtocolInFunction (PDA, Arg2DeclMap)) {
100
+ DEBUG (llvm::dbgs () << " cannot devirtualize function -> abort\n " );
101
+ return ;
102
+ }
103
+
104
+ DEBUG (llvm::dbgs () << " Function::" << F->getName () << " has a Protocol Argument and can be optimized via PDA\n " );
105
+
106
+ // / Name Mangler for naming the protocol constrained generic method.
107
+ auto P = Demangle::SpecializationPass::GenericSpecializer;
108
+ Mangle::FunctionSignatureSpecializationMangler Mangler (P, F->isSerialized (), F);
109
+
110
+ // / Save the arguments in a descriptor.
111
+ llvm::SmallVector<ArgumentDescriptor, 4 > ArgumentDescList;
112
+ auto Args = F->begin ()->getFunctionArguments ();
113
+ for (unsigned i = 0 , e = Args.size (); i != e; ++i) {
114
+ ArgumentDescList.emplace_back (Args[i]);
115
+ }
116
+
117
+ // / Instantiate the ProtocolDevirtualizerTransform pass.
118
+ ProtocolDevirtualizerTransform PDT (F, Mangler, ArgumentDescList, Arg2DeclMap);
119
+
120
+ // / Run the protocol devirtualizer.
121
+ bool Changed = PDT.run ();
122
+
123
+ if (Changed) {
124
+ // / Update statistics on the number of functions devirtualized.
125
+ ++ NumFunctionsWithProtocolArgsDevirtualized;
126
+
127
+ // / Invalidate Analysis as we introduce a new function.
128
+ invalidateAnalysis (SILAnalysis::InvalidationKind::Everything);
129
+
130
+ // / Make sure the PM knows about the new devirtualized inner function.
131
+ notifyAddFunction (PDT.getDevirtualizedProtocolFunction (), F);
132
+
133
+ // / should we restart pipeline? be conservative.
134
+ restartPassPipeline ();
135
+ }
136
+ }
137
+ };
138
+
48
139
} // end anonymous namespace
49
140
50
141
bool GenericSpecializer::specializeAppliesInFunction (SILFunction &F) {
@@ -129,6 +220,39 @@ bool GenericSpecializer::specializeAppliesInFunction(SILFunction &F) {
129
220
return Changed;
130
221
}
131
222
223
+ // / Check if any argument to a function meet the criteria for devirtualization.
224
+ bool ProtocolDevirtualizer::canDevirtualizeProtocolInFunction (ProtocolDevirtualizerAnalysis *PDA,
225
+ llvm::SmallDenseMap<int , std::pair<ProtocolDecl*, ClassDecl *>> &Arg2DeclMap) {
226
+ auto *F = getFunction ();
227
+ auto Args = F->begin ()->getFunctionArguments ();
228
+ bool returnFlag = false ;
229
+
230
+ // / Analyze the argument for protocol conformance.
231
+ for (unsigned i = 0 , e = Args.size (); i != e; ++i) {
232
+ auto ArgType = Args[i]->getType ();
233
+ // / Keep it simple for now. Do not handle Protocol constrained methods or Optionals.
234
+ auto SwiftArgType = ArgType.getSwiftRValueType ();
235
+ if (ArgType && ArgType.isAnyExistentialType ()) {
236
+ auto SwiftProtoDecl = SwiftArgType.getAnyNominal ();
237
+ if (SwiftProtoDecl) {
238
+ auto ProtoDecl = dyn_cast<ProtocolDecl>(SwiftProtoDecl);
239
+ auto CD = PDA->getSoleClassImplementingProtocol (ProtoDecl);
240
+ if (CD) {
241
+ // / Save the mapping for transformation pass.
242
+ Arg2DeclMap[i] = std::make_pair (ProtoDecl, CD);
243
+ DEBUG (llvm::dbgs () << " Function: " << F->getName () << " has a singel class decl\n " );
244
+ returnFlag |= true ;
245
+ }
246
+ }
247
+ }
248
+ }
249
+ return returnFlag;
250
+ }
251
+
132
252
SILTransform *swift::createGenericSpecializer () {
133
253
return new GenericSpecializer ();
134
254
}
255
+
256
+ SILTransform *swift::createProtocolDevirtualizer () {
257
+ return new ProtocolDevirtualizer ();
258
+ }
0 commit comments