llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Jan Svoboda (jansvoboda11) <details> <summary>Changes</summary> This enables making the whole `CompilerInvocation` more efficient through copy-on-write. --- Full diff: https://github.com/llvm/llvm-project/pull/65647.diff 2 Files Affected: - (modified) clang/include/clang/Frontend/CompilerInvocation.h (+63-87) - (modified) clang/lib/Frontend/CompilerInvocation.cpp (+70-60) ``````````diff diff --git a/clang/include/clang/Frontend/CompilerInvocation.h b/clang/include/clang/Frontend/CompilerInvocation.h index 5dc55bb7abdba..2dc73b85bd4af 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 11ffb3d6630d1..c0dab4e64ff19 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 { `````````` </details> https://github.com/llvm/llvm-project/pull/65647 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits