Skip to content

cross-module-optimization: be more conservative when emitting a TBD file. #41642

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
Mar 3, 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
2 changes: 2 additions & 0 deletions include/swift/AST/SILOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,8 @@ class SILOptions {
/// Emit a mapping of profile counters for use in coverage.
bool EmitProfileCoverageMapping = false;

bool emitTBD = false;

/// Should we use a pass pipeline passed in via a json file? Null by default.
llvm::StringRef ExternalPassPipelineFilename;

Expand Down
2 changes: 2 additions & 0 deletions lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1670,6 +1670,8 @@ static bool ParseSILArgs(SILOptions &Opts, ArgList &Args,
OPT_disable_previous_implementation_calls_in_dynamic_replacements);
Opts.ParseStdlib = FEOpts.ParseStdlib;

Opts.emitTBD = FEOpts.InputsAndOutputs.hasTBDPath();

if (const Arg *A = Args.getLastArg(OPT_save_optimization_record_EQ)) {
llvm::Expected<llvm::remarks::Format> formatOrErr =
llvm::remarks::parseFormat(A->getValue());
Expand Down
36 changes: 32 additions & 4 deletions lib/SILOptimizer/IPO/CrossModuleOptimization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -338,12 +338,40 @@ bool CrossModuleOptimization::canSerializeType(SILType type) {
return success;
}

/// Returns true if the function in \p funcCtxt could be linked statically to
/// this module.
static bool couldBeLinkedStatically(DeclContext *funcCtxt, SILModule &module) {
if (!funcCtxt)
return true;
ModuleDecl *funcModule = funcCtxt->getParentModule();
// If the function is in the same module, it's not in another module which
// could be linked statically.
if (module.getSwiftModule() == funcModule)
return false;

// The stdlib module is always linked dynamically.
if (funcModule == module.getASTContext().getStdlibModule())
return false;

// Conservatively assume the function is in a statically linked module.
return true;
}

/// Returns true if the function \p func can be used from a serialized function.
bool CrossModuleOptimization::canUseFromInline(SILFunction *function) {
if (DeclContext *funcCtxt = function->getDeclContext()) {
if (!M.getSwiftModule()->canBeUsedForCrossModuleOptimization(funcCtxt))
return false;
}
DeclContext *funcCtxt = function->getDeclContext();
if (funcCtxt && !M.getSwiftModule()->canBeUsedForCrossModuleOptimization(funcCtxt))
return false;

/// If we are emitting a TBD file, the TBD file only contains public symbols
/// of this module. But not public symbols of imported modules which are
/// statically linked to the current binary.
/// This prevents referencing public symbols from other modules which could
/// (potentially) linked statically. Unfortunately there is no way to find out
/// if another module is linked statically or dynamically, so we have to be
/// conservative here.
if (conservative && M.getOptions().emitTBD && couldBeLinkedStatically(funcCtxt, M))
return false;

switch (function->getLinkage()) {
case SILLinkage::PublicNonABI:
Expand Down
10 changes: 10 additions & 0 deletions test/SILOptimizer/Inputs/cross-module/default-module.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

import Submodule

public func incrementByThree(_ x: Int) -> Int {
return incrementByOne(x) + 2
}

public func incrementByThreeWithCall(_ x: Int) -> Int {
return incrementByOneNoCMO(x) + 2
}
10 changes: 10 additions & 0 deletions test/SILOptimizer/Inputs/cross-module/default-submodule.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

public func incrementByOne(_ x: Int) -> Int {
return x + 1
}

@_semantics("optimize.no.crossmodule")
public func incrementByOneNoCMO(_ x: Int) -> Int {
return x + 1
}

43 changes: 43 additions & 0 deletions test/SILOptimizer/default-cmo.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@

// RUN: %empty-directory(%t)

// RUN: %target-build-swift -O -wmo -parse-as-library -emit-module -emit-module-path=%t/Submodule.swiftmodule -module-name=Submodule %S/Inputs/cross-module/default-submodule.swift -c -o %t/submodule.o
// RUN: %target-build-swift -O -wmo -parse-as-library -emit-module -emit-module-path=%t/Module.swiftmodule -module-name=Module -I%t -I%S/Inputs/cross-module %S/Inputs/cross-module/default-module.swift -c -o %t/module.o
// RUN: %target-build-swift -O -wmo -parse-as-library -emit-tbd -emit-tbd-path %t/ModuleTBD.tbd -emit-module -emit-module-path=%t/ModuleTBD.swiftmodule -module-name=ModuleTBD -I%t -I%S/Inputs/cross-module %S/Inputs/cross-module/default-module.swift -c -o %t/moduletbd.o

// RUN: %target-build-swift -O -wmo -module-name=Main -I%t %s -emit-sil | %FileCheck %s


import Module
import ModuleTBD

// CHECK-LABEL: sil @$s4Main11doIncrementyS2iF
// CHECK-NOT: function_ref
// CHECK-NOT: apply
// CHECK: } // end sil function '$s4Main11doIncrementyS2iF'
public func doIncrement(_ x: Int) -> Int {
return Module.incrementByThree(x)
}

// CHECK-LABEL: sil @$s4Main19doIncrementWithCallyS2iF
// CHECK: function_ref @$s9Submodule19incrementByOneNoCMOyS2iF
// CHECK: } // end sil function '$s4Main19doIncrementWithCallyS2iF'
public func doIncrementWithCall(_ x: Int) -> Int {
return Module.incrementByThreeWithCall(x)
}

// CHECK-LABEL: sil @$s4Main14doIncrementTBDyS2iF
// CHECK-NOT: function_ref
// CHECK-NOT: apply
// CHECK: } // end sil function '$s4Main14doIncrementTBDyS2iF'
public func doIncrementTBD(_ x: Int) -> Int {
return ModuleTBD.incrementByThree(x)
}

// CHECK-LABEL: sil @$s4Main22doIncrementTBDWithCallyS2iF
// CHECK: function_ref @$s9ModuleTBD24incrementByThreeWithCallyS2iF
// CHECK: } // end sil function '$s4Main22doIncrementTBDWithCallyS2iF'
public func doIncrementTBDWithCall(_ x: Int) -> Int {
return ModuleTBD.incrementByThreeWithCall(x)
}