[clang] [clang][deps] Optimize command line generation (PR #65412)
Jan Svoboda via cfe-commits
cfe-commits at lists.llvm.org
Wed Sep 6 10:39:31 PDT 2023
https://github.com/jansvoboda11 updated https://github.com/llvm/llvm-project/pull/65412:
>From e41d54104cff710a9f6744bfcda9962386558b17 Mon Sep 17 00:00:00 2001
From: Jan Svoboda <jan_svoboda at apple.com>
Date: Fri, 1 Sep 2023 15:07:23 -0700
Subject: [PATCH 1/2] [llvm][ADT] Implement `IntrusiveRefCntPtr::useCount()`
This function has the same semantics as `std::shared_ptr<T>::use_count()`, and enables implementing copy-on-write semantics.
---
llvm/include/llvm/ADT/IntrusiveRefCntPtr.h | 9 +++++++++
llvm/unittests/ADT/IntrusiveRefCntPtrTest.cpp | 13 +++++++++++++
2 files changed, 22 insertions(+)
diff --git a/llvm/include/llvm/ADT/IntrusiveRefCntPtr.h b/llvm/include/llvm/ADT/IntrusiveRefCntPtr.h
index e41eb0639ce30eb..90349e02014dd66 100644
--- a/llvm/include/llvm/ADT/IntrusiveRefCntPtr.h
+++ b/llvm/include/llvm/ADT/IntrusiveRefCntPtr.h
@@ -93,6 +93,8 @@ template <class Derived> class RefCountedBase {
#endif
public:
+ unsigned UseCount() const { return RefCount; }
+
void Retain() const { ++RefCount; }
void Release() const {
@@ -124,6 +126,8 @@ template <class Derived> class ThreadSafeRefCountedBase {
#endif
public:
+ unsigned UseCount() const { return RefCount.load(std::memory_order_relaxed); }
+
void Retain() const { RefCount.fetch_add(1, std::memory_order_relaxed); }
void Release() const {
@@ -155,6 +159,7 @@ template <class Derived> class ThreadSafeRefCountedBase {
/// Bar.h could use IntrusiveRefCntPtr<Foo>, although it still couldn't call any
/// functions on Foo itself, because Foo would be an incomplete type.
template <typename T> struct IntrusiveRefCntPtrInfo {
+ static unsigned useCount(const T *obj) { return obj->UseCount(); }
static void retain(T *obj) { obj->Retain(); }
static void release(T *obj) { obj->Release(); }
};
@@ -213,6 +218,10 @@ template <typename T> class IntrusiveRefCntPtr {
void resetWithoutRelease() { Obj = nullptr; }
+ unsigned useCount() const {
+ return Obj ? IntrusiveRefCntPtrInfo<T>::useCount(Obj) : 0;
+ }
+
private:
void retain() {
if (Obj)
diff --git a/llvm/unittests/ADT/IntrusiveRefCntPtrTest.cpp b/llvm/unittests/ADT/IntrusiveRefCntPtrTest.cpp
index 45b8028aef20089..af2c3760bc99af2 100644
--- a/llvm/unittests/ADT/IntrusiveRefCntPtrTest.cpp
+++ b/llvm/unittests/ADT/IntrusiveRefCntPtrTest.cpp
@@ -140,4 +140,17 @@ TEST(IntrusiveRefCntPtr, InteropsWithConvertible) {
EXPECT_EQ(P4, X4.get());
}
+TEST(IntrusiveRefCntPtrTest, Unique) {
+ IntrusiveRefCntPtr<X> X1;
+ EXPECT_EQ(X1.useCount(), 0);
+ X1 = new X();
+ EXPECT_EQ(X1.useCount(), 1);
+ {
+ IntrusiveRefCntPtr<X> X2 = X1;
+ EXPECT_EQ(X1.useCount(), 2);
+ EXPECT_EQ(X2.useCount(), 2);
+ }
+ EXPECT_EQ(X1.useCount(), 1);
+}
+
} // end namespace llvm
>From 16be7a0df5f853d19fb2472e24c4b6ddd9f5a445 Mon Sep 17 00:00:00 2001
From: Jan Svoboda <jan_svoboda at apple.com>
Date: Thu, 31 Aug 2023 11:39:32 -0700
Subject: [PATCH 2/2] [clang] Introduce copy-on-write `CompilerInvocation`
---
clang/include/clang/Basic/CodeGenOptions.h | 1 +
clang/include/clang/Basic/DiagnosticOptions.h | 1 +
clang/include/clang/Basic/LangOptions.h | 1 +
.../clang/Frontend/CompilerInvocation.h | 317 ++++++++++++------
clang/lib/Frontend/CompilerInvocation.cpp | 208 +++++++-----
5 files changed, 346 insertions(+), 182 deletions(-)
diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h
index 14fc94fe27f9958..c6d7db32f2d2669 100644
--- a/clang/include/clang/Basic/CodeGenOptions.h
+++ b/clang/include/clang/Basic/CodeGenOptions.h
@@ -32,6 +32,7 @@ namespace clang {
/// that this large collection of bitfields is a trivial class type.
class CodeGenOptionsBase {
friend class CompilerInvocation;
+ friend struct CompilerInvocationBase;
public:
#define CODEGENOPT(Name, Bits, Default) unsigned Name : Bits;
diff --git a/clang/include/clang/Basic/DiagnosticOptions.h b/clang/include/clang/Basic/DiagnosticOptions.h
index 0f3120859ecef6c..9fb84415e22ead2 100644
--- a/clang/include/clang/Basic/DiagnosticOptions.h
+++ b/clang/include/clang/Basic/DiagnosticOptions.h
@@ -72,6 +72,7 @@ class DiagnosticOptions : public RefCountedBase<DiagnosticOptions>{
clang::DiagnosticsEngine *, bool);
friend class CompilerInvocation;
+ friend struct CompilerInvocationBase;
public:
enum TextDiagnosticFormat { Clang, MSVC, Vi, SARIF };
diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h
index 2adf4751444726b..aa649e675d9024d 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -34,6 +34,7 @@ namespace clang {
/// this large collection of bitfields is a trivial class type.
class LangOptionsBase {
friend class CompilerInvocation;
+ friend struct CompilerInvocationBase;
public:
// Define simple language options (with no accessors).
diff --git a/clang/include/clang/Frontend/CompilerInvocation.h b/clang/include/clang/Frontend/CompilerInvocation.h
index 5dc55bb7abdbab7..81f3107b4b4df4e 100644
--- a/clang/include/clang/Frontend/CompilerInvocation.h
+++ b/clang/include/clang/Frontend/CompilerInvocation.h
@@ -20,8 +20,8 @@
#include "clang/Frontend/MigratorOptions.h"
#include "clang/Frontend/PreprocessorOutputOptions.h"
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
-#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include <memory>
#include <string>
@@ -66,16 +66,18 @@ bool ParseDiagnosticArgs(DiagnosticOptions &Opts, llvm::opt::ArgList &Args,
DiagnosticsEngine *Diags = nullptr,
bool DefaultDiagColor = true);
+namespace CompilerInvocationDetail {
/// 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:
+/// This is a separate base class so that the client-facing sub-classes can
+/// simply declare the desired copy semantics without managing the internals
+/// themselves (for the most parts).
+class RefBase {
+protected:
/// Options controlling the language variant.
std::shared_ptr<LangOptions> LangOpts;
@@ -94,47 +96,37 @@ class CompilerInvocationRefBase {
/// Options controlling the static analyzer.
AnalyzerOptionsRef AnalyzerOpts;
- CompilerInvocationRefBase();
- CompilerInvocationRefBase(const CompilerInvocationRefBase &X);
- CompilerInvocationRefBase(CompilerInvocationRefBase &&X);
- CompilerInvocationRefBase &operator=(CompilerInvocationRefBase X);
- CompilerInvocationRefBase &operator=(CompilerInvocationRefBase &&X);
- ~CompilerInvocationRefBase();
+ struct ShallowCopy {};
+ struct DeepCopy {};
- LangOptions &getLangOpts() { return *LangOpts; }
- const LangOptions &getLangOpts() const { return *LangOpts; }
+ RefBase();
- TargetOptions &getTargetOpts() { return *TargetOpts.get(); }
- const TargetOptions &getTargetOpts() const { return *TargetOpts.get(); }
+ RefBase(const RefBase &X, DeepCopy);
+ RefBase(const RefBase &X, ShallowCopy);
+ RefBase(const RefBase &) = delete;
- DiagnosticOptions &getDiagnosticOpts() const { return *DiagnosticOpts; }
+ RefBase &assign(const RefBase &X, DeepCopy);
+ RefBase &assign(const RefBase &X, ShallowCopy);
+ RefBase &operator=(const RefBase &) = delete;
- HeaderSearchOptions &getHeaderSearchOpts() { return *HeaderSearchOpts; }
+ RefBase(RefBase &&);
+ RefBase &operator=(RefBase &&);
- const HeaderSearchOptions &getHeaderSearchOpts() const {
- return *HeaderSearchOpts;
- }
+ ~RefBase();
- 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; }
+public:
+ // clang-format off
+ const LangOptions &getLangOpts() const { return *LangOpts; }
+ const TargetOptions &getTargetOpts() const { return *TargetOpts; }
+ const DiagnosticOptions &getDiagnosticOpts() const { return *DiagnosticOpts; }
+ const HeaderSearchOptions &getHeaderSearchOpts() const { return *HeaderSearchOpts; }
+ const PreprocessorOptions &getPreprocessorOpts() const { return *PreprocessorOpts; }
const AnalyzerOptions &getAnalyzerOpts() const { return *AnalyzerOpts; }
+ // clang-format on
};
/// The base class of CompilerInvocation with value semantics.
-class CompilerInvocationValueBase {
+class ValBase {
protected:
MigratorOptions MigratorOpts;
@@ -154,36 +146,87 @@ class CompilerInvocationValueBase {
PreprocessorOutputOptions PreprocessorOutputOpts;
public:
- MigratorOptions &getMigratorOpts() { return MigratorOpts; }
+ // clang-format off
const MigratorOptions &getMigratorOpts() const { return MigratorOpts; }
-
- CodeGenOptions &getCodeGenOpts() { return CodeGenOpts; }
const CodeGenOptions &getCodeGenOpts() const { return CodeGenOpts; }
+ const DependencyOutputOptions &getDependencyOutputOpts() const { return DependencyOutputOpts; }
+ const FileSystemOptions &getFileSystemOpts() const { return FileSystemOpts; }
+ const FrontendOptions &getFrontendOpts() const { return FrontendOpts; }
+ const PreprocessorOutputOptions &getPreprocessorOutputOpts() const { return PreprocessorOutputOpts; }
+ // clang-format on
+};
+} // namespace CompilerInvocationDetail
- DependencyOutputOptions &getDependencyOutputOpts() {
- return DependencyOutputOpts;
- }
+struct CompilerInvocationBase : CompilerInvocationDetail::RefBase,
+ CompilerInvocationDetail::ValBase {
+ CompilerInvocationBase() = default;
- const DependencyOutputOptions &getDependencyOutputOpts() const {
- return DependencyOutputOpts;
- }
+ CompilerInvocationBase(const CompilerInvocationBase &X, DeepCopy)
+ : RefBase(X, DeepCopy{}), ValBase(X) {}
- FileSystemOptions &getFileSystemOpts() { return FileSystemOpts; }
+ CompilerInvocationBase(const CompilerInvocationBase &X, ShallowCopy)
+ : RefBase(X, ShallowCopy{}), ValBase(X) {}
- const FileSystemOptions &getFileSystemOpts() const {
- return FileSystemOpts;
+ CompilerInvocationBase &assign(const CompilerInvocationBase &X, DeepCopy) {
+ RefBase::assign(X, DeepCopy{});
+ ValBase::operator=(X);
+ return *this;
}
- FrontendOptions &getFrontendOpts() { return FrontendOpts; }
- const FrontendOptions &getFrontendOpts() const { return FrontendOpts; }
-
- PreprocessorOutputOptions &getPreprocessorOutputOpts() {
- return PreprocessorOutputOpts;
+ CompilerInvocationBase &assign(const CompilerInvocationBase &X, ShallowCopy) {
+ RefBase::assign(X, ShallowCopy{});
+ ValBase::operator=(X);
+ return *this;
}
- const PreprocessorOutputOptions &getPreprocessorOutputOpts() const {
- return PreprocessorOutputOpts;
+ using StringAllocator = llvm::function_ref<const char *(const Twine &)>;
+ /// Generate cc1-compatible command line arguments from this instance.
+ ///
+ /// \param [out] Args - The generated arguments. Note that the caller is
+ /// responsible for inserting the path to the clang executable and "-cc1" if
+ /// desired.
+ /// \param SA - A function that given a Twine can allocate storage for a given
+ /// command line argument and return a pointer to the newly allocated string.
+ /// The returned pointer is what gets appended to Args.
+ void generateCC1CommandLine(llvm::SmallVectorImpl<const char *> &Args,
+ StringAllocator SA) const {
+ generateCC1CommandLine([&](const Twine &Arg) {
+ // No need to allocate static string literals.
+ Args.push_back(Arg.isSingleStringLiteral()
+ ? Arg.getSingleStringRef().data()
+ : SA(Arg));
+ });
}
+
+ using ArgumentConsumer = llvm::function_ref<void(const Twine &)>;
+ /// Generate cc1-compatible command line arguments from this instance.
+ ///
+ /// \param Consumer - Callback that gets invoked for every single generated
+ /// command line argument.
+ void generateCC1CommandLine(ArgumentConsumer Consumer) const;
+
+ /// Generate cc1-compatible command line arguments from this instance,
+ /// wrapping the result as a std::vector<std::string>.
+ ///
+ /// This is a (less-efficient) wrapper over generateCC1CommandLine().
+ std::vector<std::string> getCC1CommandLine() const;
+
+ /// Generate command line options from DiagnosticOptions.
+ static void GenerateDiagnosticArgs(const DiagnosticOptions &Opts,
+ ArgumentConsumer Consumer,
+ bool DefaultDiagColor);
+
+ /// Generate command line options from LangOptions.
+ static void GenerateLangArgs(const LangOptions &Opts,
+ ArgumentConsumer Consumer, const llvm::Triple &T,
+ InputKind IK);
+
+ // Generate command line options from CodeGenOptions.
+ static void GenerateCodeGenArgs(const CodeGenOptions &Opts,
+ ArgumentConsumer Consumer,
+ const llvm::Triple &T,
+ const std::string &OutputFile,
+ const LangOptions *LangOpts);
};
/// Helper class for holding the data necessary to invoke the compiler.
@@ -191,9 +234,70 @@ 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:
+ CompilerInvocation() = default;
+
+ CompilerInvocation(const CompilerInvocation &X)
+ : CompilerInvocationBase(X, DeepCopy{}) {}
+
+ CompilerInvocation &operator=(const CompilerInvocation &X) {
+ CompilerInvocationBase::assign(X, DeepCopy{});
+ return *this;
+ }
+
+ // Mutable RefBase accessors.
+
+ LangOptions &getLangOpts() { return *LangOpts; }
+ TargetOptions &getTargetOpts() { return *TargetOpts; }
+ DiagnosticOptions &getDiagnosticOpts() { return *DiagnosticOpts; }
+ HeaderSearchOptions &getHeaderSearchOpts() { return *HeaderSearchOpts; }
+ PreprocessorOptions &getPreprocessorOpts() { return *PreprocessorOpts; }
+ AnalyzerOptions &getAnalyzerOpts() { return *AnalyzerOpts; }
+
+ // Const RefBase accessors.
+
+ using RefBase::getLangOpts;
+ using RefBase::getTargetOpts;
+ using RefBase::getDiagnosticOpts;
+ using RefBase::getHeaderSearchOpts;
+ using RefBase::getPreprocessorOpts;
+ using RefBase::getAnalyzerOpts;
+
+ // Mutable ValBase accessors.
+
+ // clang-format off
+ MigratorOptions &getMigratorOpts() { return MigratorOpts; }
+ CodeGenOptions &getCodeGenOpts() { return CodeGenOpts; }
+ DependencyOutputOptions &getDependencyOutputOpts() { return DependencyOutputOpts; }
+ FileSystemOptions &getFileSystemOpts() { return FileSystemOpts; }
+ FrontendOptions &getFrontendOpts() { return FrontendOpts; }
+ PreprocessorOutputOptions &getPreprocessorOutputOpts() { return PreprocessorOutputOpts; }
+ // clang-format on
+
+ // Const ValBase accessors.
+
+ using ValBase::getMigratorOpts;
+ using ValBase::getCodeGenOpts;
+ using ValBase::getDependencyOutputOpts;
+ using ValBase::getFileSystemOpts;
+ using ValBase::getFrontendOpts;
+ using ValBase::getPreprocessorOutputOpts;
+
+ /// RefBase innards
+
+ std::shared_ptr<HeaderSearchOptions> getHeaderSearchOptsPtr() const {
+ return HeaderSearchOpts;
+ }
+
+ std::shared_ptr<PreprocessorOptions> getPreprocessorOptsPtr() const {
+ return PreprocessorOpts;
+ }
+
+ using CompilerInvocationBase::DiagnosticOpts;
+ using CompilerInvocationBase::TargetOpts;
+ using CompilerInvocationBase::LangOpts;
+
/// Create a compiler invocation from a list of input options.
/// \returns true on success.
///
@@ -224,38 +328,6 @@ class CompilerInvocation : public CompilerInvocationRefBase,
/// identifying the conditions under which the module was built.
std::string getModuleHash() const;
- using StringAllocator = llvm::function_ref<const char *(const Twine &)>;
- /// Generate cc1-compatible command line arguments from this instance.
- ///
- /// \param [out] Args - The generated arguments. Note that the caller is
- /// responsible for inserting the path to the clang executable and "-cc1" if
- /// desired.
- /// \param SA - A function that given a Twine can allocate storage for a given
- /// command line argument and return a pointer to the newly allocated string.
- /// The returned pointer is what gets appended to Args.
- void generateCC1CommandLine(llvm::SmallVectorImpl<const char *> &Args,
- StringAllocator SA) const {
- generateCC1CommandLine([&](const Twine &Arg) {
- // No need to allocate static string literals.
- Args.push_back(Arg.isSingleStringLiteral()
- ? Arg.getSingleStringRef().data()
- : SA(Arg));
- });
- }
-
- using ArgumentConsumer = llvm::function_ref<void(const Twine &)>;
- /// Generate cc1-compatible command line arguments from this instance.
- ///
- /// \param Consumer - Callback that gets invoked for every single generated
- /// command line argument.
- void generateCC1CommandLine(ArgumentConsumer Consumer) const;
-
- /// Generate cc1-compatible command line arguments from this instance,
- /// wrapping the result as a std::vector<std::string>.
- ///
- /// This is a (less-efficient) wrapper over generateCC1CommandLine().
- std::vector<std::string> getCC1CommandLine() const;
-
/// Check that \p Args can be parsed and re-serialized without change,
/// emiting diagnostics for any differences.
///
@@ -280,35 +352,70 @@ class CompilerInvocation : public CompilerInvocationRefBase,
ArrayRef<const char *> CommandLineArgs,
DiagnosticsEngine &Diags, const char *Argv0);
- /// Generate command line options from DiagnosticOptions.
- static void GenerateDiagnosticArgs(const DiagnosticOptions &Opts,
- ArgumentConsumer Consumer,
- bool DefaultDiagColor);
-
/// Parse command line options that map to LangOptions.
static bool ParseLangArgs(LangOptions &Opts, llvm::opt::ArgList &Args,
InputKind IK, const llvm::Triple &T,
std::vector<std::string> &Includes,
DiagnosticsEngine &Diags);
- /// Generate command line options from LangOptions.
- static void GenerateLangArgs(const LangOptions &Opts,
- ArgumentConsumer Consumer, const llvm::Triple &T,
- InputKind IK);
-
/// Parse command line options that map to CodeGenOptions.
static bool ParseCodeGenArgs(CodeGenOptions &Opts, llvm::opt::ArgList &Args,
InputKind IK, DiagnosticsEngine &Diags,
const llvm::Triple &T,
const std::string &OutputFile,
const LangOptions &LangOptsRef);
+};
- // Generate command line options from CodeGenOptions.
- static void GenerateCodeGenArgs(const CodeGenOptions &Opts,
- ArgumentConsumer Consumer,
- const llvm::Triple &T,
- const std::string &OutputFile,
- const LangOptions *LangOpts);
+/// Same as CompilerInvocation, but copies are on-demand and per-opts-object.
+struct CowCompilerInvocation : CompilerInvocationBase {
+ CowCompilerInvocation(const CompilerInvocation &X)
+ : CompilerInvocationBase(X, DeepCopy{}) {}
+
+ CowCompilerInvocation(const CowCompilerInvocation &X)
+ : CompilerInvocationBase(X, ShallowCopy{}) {}
+
+ CowCompilerInvocation &operator=(const CowCompilerInvocation &X) {
+ CompilerInvocationBase::assign(X, ShallowCopy{});
+ return *this;
+ }
+
+ // Mutable RefBase accessors.
+
+ LangOptions &getMutLangOpts();
+ TargetOptions &getMutTargetOpts();
+ DiagnosticOptions &getMutDiagnosticOpts();
+ HeaderSearchOptions &getMutHeaderSearchOpts();
+ PreprocessorOptions &getMutPreprocessorOpts();
+ AnalyzerOptions &getMutAnalyzerOpts();
+
+ // Const RefBase accessors.
+
+ using RefBase::getLangOpts;
+ using RefBase::getTargetOpts;
+ using RefBase::getDiagnosticOpts;
+ using RefBase::getHeaderSearchOpts;
+ using RefBase::getPreprocessorOpts;
+ using RefBase::getAnalyzerOpts;
+
+ // Mutable ValBase accessors.
+
+ // clang-format off
+ MigratorOptions &getMutMigratorOpts() { return MigratorOpts; }
+ CodeGenOptions &getMutCodeGenOpts() { return CodeGenOpts; }
+ DependencyOutputOptions &getMutDependencyOutputOpts() { return DependencyOutputOpts; }
+ FileSystemOptions &getMutFileSystemOpts() { return FileSystemOpts; }
+ FrontendOptions &getMutFrontendOpts() { return FrontendOpts; }
+ PreprocessorOutputOptions &getMutPreprocessorOutputOpts() { return PreprocessorOutputOpts; }
+ // clang-format on
+
+ // Const ValBase accessors.
+
+ using ValBase::getMigratorOpts;
+ using ValBase::getCodeGenOpts;
+ using ValBase::getDependencyOutputOpts;
+ using ValBase::getFileSystemOpts;
+ using ValBase::getFrontendOpts;
+ using ValBase::getPreprocessorOutputOpts;
};
IntrusiveRefCntPtr<llvm::vfs::FileSystem>
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 11ffb3d6630d1fb..3fc354d6cc621d6 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -123,49 +123,101 @@ static Expected<std::optional<uint32_t>> parseToleranceOption(StringRef Arg) {
}
//===----------------------------------------------------------------------===//
-// Initialization.
+// Storage details.
//===----------------------------------------------------------------------===//
-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);
+namespace clang::CompilerInvocationDetail {
+namespace {
+template <class T> std::shared_ptr<T> make_shared(const T &X) {
+ return std::make_shared<T>(X);
+}
+
+template <class T> llvm::IntrusiveRefCntPtr<T> makeIntrusiveRefCnt(const T &X) {
+ return llvm::makeIntrusiveRefCnt<T>(X);
+}
+} // namespace
+
+RefBase::RefBase()
+ : LangOpts(std::make_shared<LangOptions>()),
+ TargetOpts(std::make_shared<TargetOptions>()),
+ DiagnosticOpts(llvm::makeIntrusiveRefCnt<DiagnosticOptions>()),
+ HeaderSearchOpts(std::make_shared<HeaderSearchOptions>()),
+ PreprocessorOpts(std::make_shared<PreprocessorOptions>()),
+ AnalyzerOpts(llvm::makeIntrusiveRefCnt<AnalyzerOptions>()) {}
+
+RefBase::RefBase(const RefBase &X, DeepCopy)
+ : LangOpts(make_shared(*X.LangOpts)),
+ TargetOpts(make_shared(*X.TargetOpts)),
+ DiagnosticOpts(makeIntrusiveRefCnt(*X.DiagnosticOpts)),
+ HeaderSearchOpts(make_shared(*X.HeaderSearchOpts)),
+ PreprocessorOpts(make_shared(*X.PreprocessorOpts)),
+ AnalyzerOpts(makeIntrusiveRefCnt(*X.AnalyzerOpts)) {}
+
+RefBase::RefBase(const RefBase &X, ShallowCopy)
+ : LangOpts(X.LangOpts), //
+ TargetOpts(X.TargetOpts), //
+ DiagnosticOpts(X.DiagnosticOpts), //
+ HeaderSearchOpts(X.HeaderSearchOpts), //
+ PreprocessorOpts(X.PreprocessorOpts), //
+ AnalyzerOpts(X.AnalyzerOpts) {}
+
+RefBase &RefBase::assign(const RefBase &X, DeepCopy) {
+ LangOpts = make_shared(*X.LangOpts);
+ TargetOpts = make_shared(*X.TargetOpts);
+ DiagnosticOpts = makeIntrusiveRefCnt(*X.DiagnosticOpts);
+ HeaderSearchOpts = make_shared(*X.HeaderSearchOpts);
+ PreprocessorOpts = make_shared(*X.PreprocessorOpts);
+ AnalyzerOpts = makeIntrusiveRefCnt(*X.AnalyzerOpts);
return *this;
}
-CompilerInvocationRefBase &
-CompilerInvocationRefBase::operator=(CompilerInvocationRefBase &&X) = default;
+RefBase &RefBase::assign(const RefBase &X, ShallowCopy) {
+ LangOpts = X.LangOpts;
+ TargetOpts = X.TargetOpts;
+ DiagnosticOpts = X.DiagnosticOpts;
+ HeaderSearchOpts = X.HeaderSearchOpts;
+ PreprocessorOpts = X.PreprocessorOpts;
+ AnalyzerOpts = X.AnalyzerOpts;
+ return *this;
+}
+
+RefBase::RefBase(RefBase &&) = default;
+RefBase &RefBase::operator=(RefBase &&) = default;
+
+RefBase::~RefBase() = default;
+} // namespace clang::CompilerInvocationDetail
+
+namespace {
+template <typename T>
+T &ensure_owned(std::shared_ptr<T> &Storage) {
+ if (Storage.use_count() > 1)
+ Storage = std::make_shared<T>(*Storage);
+ return *Storage;
+}
+
+template <typename T>
+T &ensure_owned(llvm::IntrusiveRefCntPtr<T> &Storage) {
+ if (Storage.useCount() > 1)
+ Storage = llvm::makeIntrusiveRefCnt<T>(*Storage);
+ return *Storage;
+}
+} // namespace
-CompilerInvocationRefBase::~CompilerInvocationRefBase() = default;
+// clang-format off
+LangOptions &CowCompilerInvocation::getMutLangOpts() { return ensure_owned(LangOpts); }
+TargetOptions &CowCompilerInvocation::getMutTargetOpts() { return ensure_owned(TargetOpts); }
+DiagnosticOptions &CowCompilerInvocation::getMutDiagnosticOpts() { return ensure_owned(DiagnosticOpts); }
+HeaderSearchOptions &CowCompilerInvocation::getMutHeaderSearchOpts() { return ensure_owned(HeaderSearchOpts); }
+PreprocessorOptions &CowCompilerInvocation::getMutPreprocessorOpts() { return ensure_owned(PreprocessorOpts); }
+AnalyzerOptions &CowCompilerInvocation::getMutAnalyzerOpts() { return ensure_owned(AnalyzerOpts); }
+// clang-format on
//===----------------------------------------------------------------------===//
// Normalizers
//===----------------------------------------------------------------------===//
-using ArgumentConsumer = CompilerInvocation::ArgumentConsumer;
+using ArgumentConsumer = CompilerInvocationBase::ArgumentConsumer;
+using StringAllocator = CompilerInvocationBase::StringAllocator;
#define SIMPLE_ENUM_VALUE_TABLE
#include "clang/Driver/Options.inc"
@@ -633,8 +685,7 @@ using ParseFn =
// Generate command line arguments from CompilerInvocation.
using GenerateFn = llvm::function_ref<void(
- CompilerInvocation &, SmallVectorImpl<const char *> &,
- CompilerInvocation::StringAllocator)>;
+ CompilerInvocation &, SmallVectorImpl<const char *> &, StringAllocator)>;
/// May perform round-trip of command line arguments. By default, the round-trip
/// is enabled in assert builds. This can be overwritten at run-time via the
@@ -838,7 +889,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;
@@ -1346,11 +1397,11 @@ static void setPGOUseInstrumentor(CodeGenOptions &Opts,
Opts.setProfileUse(CodeGenOptions::ProfileClangInstr);
}
-void CompilerInvocation::GenerateCodeGenArgs(const CodeGenOptions &Opts,
- ArgumentConsumer Consumer,
- const llvm::Triple &T,
- const std::string &OutputFile,
- const LangOptions *LangOpts) {
+void CompilerInvocationBase::GenerateCodeGenArgs(const CodeGenOptions &Opts,
+ ArgumentConsumer Consumer,
+ const llvm::Triple &T,
+ const std::string &OutputFile,
+ const LangOptions *LangOpts) {
const CodeGenOptions &CodeGenOpts = Opts;
if (Opts.OptimizationLevel == 0)
@@ -2254,9 +2305,9 @@ static bool ParseMigratorArgs(MigratorOptions &Opts, const ArgList &Args,
return Diags.getNumErrors() == NumErrorsBefore;
}
-void CompilerInvocation::GenerateDiagnosticArgs(const DiagnosticOptions &Opts,
- ArgumentConsumer Consumer,
- bool DefaultDiagColor) {
+void CompilerInvocationBase::GenerateDiagnosticArgs(
+ const DiagnosticOptions &Opts, ArgumentConsumer Consumer,
+ bool DefaultDiagColor) {
const DiagnosticOptions *DiagnosticOpts = &Opts;
#define DIAG_OPTION_WITH_MARSHALLING(...) \
GENERATE_OPTION_WITH_MARSHALLING(Consumer, __VA_ARGS__)
@@ -2917,7 +2968,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(...) \
@@ -3247,9 +3298,10 @@ static StringRef GetInputKindName(InputKind IK) {
llvm_unreachable("unknown input language");
}
-void CompilerInvocation::GenerateLangArgs(const LangOptions &Opts,
- ArgumentConsumer Consumer,
- const llvm::Triple &T, InputKind IK) {
+void CompilerInvocationBase::GenerateLangArgs(const LangOptions &Opts,
+ ArgumentConsumer Consumer,
+ const llvm::Triple &T,
+ InputKind IK) {
if (IK.getFormat() == InputKind::Precompiled ||
IK.getLanguage() == Language::LLVM_IR) {
if (Opts.ObjCAutoRefCount)
@@ -4103,12 +4155,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__)
@@ -4507,22 +4559,23 @@ std::string CompilerInvocation::getModuleHash() const {
HBuilder.add(serialization::VERSION_MAJOR, serialization::VERSION_MINOR);
// Extend the signature with the language options
-#define LANGOPT(Name, Bits, Default, Description) HBuilder.add(LangOpts->Name);
+#define LANGOPT(Name, Bits, Default, Description) \
+ HBuilder.add(getLangOpts().Name);
#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
- HBuilder.add(static_cast<unsigned>(LangOpts->get##Name()));
+ HBuilder.add(static_cast<unsigned>(getLangOpts().get##Name()));
#define BENIGN_LANGOPT(Name, Bits, Default, Description)
#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 +4630,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);
@@ -4588,28 +4641,29 @@ std::string CompilerInvocation::getModuleHash() const {
return toString(llvm::APInt(64, Hash), 36, /*Signed=*/false);
}
-void CompilerInvocation::generateCC1CommandLine(
+void CompilerInvocationBase::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, 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 {
+std::vector<std::string> CompilerInvocationBase::getCC1CommandLine() const {
std::vector<std::string> Args{"-cc1"};
generateCC1CommandLine(
[&Args](const Twine &Arg) { Args.push_back(Arg.str()); });
More information about the cfe-commits
mailing list