Skip to content

Commit 386d1b2

Browse files
committed
[clang][deps] Store common, partially-formed invocation (llvm#65677)
We create one `CompilerInvocation` for each modular dependency we discover. This means we create a lot of copies, even though most of the invocation is the same between modules. This patch makes use of the copy-on-write flavor of `CompilerInvocation` to share the common parts, reducing memory usage and speeding up the scan.
1 parent fda1104 commit 386d1b2

File tree

9 files changed

+145
-72
lines changed

9 files changed

+145
-72
lines changed

clang/include/clang/Frontend/CompileJobCacheKey.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ class raw_ostream;
2727
namespace clang {
2828

2929
class CompilerInvocation;
30+
class CowCompilerInvocation;
3031
class DiagnosticsEngine;
3132

3233
/// Caching-related options for a given \c CompilerInvocation that are
@@ -48,6 +49,9 @@ struct CompileJobCachingOptions {
4849
std::optional<llvm::cas::CASID>
4950
createCompileJobCacheKey(llvm::cas::ObjectStore &CAS, DiagnosticsEngine &Diags,
5051
const CompilerInvocation &Invocation);
52+
std::optional<llvm::cas::CASID>
53+
createCompileJobCacheKey(llvm::cas::ObjectStore &CAS, DiagnosticsEngine &Diags,
54+
const CowCompilerInvocation &Invocation);
5155

5256
/// Perform any destructive changes needed to canonicalize \p Invocation for
5357
/// caching, extracting the settings that affect compilation even if they do not

clang/include/clang/Frontend/CompilerInvocation.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,8 @@ class CompilerInvocationBase {
226226
}
227227
};
228228

229+
class CowCompilerInvocation;
230+
229231
/// Helper class for holding the data necessary to invoke the compiler.
230232
///
231233
/// This class is designed to represent an abstract "invocation" of the
@@ -245,6 +247,9 @@ class CompilerInvocation : public CompilerInvocationBase {
245247
}
246248
~CompilerInvocation() = default;
247249

250+
explicit CompilerInvocation(const CowCompilerInvocation &X);
251+
CompilerInvocation &operator=(const CowCompilerInvocation &X);
252+
248253
/// Const getters.
249254
/// @{
250255
// Note: These need to be pulled in manually. Otherwise, they get hidden by

clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ class DependencyActionController {
101101
return llvm::Error::success();
102102
}
103103

104-
virtual llvm::Error finalizeModuleInvocation(CompilerInvocation &CI,
104+
virtual llvm::Error finalizeModuleInvocation(CowCompilerInvocation &CI,
105105
const ModuleDeps &MD) {
106106
return llvm::Error::success();
107107
}

clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -253,8 +253,11 @@ class ModuleDepCollector final : public DependencyCollector {
253253
llvm::SetVector<const Module *> DirectModularDeps;
254254
/// Options that control the dependency output generation.
255255
std::unique_ptr<DependencyOutputOptions> Opts;
256-
/// The original Clang invocation passed to dependency scanner.
257-
CompilerInvocation OriginalInvocation;
256+
/// A Clang invocation that's based on the original TU invocation and that has
257+
/// been partially transformed into one that can perform explicit build of
258+
/// a discovered modular dependency. Note that this still needs to be adjusted
259+
/// for each individual module.
260+
CowCompilerInvocation CommonInvocation;
258261
/// Whether to optimize the modules' command-line arguments.
259262
bool OptimizeArgs;
260263
/// Whether to set up command-lines to load PCM files eagerly.
@@ -274,12 +277,11 @@ class ModuleDepCollector final : public DependencyCollector {
274277
/// Adds \p Path to \c MD.FileDeps, making it absolute if necessary.
275278
void addFileDep(ModuleDeps &MD, StringRef Path);
276279

277-
/// Constructs a CompilerInvocation that can be used to build the given
278-
/// module, excluding paths to discovered modular dependencies that are yet to
279-
/// be built.
280-
CompilerInvocation makeInvocationForModuleBuildWithoutOutputs(
280+
/// Get a Clang invocation adjusted to build the given modular dependency.
281+
/// This excludes paths that are yet-to-be-provided by the build system.
282+
CowCompilerInvocation getInvocationAdjustedForModuleBuildWithoutOutputs(
281283
const ModuleDeps &Deps,
282-
llvm::function_ref<void(CompilerInvocation &)> Optimize) const;
284+
llvm::function_ref<void(CowCompilerInvocation &)> Optimize) const;
283285

284286
/// Collect module map files for given modules.
285287
llvm::DenseSet<const FileEntry *>
@@ -291,13 +293,16 @@ class ModuleDepCollector final : public DependencyCollector {
291293
/// Add module files (pcm) to the invocation, if needed.
292294
void addModuleFiles(CompilerInvocation &CI,
293295
ArrayRef<ModuleID> ClangModuleDeps) const;
296+
void addModuleFiles(CowCompilerInvocation &CI,
297+
ArrayRef<ModuleID> ClangModuleDeps) const;
294298

295299
/// Add paths that require looking up outputs to the given dependencies.
296-
void addOutputPaths(CompilerInvocation &CI, ModuleDeps &Deps);
300+
void addOutputPaths(CowCompilerInvocation &CI, ModuleDeps &Deps);
297301

298302
/// Compute the context hash for \p Deps, and create the mapping
299303
/// \c ModuleDepsByID[Deps.ID] = &Deps.
300-
void associateWithContextHash(const CompilerInvocation &CI, ModuleDeps &Deps);
304+
void associateWithContextHash(const CowCompilerInvocation &CI,
305+
ModuleDeps &Deps);
301306
};
302307

303308
} // end namespace dependencies

clang/lib/Frontend/CompileJobCacheKey.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,9 +186,16 @@ std::optional<llvm::cas::CASID> clang::canonicalizeAndCreateCacheKey(
186186

187187
std::optional<llvm::cas::CASID>
188188
clang::createCompileJobCacheKey(ObjectStore &CAS, DiagnosticsEngine &Diags,
189-
const CompilerInvocation &OriginalInvocation) {
189+
const CompilerInvocation &OriginalCI) {
190+
CompilerInvocation CI(OriginalCI);
191+
(void)canonicalizeForCaching(CAS, Diags, CI);
192+
return createCompileJobCacheKeyImpl(CAS, Diags, std::move(CI));
193+
}
190194

191-
CompilerInvocation CI(OriginalInvocation);
195+
std::optional<llvm::cas::CASID>
196+
clang::createCompileJobCacheKey(ObjectStore &CAS, DiagnosticsEngine &Diags,
197+
const CowCompilerInvocation &OriginalCI) {
198+
CompilerInvocation CI(OriginalCI);
192199
(void)canonicalizeForCaching(CAS, Diags, CI);
193200
return createCompileJobCacheKeyImpl(CAS, Diags, std::move(CI));
194201
}

clang/lib/Frontend/CompilerInvocation.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,8 @@ CompilerInvocationBase::shallow_copy_assign(const CompilerInvocationBase &X) {
189189
PPOpts = X.PPOpts;
190190
AnalyzerOpts = X.AnalyzerOpts;
191191
MigratorOpts = X.MigratorOpts;
192+
APINotesOpts = X.APINotesOpts;
193+
CASOpts = X.CASOpts;
192194
CodeGenOpts = X.CodeGenOpts;
193195
FSOpts = X.FSOpts;
194196
FrontendOpts = X.FrontendOpts;
@@ -198,6 +200,17 @@ CompilerInvocationBase::shallow_copy_assign(const CompilerInvocationBase &X) {
198200
return *this;
199201
}
200202

203+
CompilerInvocation::CompilerInvocation(const CowCompilerInvocation &X)
204+
: CompilerInvocationBase(EmptyConstructor{}) {
205+
CompilerInvocationBase::deep_copy_assign(X);
206+
}
207+
208+
CompilerInvocation &
209+
CompilerInvocation::operator=(const CowCompilerInvocation &X) {
210+
CompilerInvocationBase::deep_copy_assign(X);
211+
return *this;
212+
}
213+
201214
namespace {
202215
template <typename T>
203216
T &ensureOwned(std::shared_ptr<T> &Storage) {

clang/lib/Tooling/DependencyScanning/CASFSActionController.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class CASFSActionController : public CallbackActionController {
3232
initializeModuleBuild(CompilerInstance &ModuleScanInstance) override;
3333
llvm::Error
3434
finalizeModuleBuild(CompilerInstance &ModuleScanInstance) override;
35-
llvm::Error finalizeModuleInvocation(CompilerInvocation &CI,
35+
llvm::Error finalizeModuleInvocation(CowCompilerInvocation &CI,
3636
const ModuleDeps &MD) override;
3737

3838
private:
@@ -178,8 +178,11 @@ Error CASFSActionController::finalizeModuleBuild(
178178
return Error::success();
179179
}
180180

181-
Error CASFSActionController::finalizeModuleInvocation(CompilerInvocation &CI,
182-
const ModuleDeps &MD) {
181+
Error CASFSActionController::finalizeModuleInvocation(
182+
CowCompilerInvocation &CowCI, const ModuleDeps &MD) {
183+
// TODO: Avoid this copy.
184+
CompilerInvocation CI(CowCI);
185+
183186
if (auto ID = MD.CASFileSystemRootID) {
184187
configureInvocationForCaching(CI, CASOpts, ID->toString(),
185188
CacheFS.getCurrentWorkingDirectory().get(),
@@ -189,6 +192,7 @@ Error CASFSActionController::finalizeModuleInvocation(CompilerInvocation &CI,
189192
if (Mapper)
190193
DepscanPrefixMapping::remapInvocationPaths(CI, *Mapper);
191194

195+
CowCI = CI;
192196
return llvm::Error::success();
193197
}
194198

clang/lib/Tooling/DependencyScanning/IncludeTreeActionController.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ class IncludeTreeActionController : public CallbackActionController {
4040

4141
Error initializeModuleBuild(CompilerInstance &ModuleScanInstance) override;
4242
Error finalizeModuleBuild(CompilerInstance &ModuleScanInstance) override;
43-
Error finalizeModuleInvocation(CompilerInvocation &CI,
43+
Error finalizeModuleInvocation(CowCompilerInvocation &CI,
4444
const ModuleDeps &MD) override;
4545

4646
private:
@@ -392,17 +392,22 @@ Error IncludeTreeActionController::finalizeModuleBuild(
392392
}
393393

394394
Error IncludeTreeActionController::finalizeModuleInvocation(
395-
CompilerInvocation &CI, const ModuleDeps &MD) {
395+
CowCompilerInvocation &CowCI, const ModuleDeps &MD) {
396396
if (!MD.IncludeTreeID)
397397
return llvm::createStringError(llvm::inconvertibleErrorCode(),
398398
"missing include-tree for module '%s'",
399399
MD.ID.ModuleName.c_str());
400400

401+
// TODO: Avoid this copy.
402+
CompilerInvocation CI(CowCI);
403+
401404
configureInvocationForCaching(CI, CASOpts, *MD.IncludeTreeID,
402405
/*CASFSWorkingDir=*/"",
403406
/*ProduceIncludeTree=*/true);
404407

405408
DepscanPrefixMapping::remapInvocationPaths(CI, PrefixMapper);
409+
410+
CowCI = CI;
406411
return Error::success();
407412
}
408413

0 commit comments

Comments
 (0)