Skip to content

[5.5][Driver] Support for emit-module-separately #39249

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 5 commits into from
Oct 8, 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
9 changes: 7 additions & 2 deletions include/swift/Option/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -581,8 +581,13 @@ def experimental_cxx_stdlib :

def experimental_emit_module_separately:
Flag<["-"], "experimental-emit-module-separately">,
Flags<[FrontendOption, NoInteractiveOption, HelpHidden]>,
HelpText<"Schedule a swift module emission job instead of a merge-modules job (new Driver only)">;
Flags<[NoInteractiveOption, HelpHidden]>,
HelpText<"Emit module files as a distinct job (new Driver only)">;

def no_emit_module_separately:
Flag<["-"], "no-emit-module-separately">,
Flags<[NoInteractiveOption, HelpHidden]>,
HelpText<"Force using merge-module as the incremental build mode (new Driver only)">;

// Diagnostic control options
def suppress_warnings : Flag<["-"], "suppress-warnings">,
Expand Down
7 changes: 5 additions & 2 deletions lib/AST/Module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -276,8 +276,11 @@ void SourceLookupCache::populateMemberCache(const ModuleDecl &Mod) {
"populate-module-class-member-cache");

for (const FileUnit *file : Mod.getFiles()) {
auto &SF = *cast<SourceFile>(file);
addToMemberCache(SF.getTopLevelDecls());
assert(isa<SourceFile>(file) ||
isa<SynthesizedFileUnit>(file));
SmallVector<Decl *, 8> decls;
file->getTopLevelDecls(decls);
addToMemberCache(decls);
}

MemberCachePopulated = true;
Expand Down
9 changes: 5 additions & 4 deletions lib/Frontend/Frontend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1144,10 +1144,10 @@ CompilerInstance::getSourceFileParsingOptions(bool forPrimary) const {
opts |= SourceFile::ParsingFlags::DisableDelayedBodies;
}

auto typeOpts = getASTContext().TypeCheckerOpts;
if (forPrimary || isWholeModuleCompilation()) {
// Disable delayed body parsing for primaries and in WMO, unless
// forcefully skipping function bodies
auto typeOpts = getASTContext().TypeCheckerOpts;
if (typeOpts.SkipFunctionBodies == FunctionBodySkipping::None)
opts |= SourceFile::ParsingFlags::DisableDelayedBodies;
} else {
Expand All @@ -1156,9 +1156,10 @@ CompilerInstance::getSourceFileParsingOptions(bool forPrimary) const {
opts |= SourceFile::ParsingFlags::SuppressWarnings;
}

// Enable interface hash computation for primaries, but not in WMO, as it's
// only currently needed for incremental mode.
if (forPrimary) {
// Enable interface hash computation for primaries or emit-module-separately,
// but not in WMO, as it's only currently needed for incremental mode.
if (forPrimary ||
typeOpts.SkipFunctionBodies == FunctionBodySkipping::NonInlinableWithoutTypes) {
opts |= SourceFile::ParsingFlags::EnableInterfaceHash;
}
return opts;
Expand Down
12 changes: 11 additions & 1 deletion lib/FrontendTool/FrontendTool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1549,9 +1549,19 @@ static bool performCompileStepsPostSILGen(CompilerInstance &Instance,
SerializationOptions serializationOpts =
Invocation.computeSerializationOptions(outs, Instance.getMainModule());

// Infer if this is an emit-module job part of an incremental build,
// vs a partial emit-module job (with primary files) or other kinds.
// We may want to rely on a flag instead to differentiate them.
const bool isEmitModuleSeparately =
Action == FrontendOptions::ActionType::EmitModuleOnly &&
MSF.is<ModuleDecl *>() &&
Instance.getInvocation()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious why this depends on the state of function body skipping.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The flag controlling NonInlinableWithoutTypes is used here as an heuristic to distinguish incremental EmitModuleOnly jobs from the classic non-incremental ones. I'd rather have a flag specifically about incremental builds but IIUC that flag was intentionally removed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@CodaFi would you prefer if the compiler emitted incremental information for all emit-module jobs? Outside of emit-module-separately, these are mostly used in testing and to build core library as far as I know.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it certainly wouldn't hurt. The cost of embedding Swiftdeps is negligible.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A quick cleanup of these check triggered some incremental test failures. I think there's another scenario that needs to be accounted for or just some tests to be updated to expect more dependency information. Let's merge this in 5.5 and fix these on main.

.getTypeCheckerOptions()
.SkipFunctionBodies == FunctionBodySkipping::NonInlinableWithoutTypes;
const bool canEmitIncrementalInfoIntoModule =
!serializationOpts.DisableCrossModuleIncrementalInfo &&
(Action == FrontendOptions::ActionType::MergeModules);
(Action == FrontendOptions::ActionType::MergeModules ||
isEmitModuleSeparately);
if (canEmitIncrementalInfoIntoModule) {
const auto alsoEmitDotFile =
Instance.getInvocation()
Expand Down
4 changes: 2 additions & 2 deletions test/Driver/Dependencies/one-way-merge-module-fine.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
// RUN: cp -r %S/Inputs/one-way-fine/* %t
// RUN: touch -t 201401240005 %t/*

// RUN: cd %t && %swiftc_driver -driver-use-frontend-path "%{python.unquoted};%S/Inputs/update-dependencies.py;%swift-dependency-tool" -output-file-map %t/output.json -incremental -driver-always-rebuild-dependents ./main.swift ./other.swift -emit-module-path %t/master.swiftmodule -module-name main -j1 -v 2>&1 | %FileCheck -check-prefix=CHECK-FIRST %s
// RUN: cd %t && %swiftc_driver -driver-use-frontend-path "%{python.unquoted};%S/Inputs/update-dependencies.py;%swift-dependency-tool" -output-file-map %t/output.json -incremental -driver-always-rebuild-dependents ./main.swift ./other.swift -emit-module-path %t/master.swiftmodule -module-name main -j1 -v -no-emit-module-separately 2>&1 | %FileCheck -check-prefix=CHECK-FIRST %s

// CHECK-FIRST-NOT: warning
// CHECK-FIRST: Handled main.swift
Expand All @@ -14,7 +14,7 @@
// swift-driver checks existence of all outputs
// RUN: touch -t 201401240006 %t/{main,other,master}.swift{module,doc,sourceinfo}

// RUN: cd %t && %swiftc_driver -driver-use-frontend-path "%{python.unquoted};%S/Inputs/update-dependencies.py;%swift-dependency-tool" -output-file-map %t/output.json -incremental -driver-always-rebuild-dependents ./main.swift ./other.swift -emit-module-path %t/master.swiftmodule -module-name main -j1 -v 2>&1 | %FileCheck -check-prefix=CHECK-SECOND %s
// RUN: cd %t && %swiftc_driver -driver-use-frontend-path "%{python.unquoted};%S/Inputs/update-dependencies.py;%swift-dependency-tool" -output-file-map %t/output.json -incremental -driver-always-rebuild-dependents ./main.swift ./other.swift -emit-module-path %t/master.swiftmodule -module-name main -j1 -v -no-emit-module-separately 2>&1 | %FileCheck -check-prefix=CHECK-SECOND %s

// CHECK-SECOND-NOT: warning
// CHECK-SECOND-NOT: Handled
Expand Down
5 changes: 5 additions & 0 deletions test/InterfaceHash/added_function.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
// RUN: %target-swift-frontend -dump-interface-hash -primary-file %t/b.swift 2> %t/b.hash
// RUN: not cmp %t/a.hash %t/b.hash

/// We should generate an interface hash for emit-module-separately jobs even
/// with no primaries.
// RUN: %target-swift-frontend -dump-interface-hash %t/b.swift -experimental-skip-non-inlinable-function-bodies-without-types 2> %t/b-emit-module.hash
// RUN: cmp %t/b.hash %t/b-emit-module.hash

// BEGIN a.swift
func f() {}

Expand Down