Skip to content

Commit e118a77

Browse files
[CAS] Integrate CAS into swift compiler
Teach swift compiler about CAS to allow compiler caching in the future. 1) Add flags to initiate CAS inside swift-frontend 2) Teach swift to compile using a CAS file system.
1 parent 8d709c4 commit e118a77

15 files changed

+218
-5
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/CachingUtils.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//===--- CachingUtils.h -----------------------------------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef SWIFT_FRONTEND_CACHINGUTILS_H
14+
#define SWIFT_FRONTEND_CACHINGUTILS_H
15+
16+
#include <memory>
17+
18+
namespace swift {
19+
20+
/// Get the default path for swift CAS.
21+
std::string getDefaultSwiftCASPath();
22+
23+
}
24+
25+
#endif

include/swift/Frontend/Frontend.h

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@
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/CASReference.h"
49+
#include "llvm/CAS/ObjectStore.h"
4750
#include "llvm/Option/ArgList.h"
4851
#include "llvm/Support/BLAKE3.h"
4952
#include "llvm/Support/HashingOutputBackend.h"
@@ -444,6 +447,13 @@ class CompilerInvocation {
444447
/// times on a single CompilerInstance is not permitted.
445448
class CompilerInstance {
446449
CompilerInvocation Invocation;
450+
451+
/// CAS Instances.
452+
/// This needs to be declared before SourceMgr because when using CASFS,
453+
/// the file buffer provided by CAS needs to outlive the SourceMgr.
454+
std::shared_ptr<llvm::cas::ObjectStore> CAS;
455+
std::shared_ptr<llvm::cas::ActionCache> Cache;
456+
447457
SourceManager SourceMgr;
448458
DiagnosticEngine Diagnostics{SourceMgr};
449459
std::unique_ptr<ASTContext> Context;
@@ -513,9 +523,6 @@ class CompilerInstance {
513523
llvm::vfs::FileSystem &getFileSystem() const {
514524
return *SourceMgr.getFileSystem();
515525
}
516-
void setFileSystem(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS) {
517-
SourceMgr.setFileSystem(FS);
518-
}
519526

520527
llvm::vfs::OutputBackend &getOutputBackend() const {
521528
return *OutputBackend;
@@ -527,6 +534,15 @@ class CompilerInstance {
527534
using HashingBackendPtrTy = llvm::IntrusiveRefCntPtr<HashBackendTy>;
528535
HashingBackendPtrTy getHashingBackend() { return HashBackend; }
529536

537+
llvm::cas::ObjectStore &getObjectStore() const { return *CAS; }
538+
llvm::cas::ActionCache &getActionCache() const { return *Cache; }
539+
std::shared_ptr<llvm::cas::ActionCache> getSharedCacheInstance() const {
540+
return Cache;
541+
}
542+
std::shared_ptr<llvm::cas::ObjectStore> getSharedCASInstance() const {
543+
return CAS;
544+
}
545+
530546
ASTContext &getASTContext() { return *Context; }
531547
const ASTContext &getASTContext() const { return *Context; }
532548

@@ -611,6 +627,9 @@ class CompilerInstance {
611627
/// i.e. if it can be found.
612628
bool canImportCxxShim() const;
613629

630+
/// Whether this compiler instance supports caching.
631+
bool supportCaching() const;
632+
614633
/// Gets the SourceFile which is the primary input for this CompilerInstance.
615634
/// \returns the primary SourceFile, or nullptr if there is no primary input;
616635
/// if there are _multiple_ primary inputs, fails with an assertion.
@@ -628,7 +647,8 @@ class CompilerInstance {
628647
}
629648

630649
/// Returns true if there was an error during setup.
631-
bool setup(const CompilerInvocation &Invocation, std::string &Error);
650+
bool setup(const CompilerInvocation &Invocation, std::string &Error,
651+
ArrayRef<const char *> Args = {});
632652

633653
const CompilerInvocation &getInvocation() const { return Invocation; }
634654

@@ -649,6 +669,7 @@ class CompilerInstance {
649669
bool setUpASTContextIfNeeded();
650670
void setupStatsReporter();
651671
void setupDependencyTrackerIfNeeded();
672+
bool setupCASIfNeeded(ArrayRef<const char *> Args);
652673
void setupOutputBackend();
653674

654675
/// \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: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1805,6 +1805,16 @@ def nostartfiles:
18051805
HelpHidden, NewDriverOnlyOption]>,
18061806
HelpText<"Do not link in the Swift language startup routines">;
18071807

1808+
def enable_cas: Flag<["-"], "enable-cas">,
1809+
Flags<[FrontendOption, NewDriverOnlyOption]>,
1810+
HelpText<"Enable CAS for swift-frontend">;
1811+
def cas_path: Separate<["-"], "cas-path">,
1812+
Flags<[FrontendOption, NewDriverOnlyOption]>,
1813+
HelpText<"Path to CAS">, MetaVarName<"<path>">;
1814+
def cas_fs: Separate<["-"], "cas-fs">,
1815+
Flags<[FrontendOption, NewDriverOnlyOption]>,
1816+
HelpText<"Root CASID for CAS FileSystem">, MetaVarName<"<cas-id>">;
1817+
18081818
// END ONLY SUPPORTED IN NEW DRIVER
18091819

18101820
def load_plugin_library:

lib/Frontend/ArgsToFrontendOptionsConverter.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "ArgsToFrontendOutputsConverter.h"
1717
#include "swift/AST/DiagnosticsFrontend.h"
1818
#include "swift/Basic/Platform.h"
19+
#include "swift/Frontend/CachingUtils.h"
1920
#include "swift/Frontend/Frontend.h"
2021
#include "swift/Option/Options.h"
2122
#include "swift/Option/SanitizerOptions.h"
@@ -349,6 +350,11 @@ 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 = Args.getLastArgValue(OPT_cas_path, getDefaultSwiftCASPath());
356+
Opts.CASFSRootID = Args.getLastArgValue(OPT_cas_fs);
357+
352358
return false;
353359
}
354360

lib/Frontend/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ add_swift_host_library(swiftFrontend STATIC
33
ArgsToFrontendInputsConverter.cpp
44
ArgsToFrontendOptionsConverter.cpp
55
ArgsToFrontendOutputsConverter.cpp
6+
CachingUtils.cpp
67
CompilerInvocation.cpp
78
DependencyVerifier.cpp
89
DiagnosticVerifier.cpp

lib/Frontend/CachingUtils.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//===--- CachingUtils.cpp ---------------------------------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "swift/Frontend/CachingUtils.h"
14+
15+
#include "llvm/ADT/SmallString.h"
16+
#include "llvm/Support/Path.h"
17+
18+
using namespace llvm;
19+
20+
namespace swift {
21+
22+
std::string getDefaultSwiftCASPath() {
23+
SmallString<256> Path;
24+
if (!llvm::sys::path::cache_directory(Path))
25+
llvm::report_fatal_error("cannot get default cache directory");
26+
llvm::sys::path::append(Path, "swift-cache");
27+
28+
return std::string(Path.data(), Path.size());
29+
}
30+
31+
} // namespace swift

lib/Frontend/CompilerInvocation.cpp

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

1425+
// Forward the FrontendOptions to clang importer option so it can be
1426+
// accessed when creating clang module compilation invocation.
1427+
if (FrontendOpts.EnableCAS)
1428+
Opts.CASPath = FrontendOpts.CASPath;
1429+
14251430
return false;
14261431
}
14271432

lib/Frontend/Frontend.cpp

Lines changed: 63 additions & 1 deletion
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(ArrayRef<const char *> Args) {
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+
Cache = 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)
@@ -415,9 +452,14 @@ void CompilerInstance::setupOutputBackend() {
415452
}
416453

417454
bool CompilerInstance::setup(const CompilerInvocation &Invoke,
418-
std::string &Error) {
455+
std::string &Error, ArrayRef<const char *> Args) {
419456
Invocation = Invoke;
420457

458+
if (setupCASIfNeeded(Args)) {
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)