Skip to content

Commit e1cc299

Browse files
authored
[clang] Introduce copy-on-write CompilerInvocation (#65412)
This PR introduces new copy-on-write `CompilerInvocation` class (`CowCompilerInvocation`), which will be used by the dependency scanner to reduce the number of copies performed when generating command lines for discovered modules.
1 parent 0a4a8be commit e1cc299

File tree

6 files changed

+287
-73
lines changed

6 files changed

+287
-73
lines changed

clang/include/clang/Basic/CodeGenOptions.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ namespace clang {
3232
/// that this large collection of bitfields is a trivial class type.
3333
class CodeGenOptionsBase {
3434
friend class CompilerInvocation;
35+
friend class CompilerInvocationBase;
3536

3637
public:
3738
#define CODEGENOPT(Name, Bits, Default) unsigned Name : Bits;

clang/include/clang/Basic/DiagnosticOptions.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ class DiagnosticOptions : public RefCountedBase<DiagnosticOptions>{
7272
clang::DiagnosticsEngine *, bool);
7373

7474
friend class CompilerInvocation;
75+
friend class CompilerInvocationBase;
7576

7677
public:
7778
enum TextDiagnosticFormat { Clang, MSVC, Vi, SARIF };

clang/include/clang/Basic/LangOptions.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ namespace clang {
3434
/// this large collection of bitfields is a trivial class type.
3535
class LangOptionsBase {
3636
friend class CompilerInvocation;
37+
friend class CompilerInvocationBase;
3738

3839
public:
3940
// Define simple language options (with no accessors).

clang/include/clang/Frontend/CompilerInvocation.h

Lines changed: 145 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -107,14 +107,23 @@ class CompilerInvocationBase {
107107
/// Options controlling preprocessed output.
108108
std::shared_ptr<PreprocessorOutputOptions> PreprocessorOutputOpts;
109109

110-
public:
110+
/// Dummy tag type whose instance can be passed into the constructor to
111+
/// prevent creation of the reference-counted option objects.
112+
struct EmptyConstructor {};
113+
111114
CompilerInvocationBase();
112-
CompilerInvocationBase(const CompilerInvocationBase &X) { operator=(X); }
115+
CompilerInvocationBase(EmptyConstructor) {}
116+
CompilerInvocationBase(const CompilerInvocationBase &X) = delete;
113117
CompilerInvocationBase(CompilerInvocationBase &&X) = default;
114-
CompilerInvocationBase &operator=(const CompilerInvocationBase &X);
118+
CompilerInvocationBase &operator=(const CompilerInvocationBase &X) = delete;
119+
CompilerInvocationBase &deep_copy_assign(const CompilerInvocationBase &X);
120+
CompilerInvocationBase &shallow_copy_assign(const CompilerInvocationBase &X);
115121
CompilerInvocationBase &operator=(CompilerInvocationBase &&X) = default;
116122
~CompilerInvocationBase() = default;
117123

124+
public:
125+
/// Const getters.
126+
/// @{
118127
const LangOptions &getLangOpts() const { return *LangOpts; }
119128
const TargetOptions &getTargetOpts() const { return *TargetOpts; }
120129
const DiagnosticOptions &getDiagnosticOpts() const { return *DiagnosticOpts; }
@@ -131,7 +140,101 @@ class CompilerInvocationBase {
131140
const PreprocessorOutputOptions &getPreprocessorOutputOpts() const {
132141
return *PreprocessorOutputOpts;
133142
}
143+
/// @}
144+
145+
/// Command line generation.
146+
/// @{
147+
using StringAllocator = llvm::function_ref<const char *(const Twine &)>;
148+
/// Generate cc1-compatible command line arguments from this instance.
149+
///
150+
/// \param [out] Args - The generated arguments. Note that the caller is
151+
/// responsible for inserting the path to the clang executable and "-cc1" if
152+
/// desired.
153+
/// \param SA - A function that given a Twine can allocate storage for a given
154+
/// command line argument and return a pointer to the newly allocated string.
155+
/// The returned pointer is what gets appended to Args.
156+
void generateCC1CommandLine(llvm::SmallVectorImpl<const char *> &Args,
157+
StringAllocator SA) const {
158+
generateCC1CommandLine([&](const Twine &Arg) {
159+
// No need to allocate static string literals.
160+
Args.push_back(Arg.isSingleStringLiteral()
161+
? Arg.getSingleStringRef().data()
162+
: SA(Arg));
163+
});
164+
}
165+
166+
using ArgumentConsumer = llvm::function_ref<void(const Twine &)>;
167+
/// Generate cc1-compatible command line arguments from this instance.
168+
///
169+
/// \param Consumer - Callback that gets invoked for every single generated
170+
/// command line argument.
171+
void generateCC1CommandLine(ArgumentConsumer Consumer) const;
172+
173+
/// Generate cc1-compatible command line arguments from this instance,
174+
/// wrapping the result as a std::vector<std::string>.
175+
///
176+
/// This is a (less-efficient) wrapper over generateCC1CommandLine().
177+
std::vector<std::string> getCC1CommandLine() const;
178+
179+
private:
180+
/// Generate command line options from DiagnosticOptions.
181+
static void GenerateDiagnosticArgs(const DiagnosticOptions &Opts,
182+
ArgumentConsumer Consumer,
183+
bool DefaultDiagColor);
184+
185+
/// Generate command line options from LangOptions.
186+
static void GenerateLangArgs(const LangOptions &Opts,
187+
ArgumentConsumer Consumer, const llvm::Triple &T,
188+
InputKind IK);
189+
190+
// Generate command line options from CodeGenOptions.
191+
static void GenerateCodeGenArgs(const CodeGenOptions &Opts,
192+
ArgumentConsumer Consumer,
193+
const llvm::Triple &T,
194+
const std::string &OutputFile,
195+
const LangOptions *LangOpts);
196+
/// @}
197+
};
198+
199+
/// Helper class for holding the data necessary to invoke the compiler.
200+
///
201+
/// This class is designed to represent an abstract "invocation" of the
202+
/// compiler, including data such as the include paths, the code generation
203+
/// options, the warning flags, and so on.
204+
class CompilerInvocation : public CompilerInvocationBase {
205+
public:
206+
CompilerInvocation() = default;
207+
CompilerInvocation(const CompilerInvocation &X)
208+
: CompilerInvocationBase(EmptyConstructor{}) {
209+
deep_copy_assign(X);
210+
}
211+
CompilerInvocation(CompilerInvocation &&) = default;
212+
CompilerInvocation &operator=(const CompilerInvocation &X) {
213+
deep_copy_assign(X);
214+
return *this;
215+
}
216+
~CompilerInvocation() = default;
134217

218+
/// Const getters.
219+
/// @{
220+
// Note: These need to be pulled in manually. Otherwise, they get hidden by
221+
// the mutable getters with the same names.
222+
using CompilerInvocationBase::getLangOpts;
223+
using CompilerInvocationBase::getTargetOpts;
224+
using CompilerInvocationBase::getDiagnosticOpts;
225+
using CompilerInvocationBase::getHeaderSearchOpts;
226+
using CompilerInvocationBase::getPreprocessorOpts;
227+
using CompilerInvocationBase::getAnalyzerOpts;
228+
using CompilerInvocationBase::getMigratorOpts;
229+
using CompilerInvocationBase::getCodeGenOpts;
230+
using CompilerInvocationBase::getFileSystemOpts;
231+
using CompilerInvocationBase::getFrontendOpts;
232+
using CompilerInvocationBase::getDependencyOutputOpts;
233+
using CompilerInvocationBase::getPreprocessorOutputOpts;
234+
/// @}
235+
236+
/// Mutable getters.
237+
/// @{
135238
LangOptions &getLangOpts() { return *LangOpts; }
136239
TargetOptions &getTargetOpts() { return *TargetOpts; }
137240
DiagnosticOptions &getDiagnosticOpts() { return *DiagnosticOpts; }
@@ -148,15 +251,8 @@ class CompilerInvocationBase {
148251
PreprocessorOutputOptions &getPreprocessorOutputOpts() {
149252
return *PreprocessorOutputOpts;
150253
}
151-
};
254+
/// @}
152255

153-
/// Helper class for holding the data necessary to invoke the compiler.
154-
///
155-
/// This class is designed to represent an abstract "invocation" of the
156-
/// compiler, including data such as the include paths, the code generation
157-
/// options, the warning flags, and so on.
158-
class CompilerInvocation : public CompilerInvocationBase {
159-
public:
160256
/// Base class internals.
161257
/// @{
162258
using CompilerInvocationBase::LangOpts;
@@ -200,38 +296,6 @@ class CompilerInvocation : public CompilerInvocationBase {
200296
/// identifying the conditions under which the module was built.
201297
std::string getModuleHash() const;
202298

203-
using StringAllocator = llvm::function_ref<const char *(const Twine &)>;
204-
/// Generate cc1-compatible command line arguments from this instance.
205-
///
206-
/// \param [out] Args - The generated arguments. Note that the caller is
207-
/// responsible for inserting the path to the clang executable and "-cc1" if
208-
/// desired.
209-
/// \param SA - A function that given a Twine can allocate storage for a given
210-
/// command line argument and return a pointer to the newly allocated string.
211-
/// The returned pointer is what gets appended to Args.
212-
void generateCC1CommandLine(llvm::SmallVectorImpl<const char *> &Args,
213-
StringAllocator SA) const {
214-
generateCC1CommandLine([&](const Twine &Arg) {
215-
// No need to allocate static string literals.
216-
Args.push_back(Arg.isSingleStringLiteral()
217-
? Arg.getSingleStringRef().data()
218-
: SA(Arg));
219-
});
220-
}
221-
222-
using ArgumentConsumer = llvm::function_ref<void(const Twine &)>;
223-
/// Generate cc1-compatible command line arguments from this instance.
224-
///
225-
/// \param Consumer - Callback that gets invoked for every single generated
226-
/// command line argument.
227-
void generateCC1CommandLine(ArgumentConsumer Consumer) const;
228-
229-
/// Generate cc1-compatible command line arguments from this instance,
230-
/// wrapping the result as a std::vector<std::string>.
231-
///
232-
/// This is a (less-efficient) wrapper over generateCC1CommandLine().
233-
std::vector<std::string> getCC1CommandLine() const;
234-
235299
/// Check that \p Args can be parsed and re-serialized without change,
236300
/// emiting diagnostics for any differences.
237301
///
@@ -256,35 +320,57 @@ class CompilerInvocation : public CompilerInvocationBase {
256320
ArrayRef<const char *> CommandLineArgs,
257321
DiagnosticsEngine &Diags, const char *Argv0);
258322

259-
/// Generate command line options from DiagnosticOptions.
260-
static void GenerateDiagnosticArgs(const DiagnosticOptions &Opts,
261-
ArgumentConsumer Consumer,
262-
bool DefaultDiagColor);
263-
264323
/// Parse command line options that map to LangOptions.
265324
static bool ParseLangArgs(LangOptions &Opts, llvm::opt::ArgList &Args,
266325
InputKind IK, const llvm::Triple &T,
267326
std::vector<std::string> &Includes,
268327
DiagnosticsEngine &Diags);
269328

270-
/// Generate command line options from LangOptions.
271-
static void GenerateLangArgs(const LangOptions &Opts,
272-
ArgumentConsumer Consumer, const llvm::Triple &T,
273-
InputKind IK);
274-
275329
/// Parse command line options that map to CodeGenOptions.
276330
static bool ParseCodeGenArgs(CodeGenOptions &Opts, llvm::opt::ArgList &Args,
277331
InputKind IK, DiagnosticsEngine &Diags,
278332
const llvm::Triple &T,
279333
const std::string &OutputFile,
280334
const LangOptions &LangOptsRef);
335+
};
281336

282-
// Generate command line options from CodeGenOptions.
283-
static void GenerateCodeGenArgs(const CodeGenOptions &Opts,
284-
ArgumentConsumer Consumer,
285-
const llvm::Triple &T,
286-
const std::string &OutputFile,
287-
const LangOptions *LangOpts);
337+
/// Same as \c CompilerInvocation, but with copy-on-write optimization.
338+
class CowCompilerInvocation : public CompilerInvocationBase {
339+
public:
340+
CowCompilerInvocation() = default;
341+
CowCompilerInvocation(const CowCompilerInvocation &X)
342+
: CompilerInvocationBase(EmptyConstructor{}) {
343+
shallow_copy_assign(X);
344+
}
345+
CowCompilerInvocation(CowCompilerInvocation &&) = default;
346+
CowCompilerInvocation &operator=(const CowCompilerInvocation &X) {
347+
shallow_copy_assign(X);
348+
return *this;
349+
}
350+
~CowCompilerInvocation() = default;
351+
352+
CowCompilerInvocation(const CompilerInvocation &X)
353+
: CompilerInvocationBase(EmptyConstructor{}) {
354+
deep_copy_assign(X);
355+
}
356+
357+
// Const getters are inherited from the base class.
358+
359+
/// Mutable getters.
360+
/// @{
361+
LangOptions &getMutLangOpts();
362+
TargetOptions &getMutTargetOpts();
363+
DiagnosticOptions &getMutDiagnosticOpts();
364+
HeaderSearchOptions &getMutHeaderSearchOpts();
365+
PreprocessorOptions &getMutPreprocessorOpts();
366+
AnalyzerOptions &getMutAnalyzerOpts();
367+
MigratorOptions &getMutMigratorOpts();
368+
CodeGenOptions &getMutCodeGenOpts();
369+
FileSystemOptions &getMutFileSystemOpts();
370+
FrontendOptions &getMutFrontendOpts();
371+
DependencyOutputOptions &getMutDependencyOutputOpts();
372+
PreprocessorOutputOptions &getMutPreprocessorOutputOpts();
373+
/// @}
288374
};
289375

290376
IntrusiveRefCntPtr<llvm::vfs::FileSystem>

0 commit comments

Comments
 (0)