Skip to content

cross-module-optimization: Don't serialize functions which reference implementationOnly-imported functions #38951

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
Aug 23, 2021
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
7 changes: 4 additions & 3 deletions include/swift/AST/Module.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand Down
13 changes: 7 additions & 6 deletions lib/AST/Module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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;
Expand Down
5 changes: 5 additions & 0 deletions lib/SILOptimizer/IPO/CrossModuleSerializationSetup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
7 changes: 7 additions & 0 deletions test/SILOptimizer/Inputs/cross-module/c-module.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

#include "c-module.h"

long privateCFunc() {
return 123;
}

3 changes: 3 additions & 0 deletions test/SILOptimizer/Inputs/cross-module/c-module.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@

long privateCFunc();

Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Submodule
@_implementationOnly import PrivateSubmodule
@_implementationOnly import PrivateCModule

private enum PE<T> {
case A
Expand Down Expand Up @@ -268,11 +269,19 @@ public func callUnrelated<T>(_ t: T) -> T {
return t
}

public func callImplementationOnly<T>(_ t: T) -> T {
public func callImplementationOnlyType<T>(_ t: T) -> T {
let p = PrivateStr(i: 27)
print(p.test())
return t
}

public func callImplementationOnlyFunc<T>(_ t: T) -> Int {
return privateFunc()
}

public func callCImplementationOnly<T>(_ t: T) -> Int {
return Int(privateCFunc())
}


public let globalLet = 529387
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,6 @@ public struct PrivateStr {
}
}

public func privateFunc() -> Int {
return 40
}
3 changes: 3 additions & 0 deletions test/SILOptimizer/Inputs/cross-module/module.modulemap
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module PrivateCModule {
header "c-module.h"
}
2 changes: 1 addition & 1 deletion test/SILOptimizer/cross-module-optimization-objc.swift
Original file line number Diff line number Diff line change
@@ -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
Expand Down
21 changes: 14 additions & 7 deletions test/SILOptimizer/cross-module-optimization.swift
Original file line number Diff line number Diff line change
@@ -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

Expand Down Expand Up @@ -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'
}

Expand Down