Skip to content

Commit cbab7a3

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. (cherry picked from commit 5e98b81)
1 parent 5f32a10 commit cbab7a3

File tree

10 files changed

+204
-9
lines changed

10 files changed

+204
-9
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

@@ -429,14 +434,20 @@ class CompilerInstance : public ModuleLoader {
429434
/// Set the output manager.
430435
void setOutputBackend(IntrusiveRefCntPtr<llvm::vfs::OutputBackend> NewOutputs);
431436

437+
void setCASOutputBackend(
438+
clang::IntrusiveRefCntPtr<llvm::cas::CASOutputBackend> NewOutputs);
439+
432440
/// Create an output manager.
433441
void createOutputBackend();
434442

435443
bool hasOutputBackend() const { return bool(TheOutputBackend); }
444+
bool hasCASOutputBackend() const { return bool(CASOutputBackend); }
436445

437446
llvm::vfs::OutputBackend &getOutputBackend();
438447
llvm::vfs::OutputBackend &getOrCreateOutputBackend();
439448

449+
llvm::cas::CASOutputBackend &getCASOutputBackend();
450+
440451
/// Get the CAS, or create it using the configuration in CompilerInvocation.
441452
llvm::cas::CASDB &getOrCreateCAS();
442453

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
@@ -20,6 +20,7 @@
2020
#include "clang/Basic/TargetInfo.h"
2121
#include "clang/Basic/Version.h"
2222
#include "clang/Config/config.h"
23+
#include "clang/Frontend/CASDependencyCollector.h"
2324
#include "clang/Frontend/ChainedDiagnosticConsumer.h"
2425
#include "clang/Frontend/FrontendAction.h"
2526
#include "clang/Frontend/FrontendActions.h"
@@ -499,9 +500,13 @@ void CompilerInstance::createPreprocessor(TranslationUnitKind TUKind) {
499500

500501
// Handle generating dependencies, if requested.
501502
const DependencyOutputOptions &DepOpts = getDependencyOutputOpts();
502-
if (!DepOpts.OutputFile.empty())
503+
if (!DepOpts.OutputFile.empty()) {
504+
if (hasCASOutputBackend())
505+
addDependencyCollector(
506+
std::make_shared<CASDependencyCollector>(DepOpts, CASOutputBackend));
503507
addDependencyCollector(
504508
std::make_shared<DependencyFileGenerator>(DepOpts, TheOutputBackend));
509+
}
505510
if (!DepOpts.DOTOutputFile.empty())
506511
AttachDependencyGraphGen(*PP, DepOpts.DOTOutputFile,
507512
getHeaderSearchOpts().Sysroot);
@@ -840,6 +845,11 @@ void CompilerInstance::setOutputBackend(
840845
assert(!TheOutputBackend && "Already has an output manager");
841846
TheOutputBackend = std::move(NewOutputs);
842847
}
848+
void CompilerInstance::setCASOutputBackend(
849+
clang::IntrusiveRefCntPtr<llvm::cas::CASOutputBackend> NewOutputs) {
850+
assert(!CASOutputBackend && "Already has a CAS output backend");
851+
CASOutputBackend = std::move(NewOutputs);
852+
}
843853

844854
void CompilerInstance::createOutputBackend() {
845855
assert(!TheOutputBackend && "Already has an output manager");
@@ -857,6 +867,11 @@ llvm::vfs::OutputBackend &CompilerInstance::getOrCreateOutputBackend() {
857867
return getOutputBackend();
858868
}
859869

870+
llvm::cas::CASOutputBackend &CompilerInstance::getCASOutputBackend() {
871+
assert(CASOutputBackend);
872+
return *CASOutputBackend;
873+
}
874+
860875
llvm::cas::CASDB &CompilerInstance::getOrCreateCAS() {
861876
if (CAS)
862877
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: 16 additions & 4 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"
@@ -450,6 +451,7 @@ Optional<int> CompileJobCache::tryReplayCachedResult(CompilerInstance &Clang) {
450451

451452
// Set up the output backend so we can save / cache the result after.
452453
CASOutputs = llvm::makeIntrusiveRefCnt<llvm::cas::CASOutputBackend>(*CAS);
454+
Clang.setCASOutputBackend(CASOutputs);
453455
for (OutputKind K : getAllOutputKinds()) {
454456
StringRef OutPath = getPathForOutputKind(K);
455457
if (!OutPath.empty())
@@ -646,6 +648,7 @@ Optional<int> CompileJobCache::replayCachedResult(CompilerInstance &Clang,
646648

647649
for (size_t I = 0, E = Outputs->getNumReferences(); I + 1 < E; I += 2) {
648650
llvm::cas::CASID PathID = Outputs->getReferenceID(I);
651+
cas::ObjectRef BytesRef = Outputs->getReference(I + 1);
649652
llvm::cas::CASID BytesID = Outputs->getReferenceID(I + 1);
650653

651654
Optional<llvm::cas::ObjectProxy> PathProxy;
@@ -663,10 +666,19 @@ Optional<int> CompileJobCache::replayCachedResult(CompilerInstance &Clang,
663666

664667
Optional<StringRef> Contents;
665668
SmallString<50> ContentsStorage;
666-
Optional<llvm::cas::ObjectProxy> Bytes;
667-
if (Error E = CAS->getProxy(BytesID).moveInto(Bytes))
668-
llvm::report_fatal_error(std::move(E));
669-
Contents = Bytes->getData();
669+
if (OutKind == OutputKind::Dependencies) {
670+
llvm::raw_svector_ostream OS(ContentsStorage);
671+
if (auto E = CASDependencyCollector::replay(
672+
Clang.getDependencyOutputOpts(), *CAS, BytesRef, OS))
673+
llvm::report_fatal_error(std::move(E));
674+
Contents = ContentsStorage;
675+
} else {
676+
Optional<llvm::cas::ObjectProxy> Bytes;
677+
if (Error E = CAS->getProxy(BytesID).moveInto(Bytes))
678+
llvm::report_fatal_error(std::move(E));
679+
Contents = Bytes->getData();
680+
}
681+
670682
std::unique_ptr<llvm::FileOutputBuffer> Output;
671683
if (Error E = llvm::FileOutputBuffer::create(Path, Contents->size())
672684
.moveInto(Output))

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)