Skip to content

Commit 5e98b81

Browse files
committed
[clang][cas] Remove -MT and -MP from the cache key
Pull the dependency options that only affect the output but not the list of filenames out of the cache key, and apply them instead when replaying the list of dependencies from the cache. The dependency file target name(s) are typically an output path, so we want to avoid it showing up in the cache key. For now, the options that *do* affect the list of dependencies like the difference between -MMD and -MD are still part of the key so that we do not store many unnecessary system paths if they will not be used. It would be straightforward to change that if it turned out to be worthwhile by storing flags like IsSystem, IsModuleFile, etc.
1 parent c6fd6d4 commit 5e98b81

File tree

10 files changed

+197
-5
lines changed

10 files changed

+197
-5
lines changed

clang/include/clang/Basic/DiagnosticCASKinds.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ def err_cas_depscan_daemon_connection: Error<
2323
"Failed to establish connection with depscan daemon: %0">, DefaultFatal;
2424
def err_cas_depscan_failed: Error<
2525
"CAS-based dependency scan failed: %0">, DefaultFatal;
26+
def err_cas_store: Error<"failed to store to CAS: %0">, DefaultFatal;
2627

2728
def warn_clang_cache_disabled_caching: Warning<
2829
"caching disabled because %0">,
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//===- CASDependencyCollector.h ---------------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_CLANG_FRONTEND_CASDEPENDENCYCOLLECTOR_H
10+
#define LLVM_CLANG_FRONTEND_CASDEPENDENCYCOLLECTOR_H
11+
12+
#include "clang/Frontend/Utils.h"
13+
14+
namespace llvm::cas {
15+
class CASOutputBackend;
16+
}
17+
18+
namespace clang {
19+
20+
/// Collects dependencies when attached to a Preprocessor (for includes) and
21+
/// ASTReader (for module imports), and writes it to the CAS in a manner
22+
/// suitable to be replayed into a DependencyFileGenerator.
23+
class CASDependencyCollector : public DependencyFileGenerator {
24+
public:
25+
CASDependencyCollector(
26+
const DependencyOutputOptions &Opts,
27+
IntrusiveRefCntPtr<llvm::cas::CASOutputBackend> OutputBackend);
28+
29+
static llvm::Error replay(const DependencyOutputOptions &Opts,
30+
cas::CASDB &CAS, cas::ObjectRef DepsRef,
31+
llvm::raw_ostream &OS);
32+
33+
private:
34+
void finishedMainFile(DiagnosticsEngine &Diags) override;
35+
36+
IntrusiveRefCntPtr<llvm::cas::CASOutputBackend> CASOutputs;
37+
std::string OutputName;
38+
};
39+
40+
} // namespace clang
41+
42+
#endif // LLVM_CLANG_FRONTEND_CASDEPENDENCYCOLLECTOR_H

clang/include/clang/Frontend/CompilerInstance.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "llvm/ADT/DenseMap.h"
2222
#include "llvm/ADT/IntrusiveRefCntPtr.h"
2323
#include "llvm/ADT/StringRef.h"
24+
#include "llvm/CAS/CASOutputBackend.h"
2425
#include "llvm/Support/BuryPointer.h"
2526
#include "llvm/Support/FileSystem.h"
2627
#include "llvm/Support/VirtualOutputBackend.h"
@@ -92,6 +93,10 @@ class CompilerInstance : public ModuleLoader {
9293
/// The output context.
9394
IntrusiveRefCntPtr<llvm::vfs::OutputBackend> TheOutputBackend;
9495

96+
/// The underlying CAS output context, if any. Used to create CAS-specific
97+
/// outputs.
98+
IntrusiveRefCntPtr<llvm::cas::CASOutputBackend> CASOutputBackend;
99+
95100
/// The source manager.
96101
IntrusiveRefCntPtr<SourceManager> SourceMgr;
97102

@@ -416,14 +421,20 @@ class CompilerInstance : public ModuleLoader {
416421
/// Set the output manager.
417422
void setOutputBackend(IntrusiveRefCntPtr<llvm::vfs::OutputBackend> NewOutputs);
418423

424+
void setCASOutputBackend(
425+
clang::IntrusiveRefCntPtr<llvm::cas::CASOutputBackend> NewOutputs);
426+
419427
/// Create an output manager.
420428
void createOutputBackend();
421429

422430
bool hasOutputBackend() const { return bool(TheOutputBackend); }
431+
bool hasCASOutputBackend() const { return bool(CASOutputBackend); }
423432

424433
llvm::vfs::OutputBackend &getOutputBackend();
425434
llvm::vfs::OutputBackend &getOrCreateOutputBackend();
426435

436+
llvm::cas::CASOutputBackend &getCASOutputBackend();
437+
427438
/// Get the CAS, or create it using the configuration in CompilerInvocation.
428439
llvm::cas::CASDB &getOrCreateCAS();
429440

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
//===--- CASDependencyCollector.cpp ---------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "clang/Frontend/CASDependencyCollector.h"
10+
#include "clang/Basic/DiagnosticCAS.h"
11+
#include "llvm/CAS/CASDB.h"
12+
#include "llvm/CAS/CASOutputBackend.h"
13+
#include "llvm/Support/VirtualOutputBackends.h"
14+
15+
using namespace clang;
16+
using namespace clang::cas;
17+
18+
CASDependencyCollector::CASDependencyCollector(
19+
const DependencyOutputOptions &Opts,
20+
IntrusiveRefCntPtr<llvm::cas::CASOutputBackend> OutputBackend)
21+
: DependencyFileGenerator(Opts, llvm::vfs::makeNullOutputBackend()),
22+
CASOutputs(std::move(OutputBackend)), OutputName(Opts.OutputFile) {}
23+
24+
llvm::Error CASDependencyCollector::replay(const DependencyOutputOptions &Opts,
25+
CASDB &CAS, ObjectRef DepsRef,
26+
llvm::raw_ostream &OS) {
27+
auto Refs = CAS.load(DepsRef);
28+
if (!Refs)
29+
return Refs.takeError();
30+
31+
CASDependencyCollector DC(Opts, nullptr);
32+
auto Err = CAS.forEachRef(*Refs, [&](ObjectRef Ref) -> llvm::Error {
33+
auto PathHandle = CAS.load(Ref);
34+
if (!PathHandle)
35+
return PathHandle.takeError();
36+
StringRef Path = CAS.getDataString(*PathHandle);
37+
// This assumes the replay has the same filtering options as when it was
38+
// originally computed. That avoids needing to store many unnecessary paths.
39+
// FIXME: if a prefix map is enabled, we should remap the paths to the
40+
// invocation's environment.
41+
DC.addDependency(Path);
42+
return llvm::Error::success();
43+
});
44+
if (Err)
45+
return Err;
46+
47+
DC.outputDependencyFile(OS);
48+
return llvm::Error::success();
49+
}
50+
51+
void CASDependencyCollector::finishedMainFile(DiagnosticsEngine &Diags) {
52+
CASDB &CAS = CASOutputs->getCAS();
53+
ArrayRef<std::string> Files = getDependencies();
54+
std::vector<ObjectRef> Refs;
55+
Refs.reserve(Files.size());
56+
for (StringRef File : Files) {
57+
auto Handle = CAS.storeFromString({}, File);
58+
if (!Handle) {
59+
Diags.Report({}, diag::err_cas_store) << toString(Handle.takeError());
60+
return;
61+
}
62+
Refs.push_back(CAS.getReference(*Handle));
63+
}
64+
65+
auto Handle = CAS.store(Refs, {});
66+
if (!Handle) {
67+
Diags.Report({}, diag::err_cas_store) << toString(Handle.takeError());
68+
return;
69+
}
70+
71+
if (auto Err = CASOutputs->addObject(OutputName, CAS.getReference(*Handle)))
72+
Diags.Report({}, diag::err_cas_store) << toString(std::move(Err));
73+
}

clang/lib/Frontend/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ add_clang_library(clangFrontend
1313
ASTConsumers.cpp
1414
ASTMerge.cpp
1515
ASTUnit.cpp
16+
CASDependencyCollector.cpp
1617
ChainedDiagnosticConsumer.cpp
1718
ChainedIncludesSource.cpp
1819
CompileJobCacheKey.cpp

clang/lib/Frontend/CompileJobCacheKey.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,14 +60,20 @@ clang::createCompileJobCacheKey(CASDB &CAS, DiagnosticsEngine &Diags,
6060
CompilerInvocation InvocationForCacheKey(OriginalInvocation);
6161
FrontendOptions &FrontendOpts = InvocationForCacheKey.getFrontendOpts();
6262
DiagnosticOptions &DiagOpts = InvocationForCacheKey.getDiagnosticOpts();
63+
DependencyOutputOptions &DepOpts =
64+
InvocationForCacheKey.getDependencyOutputOpts();
6365
// Keep the key independent of the paths of these outputs.
6466
if (!FrontendOpts.OutputFile.empty())
6567
FrontendOpts.OutputFile = "-";
66-
if (!InvocationForCacheKey.getDependencyOutputOpts().OutputFile.empty())
67-
InvocationForCacheKey.getDependencyOutputOpts().OutputFile = "-";
68+
if (!DepOpts.OutputFile.empty())
69+
DepOpts.OutputFile = "-";
6870
// We always generate the serialized diagnostics so the key is independent of
6971
// the presence of '--serialize-diagnostics'.
7072
DiagOpts.DiagnosticSerializationFile.clear();
73+
// Dependency options that do not affect the list of files are canonicalized.
74+
if (!DepOpts.Targets.empty())
75+
DepOpts.Targets = {"-"};
76+
DepOpts.UsePhonyTargets = false;
7177

7278
// Generate a new command-line in case Invocation has been canonicalized.
7379
llvm::BumpPtrAllocator Alloc;

clang/lib/Frontend/CompilerInstance.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "clang/Basic/TargetInfo.h"
2020
#include "clang/Basic/Version.h"
2121
#include "clang/Config/config.h"
22+
#include "clang/Frontend/CASDependencyCollector.h"
2223
#include "clang/Frontend/ChainedDiagnosticConsumer.h"
2324
#include "clang/Frontend/FrontendAction.h"
2425
#include "clang/Frontend/FrontendActions.h"
@@ -506,9 +507,13 @@ void CompilerInstance::createPreprocessor(TranslationUnitKind TUKind) {
506507

507508
// Handle generating dependencies, if requested.
508509
const DependencyOutputOptions &DepOpts = getDependencyOutputOpts();
509-
if (!DepOpts.OutputFile.empty())
510+
if (!DepOpts.OutputFile.empty()) {
511+
if (hasCASOutputBackend())
512+
addDependencyCollector(
513+
std::make_shared<CASDependencyCollector>(DepOpts, CASOutputBackend));
510514
addDependencyCollector(
511515
std::make_shared<DependencyFileGenerator>(DepOpts, TheOutputBackend));
516+
}
512517
if (!DepOpts.DOTOutputFile.empty())
513518
AttachDependencyGraphGen(*PP, DepOpts.DOTOutputFile,
514519
getHeaderSearchOpts().Sysroot);
@@ -826,6 +831,11 @@ void CompilerInstance::setOutputBackend(
826831
assert(!TheOutputBackend && "Already has an output manager");
827832
TheOutputBackend = std::move(NewOutputs);
828833
}
834+
void CompilerInstance::setCASOutputBackend(
835+
clang::IntrusiveRefCntPtr<llvm::cas::CASOutputBackend> NewOutputs) {
836+
assert(!CASOutputBackend && "Already has a CAS output backend");
837+
CASOutputBackend = std::move(NewOutputs);
838+
}
829839

830840
void CompilerInstance::createOutputBackend() {
831841
assert(!TheOutputBackend && "Already has an output manager");
@@ -843,6 +853,11 @@ llvm::vfs::OutputBackend &CompilerInstance::getOrCreateOutputBackend() {
843853
return getOutputBackend();
844854
}
845855

856+
llvm::cas::CASOutputBackend &CompilerInstance::getCASOutputBackend() {
857+
assert(CASOutputBackend);
858+
return *CASOutputBackend;
859+
}
860+
846861
llvm::cas::CASDB &CompilerInstance::getOrCreateCAS() {
847862
if (CAS)
848863
return *CAS;

clang/test/CAS/fcache-compile-job-dependency-file.c

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,21 @@
44
//
55
// RUN: %clang -cc1 -triple x86_64-apple-macos11 \
66
// RUN: -fcas-path %t/cas -fcas-fs @%t/casid -fcache-compile-job \
7-
// RUN: -Rcompile-job-cache %t/main.c -emit-obj -o %t/output.o \
7+
// RUN: -Rcompile-job-cache %t/main.c -emit-obj -o %t/output.o -isystem %t/sys \
88
// RUN: -dependency-file %t/deps1.d -MT depends 2>&1 \
99
// RUN: | FileCheck %s --allow-empty --check-prefix=CACHE-MISS
1010
//
1111
// RUN: FileCheck %s --input-file=%t/deps1.d --check-prefix=DEPS
1212
// DEPS: depends:
1313
// DEPS: main.c
1414
// DEPS: my_header.h
15+
// DEPS-NOT: sys.h
1516

1617
// RUN: ls %t/output.o && rm %t/output.o
1718
//
1819
// RUN: %clang -cc1 -triple x86_64-apple-macos11 \
1920
// RUN: -fcas-path %t/cas -fcas-fs @%t/casid -fcache-compile-job \
20-
// RUN: -Rcompile-job-cache %t/main.c -emit-obj -o %t/output.o \
21+
// RUN: -Rcompile-job-cache %t/main.c -emit-obj -o %t/output.o -isystem %t/sys \
2122
// RUN: -dependency-file %t/deps2.d -MT depends 2>&1 \
2223
// RUN: | FileCheck %s --check-prefix=CACHE-HIT
2324
//
@@ -27,7 +28,38 @@
2728
// CACHE-HIT: remark: compile job cache hit
2829
// CACHE-MISS-NOT: remark: compile job cache hit
2930

31+
// RUN: %clang -cc1 -triple x86_64-apple-macos11 \
32+
// RUN: -fcas-path %t/cas -fcas-fs @%t/casid -fcache-compile-job \
33+
// RUN: -Rcompile-job-cache %t/main.c -emit-obj -o %t/output.o -isystem %t/sys \
34+
// RUN: -dependency-file %t/deps3.d -MT other1 -MT other2 -MP 2>&1 \
35+
// RUN: | FileCheck %s --check-prefix=CACHE-HIT
36+
37+
// RUN: FileCheck %s --input-file=%t/deps3.d --check-prefix=DEPS_OTHER
38+
// DEPS_OTHER: other1 other2:
39+
// DEPS_OTHER: main.c
40+
// DEPS_OTHER: my_header.h
41+
// DEPS_OTHER-NOT: sys.h
42+
// DEPS_OTHER: my_header.h:
43+
44+
// RUN: %clang -cc1 -triple x86_64-apple-macos11 \
45+
// RUN: -fcas-path %t/cas -fcas-fs @%t/casid -fcache-compile-job \
46+
// RUN: -Rcompile-job-cache %t/main.c -emit-obj -o %t/output.o -isystem %t/sys \
47+
// RUN: -sys-header-deps -dependency-file %t/deps4.d -MT depends 2>&1 \
48+
// RUN: | FileCheck %s --check-prefix=CACHE-MISS
49+
50+
// Note: currently options that affect the list of deps (like sys-header-deps)
51+
// are part of the cache key, to avoid saving unnecessary paths.
52+
53+
// RUN: FileCheck %s --input-file=%t/deps4.d --check-prefix=DEPS_SYS
54+
// DEPS_SYS: depends:
55+
// DEPS_SYS: main.c
56+
// DEPS_SYS: my_header.h
57+
// DEPS_SYS: sys.h
58+
3059
//--- main.c
3160
#include "my_header.h"
61+
#include <sys.h>
3262

3363
//--- my_header.h
64+
65+
//--- sys/sys.h

clang/tools/driver/cc1_main.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "clang/Config/config.h"
2121
#include "clang/Driver/DriverDiagnostic.h"
2222
#include "clang/Driver/Options.h"
23+
#include "clang/Frontend/CASDependencyCollector.h"
2324
#include "clang/Frontend/ChainedDiagnosticConsumer.h"
2425
#include "clang/Frontend/CompileJobCacheKey.h"
2526
#include "clang/Frontend/CompilerInstance.h"
@@ -470,6 +471,7 @@ Optional<int> CompileJobCache::tryReplayCachedResult(CompilerInstance &Clang) {
470471

471472
// Set up the output backend so we can save / cache the result after.
472473
CASOutputs = llvm::makeIntrusiveRefCnt<llvm::cas::CASOutputBackend>(*CAS);
474+
Clang.setCASOutputBackend(CASOutputs);
473475
for (OutputKind K : getAllOutputKinds()) {
474476
StringRef OutPath = getPathForOutputKind(K);
475477
if (!OutPath.empty())
@@ -682,6 +684,7 @@ Optional<int> CompileJobCache::replayCachedResult(CompilerInstance &Clang,
682684

683685
for (size_t I = 0, E = Outputs->getNumReferences(); I + 1 < E; I += 2) {
684686
llvm::cas::CASID PathID = Outputs->getReferenceID(I);
687+
cas::ObjectRef BytesRef = Outputs->getReference(I + 1);
685688
llvm::cas::CASID BytesID = Outputs->getReferenceID(I + 1);
686689

687690
Optional<llvm::cas::ObjectProxy> PathProxy;
@@ -727,6 +730,12 @@ Optional<int> CompileJobCache::replayCachedResult(CompilerInstance &Clang,
727730
Contents = ContentsStorage;
728731
} else if (JustComputedResult) {
729732
continue;
733+
} else if (OutKind == OutputKind::Dependencies) {
734+
llvm::raw_svector_ostream OS(ContentsStorage);
735+
if (auto E = CASDependencyCollector::replay(
736+
Clang.getDependencyOutputOpts(), *CAS, BytesRef, OS))
737+
llvm::report_fatal_error(std::move(E));
738+
Contents = ContentsStorage;
730739
} else {
731740
Optional<llvm::cas::ObjectProxy> Bytes;
732741
if (Error E = CAS->getProxy(BytesID).moveInto(Bytes))

llvm/include/llvm/CAS/CASOutputBackend.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ class CASOutputBackend : public vfs::OutputBackend {
3636
/// the \p Kind string instead of its path.
3737
void addKindMap(StringRef Kind, StringRef Path);
3838

39+
CASDB &getCAS() const { return CAS; }
40+
3941
private:
4042
Expected<std::unique_ptr<vfs::OutputFileImpl>>
4143
createFileImpl(StringRef Path, Optional<vfs::OutputConfig> Config) override;

0 commit comments

Comments
 (0)