Skip to content

Commit 177bbe6

Browse files
Merge pull request #71118 from cachemeifyoucan/eng/PR-119275464
[Caching] Create clang importer from cc1 args directly
2 parents 7dc3914 + cb17ea8 commit 177bbe6

20 files changed

+430
-163
lines changed

include/swift/Basic/LangOptions.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -966,6 +966,10 @@ namespace swift {
966966
/// Using ClangIncludeTreeRoot for compilation.
967967
bool HasClangIncludeTreeRoot = false;
968968

969+
/// Whether the dependency scanner should construct all swift-frontend
970+
/// invocations directly from clang cc1 args.
971+
bool ClangImporterDirectCC1Scan = false;
972+
969973
/// Return a hash code of any components from these options that should
970974
/// contribute to a Swift Bridging PCH hash.
971975
llvm::hash_code getPCHHashComponents() const {

include/swift/ClangImporter/ClangImporter.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,9 @@ class ClangImporter final : public ClangModuleLoader {
514514

515515
std::string getClangModuleHash() const;
516516

517+
/// Get clang import creation cc1 args for swift explicit module build.
518+
std::vector<std::string> getSwiftExplicitModuleDirectCC1Args() const;
519+
517520
/// If we already imported a given decl successfully, return the corresponding
518521
/// Swift decl as an Optional<Decl *>, but if we previously tried and failed
519522
/// to import said decl then return nullptr.

include/swift/Frontend/ModuleInterfaceLoader.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -643,7 +643,6 @@ struct InterfaceSubContextDelegateImpl: InterfaceSubContextDelegate {
643643
llvm::StringSaver ArgSaver;
644644
std::vector<StringRef> GenericArgs;
645645
CompilerInvocation genericSubInvocation;
646-
llvm::Triple ParentInvocationTarget;
647646

648647
template<typename ...ArgTypes>
649648
InFlightDiagnostic diagnose(StringRef interfacePath,

include/swift/Option/Options.td

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1454,7 +1454,7 @@ def index_file_path : Separate<["-"], "index-file-path">,
14541454
MetaVarName<"<path>">;
14551455

14561456
def index_store_path : Separate<["-"], "index-store-path">,
1457-
Flags<[FrontendOption, ArgumentIsPath]>, MetaVarName<"<path>">,
1457+
Flags<[FrontendOption, ArgumentIsPath, CacheInvariant]>, MetaVarName<"<path>">,
14581458
HelpText<"Store indexing data to <path>">;
14591459

14601460
def index_unit_output_path : Separate<["-"], "index-unit-output-path">,
@@ -1894,6 +1894,11 @@ def gcc_toolchain: Separate<["-"], "gcc-toolchain">,
18941894
MetaVarName<"<path>">,
18951895
HelpText<"Specify a directory where the clang importer and clang linker can find headers and libraries">;
18961896

1897+
def experimental_clang_importer_direct_cc1_scan:
1898+
Flag<["-"], "experimental-clang-importer-direct-cc1-scan">,
1899+
Flags<[FrontendOption, NewDriverOnlyOption, HelpHidden]>,
1900+
HelpText<"Enables swift driver to construct swift-frontend invocations using -direct-clang-cc1-module-build">;
1901+
18971902
def cache_compile_job: Flag<["-"], "cache-compile-job">,
18981903
Flags<[FrontendOption, NewDriverOnlyOption]>,
18991904
HelpText<"Enable compiler caching">;

include/swift/Serialization/SerializedModuleLoader.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "swift/AST/ModuleLoader.h"
1919
#include "llvm/Support/MemoryBuffer.h"
2020
#include "llvm/Support/PrefixMapper.h"
21+
#include "llvm/TargetParser/Triple.h"
2122

2223
namespace swift {
2324
class ModuleFile;
@@ -552,9 +553,10 @@ class SerializedASTFile final : public LoadedFile {
552553
};
553554

554555
/// Extract compiler arguments from an interface file buffer.
555-
bool extractCompilerFlagsFromInterface(StringRef interfacePath,
556-
StringRef buffer, llvm::StringSaver &ArgSaver,
557-
SmallVectorImpl<const char *> &SubArgs);
556+
bool extractCompilerFlagsFromInterface(
557+
StringRef interfacePath, StringRef buffer, llvm::StringSaver &ArgSaver,
558+
SmallVectorImpl<const char *> &SubArgs,
559+
std::optional<llvm::Triple> PreferredTarget = std::nullopt);
558560

559561
/// Extract the user module version number from an interface file.
560562
llvm::VersionTuple extractUserModuleVersionFromInterface(StringRef moduleInterfacePath);

lib/ClangImporter/ClangImporter.cpp

Lines changed: 115 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,9 @@
5858
#include "clang/Basic/Module.h"
5959
#include "clang/Basic/TargetInfo.h"
6060
#include "clang/Basic/Version.h"
61+
#include "clang/CAS/CASOptions.h"
6162
#include "clang/CodeGen/ObjectFilePCHContainerOperations.h"
63+
#include "clang/Frontend/CompilerInvocation.h"
6264
#include "clang/Frontend/FrontendActions.h"
6365
#include "clang/Frontend/TextDiagnosticPrinter.h"
6466
#include "clang/Frontend/Utils.h"
@@ -73,8 +75,10 @@
7375
#include "clang/Sema/Sema.h"
7476
#include "clang/Serialization/ASTReader.h"
7577
#include "clang/Serialization/ASTWriter.h"
78+
#include "clang/Tooling/DependencyScanning/ScanAndUpdateArgs.h"
7679
#include "llvm/ADT/IntrusiveRefCntPtr.h"
7780
#include "llvm/ADT/STLExtras.h"
81+
#include "llvm/ADT/SmallVector.h"
7882
#include "llvm/ADT/StringExtras.h"
7983
#include "llvm/Support/CrashRecoveryContext.h"
8084
#include "llvm/Support/FileCollector.h"
@@ -1067,26 +1071,7 @@ std::optional<std::vector<std::string>> ClangImporter::getClangCC1Arguments(
10671071
ClangImporter *importer, ASTContext &ctx,
10681072
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
10691073
bool ignoreClangTarget) {
1070-
// If using direct cc1 module build, return extra args only.
1071-
if (ctx.ClangImporterOpts.DirectClangCC1ModuleBuild)
1072-
return ctx.ClangImporterOpts.ExtraArgs;
1073-
1074-
// Otherwise, create cc1 arguments from driver args.
1075-
auto driverArgs = getClangDriverArguments(ctx, ignoreClangTarget);
1076-
1077-
llvm::SmallVector<const char *> invocationArgs;
1078-
invocationArgs.reserve(driverArgs.size());
1079-
llvm::for_each(driverArgs, [&](const std::string &Arg) {
1080-
invocationArgs.push_back(Arg.c_str());
1081-
});
1082-
1083-
if (ctx.ClangImporterOpts.DumpClangDiagnostics) {
1084-
llvm::errs() << "clang importer driver args: '";
1085-
llvm::interleave(
1086-
invocationArgs, [](StringRef arg) { llvm::errs() << arg; },
1087-
[] { llvm::errs() << "' '"; });
1088-
llvm::errs() << "'\n";
1089-
}
1074+
std::unique_ptr<clang::CompilerInvocation> CI;
10901075

10911076
// Set up a temporary diagnostic client to report errors from parsing the
10921077
// command line, which may be important for Swift clients if, for example,
@@ -1098,24 +1083,64 @@ std::optional<std::vector<std::string>> ClangImporter::getClangCC1Arguments(
10981083
// clang::CompilerInstance is created.
10991084
llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> tempDiagOpts{
11001085
new clang::DiagnosticOptions};
1101-
11021086
auto *tempDiagClient =
11031087
new ClangDiagnosticConsumer(importer->Impl, *tempDiagOpts,
11041088
ctx.ClangImporterOpts.DumpClangDiagnostics);
1105-
11061089
auto clangDiags = clang::CompilerInstance::createDiagnostics(
11071090
tempDiagOpts.get(), tempDiagClient,
11081091
/*owned*/ true);
11091092

1110-
clang::CreateInvocationOptions CIOpts;
1111-
CIOpts.VFS = VFS;
1112-
CIOpts.Diags = clangDiags;
1113-
CIOpts.RecoverOnError = false;
1114-
CIOpts.ProbePrecompiled = true;
1115-
auto CI = clang::createInvocation(invocationArgs, std::move(CIOpts));
1093+
// If using direct cc1 module build, use extra args to setup ClangImporter.
1094+
if (ctx.ClangImporterOpts.DirectClangCC1ModuleBuild) {
1095+
llvm::SmallVector<const char *> clangArgs;
1096+
clangArgs.reserve(ctx.ClangImporterOpts.ExtraArgs.size());
1097+
llvm::for_each(
1098+
ctx.ClangImporterOpts.ExtraArgs,
1099+
[&](const std::string &Arg) { clangArgs.push_back(Arg.c_str()); });
1100+
1101+
// Try parse extra args, if failed, return nullopt.
1102+
CI = std::make_unique<clang::CompilerInvocation>();
1103+
if (!clang::CompilerInvocation::CreateFromArgs(*CI, clangArgs,
1104+
*clangDiags))
1105+
return std::nullopt;
11161106

1117-
if (!CI)
1118-
return std::nullopt;
1107+
// Forwards some options from swift to clang even using direct mode. This is
1108+
// to reduce the number of argument passing on the command-line and swift
1109+
// compiler can be more efficient to compute swift cache key without having
1110+
// the knowledge about clang command-line options.
1111+
if (ctx.CASOpts.EnableCaching)
1112+
CI->getCASOpts() = ctx.CASOpts.CASOpts;
1113+
1114+
// Forward the index store path. That information is not passed to scanner
1115+
// and it is cached invariant so we don't want to re-scan if that changed.
1116+
CI->getFrontendOpts().IndexStorePath = ctx.ClangImporterOpts.IndexStorePath;
1117+
} else {
1118+
// Otherwise, create cc1 arguments from driver args.
1119+
auto driverArgs = getClangDriverArguments(ctx, ignoreClangTarget);
1120+
1121+
llvm::SmallVector<const char *> invocationArgs;
1122+
invocationArgs.reserve(driverArgs.size());
1123+
llvm::for_each(driverArgs, [&](const std::string &Arg) {
1124+
invocationArgs.push_back(Arg.c_str());
1125+
});
1126+
1127+
if (ctx.ClangImporterOpts.DumpClangDiagnostics) {
1128+
llvm::errs() << "clang importer driver args: '";
1129+
llvm::interleave(
1130+
invocationArgs, [](StringRef arg) { llvm::errs() << arg; },
1131+
[] { llvm::errs() << "' '"; });
1132+
llvm::errs() << "'\n";
1133+
}
1134+
1135+
clang::CreateInvocationOptions CIOpts;
1136+
CIOpts.VFS = VFS;
1137+
CIOpts.Diags = clangDiags;
1138+
CIOpts.RecoverOnError = false;
1139+
CIOpts.ProbePrecompiled = true;
1140+
CI = clang::createInvocation(invocationArgs, std::move(CIOpts));
1141+
if (!CI)
1142+
return std::nullopt;
1143+
}
11191144

11201145
// FIXME: clang fails to generate a module if there is a `-fmodule-map-file`
11211146
// argument pointing to a missing file.
@@ -3919,6 +3944,66 @@ std::string ClangImporter::getClangModuleHash() const {
39193944
return Impl.Invocation->getModuleHash(Impl.Instance->getDiagnostics());
39203945
}
39213946

3947+
std::vector<std::string>
3948+
ClangImporter::getSwiftExplicitModuleDirectCC1Args() const {
3949+
llvm::SmallVector<const char*> clangArgs;
3950+
clangArgs.reserve(Impl.ClangArgs.size());
3951+
llvm::for_each(Impl.ClangArgs, [&](const std::string &Arg) {
3952+
clangArgs.push_back(Arg.c_str());
3953+
});
3954+
3955+
clang::CompilerInvocation instance;
3956+
clang::DiagnosticsEngine clangDiags(new clang::DiagnosticIDs(),
3957+
new clang::DiagnosticOptions(),
3958+
new clang::IgnoringDiagConsumer());
3959+
bool success = clang::CompilerInvocation::CreateFromArgs(instance, clangArgs,
3960+
clangDiags);
3961+
(void)success;
3962+
assert(success && "clang options from clangImporter failed to parse");
3963+
3964+
if (!Impl.SwiftContext.CASOpts.EnableCaching)
3965+
return instance.getCC1CommandLine();
3966+
3967+
// Clear some options that are not needed.
3968+
instance.clearImplicitModuleBuildOptions();
3969+
3970+
// CASOpts are forwarded from swift arguments.
3971+
instance.getCASOpts() = clang::CASOptions();
3972+
3973+
// HeaderSearchOptions.
3974+
// Clang search options are only used by scanner and clang importer from main
3975+
// module should not using search paths to find modules.
3976+
auto &HSOpts = instance.getHeaderSearchOpts();
3977+
HSOpts.VFSOverlayFiles.clear();
3978+
HSOpts.UserEntries.clear();
3979+
HSOpts.SystemHeaderPrefixes.clear();
3980+
3981+
// FrontendOptions.
3982+
auto &FEOpts = instance.getFrontendOpts();
3983+
FEOpts.IncludeTimestamps = false;
3984+
FEOpts.ModuleMapFiles.clear();
3985+
3986+
// IndexStorePath is forwarded from swift.
3987+
FEOpts.IndexStorePath.clear();
3988+
3989+
// PreprocessorOptions.
3990+
// Cannot clear macros as the main module clang importer doesn't have clang
3991+
// include tree created and it has to be created from command-line. However,
3992+
// include files are no collected into CASFS so they will not be found so
3993+
// clear them to avoid problem.
3994+
auto &PPOpts = instance.getPreprocessorOpts();
3995+
PPOpts.MacroIncludes.clear();
3996+
PPOpts.Includes.clear();
3997+
3998+
if (Impl.SwiftContext.ClangImporterOpts.UseClangIncludeTree) {
3999+
// FileSystemOptions.
4000+
auto &FSOpts = instance.getFileSystemOpts();
4001+
FSOpts.WorkingDir.clear();
4002+
}
4003+
4004+
return instance.getCC1CommandLine();
4005+
}
4006+
39224007
std::optional<Decl *>
39234008
ClangImporter::importDeclCached(const clang::NamedDecl *ClangDecl) {
39244009
return Impl.importDeclCached(ClangDecl, Impl.CurrentVersion);

lib/DependencyScan/ModuleDependencyScanner.cpp

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,9 @@ ModuleDependencyScanner::getMainModuleDependencyInfo(
346346
{"-Xcc", "-target", "-Xcc", ScanASTContext.LangOpts.Target.str()});
347347

348348
std::string rootID;
349+
std::vector<std::string> buildArgs;
350+
auto clangImporter =
351+
static_cast<ClangImporter *>(ScanASTContext.getClangModuleLoader());
349352
if (tracker) {
350353
tracker->startTracking();
351354
for (auto fileUnit : mainModule->getFiles()) {
@@ -358,8 +361,6 @@ ModuleDependencyScanner::getMainModuleDependencyInfo(
358361
ScanCompilerInvocation.getSearchPathOptions());
359362
// Fetch some dependency files from clang importer.
360363
std::vector<std::string> clangDependencyFiles;
361-
auto clangImporter =
362-
static_cast<ClangImporter *>(ScanASTContext.getClangModuleLoader());
363364
clangImporter->addClangInvovcationDependencies(clangDependencyFiles);
364365
llvm::for_each(clangDependencyFiles,
365366
[&](std::string &file) { tracker->trackFile(file); });
@@ -373,8 +374,22 @@ ModuleDependencyScanner::getMainModuleDependencyInfo(
373374
rootID = root->getID().toString();
374375
}
375376

376-
auto mainDependencies =
377-
ModuleDependencyInfo::forSwiftSourceModule(rootID, {}, {}, ExtraPCMArgs);
377+
if (ScanASTContext.ClangImporterOpts.ClangImporterDirectCC1Scan) {
378+
buildArgs.push_back("-direct-clang-cc1-module-build");
379+
for (auto &arg : clangImporter->getSwiftExplicitModuleDirectCC1Args()) {
380+
buildArgs.push_back("-Xcc");
381+
buildArgs.push_back(arg);
382+
}
383+
}
384+
385+
llvm::SmallVector<StringRef> buildCommands;
386+
buildCommands.reserve(buildArgs.size());
387+
llvm::for_each(buildArgs, [&](const std::string &arg) {
388+
buildCommands.emplace_back(arg);
389+
});
390+
391+
auto mainDependencies = ModuleDependencyInfo::forSwiftSourceModule(
392+
rootID, buildCommands, {}, ExtraPCMArgs);
378393

379394
llvm::StringSet<> alreadyAddedModules;
380395
// Compute Implicit dependencies of the main module

lib/DependencyScan/ScanDependencies.cpp

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -290,19 +290,11 @@ static llvm::Error resolveExplicitModuleInputs(
290290
}
291291
}
292292
if (!clangDepDetails->moduleCacheKey.empty()) {
293-
auto appendXclang = [&]() {
294-
if (!resolvingDepInfo.isClangModule()) {
295-
// clang module build using cc1 arg so this is not needed.
296-
commandLine.push_back("-Xcc");
297-
commandLine.push_back("-Xclang");
298-
}
299-
commandLine.push_back("-Xcc");
300-
};
301-
appendXclang();
293+
commandLine.push_back("-Xcc");
302294
commandLine.push_back("-fmodule-file-cache-key");
303-
appendXclang();
295+
commandLine.push_back("-Xcc");
304296
commandLine.push_back(clangDepDetails->mappedPCMPath);
305-
appendXclang();
297+
commandLine.push_back("-Xcc");
306298
commandLine.push_back(clangDepDetails->moduleCacheKey);
307299
}
308300

0 commit comments

Comments
 (0)