Skip to content

Commit f88c919

Browse files
authored
Merge pull request #68727 from kubamracek/embedded-serialize-everything2
[embedded] Make CMO's 'serialize everything' mode even more aggressive and allow serialization of private and shared functions
2 parents 8fa720d + 8f335b1 commit f88c919

File tree

6 files changed

+115
-42
lines changed

6 files changed

+115
-42
lines changed

include/swift/AST/SILOptions.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ enum class DestroyHoistingOption : uint8_t {
6969
enum class CrossModuleOptimizationMode : uint8_t {
7070
Off = 0,
7171
Default = 1,
72-
Aggressive = 2
72+
Aggressive = 2,
73+
Everything = 3,
7374
};
7475

7576
class SILModule;

lib/Frontend/CompilerInvocation.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3117,6 +3117,7 @@ bool CompilerInvocation::parseArgs(
31173117
if (LangOpts.hasFeature(Feature::Embedded)) {
31183118
IRGenOpts.InternalizeAtLink = true;
31193119
IRGenOpts.DisableLegacyTypeInfo = true;
3120+
SILOpts.CMOMode = CrossModuleOptimizationMode::Everything;
31203121
}
31213122

31223123
return false;

lib/SIL/Verifier/SILVerifier.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6674,6 +6674,7 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
66746674
verifySILFunctionType(FTy);
66756675

66766676
SILModule &mod = F->getModule();
6677+
bool embedded = mod.getASTContext().LangOpts.hasFeature(Feature::Embedded);
66776678

66786679
require(!F->isSerialized() || !mod.isSerialized() || mod.isParsedAsSerializedSIL(),
66796680
"cannot have a serialized function after the module has been serialized");
@@ -6694,7 +6695,7 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
66946695
case SILLinkage::Private:
66956696
require(F->isDefinition() || F->hasForeignBody(),
66966697
"internal/private function must have a body");
6697-
require(!F->isSerialized(),
6698+
require(!F->isSerialized() || embedded,
66986699
"internal/private function cannot be serialized or serializable");
66996700
break;
67006701
case SILLinkage::PublicExternal:

lib/SILOptimizer/IPO/CrossModuleOptimization.cpp

Lines changed: 43 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,15 @@ class CrossModuleOptimization {
6060
/// avoid code size increase.
6161
bool conservative;
6262

63+
/// True if CMO should serialize literally everything in the module,
64+
/// regardless of linkage.
65+
bool everything;
66+
6367
typedef llvm::DenseMap<SILFunction *, bool> FunctionFlags;
6468

6569
public:
66-
CrossModuleOptimization(SILModule &M, bool conservative)
67-
: M(M), conservative(conservative) { }
70+
CrossModuleOptimization(SILModule &M, bool conservative, bool everything)
71+
: M(M), conservative(conservative), everything(everything) { }
6872

6973
void serializeFunctionsInModule();
7074

@@ -164,9 +168,10 @@ void CrossModuleOptimization::serializeFunctionsInModule() {
164168

165169
// Start with public functions.
166170
for (SILFunction &F : M) {
167-
if (F.getLinkage() == SILLinkage::Public) {
168-
if (canSerializeFunction(&F, canSerializeFlags, /*maxDepth*/ 64))
171+
if (F.getLinkage() == SILLinkage::Public || everything) {
172+
if (canSerializeFunction(&F, canSerializeFlags, /*maxDepth*/ 64)) {
169173
serializeFunction(&F, canSerializeFlags);
174+
}
170175
}
171176
}
172177
}
@@ -189,6 +194,11 @@ bool CrossModuleOptimization::canSerializeFunction(
189194
// it to true at the end of this function.
190195
canSerializeFlags[function] = false;
191196

197+
if (everything) {
198+
canSerializeFlags[function] = true;
199+
return true;
200+
}
201+
192202
if (DeclContext *funcCtxt = function->getDeclContext()) {
193203
if (!canUseFromInline(funcCtxt))
194204
return false;
@@ -392,6 +402,9 @@ static bool couldBeLinkedStatically(DeclContext *funcCtxt, SILModule &module) {
392402

393403
/// Returns true if the \p declCtxt can be used from a serialized function.
394404
bool CrossModuleOptimization::canUseFromInline(DeclContext *declCtxt) {
405+
if (everything)
406+
return true;
407+
395408
if (!M.getSwiftModule()->canBeUsedForCrossModuleOptimization(declCtxt))
396409
return false;
397410

@@ -410,6 +423,9 @@ bool CrossModuleOptimization::canUseFromInline(DeclContext *declCtxt) {
410423

411424
/// Returns true if the function \p func can be used from a serialized function.
412425
bool CrossModuleOptimization::canUseFromInline(SILFunction *function) {
426+
if (everything)
427+
return true;
428+
413429
if (DeclContext *funcCtxt = function->getDeclContext()) {
414430
if (!canUseFromInline(funcCtxt))
415431
return false;
@@ -439,14 +455,12 @@ bool CrossModuleOptimization::shouldSerialize(SILFunction *function) {
439455
if (function->isSerialized())
440456
return false;
441457

458+
if (everything)
459+
return true;
460+
442461
if (function->hasSemanticsAttr("optimize.no.crossmodule"))
443462
return false;
444463

445-
// In embedded Swift we serialize everything.
446-
if (SerializeEverything ||
447-
function->getASTContext().LangOpts.hasFeature(Feature::Embedded))
448-
return true;
449-
450464
if (!conservative) {
451465
// The basic heuristic: serialize all generic functions, because it makes a
452466
// huge difference if generic functions can be specialized or not.
@@ -652,23 +666,29 @@ class CrossModuleOptimizationPass: public SILModuleTransform {
652666
return;
653667
if (!M.isWholeModule())
654668
return;
655-
669+
656670
bool conservative = false;
657-
// In embedded Swift we serialize everything.
658-
if (!M.getASTContext().LangOpts.hasFeature(Feature::Embedded)) {
659-
switch (M.getOptions().CMOMode) {
660-
case swift::CrossModuleOptimizationMode::Off:
661-
return;
662-
case swift::CrossModuleOptimizationMode::Default:
663-
conservative = true;
664-
break;
665-
case swift::CrossModuleOptimizationMode::Aggressive:
666-
conservative = false;
667-
break;
668-
}
671+
bool everything = SerializeEverything;
672+
switch (M.getOptions().CMOMode) {
673+
case swift::CrossModuleOptimizationMode::Off:
674+
break;
675+
case swift::CrossModuleOptimizationMode::Default:
676+
conservative = true;
677+
break;
678+
case swift::CrossModuleOptimizationMode::Aggressive:
679+
conservative = false;
680+
break;
681+
case swift::CrossModuleOptimizationMode::Everything:
682+
everything = true;
683+
break;
684+
}
685+
686+
if (!everything &&
687+
M.getOptions().CMOMode == swift::CrossModuleOptimizationMode::Off) {
688+
return;
669689
}
670690

671-
CrossModuleOptimization CMO(M, conservative);
691+
CrossModuleOptimization CMO(M, conservative, everything);
672692
CMO.serializeFunctionsInModule();
673693
}
674694
};

test/embedded/globals.swift

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-swift-emit-ir -target armv7-apple-none-macho -parse-stdlib -module-name Swift %s -enable-experimental-feature Embedded -wmo -parse-as-library | %FileCheck %s
1+
// RUN: %target-swift-emit-ir -target armv7-apple-none-macho -parse-stdlib -module-name Swift %s -enable-experimental-feature Embedded -wmo -parse-as-library | %FileCheck %s --check-prefix CHECK --check-prefix CHECK-NONOPT
22
// RUN: %target-swift-emit-ir -target armv7-apple-none-macho -parse-stdlib -module-name Swift %s -enable-experimental-feature Embedded -wmo -parse-as-library -O | %FileCheck %s
33

44
// REQUIRES: swift_in_compiler
@@ -98,19 +98,19 @@ extension MyPublicEnum {
9898
public static var static_mypublicstruct_4: MyPublicStruct = MyPublicStruct(x: 0, y: 0)
9999
}
100100

101-
// CHECK-NOT: global_int_1
102-
// CHECK: @"$ss12global_int_2Sivp" = {{.*}}zeroinitializer
103-
// CHECK-NOT: global_int_3
104-
// CHECK: @"$ss12global_int_4Sivp" = {{.*}}zeroinitializer
105-
// CHECK-NOT: static_int_1
106-
// CHECK: @"$ss12MyPublicEnumO12static_int_2SivpZ" = {{.*}}zeroinitializer
107-
// CHECK-NOT: static_int_3
108-
// CHECK: @"$ss12MyPublicEnumO12static_int_4SivpZ" = {{.*}}zeroinitializer
109-
// CHECK-NOT: global_my_publicstruct_1
110-
// CHECK: @"$ss24global_my_publicstruct_2s14MyPublicStructVvp" = {{.*}}zeroinitializer
111-
// CHECK-NOT: global_my_publicstruct_3
112-
// CHECK: @"$ss24global_my_publicstruct_4s14MyPublicStructVvp" = {{.*}}zeroinitializer
113-
// CHECK-NOT: stati_my_publicstruct_1
114-
// CHECK: @"$ss12MyPublicEnumO23static_mypublicstruct_2s0aB6StructVvpZ" = {{.*}}zeroinitializer
115-
// CHECK-NOT: stati_my_publicstruct_3
116-
// CHECK: @"$ss12MyPublicEnumO23static_mypublicstruct_4s0aB6StructVvpZ" = {{.*}}zeroinitializer
101+
// CHECK-NONOPT: @"$ss12global_int_133_056BEF60D619AD2945081A9CBFC2AAE9LLSivp" = {{.*}}zeroinitializer
102+
// CHECK: @"$ss12global_int_2Sivp" = {{.*}}zeroinitializer
103+
// CHECK-NONOPT: @"$ss12global_int_333_056BEF60D619AD2945081A9CBFC2AAE9LLSivp" = {{.*}}zeroinitializer
104+
// CHECK: @"$ss12global_int_4Sivp" = {{.*}}zeroinitializer
105+
// CHECK-NONOPT: @"$ss12MyPublicEnumO12static_int_133_056BEF60D619AD2945081A9CBFC2AAE9LLSivpZ" = {{.*}}zeroinitializer
106+
// CHECK: @"$ss12MyPublicEnumO12static_int_2SivpZ" = {{.*}}zeroinitializer
107+
// CHECK-NONOPT: @"$ss12MyPublicEnumO12static_int_333_056BEF60D619AD2945081A9CBFC2AAE9LLSivpZ" = {{.*}}zeroinitializer
108+
// CHECK: @"$ss12MyPublicEnumO12static_int_4SivpZ" = {{.*}}zeroinitializer
109+
// CHECK-NONOPT: @"$ss24global_my_publicstruct_133_056BEF60D619AD2945081A9CBFC2AAE9LLs14MyPublicStructVvp" = {{.*}}zeroinitializer
110+
// CHECK: @"$ss24global_my_publicstruct_2s14MyPublicStructVvp" = {{.*}}zeroinitializer
111+
// CHECK-NONOPT: @"$ss24global_my_publicstruct_333_056BEF60D619AD2945081A9CBFC2AAE9LLs14MyPublicStructVvp" = {{.*}}zeroinitializer
112+
// CHECK: @"$ss24global_my_publicstruct_4s14MyPublicStructVvp" = {{.*}}zeroinitializer
113+
// CHECK-NOT: static_my_publicstruct_1
114+
// CHECK: @"$ss12MyPublicEnumO23static_mypublicstruct_2s0aB6StructVvpZ" = {{.*}}zeroinitializer
115+
// CHECK-NOT: static_my_publicstruct_3
116+
// CHECK: @"$ss12MyPublicEnumO23static_mypublicstruct_4s0aB6StructVvpZ" = {{.*}}zeroinitializer
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %{python} %utils/split_file.py -o %t %s
3+
4+
// RUN: %target-swift-frontend -emit-module -o %t/MyModule.swiftmodule %t/MyModule.swift -enable-experimental-feature Embedded -parse-as-library
5+
// RUN: %target-swift-frontend -c -I %t %t/Main.swift -enable-experimental-feature Embedded -o %t/a.o
6+
// RUN: %target-clang -x c -c %S/Inputs/tiny-runtime-dummy-refcounting.c -o %t/runtime.o
7+
// RUN: %target-clang -x c -c %S/Inputs/print.c -o %t/print.o
8+
// RUN: %target-clang %t/a.o %t/print.o %t/runtime.o -o %t/a.out
9+
// RUN: %target-run %t/a.out | %FileCheck %s
10+
11+
// REQUIRES: executable_test
12+
// REQUIRES: VENDOR=apple
13+
// REQUIRES: OS=macosx
14+
15+
// BEGIN MyModule.swift
16+
17+
@_silgen_name("putchar")
18+
func putchar(_: UInt8)
19+
20+
public func print(_ s: StaticString, terminator: StaticString) {
21+
var p = s.utf8Start
22+
while p.pointee != 0 {
23+
putchar(p.pointee)
24+
p += 1
25+
}
26+
p = terminator.utf8Start
27+
while p.pointee != 0 {
28+
putchar(p.pointee)
29+
p += 1
30+
}
31+
}
32+
33+
@_silgen_name("print_long")
34+
func print_long(_: Int)
35+
36+
public func print(_ n: Int, terminator: StaticString) {
37+
print_long(n)
38+
print("", terminator: terminator)
39+
}
40+
41+
// BEGIN Main.swift
42+
43+
import MyModule
44+
45+
func test() {
46+
print("Hello world", terminator: "\n") // CHECK: Hello world
47+
print(42, terminator: "\n") // CHECK-NEXT: 42
48+
}
49+
50+
test()

0 commit comments

Comments
 (0)