Skip to content

Commit b9f9eeb

Browse files
Merge pull request #65058 from cachemeifyoucan/eng/PR-swift-cas-fs
[CAS] Integrate CAS into swift compiler
2 parents 9dff5f2 + e2c4941 commit b9f9eeb

File tree

12 files changed

+157
-3
lines changed

12 files changed

+157
-3
lines changed

include/swift/AST/DiagnosticsFrontend.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,11 @@ ERROR(error_output_missing,none,
485485
REMARK(matching_output_produced,none,
486486
"produced matching output file '%0' for deterministic check: hash '%1'", (StringRef, StringRef))
487487

488+
// CAS related diagnostics
489+
ERROR(error_create_cas, none, "failed to create CAS '%0' (%1)", (StringRef, StringRef))
490+
ERROR(error_invalid_cas_id, none, "invalid CASID '%0' (%1)", (StringRef, StringRef))
491+
ERROR(error_cas, none, "CAS error encountered: %0", (StringRef))
492+
488493
// Dependency Verifier Diagnostics
489494
ERROR(missing_member_dependency,none,
490495
"expected "

include/swift/Basic/LangOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -804,6 +804,9 @@ namespace swift {
804804
/// import, but it can affect Clang's IR generation of static functions.
805805
std::string Optimization;
806806

807+
/// clang CASOptions.
808+
std::string CASPath;
809+
807810
/// Disable validating the persistent PCH.
808811
bool PCHDisableValidation = false;
809812

include/swift/Frontend/Frontend.h

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@
4444
#include "clang/Basic/FileManager.h"
4545
#include "llvm/ADT/IntrusiveRefCntPtr.h"
4646
#include "llvm/ADT/SetVector.h"
47+
#include "llvm/CAS/ActionCache.h"
48+
#include "llvm/CAS/ObjectStore.h"
4749
#include "llvm/Option/ArgList.h"
4850
#include "llvm/Support/BLAKE3.h"
4951
#include "llvm/Support/HashingOutputBackend.h"
@@ -447,6 +449,13 @@ class CompilerInvocation {
447449
/// times on a single CompilerInstance is not permitted.
448450
class CompilerInstance {
449451
CompilerInvocation Invocation;
452+
453+
/// CAS Instances.
454+
/// This needs to be declared before SourceMgr because when using CASFS,
455+
/// the file buffer provided by CAS needs to outlive the SourceMgr.
456+
std::shared_ptr<llvm::cas::ObjectStore> CAS;
457+
std::shared_ptr<llvm::cas::ActionCache> ResultCache;
458+
450459
SourceManager SourceMgr;
451460
DiagnosticEngine Diagnostics{SourceMgr};
452461
std::unique_ptr<ASTContext> Context;
@@ -516,9 +525,6 @@ class CompilerInstance {
516525
llvm::vfs::FileSystem &getFileSystem() const {
517526
return *SourceMgr.getFileSystem();
518527
}
519-
void setFileSystem(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS) {
520-
SourceMgr.setFileSystem(FS);
521-
}
522528

523529
llvm::vfs::OutputBackend &getOutputBackend() const {
524530
return *OutputBackend;
@@ -530,6 +536,15 @@ class CompilerInstance {
530536
using HashingBackendPtrTy = llvm::IntrusiveRefCntPtr<HashBackendTy>;
531537
HashingBackendPtrTy getHashingBackend() { return HashBackend; }
532538

539+
llvm::cas::ObjectStore &getObjectStore() const { return *CAS; }
540+
llvm::cas::ActionCache &getActionCache() const { return *ResultCache; }
541+
std::shared_ptr<llvm::cas::ActionCache> getSharedCacheInstance() const {
542+
return ResultCache;
543+
}
544+
std::shared_ptr<llvm::cas::ObjectStore> getSharedCASInstance() const {
545+
return CAS;
546+
}
547+
533548
ASTContext &getASTContext() { return *Context; }
534549
const ASTContext &getASTContext() const { return *Context; }
535550

@@ -652,6 +667,7 @@ class CompilerInstance {
652667
bool setUpASTContextIfNeeded();
653668
void setupStatsReporter();
654669
void setupDependencyTrackerIfNeeded();
670+
bool setupCASIfNeeded();
655671
void setupOutputBackend();
656672

657673
/// \return false if successful, true on error.

include/swift/Frontend/FrontendOptions.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,15 @@ class FrontendOptions {
122122
/// The module for which we should verify all of the generic signatures.
123123
std::string VerifyGenericSignaturesInModule;
124124

125+
/// Use CAS.
126+
bool EnableCAS = false;
127+
128+
/// The CAS Path.
129+
std::string CASPath;
130+
131+
/// CASFS Root.
132+
std::string CASFSRootID;
133+
125134
/// Number of retry opening an input file if the previous opening returns
126135
/// bad file descriptor error.
127136
unsigned BadFileDescriptorRetryCount = 0;

include/swift/Option/Options.td

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1810,8 +1810,20 @@ def gcc_toolchain: Separate<["-"], "gcc-toolchain">,
18101810
MetaVarName<"<path>">,
18111811
HelpText<"Specify a directory where the clang importer and clang linker can find headers and libraries">;
18121812

1813+
def cas_path: Separate<["-"], "cas-path">,
1814+
Flags<[FrontendOption, NewDriverOnlyOption]>,
1815+
HelpText<"Path to CAS">, MetaVarName<"<path>">;
1816+
18131817
// END ONLY SUPPORTED IN NEW DRIVER
18141818

1819+
def enable_cas: Flag<["-"], "enable-cas">,
1820+
Flags<[FrontendOption, NoDriverOption]>,
1821+
HelpText<"Enable CAS for swift-frontend">;
1822+
1823+
def cas_fs: Separate<["-"], "cas-fs">,
1824+
Flags<[FrontendOption, NoDriverOption]>,
1825+
HelpText<"Root CASID for CAS FileSystem">, MetaVarName<"<cas-id>">;
1826+
18151827
def load_plugin_library:
18161828
Separate<["-"], "load-plugin-library">,
18171829
Flags<[FrontendOption, DoesNotAffectIncrementalBuild, ArgumentIsPath]>,

lib/Frontend/ArgsToFrontendOptionsConverter.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "swift/Strings.h"
2424
#include "llvm/ADT/STLExtras.h"
2525
#include "llvm/ADT/Triple.h"
26+
#include "llvm/CAS/ObjectStore.h"
2627
#include "llvm/Option/Arg.h"
2728
#include "llvm/Option/ArgList.h"
2829
#include "llvm/Option/Option.h"
@@ -349,6 +350,12 @@ bool ArgsToFrontendOptionsConverter::convert(
349350
for (auto A : Args.getAllArgValues(options::OPT_block_list_file)) {
350351
Opts.BlocklistConfigFilePaths.push_back(A);
351352
}
353+
354+
Opts.EnableCAS = Args.hasArg(OPT_enable_cas);
355+
Opts.CASPath =
356+
Args.getLastArgValue(OPT_cas_path, llvm::cas::getDefaultOnDiskCASPath());
357+
Opts.CASFSRootID = Args.getLastArgValue(OPT_cas_fs);
358+
352359
return false;
353360
}
354361

lib/Frontend/CompilerInvocation.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1465,6 +1465,11 @@ static bool ParseClangImporterArgs(ClangImporterOptions &Opts,
14651465
Opts.DisableSourceImport |=
14661466
Args.hasArg(OPT_disable_clangimporter_source_import);
14671467

1468+
// Forward the FrontendOptions to clang importer option so it can be
1469+
// accessed when creating clang module compilation invocation.
1470+
if (FrontendOpts.EnableCAS)
1471+
Opts.CASPath = FrontendOpts.CASPath;
1472+
14681473
return false;
14691474
}
14701475

lib/Frontend/Frontend.cpp

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@
4141
#include "llvm/ADT/IntrusiveRefCntPtr.h"
4242
#include "llvm/ADT/SmallVector.h"
4343
#include "llvm/ADT/Triple.h"
44+
#include "llvm/CAS/ActionCache.h"
45+
#include "llvm/CAS/BuiltinUnifiedCASDatabases.h"
46+
#include "llvm/CAS/CASFileSystem.h"
4447
#include "llvm/Support/CommandLine.h"
4548
#include "llvm/Support/Error.h"
4649
#include "llvm/Support/MemoryBuffer.h"
@@ -395,6 +398,40 @@ void CompilerInstance::setupDependencyTrackerIfNeeded() {
395398
DepTracker->addDependency(path, /*isSystem=*/false);
396399
}
397400

401+
bool CompilerInstance::setupCASIfNeeded() {
402+
const auto &Opts = getInvocation().getFrontendOptions();
403+
if (!Opts.EnableCAS)
404+
return false;
405+
406+
auto MaybeCache = llvm::cas::createOnDiskUnifiedCASDatabases(Opts.CASPath);
407+
if (!MaybeCache) {
408+
Diagnostics.diagnose(SourceLoc(), diag::error_create_cas, Opts.CASPath,
409+
toString(MaybeCache.takeError()));
410+
return true;
411+
}
412+
CAS = std::move(MaybeCache->first);
413+
ResultCache = std::move(MaybeCache->second);
414+
415+
// create baseline key.
416+
llvm::Optional<llvm::cas::ObjectRef> FSRef;
417+
if (!Opts.CASFSRootID.empty()) {
418+
auto CASFSID = CAS->parseID(Opts.CASFSRootID);
419+
if (!CASFSID) {
420+
Diagnostics.diagnose(SourceLoc(), diag::error_cas,
421+
toString(CASFSID.takeError()));
422+
return true;
423+
}
424+
FSRef = CAS->getReference(*CASFSID);
425+
if (!FSRef) {
426+
Diagnostics.diagnose(SourceLoc(), diag::error_cas,
427+
"-cas-fs value does not exist in CAS");
428+
return true;
429+
}
430+
}
431+
432+
return false;
433+
}
434+
398435
void CompilerInstance::setupOutputBackend() {
399436
// Skip if output backend is not setup, default to OnDiskOutputBackend.
400437
if (OutputBackend)
@@ -418,6 +455,11 @@ bool CompilerInstance::setup(const CompilerInvocation &Invoke,
418455
std::string &Error) {
419456
Invocation = Invoke;
420457

458+
if (setupCASIfNeeded()) {
459+
Error = "Setting up CAS failed";
460+
return true;
461+
}
462+
421463
setupDependencyTrackerIfNeeded();
422464
setupOutputBackend();
423465

@@ -463,6 +505,26 @@ bool CompilerInstance::setup(const CompilerInvocation &Invoke,
463505
}
464506

465507
bool CompilerInstance::setUpVirtualFileSystemOverlays() {
508+
if (Invocation.getFrontendOptions().EnableCAS &&
509+
!Invocation.getFrontendOptions().CASFSRootID.empty()) {
510+
// Set up CASFS as BaseFS.
511+
auto RootID = CAS->parseID(Invocation.getFrontendOptions().CASFSRootID);
512+
if (!RootID) {
513+
Diagnostics.diagnose(SourceLoc(), diag::error_invalid_cas_id,
514+
Invocation.getFrontendOptions().CASFSRootID,
515+
toString(RootID.takeError()));
516+
return true;
517+
}
518+
auto FS = llvm::cas::createCASFileSystem(*CAS, *RootID);
519+
if (!FS) {
520+
Diagnostics.diagnose(SourceLoc(), diag::error_invalid_cas_id,
521+
Invocation.getFrontendOptions().CASFSRootID,
522+
toString(FS.takeError()));
523+
return true;
524+
}
525+
SourceMgr.setFileSystem(std::move(*FS));
526+
}
527+
466528
auto ExpectedOverlay =
467529
Invocation.getSearchPathOptions().makeOverlayFileSystem(
468530
SourceMgr.getFileSystem());

test/CAS/Inputs/objc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
int test(int);

test/CAS/cas_fs.swift

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: mkdir -p %t/empty
3+
// RUN: mkdir -p %t/cas
4+
5+
// RUN: llvm-cas --cas %t/cas --ingest --data %t/empty > %t/empty.casid
6+
// RUN: not %target-swift-frontend -typecheck -enable-cas -cas-fs @%t/empty.casid -cas-path %t/cas %s 2>&1 | %FileCheck %s --check-prefix NO-INPUTS
7+
// NO-INPUTS: error: error opening input file
8+
9+
// RUN: llvm-cas --cas %t/cas --ingest --data %s > %t/source.casid
10+
// RUN: not %target-swift-frontend -typecheck -enable-cas -cas-fs @%t/source.casid -cas-path %t/cas %s 2>&1 | %FileCheck %s --check-prefix NO-RESOURCES
11+
// NO-RESOURCES: error: unable to set working directory
12+
// NO-RESOURCES: error: unable to load standard library
13+
14+
/// Ingest the resource directory to satisfy the file system requirement. Also switch CWD to resource dir.
15+
// RUN: llvm-cas --cas %t/cas --merge @%t/source.casid %test-resource-dir > %t/full.casid
16+
// RUN: cd %test-resource-dir
17+
// RUN: %target-swift-frontend -typecheck -enable-cas -cas-fs @%t/full.casid -cas-path %t/cas %s
18+
19+
/// Try clang importer.
20+
// RUN: not %target-swift-frontend -typecheck -enable-cas -cas-fs @%t/full.casid -cas-path %t/cas %s -import-objc-header %S/Inputs/objc.h 2>&1 | %FileCheck %s --check-prefix NO-BRIDGING-HEADER
21+
// NO-BRIDGING-HEADER: error: bridging header
22+
23+
// RUN: llvm-cas --cas %t/cas --merge @%t/full.casid %S/Inputs/objc.h > %t/bridging_header.casid
24+
// RUN: %target-swift-frontend -typecheck -enable-cas -cas-fs @%t/bridging_header.casid -cas-path %t/cas %s -import-objc-header %S/Inputs/objc.h
25+
26+
/// Clean the CAS to save space.
27+
// RUN: %empty-directory(%t)
28+
29+
func testFunc() {}

test/CAS/lit.local.cfg

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# FIXME: CAS file system doesn't support windows. Unsupported for now.
2+
import platform
3+
if platform.system() == 'Windows':
4+
config.unsupported = True

test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ function(get_test_dependencies SDK result_var_name)
8585
llvm-ar
8686
llvm-as
8787
llvm-bcanalyzer
88+
llvm-cas
8889
llvm-cov
8990
llvm-dis
9091
llvm-dwarfdump

0 commit comments

Comments
 (0)