diff --git a/include/swift/AST/Module.h b/include/swift/AST/Module.h index 7b3eb44587b8e..499f24c52960f 100644 --- a/include/swift/AST/Module.h +++ b/include/swift/AST/Module.h @@ -676,9 +676,10 @@ class ModuleDecl : public DeclContext, public TypeDecl { /// This assumes that \p module was imported. bool isImportedImplementationOnly(const ModuleDecl *module) const; - /// Returns true if a function, which is using \p nominal, can be serialized - /// by cross-module-optimization. - bool canBeUsedForCrossModuleOptimization(NominalTypeDecl *nominal) const; + /// Returns true if decl context or its content can be serialized by + /// cross-module-optimization. + /// The \p ctxt can e.g. be a NominalType or the context of a function. + bool canBeUsedForCrossModuleOptimization(DeclContext *ctxt) const; /// Finds all top-level decls of this module. /// diff --git a/lib/AST/Module.cpp b/lib/AST/Module.cpp index 205f5fec6c74d..3bc88ab72adec 100644 --- a/lib/AST/Module.cpp +++ b/lib/AST/Module.cpp @@ -2353,14 +2353,15 @@ bool ModuleDecl::isImportedImplementationOnly(const ModuleDecl *module) const { } bool ModuleDecl:: -canBeUsedForCrossModuleOptimization(NominalTypeDecl *nominal) const { - ModuleDecl *moduleOfNominal = nominal->getParentModule(); +canBeUsedForCrossModuleOptimization(DeclContext *ctxt) const { + ModuleDecl *moduleOfCtxt = ctxt->getParentModule(); - // If the nominal is defined in the same module, it's fine. - if (moduleOfNominal == this) + // If the context defined in the same module - or is the same module, it's + // fine. + if (moduleOfCtxt == this) return true; - // See if nominal is imported in a "regular" way, i.e. not with + // See if context is imported in a "regular" way, i.e. not with // @_implementationOnly or @_spi. ModuleDecl::ImportFilter filter = { ModuleDecl::ImportFilterKind::Exported, @@ -2370,7 +2371,7 @@ canBeUsedForCrossModuleOptimization(NominalTypeDecl *nominal) const { auto &imports = getASTContext().getImportCache(); for (auto &desc : results) { - if (imports.isImportedBy(moduleOfNominal, desc.importedModule)) + if (imports.isImportedBy(moduleOfCtxt, desc.importedModule)) return true; } return false; diff --git a/lib/SILOptimizer/IPO/CrossModuleSerializationSetup.cpp b/lib/SILOptimizer/IPO/CrossModuleSerializationSetup.cpp index 90e6895fba47e..fde588c301a3f 100644 --- a/lib/SILOptimizer/IPO/CrossModuleSerializationSetup.cpp +++ b/lib/SILOptimizer/IPO/CrossModuleSerializationSetup.cpp @@ -386,6 +386,11 @@ bool CrossModuleSerializationSetup::canUseFromInline(SILFunction *func, if (!func) return false; + if (DeclContext *funcCtxt = func->getDeclContext()) { + if (!M.getSwiftModule()->canBeUsedForCrossModuleOptimization(funcCtxt)) + return false; + } + switch (func->getLinkage()) { case SILLinkage::PublicNonABI: return func->isSerialized() != IsNotSerialized; diff --git a/test/SILOptimizer/Inputs/cross-module/c-module.c b/test/SILOptimizer/Inputs/cross-module/c-module.c new file mode 100644 index 0000000000000..808c26c020781 --- /dev/null +++ b/test/SILOptimizer/Inputs/cross-module/c-module.c @@ -0,0 +1,7 @@ + +#include "c-module.h" + +long privateCFunc() { + return 123; +} + diff --git a/test/SILOptimizer/Inputs/cross-module/c-module.h b/test/SILOptimizer/Inputs/cross-module/c-module.h new file mode 100644 index 0000000000000..ef27e8d9c2114 --- /dev/null +++ b/test/SILOptimizer/Inputs/cross-module/c-module.h @@ -0,0 +1,3 @@ + +long privateCFunc(); + diff --git a/test/SILOptimizer/Inputs/cross-module-objc.swift b/test/SILOptimizer/Inputs/cross-module/cross-module-objc.swift similarity index 100% rename from test/SILOptimizer/Inputs/cross-module-objc.swift rename to test/SILOptimizer/Inputs/cross-module/cross-module-objc.swift diff --git a/test/SILOptimizer/Inputs/cross-module.swift b/test/SILOptimizer/Inputs/cross-module/cross-module.swift similarity index 94% rename from test/SILOptimizer/Inputs/cross-module.swift rename to test/SILOptimizer/Inputs/cross-module/cross-module.swift index 68d5c0b8aba72..09a38be6e1cee 100644 --- a/test/SILOptimizer/Inputs/cross-module.swift +++ b/test/SILOptimizer/Inputs/cross-module/cross-module.swift @@ -1,5 +1,6 @@ import Submodule @_implementationOnly import PrivateSubmodule +@_implementationOnly import PrivateCModule private enum PE { case A @@ -268,11 +269,19 @@ public func callUnrelated(_ t: T) -> T { return t } -public func callImplementationOnly(_ t: T) -> T { +public func callImplementationOnlyType(_ t: T) -> T { let p = PrivateStr(i: 27) print(p.test()) return t } +public func callImplementationOnlyFunc(_ t: T) -> Int { + return privateFunc() +} + +public func callCImplementationOnly(_ t: T) -> Int { + return Int(privateCFunc()) +} + public let globalLet = 529387 diff --git a/test/SILOptimizer/Inputs/cross-private-submodule.swift b/test/SILOptimizer/Inputs/cross-module/cross-private-submodule.swift similarity index 75% rename from test/SILOptimizer/Inputs/cross-private-submodule.swift rename to test/SILOptimizer/Inputs/cross-module/cross-private-submodule.swift index f43a8e65e2ee8..2de51eafa7664 100644 --- a/test/SILOptimizer/Inputs/cross-private-submodule.swift +++ b/test/SILOptimizer/Inputs/cross-module/cross-private-submodule.swift @@ -12,3 +12,6 @@ public struct PrivateStr { } } +public func privateFunc() -> Int { + return 40 +} diff --git a/test/SILOptimizer/Inputs/cross-submodule.swift b/test/SILOptimizer/Inputs/cross-module/cross-submodule.swift similarity index 100% rename from test/SILOptimizer/Inputs/cross-submodule.swift rename to test/SILOptimizer/Inputs/cross-module/cross-submodule.swift diff --git a/test/SILOptimizer/Inputs/cross-module/module.modulemap b/test/SILOptimizer/Inputs/cross-module/module.modulemap new file mode 100644 index 0000000000000..ef50f56508135 --- /dev/null +++ b/test/SILOptimizer/Inputs/cross-module/module.modulemap @@ -0,0 +1,3 @@ +module PrivateCModule { + header "c-module.h" +} diff --git a/test/SILOptimizer/cross-module-optimization-objc.swift b/test/SILOptimizer/cross-module-optimization-objc.swift index 8d3129a3c1735..bf692cf641501 100644 --- a/test/SILOptimizer/cross-module-optimization-objc.swift +++ b/test/SILOptimizer/cross-module-optimization-objc.swift @@ -1,7 +1,7 @@ // First test: functional correctness // RUN: %empty-directory(%t) -// RUN: %target-build-swift -O -wmo -parse-as-library -cross-module-optimization -emit-module -emit-module-path=%t/Test.swiftmodule -module-name=Test -I%t %S/Inputs/cross-module-objc.swift -c -o %t/test.o +// RUN: %target-build-swift -O -wmo -parse-as-library -cross-module-optimization -emit-module -emit-module-path=%t/Test.swiftmodule -module-name=Test -I%t %S/Inputs/cross-module/cross-module-objc.swift -c -o %t/test.o // RUN: %target-build-swift -O -wmo -module-name=Main -I%t %s -c -o %t/main.o // RUN: %target-swiftc_driver %t/main.o %t/test.o -o %t/a.out // RUN: %target-codesign %t/a.out diff --git a/test/SILOptimizer/cross-module-optimization.swift b/test/SILOptimizer/cross-module-optimization.swift index 7ccf14386faa3..e8934eafcb059 100644 --- a/test/SILOptimizer/cross-module-optimization.swift +++ b/test/SILOptimizer/cross-module-optimization.swift @@ -1,18 +1,19 @@ // First test: functional correctness // RUN: %empty-directory(%t) -// RUN: %target-build-swift -O -wmo -parse-as-library -cross-module-optimization -emit-module -emit-module-path=%t/Submodule.swiftmodule -module-name=Submodule %S/Inputs/cross-submodule.swift -c -o %t/submodule.o -// RUN: %target-build-swift -O -wmo -parse-as-library -cross-module-optimization -emit-module -emit-module-path=%t/PrivateSubmodule.swiftmodule -module-name=PrivateSubmodule %S/Inputs/cross-private-submodule.swift -c -o %t/privatesubmodule.o -// RUN: %target-build-swift -O -wmo -parse-as-library -cross-module-optimization -emit-module -emit-module-path=%t/Test.swiftmodule -module-name=Test -I%t %S/Inputs/cross-module.swift -c -o %t/test.o +// RUN: %target-build-swift -O -wmo -parse-as-library -cross-module-optimization -emit-module -emit-module-path=%t/Submodule.swiftmodule -module-name=Submodule %S/Inputs/cross-module/cross-submodule.swift -c -o %t/submodule.o +// RUN: %target-build-swift -O -wmo -parse-as-library -cross-module-optimization -emit-module -emit-module-path=%t/PrivateSubmodule.swiftmodule -module-name=PrivateSubmodule %S/Inputs/cross-module/cross-private-submodule.swift -c -o %t/privatesubmodule.o +// RUN: %target-clang -c --language=c %S/Inputs/cross-module/c-module.c -o %t/c-module.o +// RUN: %target-build-swift -O -wmo -parse-as-library -cross-module-optimization -emit-module -emit-module-path=%t/Test.swiftmodule -module-name=Test -I%t -I%S/Inputs/cross-module %S/Inputs/cross-module/cross-module.swift -c -o %t/test.o // RUN: %target-build-swift -O -wmo -module-name=Main -I%t %s -c -o %t/main.o -// RUN: %target-swiftc_driver %t/main.o %t/test.o %t/submodule.o %t/privatesubmodule.o -o %t/a.out +// RUN: %target-swiftc_driver %t/main.o %t/test.o %t/submodule.o %t/privatesubmodule.o %t/c-module.o -o %t/a.out // RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s -check-prefix=CHECK-OUTPUT // Check if it also works if the main module is compiled with -Onone: // RUN: %target-build-swift -Onone -wmo -module-name=Main -I%t %s -c -o %t/main-onone.o -// RUN: %target-swiftc_driver %t/main-onone.o %t/test.o %t/submodule.o %t/privatesubmodule.o -o %t/a.out +// RUN: %target-swiftc_driver %t/main-onone.o %t/test.o %t/submodule.o %t/privatesubmodule.o %t/c-module.o -o %t/a.out // RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s -check-prefix=CHECK-OUTPUT @@ -146,8 +147,14 @@ func testGlobal() { @inline(never) func testImplementationOnly() { // CHECK-OUTPUT: 27 - // CHECK-SIL2: function_ref @$s4Test22callImplementationOnlyyxxlF - print(callImplementationOnly(27)) + // CHECK-SIL2: function_ref @$s4Test26callImplementationOnlyTypeyxxlF + print(callImplementationOnlyType(27)) + // CHECK-OUTPUT: 40 + // CHECK-SIL2: function_ref @$s4Test26callImplementationOnlyFuncySixlF + print(callImplementationOnlyFunc(0)) + // CHECK-OUTPUT: 123 + // CHECK-SIL2: function_ref @$s4Test23callCImplementationOnlyySixlF + print(callCImplementationOnly(0)) // CHECK-SIL2: } // end sil function '$s4Main22testImplementationOnlyyyF' }