[clang] [clang] Make the entire `CompilerInvocation` ref-counted (PR #65647)
Jan Svoboda via cfe-commits
cfe-commits at lists.llvm.org
Thu Sep 7 10:33:15 PDT 2023
https://github.com/jansvoboda11 created https://github.com/llvm/llvm-project/pull/65647:
This enables making the whole `CompilerInvocation` more efficient through copy-on-write.
>From 4a29ff15728ac3e93de26066274493c1fd6c50fa Mon Sep 17 00:00:00 2001
From: Jan Svoboda <jan_svoboda at apple.com>
Date: Thu, 7 Sep 2023 10:30:06 -0700
Subject: [PATCH] [clang] Make the entire `CompilerInvocation` ref-counted
This enables making the whole `CompilerInvocation` more efficient through copy-on-write.
---
.../clang/Frontend/CompilerInvocation.h | 150 ++++++++----------
clang/lib/Frontend/CompilerInvocation.cpp | 130 ++++++++-------
2 files changed, 133 insertions(+), 147 deletions(-)
diff --git a/clang/include/clang/Frontend/CompilerInvocation.h b/clang/include/clang/Frontend/CompilerInvocation.h
index 5dc55bb7abdbab..2dc73b85bd4afe 100644
--- a/clang/include/clang/Frontend/CompilerInvocation.h
+++ b/clang/include/clang/Frontend/CompilerInvocation.h
@@ -66,16 +66,12 @@ bool ParseDiagnosticArgs(DiagnosticOptions &Opts, llvm::opt::ArgList &Args,
DiagnosticsEngine *Diags = nullptr,
bool DefaultDiagColor = true);
-/// The base class of CompilerInvocation with reference semantics.
-///
-/// This class stores option objects behind reference-counted pointers. This is
-/// useful for clients that want to keep some option object around even after
-/// CompilerInvocation gets destroyed, without making a copy.
-///
-/// This is a separate class so that we can implement the copy constructor and
-/// assignment here and leave them defaulted in the rest of CompilerInvocation.
-class CompilerInvocationRefBase {
-public:
+/// The base class of CompilerInvocation. It keeps individual option objects
+/// behind reference-counted pointers, which is useful for clients that want to
+/// keep select option objects alive (even after CompilerInvocation gets
+/// destroyed) without making a copy.
+class CompilerInvocationBase {
+protected:
/// Options controlling the language variant.
std::shared_ptr<LangOptions> LangOpts;
@@ -86,103 +82,71 @@ class CompilerInvocationRefBase {
IntrusiveRefCntPtr<DiagnosticOptions> DiagnosticOpts;
/// Options controlling the \#include directive.
- std::shared_ptr<HeaderSearchOptions> HeaderSearchOpts;
+ std::shared_ptr<HeaderSearchOptions> HSOpts;
/// Options controlling the preprocessor (aside from \#include handling).
- std::shared_ptr<PreprocessorOptions> PreprocessorOpts;
+ std::shared_ptr<PreprocessorOptions> PPOpts;
/// Options controlling the static analyzer.
AnalyzerOptionsRef AnalyzerOpts;
- CompilerInvocationRefBase();
- CompilerInvocationRefBase(const CompilerInvocationRefBase &X);
- CompilerInvocationRefBase(CompilerInvocationRefBase &&X);
- CompilerInvocationRefBase &operator=(CompilerInvocationRefBase X);
- CompilerInvocationRefBase &operator=(CompilerInvocationRefBase &&X);
- ~CompilerInvocationRefBase();
-
- LangOptions &getLangOpts() { return *LangOpts; }
- const LangOptions &getLangOpts() const { return *LangOpts; }
-
- TargetOptions &getTargetOpts() { return *TargetOpts.get(); }
- const TargetOptions &getTargetOpts() const { return *TargetOpts.get(); }
-
- DiagnosticOptions &getDiagnosticOpts() const { return *DiagnosticOpts; }
-
- HeaderSearchOptions &getHeaderSearchOpts() { return *HeaderSearchOpts; }
-
- const HeaderSearchOptions &getHeaderSearchOpts() const {
- return *HeaderSearchOpts;
- }
-
- std::shared_ptr<HeaderSearchOptions> getHeaderSearchOptsPtr() const {
- return HeaderSearchOpts;
- }
-
- std::shared_ptr<PreprocessorOptions> getPreprocessorOptsPtr() {
- return PreprocessorOpts;
- }
-
- PreprocessorOptions &getPreprocessorOpts() { return *PreprocessorOpts; }
-
- const PreprocessorOptions &getPreprocessorOpts() const {
- return *PreprocessorOpts;
- }
-
- AnalyzerOptions &getAnalyzerOpts() { return *AnalyzerOpts; }
- const AnalyzerOptions &getAnalyzerOpts() const { return *AnalyzerOpts; }
-};
-
-/// The base class of CompilerInvocation with value semantics.
-class CompilerInvocationValueBase {
-protected:
- MigratorOptions MigratorOpts;
+ std::shared_ptr<MigratorOptions> MigratorOpts;
/// Options controlling IRgen and the backend.
- CodeGenOptions CodeGenOpts;
-
- /// Options controlling dependency output.
- DependencyOutputOptions DependencyOutputOpts;
+ std::shared_ptr<CodeGenOptions> CodeGenOpts;
/// Options controlling file system operations.
- FileSystemOptions FileSystemOpts;
+ std::shared_ptr<FileSystemOptions> FSOpts;
/// Options controlling the frontend itself.
- FrontendOptions FrontendOpts;
+ std::shared_ptr<FrontendOptions> FrontendOpts;
+
+ /// Options controlling dependency output.
+ std::shared_ptr<DependencyOutputOptions> DependencyOutputOpts;
/// Options controlling preprocessed output.
- PreprocessorOutputOptions PreprocessorOutputOpts;
+ std::shared_ptr<PreprocessorOutputOptions> PreprocessorOutputOpts;
public:
- MigratorOptions &getMigratorOpts() { return MigratorOpts; }
- const MigratorOptions &getMigratorOpts() const { return MigratorOpts; }
-
- CodeGenOptions &getCodeGenOpts() { return CodeGenOpts; }
- const CodeGenOptions &getCodeGenOpts() const { return CodeGenOpts; }
-
- DependencyOutputOptions &getDependencyOutputOpts() {
- return DependencyOutputOpts;
- }
+ CompilerInvocationBase();
+ CompilerInvocationBase(const CompilerInvocationBase &X) { operator=(X); }
+ CompilerInvocationBase(CompilerInvocationBase &&X) = default;
+ CompilerInvocationBase &operator=(const CompilerInvocationBase &X);
+ CompilerInvocationBase &operator=(CompilerInvocationBase &&X) = default;
+ ~CompilerInvocationBase() = default;
+ const LangOptions &getLangOpts() const { return *LangOpts; }
+ const TargetOptions &getTargetOpts() const { return *TargetOpts; }
+ const DiagnosticOptions &getDiagnosticOpts() const { return *DiagnosticOpts; }
+ const HeaderSearchOptions &getHeaderSearchOpts() const { return *HSOpts; }
+ const PreprocessorOptions &getPreprocessorOpts() const { return *PPOpts; }
+ const AnalyzerOptions &getAnalyzerOpts() const { return *AnalyzerOpts; }
+ const MigratorOptions &getMigratorOpts() const { return *MigratorOpts; }
+ const CodeGenOptions &getCodeGenOpts() const { return *CodeGenOpts; }
+ const FileSystemOptions &getFileSystemOpts() const { return *FSOpts; }
+ const FrontendOptions &getFrontendOpts() const { return *FrontendOpts; }
const DependencyOutputOptions &getDependencyOutputOpts() const {
- return DependencyOutputOpts;
+ return *DependencyOutputOpts;
}
-
- FileSystemOptions &getFileSystemOpts() { return FileSystemOpts; }
-
- const FileSystemOptions &getFileSystemOpts() const {
- return FileSystemOpts;
+ const PreprocessorOutputOptions &getPreprocessorOutputOpts() const {
+ return *PreprocessorOutputOpts;
}
- FrontendOptions &getFrontendOpts() { return FrontendOpts; }
- const FrontendOptions &getFrontendOpts() const { return FrontendOpts; }
-
- PreprocessorOutputOptions &getPreprocessorOutputOpts() {
- return PreprocessorOutputOpts;
+ LangOptions &getLangOpts() { return *LangOpts; }
+ TargetOptions &getTargetOpts() { return *TargetOpts; }
+ DiagnosticOptions &getDiagnosticOpts() { return *DiagnosticOpts; }
+ HeaderSearchOptions &getHeaderSearchOpts() { return *HSOpts; }
+ PreprocessorOptions &getPreprocessorOpts() { return *PPOpts; }
+ AnalyzerOptions &getAnalyzerOpts() { return *AnalyzerOpts; }
+ MigratorOptions &getMigratorOpts() { return *MigratorOpts; }
+ CodeGenOptions &getCodeGenOpts() { return *CodeGenOpts; }
+ FileSystemOptions &getFileSystemOpts() { return *FSOpts; }
+ FrontendOptions &getFrontendOpts() { return *FrontendOpts; }
+ DependencyOutputOptions &getDependencyOutputOpts() {
+ return *DependencyOutputOpts;
}
-
- const PreprocessorOutputOptions &getPreprocessorOutputOpts() const {
- return PreprocessorOutputOpts;
+ PreprocessorOutputOptions &getPreprocessorOutputOpts() {
+ return *PreprocessorOutputOpts;
}
};
@@ -191,9 +155,21 @@ class CompilerInvocationValueBase {
/// This class is designed to represent an abstract "invocation" of the
/// compiler, including data such as the include paths, the code generation
/// options, the warning flags, and so on.
-class CompilerInvocation : public CompilerInvocationRefBase,
- public CompilerInvocationValueBase {
+class CompilerInvocation : public CompilerInvocationBase {
public:
+ /// Base class internals.
+ /// @{
+ using CompilerInvocationBase::LangOpts;
+ using CompilerInvocationBase::TargetOpts;
+ using CompilerInvocationBase::DiagnosticOpts;
+ std::shared_ptr<HeaderSearchOptions> getHeaderSearchOptsPtr() {
+ return HSOpts;
+ }
+ std::shared_ptr<PreprocessorOptions> getPreprocessorOptsPtr() {
+ return PPOpts;
+ }
+ /// @}
+
/// Create a compiler invocation from a list of input options.
/// \returns true on success.
///
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 11ffb3d6630d1f..c0dab4e64ff192 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -126,40 +126,49 @@ static Expected<std::optional<uint32_t>> parseToleranceOption(StringRef Arg) {
// Initialization.
//===----------------------------------------------------------------------===//
-CompilerInvocationRefBase::CompilerInvocationRefBase()
- : LangOpts(new LangOptions()), TargetOpts(new TargetOptions()),
- DiagnosticOpts(new DiagnosticOptions()),
- HeaderSearchOpts(new HeaderSearchOptions()),
- PreprocessorOpts(new PreprocessorOptions()),
- AnalyzerOpts(new AnalyzerOptions()) {}
-
-CompilerInvocationRefBase::CompilerInvocationRefBase(
- const CompilerInvocationRefBase &X)
- : LangOpts(new LangOptions(X.getLangOpts())),
- TargetOpts(new TargetOptions(X.getTargetOpts())),
- DiagnosticOpts(new DiagnosticOptions(X.getDiagnosticOpts())),
- HeaderSearchOpts(new HeaderSearchOptions(X.getHeaderSearchOpts())),
- PreprocessorOpts(new PreprocessorOptions(X.getPreprocessorOpts())),
- AnalyzerOpts(new AnalyzerOptions(X.getAnalyzerOpts())) {}
-
-CompilerInvocationRefBase::CompilerInvocationRefBase(
- CompilerInvocationRefBase &&X) = default;
-
-CompilerInvocationRefBase &
-CompilerInvocationRefBase::operator=(CompilerInvocationRefBase X) {
- LangOpts.swap(X.LangOpts);
- TargetOpts.swap(X.TargetOpts);
- DiagnosticOpts.swap(X.DiagnosticOpts);
- HeaderSearchOpts.swap(X.HeaderSearchOpts);
- PreprocessorOpts.swap(X.PreprocessorOpts);
- AnalyzerOpts.swap(X.AnalyzerOpts);
- return *this;
+namespace {
+template <class T> std::shared_ptr<T> make_shared_copy(const T &X) {
+ return std::make_shared<T>(X);
}
-CompilerInvocationRefBase &
-CompilerInvocationRefBase::operator=(CompilerInvocationRefBase &&X) = default;
-
-CompilerInvocationRefBase::~CompilerInvocationRefBase() = default;
+template <class T>
+llvm::IntrusiveRefCntPtr<T> makeIntrusiveRefCntCopy(const T &X) {
+ return llvm::makeIntrusiveRefCnt<T>(X);
+}
+} // namespace
+
+CompilerInvocationBase::CompilerInvocationBase()
+ : LangOpts(std::make_shared<LangOptions>()),
+ TargetOpts(std::make_shared<TargetOptions>()),
+ DiagnosticOpts(llvm::makeIntrusiveRefCnt<DiagnosticOptions>()),
+ HSOpts(std::make_shared<HeaderSearchOptions>()),
+ PPOpts(std::make_shared<PreprocessorOptions>()),
+ AnalyzerOpts(llvm::makeIntrusiveRefCnt<AnalyzerOptions>()),
+ MigratorOpts(std::make_shared<MigratorOptions>()),
+ CodeGenOpts(std::make_shared<CodeGenOptions>()),
+ FSOpts(std::make_shared<FileSystemOptions>()),
+ FrontendOpts(std::make_shared<FrontendOptions>()),
+ DependencyOutputOpts(std::make_shared<DependencyOutputOptions>()),
+ PreprocessorOutputOpts(std::make_shared<PreprocessorOutputOptions>()) {}
+
+CompilerInvocationBase &
+CompilerInvocationBase::operator=(const CompilerInvocationBase &X) {
+ if (this != &X) {
+ LangOpts = make_shared_copy(X.getLangOpts());
+ TargetOpts = make_shared_copy(X.getTargetOpts());
+ DiagnosticOpts = makeIntrusiveRefCntCopy(X.getDiagnosticOpts());
+ HSOpts = make_shared_copy(X.getHeaderSearchOpts());
+ PPOpts = make_shared_copy(X.getPreprocessorOpts());
+ AnalyzerOpts = makeIntrusiveRefCntCopy(X.getAnalyzerOpts());
+ MigratorOpts = make_shared_copy(X.getMigratorOpts());
+ CodeGenOpts = make_shared_copy(X.getCodeGenOpts());
+ FSOpts = make_shared_copy(X.getFileSystemOpts());
+ FrontendOpts = make_shared_copy(X.getFrontendOpts());
+ DependencyOutputOpts = make_shared_copy(X.getDependencyOutputOpts());
+ PreprocessorOutputOpts = make_shared_copy(X.getPreprocessorOutputOpts());
+ }
+ return *this;
+}
//===----------------------------------------------------------------------===//
// Normalizers
@@ -838,7 +847,7 @@ static void getAllNoBuiltinFuncValues(ArgList &Args,
Funcs.insert(Funcs.end(), Values.begin(), BuiltinEnd);
}
-static void GenerateAnalyzerArgs(AnalyzerOptions &Opts,
+static void GenerateAnalyzerArgs(const AnalyzerOptions &Opts,
ArgumentConsumer Consumer) {
const AnalyzerOptions *AnalyzerOpts = &Opts;
@@ -2917,7 +2926,7 @@ std::string CompilerInvocation::GetResourcesPath(const char *Argv0,
return Driver::GetResourcesPath(ClangExecutable, CLANG_RESOURCE_DIR);
}
-static void GenerateHeaderSearchArgs(HeaderSearchOptions &Opts,
+static void GenerateHeaderSearchArgs(const HeaderSearchOptions &Opts,
ArgumentConsumer Consumer) {
const HeaderSearchOptions *HeaderSearchOpts = &Opts;
#define HEADER_SEARCH_OPTION_WITH_MARSHALLING(...) \
@@ -4103,12 +4112,12 @@ static bool isStrictlyPreprocessorAction(frontend::ActionKind Action) {
llvm_unreachable("invalid frontend action");
}
-static void GeneratePreprocessorArgs(PreprocessorOptions &Opts,
+static void GeneratePreprocessorArgs(const PreprocessorOptions &Opts,
ArgumentConsumer Consumer,
const LangOptions &LangOpts,
const FrontendOptions &FrontendOpts,
const CodeGenOptions &CodeGenOpts) {
- PreprocessorOptions *PreprocessorOpts = &Opts;
+ const PreprocessorOptions *PreprocessorOpts = &Opts;
#define PREPROCESSOR_OPTION_WITH_MARSHALLING(...) \
GENERATE_OPTION_WITH_MARSHALLING(Consumer, __VA_ARGS__)
@@ -4514,15 +4523,15 @@ std::string CompilerInvocation::getModuleHash() const {
#define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description)
#include "clang/Basic/LangOptions.def"
- HBuilder.addRange(LangOpts->ModuleFeatures);
+ HBuilder.addRange(getLangOpts().ModuleFeatures);
- HBuilder.add(LangOpts->ObjCRuntime);
- HBuilder.addRange(LangOpts->CommentOpts.BlockCommandNames);
+ HBuilder.add(getLangOpts().ObjCRuntime);
+ HBuilder.addRange(getLangOpts().CommentOpts.BlockCommandNames);
// Extend the signature with the target options.
- HBuilder.add(TargetOpts->Triple, TargetOpts->CPU, TargetOpts->TuneCPU,
- TargetOpts->ABI);
- HBuilder.addRange(TargetOpts->FeaturesAsWritten);
+ HBuilder.add(getTargetOpts().Triple, getTargetOpts().CPU,
+ getTargetOpts().TuneCPU, getTargetOpts().ABI);
+ HBuilder.addRange(getTargetOpts().FeaturesAsWritten);
// Extend the signature with preprocessor options.
const PreprocessorOptions &ppOpts = getPreprocessorOpts();
@@ -4577,7 +4586,7 @@ std::string CompilerInvocation::getModuleHash() const {
// Extend the signature with the enabled sanitizers, if at least one is
// enabled. Sanitizers which cannot affect AST generation aren't hashed.
- SanitizerSet SanHash = LangOpts->Sanitize;
+ SanitizerSet SanHash = getLangOpts().Sanitize;
SanHash.clear(getPPTransparentSanitizers());
if (!SanHash.empty())
HBuilder.add(SanHash.Mask);
@@ -4590,23 +4599,24 @@ std::string CompilerInvocation::getModuleHash() const {
void CompilerInvocation::generateCC1CommandLine(
ArgumentConsumer Consumer) const {
- llvm::Triple T(TargetOpts->Triple);
-
- GenerateFileSystemArgs(FileSystemOpts, Consumer);
- GenerateMigratorArgs(MigratorOpts, Consumer);
- GenerateAnalyzerArgs(*AnalyzerOpts, Consumer);
- GenerateDiagnosticArgs(*DiagnosticOpts, Consumer, false);
- GenerateFrontendArgs(FrontendOpts, Consumer, LangOpts->IsHeaderFile);
- GenerateTargetArgs(*TargetOpts, Consumer);
- GenerateHeaderSearchArgs(*HeaderSearchOpts, Consumer);
- GenerateLangArgs(*LangOpts, Consumer, T, FrontendOpts.DashX);
- GenerateCodeGenArgs(CodeGenOpts, Consumer, T, FrontendOpts.OutputFile,
- &*LangOpts);
- GeneratePreprocessorArgs(*PreprocessorOpts, Consumer, *LangOpts, FrontendOpts,
- CodeGenOpts);
- GeneratePreprocessorOutputArgs(PreprocessorOutputOpts, Consumer,
- FrontendOpts.ProgramAction);
- GenerateDependencyOutputArgs(DependencyOutputOpts, Consumer);
+ llvm::Triple T(getTargetOpts().Triple);
+
+ GenerateFileSystemArgs(getFileSystemOpts(), Consumer);
+ GenerateMigratorArgs(getMigratorOpts(), Consumer);
+ GenerateAnalyzerArgs(getAnalyzerOpts(), Consumer);
+ GenerateDiagnosticArgs(getDiagnosticOpts(), Consumer,
+ /*DefaultDiagColor=*/false);
+ GenerateFrontendArgs(getFrontendOpts(), Consumer, getLangOpts().IsHeaderFile);
+ GenerateTargetArgs(getTargetOpts(), Consumer);
+ GenerateHeaderSearchArgs(getHeaderSearchOpts(), Consumer);
+ GenerateLangArgs(getLangOpts(), Consumer, T, getFrontendOpts().DashX);
+ GenerateCodeGenArgs(getCodeGenOpts(), Consumer, T,
+ getFrontendOpts().OutputFile, &getLangOpts());
+ GeneratePreprocessorArgs(getPreprocessorOpts(), Consumer, getLangOpts(),
+ getFrontendOpts(), getCodeGenOpts());
+ GeneratePreprocessorOutputArgs(getPreprocessorOutputOpts(), Consumer,
+ getFrontendOpts().ProgramAction);
+ GenerateDependencyOutputArgs(getDependencyOutputOpts(), Consumer);
}
std::vector<std::string> CompilerInvocation::getCC1CommandLine() const {
More information about the cfe-commits
mailing list