Skip to content

Do conservative cross-module-optimization by default #40721

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 55 additions & 13 deletions lib/SILOptimizer/IPO/CrossModuleOptimization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,16 @@ class CrossModuleOptimization {

SILModule &M;

/// True, if CMO runs by default.
/// In this case, serialization decisions are made very conservatively to
/// avoid code size increase.
bool conservative;

typedef llvm::DenseMap<SILFunction *, bool> FunctionFlags;

public:
CrossModuleOptimization(SILModule &M)
: M(M) { }
CrossModuleOptimization(SILModule &M, bool conservative)
: M(M), conservative(conservative) { }

void serializeFunctionsInModule();

Expand Down Expand Up @@ -255,6 +260,12 @@ bool CrossModuleOptimization::canSerializeInstruction(SILInstruction *inst,
if (!canUseFromInline(callee))
return false;

// In conservative mode we don't want to turn non-public functions into
// public functions, because that can increase code size. E.g. if the
// function is completely inlined afterwards.
if (conservative && callee->getLinkage() != SILLinkage::Public)
return false;

return true;
}
if (auto *KPI = dyn_cast<KeyPathInst>(inst)) {
Expand All @@ -273,6 +284,13 @@ bool CrossModuleOptimization::canSerializeInstruction(SILInstruction *inst,
if (auto *MI = dyn_cast<MethodInst>(inst)) {
return !MI->getMember().isForeign;
}
if (auto *REAI = dyn_cast<RefElementAddrInst>(inst)) {
// In conservative mode, we don't support class field accesse of non-public
// properties, because that would require to make the field decl public -
// which keeps more metadata alive.
return !conservative ||
REAI->getField()->getEffectiveAccess() >= AccessLevel::Public;
}
return true;
}

Expand All @@ -298,6 +316,10 @@ bool CrossModuleOptimization::canSerializeType(SILType type) {
CanType subType = rawSubType->getCanonicalType();
if (NominalTypeDecl *subNT = subType->getNominalOrBoundGenericNominal()) {

if (conservative && subNT->getEffectiveAccess() < AccessLevel::Public) {
return true;
}

// Exclude types which are defined in an @_implementationOnly imported
// module. Such modules are not transitively available.
if (!M.getSwiftModule()->canBeUsedForCrossModuleOptimization(subNT)) {
Expand Down Expand Up @@ -348,13 +370,15 @@ bool CrossModuleOptimization::shouldSerialize(SILFunction *function) {
if (SerializeEverything)
return true;

// The basic heursitic: serialize all generic functions, because it makes a
// huge difference if generic functions can be specialized or not.
if (function->getLoweredFunctionType()->isPolymorphic())
return true;
if (!conservative) {
// The basic heursitic: serialize all generic functions, because it makes a
// huge difference if generic functions can be specialized or not.
if (function->getLoweredFunctionType()->isPolymorphic())
return true;

if (function->getLinkage() == SILLinkage::Shared)
return true;
if (function->getLinkage() == SILLinkage::Shared)
return true;
}

// Also serialize "small" non-generic functions.
int size = 0;
Expand Down Expand Up @@ -401,8 +425,27 @@ void CrossModuleOptimization::serializeInstruction(SILInstruction *inst,
if (!callee->isDefinition() || callee->isAvailableExternally())
return;
if (canUseFromInline(callee)) {
// Make the function 'public'.
makeFunctionUsableFromInline(callee);
if (conservative) {
// In conservative mode, avoid making non-public functions public,
// because that can increase code size.
if (callee->getLinkage() == SILLinkage::Private ||
callee->getLinkage() == SILLinkage::Hidden) {
if (callee->getEffectiveSymbolLinkage() == SILLinkage::Public) {
// It's a internal/private class method. There is no harm in making
// it public, because it gets public symbol linkage anyway.
makeFunctionUsableFromInline(callee);
} else {
// Treat the function like a 'shared' function, e.g. like a
// specialization. This is better for code size than to make it
// public, because in conservative mode we are only do this for very
// small functions.
callee->setLinkage(SILLinkage::Shared);
}
}
} else {
// Make the function 'public'.
makeFunctionUsableFromInline(callee);
}
}
serializeFunction(callee, canSerializeFlags);
assert(callee->isSerialized() == IsSerialized ||
Expand Down Expand Up @@ -531,10 +574,9 @@ class CrossModuleOptimizationPass: public SILModuleTransform {
return;
if (!M.isWholeModule())
return;
if (!M.getOptions().CrossModuleOptimization)
return;

CrossModuleOptimization CMO(M);
CrossModuleOptimization CMO(M,
/*conservative*/ !M.getOptions().CrossModuleOptimization);
CMO.serializeFunctionsInModule();
}
};
Expand Down
4 changes: 2 additions & 2 deletions test/AutoDiff/TBD/derivative_symbols.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// RUN: %target-swift-frontend -emit-ir -o/dev/null -parse-as-library -module-name test -validate-tbd-against-ir=all %s
// RUN: %target-swift-frontend -emit-ir -o/dev/null -parse-as-library -module-name test -validate-tbd-against-ir=all %s -O
// RUN: %target-swift-frontend -emit-ir -o/dev/null -Xllvm -sil-disable-pass=cmo -parse-as-library -module-name test -validate-tbd-against-ir=all %s
// RUN: %target-swift-frontend -emit-ir -o/dev/null -Xllvm -sil-disable-pass=cmo -parse-as-library -module-name test -validate-tbd-against-ir=all %s -O
// RUN: %target-swift-frontend -emit-ir -o/dev/null -parse-as-library -module-name test -validate-tbd-against-ir=missing %s -enable-testing
// RUN: %target-swift-frontend -emit-ir -o/dev/null -parse-as-library -module-name test -validate-tbd-against-ir=missing %s -enable-testing -O

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// RUN: %empty-directory(%t)
// RUN: cp %s %t/main.swift
// RUN: %target-build-swift -whole-module-optimization -emit-module-path %t/UsingObjCStuff.swiftmodule -c -o %t/UsingObjCStuff.o -module-name UsingObjCStuff -I %t -I %S/Inputs/mixed_mode -swift-version 5 -parse-as-library %S/Inputs/mixed_mode/UsingObjCStuff.swift

// CMO does not work because of a deserialization failure: rdar://86575886
// RUN: %target-build-swift -Xllvm -sil-disable-pass=cmo -whole-module-optimization -emit-module-path %t/UsingObjCStuff.swiftmodule -c -o %t/UsingObjCStuff.o -module-name UsingObjCStuff -I %t -I %S/Inputs/mixed_mode -swift-version 5 -parse-as-library %S/Inputs/mixed_mode/UsingObjCStuff.swift
// RUN: %target-build-swift -o %t/a.out.v4 -I %t -I %S/Inputs/mixed_mode -module-name main -swift-version 4 %t/main.swift %t/UsingObjCStuff.o
// RUN: %target-build-swift -o %t/a.out.v5 -I %t -I %S/Inputs/mixed_mode -module-name main -swift-version 5 %t/main.swift %t/UsingObjCStuff.o
// RUN: %target-codesign %t/a.out.v4
Expand Down
2 changes: 1 addition & 1 deletion test/SIL/Parser/array_roundtrip.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %target-swift-frontend %s -emit-sil -Ounchecked | %target-sil-opt
// RUN: %target-swift-frontend %s -emit-sil -Ounchecked -Xllvm -sil-disable-pass=cmo | %target-sil-opt

// Fails if the positions of the two Collection subscript requirements are
// reversed. rdar://problem/46650834
Expand Down
2 changes: 1 addition & 1 deletion test/SILGen/fragile_globals.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ var mygg = 29
// Check if we have one token: from mygg.
// Initializers from other modules are never fragile.

// CHECK: sil_global private{{.*}} @[[T3:.*]]Wz
// CHECK: sil_global {{.*}} @[[T3:.*]]Wz

//@inlinable
public func sum() -> Int {
Expand Down
2 changes: 1 addition & 1 deletion test/SILOptimizer/access_enforcement_options.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public func accessIntTwice() {
// CHECK-LABEL: } // end sil function '$s26access_enforcement_options0A8IntTwiceyyF'

// closure #1 in accessIntTwice()
// CHECK-LABEL: sil private @$s26access_enforcement_options0A8IntTwiceyyFyycfU_ : $@convention(thin) (@guaranteed { var Int }) -> () {
// CHECK-LABEL: sil {{.*}}@$s26access_enforcement_options0A8IntTwiceyyFyycfU_ : $@convention(thin) (@guaranteed { var Int }) -> () {
// CHECK: bb0(%0 : ${ var Int }):
// CHECK: [[PROJ:%.*]] = project_box %0 : ${ var Int }, 0
// NONE: [[ACCESS:%.*]] = begin_access [modify] [dynamic] [[PROJ]] : $*Int
Expand Down
2 changes: 1 addition & 1 deletion test/SILOptimizer/dead_function_elimination.swift
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ public func keepPtrAlive() {
// CHECK-TESTING: sil {{.*}}publicClassMethod
// CHECK-TESTING: sil {{.*}}DeadWitness

// CHECK-LABEL: sil_global hidden @$s25dead_function_elimination5GFStrV12aliveFuncPtryycvpZ
// CHECK-LABEL: sil_global {{.*}}@$s25dead_function_elimination5GFStrV12aliveFuncPtryycvpZ
// CHECK-LABEL: @$s25dead_function_elimination14donotEliminateyyF
// CHECK-LABEL: sil @$s25dead_function_elimination12keepPtrAliveyyF

Expand Down
2 changes: 1 addition & 1 deletion test/SILOptimizer/dont_remove_dynamic_self_arg.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ func transform<T>(_ a: Any, c: (Any) -> T?) -> T? {
return c(a)
}

// CHECK-LABEL: sil private @$s4test1XC6testityACSgypFACXDSgypXEfU_ :
// CHECK-LABEL: sil {{.*}}@$s4test1XC6testityACSgypFACXDSgypXEfU_ :
// CHECK: bb0({{.*}}, {{%[0-9]+}} : $@thick @dynamic_self X.Type):

// The checked_cast_addr_br must have %1 as implicit type dependend operand.
Expand Down
4 changes: 2 additions & 2 deletions test/Serialization/xref-private-type.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// RUN: %empty-directory(%t)
// RUN: %target-build-swift -swift-version 4 -O -whole-module-optimization -emit-module-path %t/LibCore.swiftmodule %S/Inputs/xref-private-type/LibCore.swift
// RUN: %target-build-swift -swift-version 4 -O -I %t -whole-module-optimization -emit-module-path %t/Lib.swiftmodule %S/Inputs/xref-private-type/Lib.swift
// RUN: %target-build-swift -swift-version 4 -O -Xllvm -sil-disable-pass=cmo -whole-module-optimization -emit-module-path %t/LibCore.swiftmodule %S/Inputs/xref-private-type/LibCore.swift
// RUN: %target-build-swift -swift-version 4 -O -Xllvm -sil-disable-pass=cmo -I %t -whole-module-optimization -emit-module-path %t/Lib.swiftmodule %S/Inputs/xref-private-type/Lib.swift
// RUN: %target-build-swift -swift-version 4 -O -I %t -emit-sil %s | %FileCheck %s

import Lib
Expand Down
2 changes: 1 addition & 1 deletion test/TBD/all-in-one.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
// RUN: %target-build-swift -module-name all_in_one -emit-module-path %t/all_in_one.swiftmodule -emit-tbd-path %t/wmo_Onone.tbd %S/class.swift %t/class_objc.swift %S/enum.swift %t/extension.swift %S/function.swift %S/global.swift %S/main.swift %S/protocol.swift %S/struct.swift %t/subclass.swift -I %t -import-objc-header %S/Inputs/objc_class_header.h -Xfrontend -disable-objc-attr-requires-foundation-module -wmo

// RUN: %target-build-swift -module-name all_in_one -emit-module-path %t/all_in_one.swiftmodule -emit-tbd-path %t/incremental_O.tbd %S/class.swift %t/class_objc.swift %S/enum.swift %t/extension.swift %S/function.swift %S/global.swift %S/main.swift %S/protocol.swift %S/struct.swift %t/subclass.swift -I %t -import-objc-header %S/Inputs/objc_class_header.h -Xfrontend -disable-objc-attr-requires-foundation-module -O
// RUN: %target-build-swift -module-name all_in_one -emit-module-path %t/all_in_one.swiftmodule -emit-tbd-path %t/wmo_O.tbd %S/class.swift %t/class_objc.swift %S/enum.swift %t/extension.swift %S/function.swift %S/global.swift %S/main.swift %S/protocol.swift %S/struct.swift %t/subclass.swift -I %t -import-objc-header %S/Inputs/objc_class_header.h -Xfrontend -disable-objc-attr-requires-foundation-module -wmo -O
// RUN: %target-build-swift -module-name all_in_one -emit-module-path %t/all_in_one.swiftmodule -emit-tbd-path %t/wmo_O.tbd %S/class.swift %t/class_objc.swift %S/enum.swift %t/extension.swift %S/function.swift %S/global.swift %S/main.swift %S/protocol.swift %S/struct.swift %t/subclass.swift -I %t -import-objc-header %S/Inputs/objc_class_header.h -Xfrontend -disable-objc-attr-requires-foundation-module -wmo -O -Xllvm -sil-disable-pass=cmo

// RUN: diff %t/incremental_Onone.tbd %t/wmo_Onone.tbd
// RUN: diff %t/incremental_O.tbd %t/wmo_O.tbd
Expand Down
2 changes: 1 addition & 1 deletion test/TBD/specialization.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// REQUIRES: VENDOR=apple
// Validate the the specializations actually exist (if they don't then we're not
// validating that they end up with the correct linkages):
// RUN: %target-swift-frontend -emit-sil -o- -O -validate-tbd-against-ir=none %s | %FileCheck %s
// RUN: %target-swift-frontend -emit-sil -o- -O -Xllvm -sil-disable-pass=cmo -validate-tbd-against-ir=none %s | %FileCheck %s

// RUN: %target-swift-frontend -emit-ir -o/dev/null -O -validate-tbd-against-ir=all %s
// RUN: %target-swift-frontend -emit-ir -o/dev/null -O -validate-tbd-against-ir=all -enable-library-evolution %s
Expand Down