diff --git a/clang/include/clang/Lex/HeaderSearch.h b/clang/include/clang/Lex/HeaderSearch.h --- a/clang/include/clang/Lex/HeaderSearch.h +++ b/clang/include/clang/Lex/HeaderSearch.h @@ -21,12 +21,13 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringMap.h" -#include "llvm/ADT/StringSet.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSet.h" #include "llvm/Support/Allocator.h" #include #include #include +#include #include #include #include @@ -290,6 +291,15 @@ SystemDirIdx++; } + /// Return indices of used search paths. + std::set GetUsedSearchPathIdxs() const { + std::set UsedSearchPathIdxs; + for (const auto &Entry : LookupFileCache) + if (Entry.second.HitIdx < SearchDirs.size()) + UsedSearchPathIdxs.insert(Entry.second.HitIdx); + return UsedSearchPathIdxs; + } + /// Set the list of system header prefixes. void SetSystemHeaderPrefixes(ArrayRef> P) { SystemHeaderPrefixes.assign(P.begin(), P.end()); diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -402,6 +402,10 @@ /// Record code for \#pragma diagnostic mappings. DIAG_PRAGMA_MAPPINGS, + + /// Record code for indices of header search paths that were actually used + /// when building the module. + USED_HEADER_SEARCH_PATHS, }; /// Record code for extension blocks. diff --git a/clang/include/clang/Serialization/ModuleFile.h b/clang/include/clang/Serialization/ModuleFile.h --- a/clang/include/clang/Serialization/ModuleFile.h +++ b/clang/include/clang/Serialization/ModuleFile.h @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -173,6 +174,10 @@ /// unique module files based on AST contents. ASTFileSignature ASTBlockHash; + /// The indices of header search paths that were actually used when building + /// the module file. + std::set UsedHeaderSearchPathIdxs; + /// Whether this module has been directly imported by the /// user. bool DirectlyImported = false; diff --git a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h --- a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h +++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h @@ -48,7 +48,8 @@ public: DependencyScanningService(ScanningMode Mode, ScanningOutputFormat Format, bool ReuseFileManager = true, - bool SkipExcludedPPRanges = true); + bool SkipExcludedPPRanges = true, + bool OptimizeArgs = false); ScanningMode getMode() const { return Mode; } @@ -58,6 +59,8 @@ bool canSkipExcludedPPRanges() const { return SkipExcludedPPRanges; } + bool canOptimizeArgs() const { return OptimizeArgs; } + DependencyScanningFilesystemSharedCache &getSharedCache() { return SharedCache; } @@ -70,6 +73,7 @@ /// ranges by bumping the buffer pointer in the lexer instead of lexing the /// tokens in the range until reaching the corresponding directive. const bool SkipExcludedPPRanges; + const bool OptimizeArgs; /// The global file system cache. DependencyScanningFilesystemSharedCache SharedCache; }; diff --git a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h --- a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h +++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h @@ -77,6 +77,7 @@ /// worker. If null, the file manager will not be reused. llvm::IntrusiveRefCntPtr Files; ScanningOutputFormat Format; + bool OptimizeArgs; }; } // end namespace dependencies diff --git a/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h b/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h --- a/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h +++ b/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h @@ -20,6 +20,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringSet.h" #include "llvm/Support/raw_ostream.h" +#include #include #include @@ -158,7 +159,8 @@ class ModuleDepCollector final : public DependencyCollector { public: ModuleDepCollector(std::unique_ptr Opts, - CompilerInstance &I, DependencyConsumer &C); + CompilerInstance &I, DependencyConsumer &C, + bool OptimizeArgs); void attachToPreprocessor(Preprocessor &PP) override; void attachToASTReader(ASTReader &R) override; @@ -170,6 +172,8 @@ CompilerInstance &Instance; /// The consumer of collected dependency information. DependencyConsumer &Consumer; + /// Whether to optimize the modules' command-line arguments. + bool OptimizeArgs; /// Path to the main source file. std::string MainFile; /// Hash identifying the compilation conditions of the current TU. diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -4795,6 +4795,14 @@ F->PragmaDiagMappings.insert(F->PragmaDiagMappings.end(), Record.begin(), Record.end()); break; + case USED_HEADER_SEARCH_PATHS: + if (F) { + unsigned Idx = 0; + unsigned Count = Record[Idx++]; + for (unsigned I = 0; I < Count; ++I) + F->UsedHeaderSearchPathIdxs.insert(Record[Idx++]); + } + break; } } } diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -1097,6 +1097,16 @@ // Write out the diagnostic/pragma mappings. WritePragmaDiagnosticMappings(Diags, /* isModule = */ WritingModule); + Record.clear(); + + // Used search path indices. + auto UsedSearchPathIdxs = PP.getHeaderSearchInfo().GetUsedSearchPathIdxs(); + Record.push_back(UsedSearchPathIdxs.size()); + for (unsigned Idx : UsedSearchPathIdxs) + Record.push_back(Idx); + + Stream.EmitRecord(USED_HEADER_SEARCH_PATHS, Record); + // Leave the options block. Stream.ExitBlock(); return Signature; diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp @@ -14,6 +14,6 @@ DependencyScanningService::DependencyScanningService( ScanningMode Mode, ScanningOutputFormat Format, bool ReuseFileManager, - bool SkipExcludedPPRanges) + bool SkipExcludedPPRanges, bool OptimizeArgs) : Mode(Mode), Format(Format), ReuseFileManager(ReuseFileManager), - SkipExcludedPPRanges(SkipExcludedPPRanges) {} + SkipExcludedPPRanges(SkipExcludedPPRanges), OptimizeArgs(OptimizeArgs) {} diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp @@ -52,10 +52,10 @@ StringRef WorkingDirectory, DependencyConsumer &Consumer, llvm::IntrusiveRefCntPtr DepFS, ExcludedPreprocessorDirectiveSkipMapping *PPSkipMappings, - ScanningOutputFormat Format) + ScanningOutputFormat Format, bool OptimizeArgs) : WorkingDirectory(WorkingDirectory), Consumer(Consumer), - DepFS(std::move(DepFS)), PPSkipMappings(PPSkipMappings), - Format(Format) {} + DepFS(std::move(DepFS)), PPSkipMappings(PPSkipMappings), Format(Format), + OptimizeArgs(OptimizeArgs) {} bool runInvocation(std::shared_ptr Invocation, FileManager *FileMgr, @@ -121,7 +121,7 @@ break; case ScanningOutputFormat::Full: Compiler.addDependencyCollector(std::make_shared( - std::move(Opts), Compiler, Consumer)); + std::move(Opts), Compiler, Consumer, OptimizeArgs)); break; } @@ -145,13 +145,14 @@ llvm::IntrusiveRefCntPtr DepFS; ExcludedPreprocessorDirectiveSkipMapping *PPSkipMappings; ScanningOutputFormat Format; + bool OptimizeArgs; }; } // end anonymous namespace DependencyScanningWorker::DependencyScanningWorker( DependencyScanningService &Service) - : Format(Service.getFormat()) { + : Format(Service.getFormat()), OptimizeArgs(Service.canOptimizeArgs()) { DiagOpts = new DiagnosticOptions(); PCHContainerOps = std::make_shared(); RealFS = llvm::vfs::createPhysicalFileSystem(); @@ -194,7 +195,7 @@ Tool.setPrintErrorMessage(false); Tool.setDiagnosticConsumer(&DC); DependencyScanningAction Action(WorkingDirectory, Consumer, DepFS, - PPSkipMappings.get(), Format); + PPSkipMappings.get(), Format, OptimizeArgs); return !Tool.run(&Action); }); } diff --git a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp --- a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp +++ b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp @@ -18,9 +18,19 @@ using namespace tooling; using namespace dependencies; -static CompilerInvocation -makeInvocationForModuleBuildWithoutPaths(const ModuleDeps &Deps, - const CompilerInvocation &Invocation) { +static void optimizeHeaderSearchOpts(HeaderSearchOptions &Opts, + const std::set &UsedEntryIdxs) { + std::vector &Entries = Opts.UserEntries; + std::vector OrigEntries(Entries); + + Entries.clear(); + for (unsigned Idx : UsedEntryIdxs) + Entries.push_back(OrigEntries[Idx]); +} + +static CompilerInvocation makeInvocationForModuleBuildWithoutPaths( + const ModuleDeps &Deps, const CompilerInvocation &Invocation, + llvm::function_ref Optimize) { // Make a deep copy of the invocation. CompilerInvocation CI(Invocation); @@ -35,6 +45,8 @@ CI.getLangOpts()->ImplicitModules = false; CI.getHeaderSearchOpts().ImplicitModuleMaps = false; + Optimize(CI); + return CI; } @@ -189,8 +201,12 @@ MD.FileDeps.insert(IF.getFile()->getName()); }); - MD.Invocation = - makeInvocationForModuleBuildWithoutPaths(MD, Instance.getInvocation()); + MD.Invocation = makeInvocationForModuleBuildWithoutPaths( + MD, Instance.getInvocation(), [&](CompilerInvocation &CI) { + if (MDC.OptimizeArgs) + optimizeHeaderSearchOpts(CI.getHeaderSearchOpts(), + MF->UsedHeaderSearchPathIdxs); + }); MD.ID.ContextHash = MD.Invocation.getModuleHash(); llvm::DenseSet AddedModules; @@ -222,8 +238,9 @@ ModuleDepCollector::ModuleDepCollector( std::unique_ptr Opts, CompilerInstance &I, - DependencyConsumer &C) - : Instance(I), Consumer(C), Opts(std::move(Opts)) {} + DependencyConsumer &C, bool OptimizeArgs) + : Instance(I), Consumer(C), OptimizeArgs(OptimizeArgs), + Opts(std::move(Opts)) {} void ModuleDepCollector::attachToPreprocessor(Preprocessor &PP) { PP.addPPCallbacks(std::make_unique(Instance, *this)); diff --git a/clang/test/ClangScanDeps/Inputs/header-search-pruning/a/a.h b/clang/test/ClangScanDeps/Inputs/header-search-pruning/a/a.h new file mode 100644 diff --git a/clang/test/ClangScanDeps/Inputs/header-search-pruning/b/b.h b/clang/test/ClangScanDeps/Inputs/header-search-pruning/b/b.h new file mode 100644 diff --git a/clang/test/ClangScanDeps/Inputs/header-search-pruning/cdb.json b/clang/test/ClangScanDeps/Inputs/header-search-pruning/cdb.json new file mode 100644 --- /dev/null +++ b/clang/test/ClangScanDeps/Inputs/header-search-pruning/cdb.json @@ -0,0 +1,7 @@ +[ + { + "directory": "DIR", + "command": "clang -E DIR/header-search-pruning.cpp -Ia -Ib DEFINES -fmodules -fcxx-modules -fmodules-cache-path=DIR/module-cache -fimplicit-modules -fmodule-map-file=DIR/module.modulemap", + "file": "DIR/header-search-pruning.cpp" + } +] diff --git a/clang/test/ClangScanDeps/Inputs/header-search-pruning/mod.h b/clang/test/ClangScanDeps/Inputs/header-search-pruning/mod.h new file mode 100644 --- /dev/null +++ b/clang/test/ClangScanDeps/Inputs/header-search-pruning/mod.h @@ -0,0 +1,7 @@ +#ifdef INCLUDE_A +#include "a.h" +#endif + +#ifdef INCLUDE_B +#include "b.h" +#endif diff --git a/clang/test/ClangScanDeps/Inputs/header-search-pruning/module.modulemap b/clang/test/ClangScanDeps/Inputs/header-search-pruning/module.modulemap new file mode 100644 --- /dev/null +++ b/clang/test/ClangScanDeps/Inputs/header-search-pruning/module.modulemap @@ -0,0 +1,4 @@ +module mod { + header "mod.h" + export * +} diff --git a/clang/test/ClangScanDeps/header-search-pruning.cpp b/clang/test/ClangScanDeps/header-search-pruning.cpp new file mode 100644 --- /dev/null +++ b/clang/test/ClangScanDeps/header-search-pruning.cpp @@ -0,0 +1,87 @@ +// RUN: rm -rf %t && mkdir -p %t +// RUN: cp -r %S/Inputs/header-search-pruning/* %t +// RUN: cp %S/header-search-pruning.cpp %t/header-search-pruning.cpp +// RUN: sed -e "s|DIR|%t|g" -e "s|DEFINES|-DINCLUDE_A|g" %S/Inputs/header-search-pruning/cdb.json > %t/cdb_a.json +// RUN: sed -e "s|DIR|%t|g" -e "s|DEFINES|-DINCLUDE_B|g" %S/Inputs/header-search-pruning/cdb.json > %t/cdb_b.json +// RUN: sed -e "s|DIR|%t|g" -e "s|DEFINES|-DINCLUDE_A -DINCLUDE_B|g" %S/Inputs/header-search-pruning/cdb.json > %t/cdb_ab.json +// +// RUN: clang-scan-deps -compilation-database %t/cdb_a.json -format experimental-full -optimize-args >> %t/result_a.json +// RUN: cat %t/result_a.json | sed 's/\\/\//g' | FileCheck --check-prefixes=CHECK_A %s +// +// RUN: clang-scan-deps -compilation-database %t/cdb_b.json -format experimental-full -optimize-args >> %t/result_b.json +// RUN: cat %t/result_b.json | sed 's/\\/\//g' | FileCheck --check-prefixes=CHECK_B %s +// +// RUN: clang-scan-deps -compilation-database %t/cdb_ab.json -format experimental-full -optimize-args >> %t/result_ab.json +// RUN: cat %t/result_ab.json | sed 's/\\/\//g' | FileCheck --check-prefixes=CHECK_AB %s + +#include "mod.h" + +// CHECK_A: { +// CHECK_A-NEXT: "modules": [ +// CHECK_A-NEXT: { +// CHECK_A-NEXT: "clang-module-deps": [], +// CHECK_A-NEXT: "clang-modulemap-file": "{{.*}}", +// CHECK_A-NEXT: "command-line": [ +// CHECK_A-NEXT: "-cc1" +// CHECK_A: "-I" +// CHECK_A: "a" +// CHECK_A-NOT: "-I" +// CHECK_A-NOT: "b" +// CHECK_A: ], +// CHECK_A-NEXT: "context-hash": "[[HASH:.*]]", +// CHECK_A-NEXT: "file-deps": [ +// CHECK_A-NEXT: "[[PREFIX:.*]]/a/a.h", +// CHECK_A-NEXT: "[[PREFIX]]/mod.h", +// CHECK_A-NEXT: "[[PREFIX]]/module.modulemap" +// CHECK_A-NEXT: ], +// CHECK_A-NEXT: "name": "mod" +// CHECK_A-NEXT: } +// CHECK_A-NEXT: ] +// CHECK_A: } + +// CHECK_B: { +// CHECK_B-NEXT: "modules": [ +// CHECK_B-NEXT: { +// CHECK_B-NEXT: "clang-module-deps": [], +// CHECK_B-NEXT: "clang-modulemap-file": "{{.*}}", +// CHECK_B-NEXT: "command-line": [ +// CHECK_B-NEXT: "-cc1" +// CHECK_B-NOT: "-I" +// CHECK_B-NOT: "a" +// CHECK_B: "-I" +// CHECK_B: "b" +// CHECK_B: ], +// CHECK_B-NEXT: "context-hash": "[[HASH:.*]]", +// CHECK_B-NEXT: "file-deps": [ +// CHECK_B-NEXT: "[[PREFIX:.*]]/b/b.h", +// CHECK_B-NEXT: "[[PREFIX]]/mod.h", +// CHECK_B-NEXT: "[[PREFIX]]/module.modulemap" +// CHECK_B-NEXT: ], +// CHECK_B-NEXT: "name": "mod" +// CHECK_B-NEXT: } +// CHECK_B-NEXT: ] +// CHECK_B: } + +// CHECK_AB: { +// CHECK_AB-NEXT: "modules": [ +// CHECK_AB-NEXT: { +// CHECK_AB-NEXT: "clang-module-deps": [], +// CHECK_AB-NEXT: "clang-modulemap-file": "{{.*}}", +// CHECK_AB-NEXT: "command-line": [ +// CHECK_AB-NEXT: "-cc1" +// CHECK_AB: "-I" +// CHECK_AB: "a" +// CHECK_AB: "-I" +// CHECK_AB: "b" +// CHECK_AB: ], +// CHECK_AB-NEXT: "context-hash": "[[HASH:.*]]", +// CHECK_AB-NEXT: "file-deps": [ +// CHECK_AB-NEXT: "[[PREFIX:.*]]/a/a.h", +// CHECK_AB-NEXT: "[[PREFIX:.*]]/b/b.h", +// CHECK_AB-NEXT: "[[PREFIX]]/mod.h", +// CHECK_AB-NEXT: "[[PREFIX]]/module.modulemap" +// CHECK_AB-NEXT: ], +// CHECK_AB-NEXT: "name": "mod" +// CHECK_AB-NEXT: } +// CHECK_AB-NEXT: ] +// CHECK_AB: } diff --git a/clang/test/ClangScanDeps/modules-full.cpp b/clang/test/ClangScanDeps/modules-full.cpp --- a/clang/test/ClangScanDeps/modules-full.cpp +++ b/clang/test/ClangScanDeps/modules-full.cpp @@ -96,7 +96,7 @@ // CHECK-NEXT: ], // CHECK-NEXT: "translation-units": [ // CHECK-NEXT: { -// CHECK-NEXT: "clang-context-hash": "[[CONTEXT_HASH_H2]]", +// CHECK-NEXT: "clang-context-hash": "[[CONTEXT_HASH_H3:[A-Z0-9]+]]", // CHECK-NEXT: "clang-module-deps": [ // CHECK-NEXT: { // CHECK-NEXT: "context-hash": "[[CONTEXT_HASH_H2]]", @@ -117,7 +117,7 @@ // CHECK-NEXT: "input-file": "[[PREFIX]]/modules_cdb_input.cpp" // CHECK-NEXT: }, // CHECK-NEXT: { -// CHECK-NEXT: "clang-context-hash": "[[CONTEXT_HASH_H2]]", +// CHECK-NEXT: "clang-context-hash": "[[CONTEXT_HASH_H3]]", // CHECK-NEXT: "clang-module-deps": [ // CHECK-NEXT: { // CHECK-NEXT: "context-hash": "[[CONTEXT_HASH_H2]]", @@ -138,7 +138,7 @@ // CHECK-NEXT: "input-file": "[[PREFIX]]/modules_cdb_input.cpp" // CHECK-NEXT: }, // CHECK-NEXT: { -// CHECK-NEXT: "clang-context-hash": "[[CONTEXT_HASH_H2]]", +// CHECK-NEXT: "clang-context-hash": "[[CONTEXT_HASH_H3]]", // CHECK-NEXT: "clang-module-deps": [ // CHECK-NEXT: { // CHECK-NEXT: "context-hash": "[[CONTEXT_HASH_H2]]", @@ -159,7 +159,7 @@ // CHECK-NEXT: "input-file": "[[PREFIX]]/modules_cdb_input.cpp" // CHECK-NEXT: }, // CHECK-NEXT: { -// CHECK-NEXT: "clang-context-hash": "[[CONTEXT_HASH_H1]]", +// CHECK-NEXT: "clang-context-hash": "[[CONTEXT_HASH_H4:[A-Z0-9]+]]", // CHECK-NEXT: "clang-module-deps": [ // CHECK-NEXT: { // CHECK-NEXT: "context-hash": "[[CONTEXT_HASH_H1]]", diff --git a/clang/tools/clang-scan-deps/ClangScanDeps.cpp b/clang/tools/clang-scan-deps/ClangScanDeps.cpp --- a/clang/tools/clang-scan-deps/ClangScanDeps.cpp +++ b/clang/tools/clang-scan-deps/ClangScanDeps.cpp @@ -163,6 +163,11 @@ "'-fmodule-file=', '-o', '-fmodule-map-file='."), llvm::cl::init(false), llvm::cl::cat(DependencyScannerCategory)); +static llvm::cl::opt OptimizeArgs( + "optimize-args", + llvm::cl::desc("Whether to optimize command-line arguments of modules."), + llvm::cl::init(false), llvm::cl::cat(DependencyScannerCategory)); + llvm::cl::opt NumThreads("j", llvm::cl::Optional, llvm::cl::desc("Number of worker threads to use (default: use " @@ -357,7 +362,26 @@ private: StringRef lookupPCMPath(ModuleID MID) { - return Modules[IndexedModuleID{MID, 0}].ImplicitModulePCMPath; + auto PCMPath = PCMPaths.insert({IndexedModuleID{MID, 0}, ""}); + if (PCMPath.second) + PCMPath.first->second = constructPCMPath(lookupModuleDeps(MID)); + return PCMPath.first->second; + } + + /// Construct a path where to put the explicitly built PCM - essentially the + /// path to implicitly built PCM with the context hash replaced by the final + /// (potentially modified) context hash. + std::string constructPCMPath(const ModuleDeps &MD) const { + const std::string &ImplicitPCMPath = MD.ImplicitModulePCMPath; + StringRef Filename = llvm::sys::path::filename(ImplicitPCMPath); + StringRef ImplicitContextHashPath = + llvm::sys::path::parent_path(ImplicitPCMPath); + StringRef ModuleCachePath = + llvm::sys::path::parent_path(ImplicitContextHashPath); + + SmallString<64> ExplicitPCMPath = ModuleCachePath; + llvm::sys::path::append(ExplicitPCMPath, MD.ID.ContextHash, Filename); + return std::string(ExplicitPCMPath); } const ModuleDeps &lookupModuleDeps(ModuleID MID) { @@ -395,6 +419,8 @@ std::mutex Lock; std::unordered_map Modules; + std::unordered_map + PCMPaths; std::vector Inputs; }; @@ -554,7 +580,7 @@ SharedStream DependencyOS(llvm::outs()); DependencyScanningService Service(ScanMode, Format, ReuseFileManager, - SkipExcludedPPRanges); + SkipExcludedPPRanges, OptimizeArgs); llvm::ThreadPool Pool(llvm::hardware_concurrency(NumThreads)); std::vector> WorkerTools; for (unsigned I = 0; I < Pool.getThreadCount(); ++I)