23
23
#include " swift/SILOptimizer/PassManager/Passes.h"
24
24
#include " swift/SILOptimizer/PassManager/Transforms.h"
25
25
#include " swift/SILOptimizer/Utils/InstOptUtils.h"
26
+ #include " swift/SILOptimizer/Utils/SILInliner.h"
26
27
#include " llvm/Support/CommandLine.h"
27
28
#include " llvm/Support/Debug.h"
28
29
29
30
using namespace swift ;
30
31
32
+ // / Functions up to this (abstract) size are serialized, even if they are not
33
+ // / generic.
34
+ static llvm::cl::opt<int > CMOFunctionSizeLimit (" cmo-function-size-limit" ,
35
+ llvm::cl::init (20 ));
36
+
31
37
namespace {
32
38
33
39
// / Scans a whole module and marks functions and types as inlinable or usable
@@ -54,6 +60,8 @@ class CrossModuleSerializationSetup {
54
60
55
61
bool canSerialize (SILFunction *F, bool lookIntoThunks);
56
62
63
+ bool canSerialize (SILInstruction *inst, bool lookIntoThunks);
64
+
57
65
void setUpForSerialization (SILFunction *F);
58
66
59
67
void prepareInstructionForSerialization (SILInstruction *inst);
@@ -193,18 +201,31 @@ static llvm::cl::opt<bool> SerializeEverything(
193
201
194
202
// / Decide whether to serialize a function.
195
203
static bool shouldSerialize (SILFunction *F) {
196
- // The basic heursitic: serialize all generic functions, because it makes a
197
- // huge difference if generic functions can be specialized or not.
198
- if (!F->getLoweredFunctionType ()->isPolymorphic () && !SerializeEverything)
199
- return false ;
200
-
201
204
// Check if we already handled this function before.
202
205
if (F->isSerialized () == IsSerialized)
203
206
return false ;
204
207
205
208
if (F->hasSemanticsAttr (" optimize.no.crossmodule" ))
206
209
return false ;
207
210
211
+ if (SerializeEverything)
212
+ return true ;
213
+
214
+ // The basic heursitic: serialize all generic functions, because it makes a
215
+ // huge difference if generic functions can be specialized or not.
216
+ if (F->getLoweredFunctionType ()->isPolymorphic ())
217
+ return true ;
218
+
219
+ // Also serialize "small" non-generic functions.
220
+ int size = 0 ;
221
+ for (SILBasicBlock &block : *F) {
222
+ for (SILInstruction &inst : block) {
223
+ size += (int )instructionInlineCost (inst);
224
+ if (size >= CMOFunctionSizeLimit)
225
+ return false ;
226
+ }
227
+ }
228
+
208
229
return true ;
209
230
}
210
231
@@ -227,6 +248,11 @@ prepareInstructionForSerialization(SILInstruction *inst) {
227
248
handleReferencedFunction (callee);
228
249
return ;
229
250
}
251
+ if (auto *GAI = dyn_cast<GlobalAddrInst>(inst)) {
252
+ GAI->getReferencedGlobal ()->setSerialized (IsSerialized);
253
+ GAI->getReferencedGlobal ()->setLinkage (SILLinkage::Public);
254
+ return ;
255
+ }
230
256
if (auto *MI = dyn_cast<MethodInst>(inst)) {
231
257
handleReferencedMethod (MI->getMember ());
232
258
return ;
@@ -285,26 +311,42 @@ bool CrossModuleSerializationSetup::canSerialize(SILFunction *F,
285
311
// First step: check if serializing F is even possible.
286
312
for (SILBasicBlock &block : *F) {
287
313
for (SILInstruction &inst : block) {
288
- if (auto *FRI = dyn_cast<FunctionRefBaseInst>(&inst)) {
289
- SILFunction *callee = FRI->getReferencedFunctionOrNull ();
290
- if (!canUseFromInline (callee, lookIntoThunks))
291
- return false ;
292
- } else if (auto *KPI = dyn_cast<KeyPathInst>(&inst)) {
293
- bool canUse = true ;
294
- KPI->getPattern ()->visitReferencedFunctionsAndMethods (
295
- [&](SILFunction *func) {
296
- if (!canUseFromInline (func, lookIntoThunks))
297
- canUse = false ;
298
- },
299
- [](SILDeclRef method) { });
300
- if (!canUse)
301
- return false ;
302
- }
314
+ if (!canSerialize (&inst, lookIntoThunks))
315
+ return false ;
303
316
}
304
317
}
305
318
return true ;
306
319
}
307
320
321
+ bool CrossModuleSerializationSetup::canSerialize (SILInstruction *inst,
322
+ bool lookIntoThunks) {
323
+ if (auto *FRI = dyn_cast<FunctionRefBaseInst>(inst)) {
324
+ SILFunction *callee = FRI->getReferencedFunctionOrNull ();
325
+ return canUseFromInline (callee, lookIntoThunks);
326
+ }
327
+ if (auto *KPI = dyn_cast<KeyPathInst>(inst)) {
328
+ bool canUse = true ;
329
+ KPI->getPattern ()->visitReferencedFunctionsAndMethods (
330
+ [&](SILFunction *func) {
331
+ if (!canUseFromInline (func, lookIntoThunks))
332
+ canUse = false ;
333
+ },
334
+ [&](SILDeclRef method) {
335
+ if (method.isForeign )
336
+ canUse = false ;
337
+ });
338
+ return canUse;
339
+ }
340
+ if (auto *GAI = dyn_cast<GlobalAddrInst>(inst)) {
341
+ return !GAI->getReferencedGlobal ()->getName ().startswith (" globalinit_" );
342
+ }
343
+ if (auto *MI = dyn_cast<MethodInst>(inst)) {
344
+ return !MI->getMember ().isForeign ;
345
+ }
346
+
347
+ return true ;
348
+ }
349
+
308
350
// / Returns true if the function \p func can be used from a serialized function.
309
351
// /
310
352
// / If \p lookIntoThunks is true, serializable shared thunks are also accepted.
@@ -351,12 +393,17 @@ void CrossModuleSerializationSetup::setUpForSerialization(SILFunction *F) {
351
393
}
352
394
F->setSerialized (IsSerialized);
353
395
354
- // As a code size optimization, make serialized functions
355
- // @alwaysEmitIntoClient.
356
- // Also, for shared thunks it's required to make them @alwaysEmitIntoClient.
357
- // SILLinkage::Public would not work for shared functions, because it could
358
- // result in duplicate-symbol linker errors.
359
- F->setLinkage (SILLinkage::PublicNonABI);
396
+ if (F->getLoweredFunctionType ()->isPolymorphic () ||
397
+ F->getLinkage () != SILLinkage::Public) {
398
+ // As a code size optimization, make serialized functions
399
+ // @alwaysEmitIntoClient.
400
+ // Also, for shared thunks it's required to make them @alwaysEmitIntoClient.
401
+ // SILLinkage::Public would not work for shared functions, because it could
402
+ // result in duplicate-symbol linker errors.
403
+ F->setLinkage (SILLinkage::PublicNonABI);
404
+ } else {
405
+ F->setLinkage (SILLinkage::Public);
406
+ }
360
407
}
361
408
362
409
// / Select functions in the module which should be serialized.
0 commit comments