Skip to content

[Caching] Reduce the number of cas ID passed on frontend commandline #81264

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
May 13, 2025
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
1 change: 1 addition & 0 deletions include/swift/AST/DiagnosticsFrontend.def
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,7 @@ ERROR(error_cache_key_creation, none, "cannot create cache key for compilation %
ERROR(error_cas_file_ref, none, "cannot load file %0 from CAS filesystem", (StringRef))
ERROR(error_cas_conflict_options, none, "cannot setup CAS due to conflicting '-cas-*' options", ())
ERROR(error_cas_initialization, none, "CAS cannot be initialized from the specified '-cas-*' options: %0", (StringRef))
ERROR(error_cas_malformed_input, none, "CAS input '%0' is malformed: %1", (StringRef, StringRef))
WARNING(cache_replay_failed, none, "cache replay failed: %0", (StringRef))

ERROR(error_failed_cached_diag, none, "failed to serialize cached diagnostics: %0", (StringRef))
Expand Down
6 changes: 3 additions & 3 deletions include/swift/Basic/CASOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@ class CASOptions final {
std::vector<std::string> CASFSRootIDs;

/// Clang Include Trees.
std::vector<std::string> ClangIncludeTrees;
std::string ClangIncludeTree;

/// Clang Include Tree FileList.
std::vector<std::string> ClangIncludeTreeFileList;
std::string ClangIncludeTreeFileList;

/// CacheKey for input file.
std::string InputFileKey;
Expand All @@ -62,7 +62,7 @@ class CASOptions final {
/// Check to see if a CASFileSystem is required.
bool requireCASFS() const {
return EnableCaching &&
(!CASFSRootIDs.empty() || !ClangIncludeTrees.empty() ||
(!CASFSRootIDs.empty() || !ClangIncludeTree.empty() ||
!ClangIncludeTreeFileList.empty() || !InputFileKey.empty() ||
!BridgingHeaderPCHCacheKey.empty());
}
Expand Down
4 changes: 2 additions & 2 deletions include/swift/Frontend/CachingUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ std::unique_ptr<llvm::MemoryBuffer> loadCachedCompileResultFromCacheKey(

llvm::Expected<llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>>
createCASFileSystem(llvm::cas::ObjectStore &CAS, ArrayRef<std::string> FSRoots,
ArrayRef<std::string> IncludeTreeRoots,
ArrayRef<std::string> IncludeTreeFileList);
const std::string &IncludeTreeRoot,
const std::string &IncludeTreeFileList);

std::vector<std::string> remapPathsFromCommandLine(
ArrayRef<std::string> Args,
Expand Down
4 changes: 2 additions & 2 deletions lib/AST/PluginLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,9 @@ static StringRef pluginModuleNameStringFromPath(StringRef path) {

static llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>
getPluginLoadingFS(ASTContext &Ctx) {
// If there is a clang include tree FS, using real file system to load plugin
// If there is an immutable file system, using real file system to load plugin
// as the FS in SourceMgr doesn't support directory iterator.
if (Ctx.ClangImporterOpts.HasClangIncludeTreeRoot)
if (Ctx.CASOpts.HasImmutableFileSystem)
return llvm::vfs::getRealFileSystem();
return Ctx.SourceMgr.getFileSystem();
}
Expand Down
7 changes: 3 additions & 4 deletions lib/ClangImporter/ClangImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1187,8 +1187,7 @@ std::optional<std::vector<std::string>> ClangImporter::getClangCC1Arguments(
CI->getFrontendOpts().ProgramAction ==
clang::frontend::ActionKind::GeneratePCH) &&
ctx.ClangImporterOpts.HasClangIncludeTreeRoot) {
CI->getFrontendOpts().CASIncludeTreeID =
ctx.CASOpts.ClangIncludeTrees.back();
CI->getFrontendOpts().CASIncludeTreeID = ctx.CASOpts.ClangIncludeTree;
CI->getFrontendOpts().Inputs.clear();
}
}
Expand Down Expand Up @@ -1247,7 +1246,7 @@ std::optional<std::vector<std::string>> ClangImporter::getClangCC1Arguments(

std::vector<std::string> FilteredModuleMapFiles;
for (auto ModuleMapFile : CI->getFrontendOpts().ModuleMapFiles) {
if (ctx.ClangImporterOpts.HasClangIncludeTreeRoot) {
if (ctx.ClangImporterOpts.UseClangIncludeTree) {
// There is no need to add any module map file here. Issue a warning and
// drop the option.
Impl.diagnose(SourceLoc(), diag::module_map_ignored, ModuleMapFile);
Expand Down Expand Up @@ -1327,7 +1326,7 @@ ClangImporter::create(ASTContext &ctx,
fileMapping.requiresBuiltinHeadersInSystemModules;

// Avoid creating indirect file system when using include tree.
if (!ctx.ClangImporterOpts.HasClangIncludeTreeRoot) {
if (!ctx.CASOpts.HasImmutableFileSystem) {
// Wrap Swift's FS to allow Clang to override the working directory
VFS = llvm::vfs::RedirectingFileSystem::create(
fileMapping.redirectedFiles, true, *ctx.SourceMgr.getFileSystem());
Expand Down
91 changes: 63 additions & 28 deletions lib/DependencyScan/ScanDependencies.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
#include "swift/Frontend/FrontendOptions.h"
#include "swift/Frontend/ModuleInterfaceLoader.h"
#include "swift/Strings.h"
#include "clang/Basic/Module.h"
#include "clang/CAS/IncludeTree.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SetOperations.h"
#include "llvm/ADT/SetVector.h"
Expand All @@ -69,7 +69,6 @@
#include <sstream>
#include <stack>
#include <string>
#include <algorithm>

using namespace swift;
using namespace swift::dependencies;
Expand Down Expand Up @@ -101,9 +100,6 @@ class ExplicitModuleDependencyResolver {
if (resolvingDepInfo.isFinalized())
return false;

if (auto ID = resolvingDepInfo.getClangIncludeTree())
includeTrees.push_back(*ID);

for (const auto &depModuleID : dependencies) {
const auto &depInfo = cache.findKnownDependency(depModuleID);
switch (depModuleID.Kind) {
Expand Down Expand Up @@ -322,8 +318,10 @@ class ExplicitModuleDependencyResolver {
// Collect CAS deppendencies from clang modules.
if (!clangDepDetails.CASFileSystemRootID.empty())
rootIDs.push_back(clangDepDetails.CASFileSystemRootID);
if (!clangDepDetails.CASClangIncludeTreeRootID.empty())
includeTrees.push_back(clangDepDetails.CASClangIncludeTreeRootID);
if (!clangDepDetails.CASClangIncludeTreeRootID.empty()) {
if (addIncludeTree(clangDepDetails.CASClangIncludeTreeRootID))
return true;
}

collectUsedVFSOverlay(clangDepDetails);

Expand Down Expand Up @@ -358,12 +356,14 @@ class ExplicitModuleDependencyResolver {
auto bridgeRoot = tracker->createTreeFromDependencies();
if (!bridgeRoot)
return diagnoseCASFSCreationError(bridgeRoot.takeError());
fileListIDs.push_back(bridgeRoot->getID().toString());

fileListRefs.push_back(bridgeRoot->getRef());
}
}
} else
includeTrees.push_back(sourceDepDetails.textualModuleDetails
.CASBridgingHeaderIncludeTreeRootID);
} else if (addIncludeTree(sourceDepDetails.textualModuleDetails
.CASBridgingHeaderIncludeTreeRootID))
return true;

return false;
};

Expand Down Expand Up @@ -499,9 +499,7 @@ class ExplicitModuleDependencyResolver {
auto root = tracker->createTreeFromDependencies();
if (!root)
return diagnoseCASFSCreationError(root.takeError());
auto rootID = root->getID().toString();
dependencyInfoCopy.updateCASFileSystemRootID(rootID);
fileListIDs.push_back(rootID);
fileListRefs.push_back(root->getRef());
} else if (auto *textualDep =
resolvingDepInfo.getAsSwiftInterfaceModule()) {
tracker->startTracking();
Expand All @@ -516,9 +514,7 @@ class ExplicitModuleDependencyResolver {
auto root = tracker->createTreeFromDependencies();
if (!root)
return diagnoseCASFSCreationError(root.takeError());
auto rootID = root->getID().toString();
dependencyInfoCopy.updateCASFileSystemRootID(rootID);
fileListIDs.push_back(rootID);
fileListRefs.push_back(root->getRef());
}

// Update build command line.
Expand All @@ -530,15 +526,8 @@ class ExplicitModuleDependencyResolver {
commandline.push_back(rootID);
}

for (auto tree : includeTrees) {
commandline.push_back("-clang-include-tree-root");
commandline.push_back(tree);
}

for (auto list : fileListIDs) {
commandline.push_back("-clang-include-tree-filelist");
commandline.push_back(list);
}
if (computeCASFileSystem(dependencyInfoCopy))
return true;
}

// Compute and update module cache key.
Expand Down Expand Up @@ -636,6 +625,53 @@ class ExplicitModuleDependencyResolver {
cmd.push_back("-cache-disable-replay");
}

bool addIncludeTree(StringRef includeTree) {
auto &db = cache.getScanService().getCAS();
auto casID = db.parseID(includeTree);
if (!casID) {
instance.getDiags().diagnose(SourceLoc(), diag::error_invalid_cas_id,
includeTree, toString(casID.takeError()));
return true;
}
auto ref = db.getReference(*casID);
if (!ref) {
instance.getDiags().diagnose(SourceLoc(), diag::error_load_input_from_cas,
includeTree);
return true;
}

auto root = clang::cas::IncludeTreeRoot::get(db, *ref);
if (!root) {
instance.getDiags().diagnose(SourceLoc(), diag::error_cas_malformed_input,
includeTree, toString(root.takeError()));
return true;
}

fileListRefs.push_back(root->getFileListRef());
return false;
}

bool computeCASFileSystem(ModuleDependencyInfo &dependencyInfoCopy) {
if (fileListRefs.empty())
return false;

auto &db = cache.getScanService().getCAS();
auto casFS =
clang::cas::IncludeTree::FileList::create(db, {}, fileListRefs);
if (!casFS) {
instance.getDiags().diagnose(SourceLoc(), diag::error_cas,
"CAS IncludeTree FileList creation",
toString(casFS.takeError()));
return true;
}

auto casID = casFS->getID().toString();
dependencyInfoCopy.updateCASFileSystemRootID(casID);
commandline.push_back("-clang-include-tree-filelist");
commandline.push_back(casID);
return false;
}

private:
const ModuleDependencyID &moduleID;
ModuleDependenciesCache &cache;
Expand All @@ -644,8 +680,7 @@ class ExplicitModuleDependencyResolver {

std::optional<SwiftDependencyTracker> tracker;
std::vector<std::string> rootIDs;
std::vector<std::string> includeTrees;
std::vector<std::string> fileListIDs;
std::vector<llvm::cas::ObjectRef> fileListRefs;
std::vector<std::string> commandline;
std::vector<std::string> bridgingHeaderBuildCmd;
llvm::StringMap<MacroPluginDependency> macros;
Expand Down
59 changes: 19 additions & 40 deletions lib/Frontend/CachingUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -472,16 +472,10 @@ static Expected<ObjectRef> mergeCASFileSystem(ObjectStore &CAS,

Expected<IntrusiveRefCntPtr<vfs::FileSystem>>
createCASFileSystem(ObjectStore &CAS, ArrayRef<std::string> FSRoots,
ArrayRef<std::string> IncludeTrees,
ArrayRef<std::string> IncludeTreeFileList) {
assert(!FSRoots.empty() || !IncludeTrees.empty() ||
const std::string &IncludeTree,
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't we prefer StringRef here?

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 input is always a std::string from FrontendOptions. I don't see StringRef is necessary and it adds overhead if not inlined.

const std::string &IncludeTreeFileList) {
assert(!FSRoots.empty() || !IncludeTree.empty() ||
!IncludeTreeFileList.empty() && "no root ID provided");
if (FSRoots.size() == 1 && IncludeTrees.empty()) {
auto ID = CAS.parseID(FSRoots.front());
if (!ID)
return ID.takeError();
return createCASFileSystem(CAS, *ID);
}

auto NewRoot = mergeCASFileSystem(CAS, FSRoots);
if (!NewRoot)
Expand All @@ -492,10 +486,9 @@ createCASFileSystem(ObjectStore &CAS, ArrayRef<std::string> FSRoots,
return FS.takeError();

auto CASFS = makeIntrusiveRefCnt<vfs::OverlayFileSystem>(std::move(*FS));
std::vector<clang::cas::IncludeTree::FileList::FileEntry> Files;
// Push all Include File System onto overlay.
for (auto &Tree : IncludeTrees) {
auto ID = CAS.parseID(Tree);

if (!IncludeTree.empty()) {
auto ID = CAS.parseID(IncludeTree);
if (!ID)
return ID.takeError();

Expand All @@ -510,46 +503,32 @@ createCASFileSystem(ObjectStore &CAS, ArrayRef<std::string> FSRoots,
if (!ITF)
return ITF.takeError();

auto Err = ITF->forEachFile(
[&](clang::cas::IncludeTree::File File,
clang::cas::IncludeTree::FileList::FileSizeTy Size) -> llvm::Error {
Files.push_back({File.getRef(), Size});
return llvm::Error::success();
});
auto ITFS = clang::cas::createIncludeTreeFileSystem(*ITF);
if (!ITFS)
return ITFS.takeError();

if (Err)
return std::move(Err);
CASFS->pushOverlay(*ITFS);
}

for (auto &List: IncludeTreeFileList) {
auto ID = CAS.parseID(List);
if (!IncludeTreeFileList.empty()) {
auto ID = CAS.parseID(IncludeTreeFileList);
if (!ID)
return ID.takeError();

auto Ref = CAS.getReference(*ID);
if (!Ref)
return createCASObjectNotFoundError(*ID);
auto IT = clang::cas::IncludeTree::FileList::get(CAS, *Ref);
if (!IT)
return IT.takeError();
auto ITF = clang::cas::IncludeTree::FileList::get(CAS, *Ref);
if (!ITF)
return ITF.takeError();

auto Err = IT->forEachFile(
[&](clang::cas::IncludeTree::File File,
clang::cas::IncludeTree::FileList::FileSizeTy Size) -> llvm::Error {
Files.push_back({File.getRef(), Size});
return llvm::Error::success();
});
auto ITFS = clang::cas::createIncludeTreeFileSystem(*ITF);
if (!ITFS)
return ITFS.takeError();

if (Err)
return std::move(Err);
CASFS->pushOverlay(std::move(*ITFS));
}

auto ITFS = clang::cas::createIncludeTreeFileSystem(CAS, Files);
if (!ITFS)
return ITFS.takeError();

CASFS->pushOverlay(std::move(*ITFS));

return CASFS;
}

Expand Down
10 changes: 5 additions & 5 deletions lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -763,18 +763,18 @@ static bool ParseCASArgs(CASOptions &Opts, ArgList &Args,

for (const auto &A : Args.getAllArgValues(OPT_cas_fs))
Opts.CASFSRootIDs.emplace_back(A);
for (const auto &A : Args.getAllArgValues(OPT_clang_include_tree_root))
Opts.ClangIncludeTrees.emplace_back(A);
for (const auto &A : Args.getAllArgValues(OPT_clang_include_tree_filelist))
Opts.ClangIncludeTreeFileList.emplace_back(A);
if (auto *A = Args.getLastArg(OPT_clang_include_tree_root))
Opts.ClangIncludeTree = A->getValue();
if (auto *A = Args.getLastArg(OPT_clang_include_tree_filelist))
Opts.ClangIncludeTreeFileList = A->getValue();

if (const Arg *A = Args.getLastArg(OPT_input_file_key))
Opts.InputFileKey = A->getValue();

if (const Arg*A = Args.getLastArg(OPT_bridging_header_pch_key))
Opts.BridgingHeaderPCHCacheKey = A->getValue();

if (!Opts.CASFSRootIDs.empty() || !Opts.ClangIncludeTrees.empty() ||
if (!Opts.CASFSRootIDs.empty() || !Opts.ClangIncludeTree.empty() ||
!Opts.ClangIncludeTreeFileList.empty())
Opts.HasImmutableFileSystem = true;

Expand Down
4 changes: 2 additions & 2 deletions lib/Frontend/Frontend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -630,11 +630,11 @@ bool CompilerInstance::setUpVirtualFileSystemOverlays() {
}

if (Invocation.getCASOptions().requireCASFS()) {
if (!CASOpts.CASFSRootIDs.empty() || !CASOpts.ClangIncludeTrees.empty() ||
if (!CASOpts.CASFSRootIDs.empty() || !CASOpts.ClangIncludeTree.empty() ||
!CASOpts.ClangIncludeTreeFileList.empty()) {
// Set up CASFS as BaseFS.
auto FS = createCASFileSystem(*CAS, CASOpts.CASFSRootIDs,
CASOpts.ClangIncludeTrees,
CASOpts.ClangIncludeTree,
CASOpts.ClangIncludeTreeFileList);
if (!FS) {
Diagnostics.diagnose(SourceLoc(), diag::error_cas_fs_creation,
Expand Down
2 changes: 1 addition & 1 deletion lib/Sema/TypeCheckMacros.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ initializePlugin(ASTContext &ctx, CompilerPlugin *plugin, StringRef libraryPath,
if (!libraryPath.empty()) {
#if SWIFT_BUILD_SWIFT_SYNTAX
llvm::SmallString<128> resolvedLibraryPath;
auto fs = ctx.ClangImporterOpts.HasClangIncludeTreeRoot
auto fs = ctx.CASOpts.HasImmutableFileSystem
? llvm::vfs::getRealFileSystem()
: ctx.SourceMgr.getFileSystem();
if (auto err = fs->getRealPath(libraryPath, resolvedLibraryPath)) {
Expand Down
1 change: 0 additions & 1 deletion test/CAS/module_deps_include_tree.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@
// INCLUDE_TREE_F-NEXT: CHeaders/F.h

// MAIN_CMD: -direct-clang-cc1-module-build
// MAIN_CMD: -clang-include-tree-root
// MAIN_CMD: -clang-include-tree-filelist

import C
Expand Down