Skip to content

Commit fda1104

Browse files
committed
[clang] Introduce copy-on-write CompilerInvocation (llvm#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 4a493d1 commit fda1104

File tree

6 files changed

+316
-86
lines changed

6 files changed

+316
-86
lines changed

clang/include/clang/Basic/CodeGenOptions.h

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

3738
public:
3839
#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: 164 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -120,14 +120,23 @@ class CompilerInvocationBase {
120120
/// Options controlling preprocessed output.
121121
std::shared_ptr<PreprocessorOutputOptions> PreprocessorOutputOpts;
122122

123-
public:
123+
/// Dummy tag type whose instance can be passed into the constructor to
124+
/// prevent creation of the reference-counted option objects.
125+
struct EmptyConstructor {};
126+
124127
CompilerInvocationBase();
125-
CompilerInvocationBase(const CompilerInvocationBase &X) { operator=(X); }
128+
CompilerInvocationBase(EmptyConstructor) {}
129+
CompilerInvocationBase(const CompilerInvocationBase &X) = delete;
126130
CompilerInvocationBase(CompilerInvocationBase &&X) = default;
127-
CompilerInvocationBase &operator=(const CompilerInvocationBase &X);
131+
CompilerInvocationBase &operator=(const CompilerInvocationBase &X) = delete;
132+
CompilerInvocationBase &deep_copy_assign(const CompilerInvocationBase &X);
133+
CompilerInvocationBase &shallow_copy_assign(const CompilerInvocationBase &X);
128134
CompilerInvocationBase &operator=(CompilerInvocationBase &&X) = default;
129135
~CompilerInvocationBase() = default;
130136

137+
public:
138+
/// Const getters.
139+
/// @{
131140
const LangOptions &getLangOpts() const { return *LangOpts; }
132141
const TargetOptions &getTargetOpts() const { return *TargetOpts; }
133142
const DiagnosticOptions &getDiagnosticOpts() const { return *DiagnosticOpts; }
@@ -146,7 +155,118 @@ class CompilerInvocationBase {
146155
const PreprocessorOutputOptions &getPreprocessorOutputOpts() const {
147156
return *PreprocessorOutputOpts;
148157
}
158+
/// @}
159+
160+
/// Command line generation.
161+
/// @{
162+
using StringAllocator = llvm::function_ref<const char *(const Twine &)>;
163+
/// Generate cc1-compatible command line arguments from this instance.
164+
///
165+
/// \param [out] Args - The generated arguments. Note that the caller is
166+
/// responsible for inserting the path to the clang executable and "-cc1" if
167+
/// desired.
168+
/// \param SA - A function that given a Twine can allocate storage for a given
169+
/// command line argument and return a pointer to the newly allocated string.
170+
/// The returned pointer is what gets appended to Args.
171+
void generateCC1CommandLine(llvm::SmallVectorImpl<const char *> &Args,
172+
StringAllocator SA) const {
173+
generateCC1CommandLine([&](const Twine &Arg) {
174+
// No need to allocate static string literals.
175+
Args.push_back(Arg.isSingleStringLiteral()
176+
? Arg.getSingleStringRef().data()
177+
: SA(Arg));
178+
});
179+
}
180+
181+
using ArgumentConsumer = llvm::function_ref<void(const Twine &)>;
182+
/// Generate cc1-compatible command line arguments from this instance.
183+
///
184+
/// \param Consumer - Callback that gets invoked for every single generated
185+
/// command line argument.
186+
void generateCC1CommandLine(ArgumentConsumer Consumer) const;
187+
188+
/// Generate cc1-compatible command line arguments from this instance,
189+
/// wrapping the result as a std::vector<std::string>.
190+
///
191+
/// This is a (less-efficient) wrapper over generateCC1CommandLine().
192+
std::vector<std::string> getCC1CommandLine() const;
193+
194+
private:
195+
/// Generate command line options from DiagnosticOptions.
196+
static void GenerateDiagnosticArgs(const DiagnosticOptions &Opts,
197+
ArgumentConsumer Consumer,
198+
bool DefaultDiagColor);
199+
200+
/// Generate command line options from LangOptions.
201+
static void GenerateLangArgs(const LangOptions &Opts,
202+
ArgumentConsumer Consumer, const llvm::Triple &T,
203+
InputKind IK);
204+
205+
// Generate command line options from CodeGenOptions.
206+
static void GenerateCodeGenArgs(const CodeGenOptions &Opts,
207+
ArgumentConsumer Consumer,
208+
const llvm::Triple &T,
209+
const std::string &OutputFile,
210+
const LangOptions *LangOpts);
211+
/// @}
212+
213+
public:
214+
/// Generate command line options from CASOptions.
215+
static void GenerateCASArgs(const CASOptions &Opts,
216+
ArgumentConsumer Consumer);
217+
static void GenerateCASArgs(const CASOptions &Opts,
218+
SmallVectorImpl<const char *> &Args,
219+
StringAllocator SA) {
220+
GenerateCASArgs(Opts, [&](const Twine &Arg) {
221+
// No need to allocate static string literals.
222+
Args.push_back(Arg.isSingleStringLiteral()
223+
? Arg.getSingleStringRef().data()
224+
: SA(Arg));
225+
});
226+
}
227+
};
228+
229+
/// Helper class for holding the data necessary to invoke the compiler.
230+
///
231+
/// This class is designed to represent an abstract "invocation" of the
232+
/// compiler, including data such as the include paths, the code generation
233+
/// options, the warning flags, and so on.
234+
class CompilerInvocation : public CompilerInvocationBase {
235+
public:
236+
CompilerInvocation() = default;
237+
CompilerInvocation(const CompilerInvocation &X)
238+
: CompilerInvocationBase(EmptyConstructor{}) {
239+
deep_copy_assign(X);
240+
}
241+
CompilerInvocation(CompilerInvocation &&) = default;
242+
CompilerInvocation &operator=(const CompilerInvocation &X) {
243+
deep_copy_assign(X);
244+
return *this;
245+
}
246+
~CompilerInvocation() = default;
149247

248+
/// Const getters.
249+
/// @{
250+
// Note: These need to be pulled in manually. Otherwise, they get hidden by
251+
// the mutable getters with the same names.
252+
using CompilerInvocationBase::getLangOpts;
253+
using CompilerInvocationBase::getTargetOpts;
254+
using CompilerInvocationBase::getDiagnosticOpts;
255+
using CompilerInvocationBase::getHeaderSearchOpts;
256+
using CompilerInvocationBase::getPreprocessorOpts;
257+
using CompilerInvocationBase::getAnalyzerOpts;
258+
using CompilerInvocationBase::getMigratorOpts;
259+
using CompilerInvocationBase::getAPINotesOpts;
260+
using CompilerInvocationBase::getCASOpts;
261+
using CompilerInvocationBase::getCodeGenOpts;
262+
using CompilerInvocationBase::getFileSystemOpts;
263+
using CompilerInvocationBase::getFrontendOpts;
264+
using CompilerInvocationBase::getDependencyOutputOpts;
265+
using CompilerInvocationBase::getPreprocessorOutputOpts;
266+
/// @}
267+
268+
/// Mutable getters.
269+
/// @{
150270
LangOptions &getLangOpts() { return *LangOpts; }
151271
TargetOptions &getTargetOpts() { return *TargetOpts; }
152272
DiagnosticOptions &getDiagnosticOpts() { return *DiagnosticOpts; }
@@ -165,15 +285,8 @@ class CompilerInvocationBase {
165285
PreprocessorOutputOptions &getPreprocessorOutputOpts() {
166286
return *PreprocessorOutputOpts;
167287
}
168-
};
288+
/// @}
169289

170-
/// Helper class for holding the data necessary to invoke the compiler.
171-
///
172-
/// This class is designed to represent an abstract "invocation" of the
173-
/// compiler, including data such as the include paths, the code generation
174-
/// options, the warning flags, and so on.
175-
class CompilerInvocation : public CompilerInvocationBase {
176-
public:
177290
/// Base class internals.
178291
/// @{
179292
using CompilerInvocationBase::LangOpts;
@@ -217,38 +330,6 @@ class CompilerInvocation : public CompilerInvocationBase {
217330
/// identifying the conditions under which the module was built.
218331
std::string getModuleHash(DiagnosticsEngine &Diags) const;
219332

220-
using StringAllocator = llvm::function_ref<const char *(const Twine &)>;
221-
/// Generate cc1-compatible command line arguments from this instance.
222-
///
223-
/// \param [out] Args - The generated arguments. Note that the caller is
224-
/// responsible for inserting the path to the clang executable and "-cc1" if
225-
/// desired.
226-
/// \param SA - A function that given a Twine can allocate storage for a given
227-
/// command line argument and return a pointer to the newly allocated string.
228-
/// The returned pointer is what gets appended to Args.
229-
void generateCC1CommandLine(llvm::SmallVectorImpl<const char *> &Args,
230-
StringAllocator SA) const {
231-
generateCC1CommandLine([&](const Twine &Arg) {
232-
// No need to allocate static string literals.
233-
Args.push_back(Arg.isSingleStringLiteral()
234-
? Arg.getSingleStringRef().data()
235-
: SA(Arg));
236-
});
237-
}
238-
239-
using ArgumentConsumer = llvm::function_ref<void(const Twine &)>;
240-
/// Generate cc1-compatible command line arguments from this instance.
241-
///
242-
/// \param Consumer - Callback that gets invoked for every single generated
243-
/// command line argument.
244-
void generateCC1CommandLine(ArgumentConsumer Consumer) const;
245-
246-
/// Generate cc1-compatible command line arguments from this instance,
247-
/// wrapping the result as a std::vector<std::string>.
248-
///
249-
/// This is a (less-efficient) wrapper over generateCC1CommandLine().
250-
std::vector<std::string> getCC1CommandLine() const;
251-
252333
/// Check that \p Args can be parsed and re-serialized without change,
253334
/// emiting diagnostics for any differences.
254335
///
@@ -272,38 +353,17 @@ class CompilerInvocation : public CompilerInvocationBase {
272353
static bool ParseCASArgs(CASOptions &Opts, const llvm::opt::ArgList &Args,
273354
DiagnosticsEngine &Diags);
274355

275-
/// Generate command line options from CASOptions.
276-
static void GenerateCASArgs(const CASOptions &Opts,
277-
ArgumentConsumer);
278-
static void GenerateCASArgs(const CASOptions &Opts,
279-
SmallVectorImpl<const char *> &Args,
280-
CompilerInvocation::StringAllocator SA) {
281-
GenerateCASArgs(Opts, [&](const Twine &Arg) { Args.push_back(SA(Arg)); });
282-
}
283-
284356
private:
285357
static bool CreateFromArgsImpl(CompilerInvocation &Res,
286358
ArrayRef<const char *> CommandLineArgs,
287359
DiagnosticsEngine &Diags, const char *Argv0);
288360

289-
/// Generate command line options from DiagnosticOptions.
290-
static void GenerateDiagnosticArgs(const DiagnosticOptions &Opts,
291-
ArgumentConsumer Consumer,
292-
bool DefaultDiagColor);
293-
294361
/// Parse command line options that map to LangOptions.
295362
static bool ParseLangArgs(LangOptions &Opts, llvm::opt::ArgList &Args,
296363
InputKind IK, const llvm::Triple &T,
297364
std::vector<std::string> &Includes,
298365
DiagnosticsEngine &Diags);
299366

300-
public:
301-
/// Generate command line options from LangOptions.
302-
static void GenerateLangArgs(const LangOptions &Opts,
303-
ArgumentConsumer Consumer, const llvm::Triple &T,
304-
InputKind IK);
305-
306-
private:
307367
/// Parse command line options that map to CodeGenOptions.
308368
static bool ParseCodeGenArgs(CodeGenOptions &Opts, llvm::opt::ArgList &Args,
309369
InputKind IK, DiagnosticsEngine &Diags,
@@ -313,13 +373,47 @@ class CompilerInvocation : public CompilerInvocationBase {
313373
const FileSystemOptions &FSOpts,
314374
const FrontendOptions &FEOpts,
315375
const CASOptions &CASOpts);
376+
};
316377

317-
// Generate command line options from CodeGenOptions.
318-
static void GenerateCodeGenArgs(const CodeGenOptions &Opts,
319-
ArgumentConsumer Consumer,
320-
const llvm::Triple &T,
321-
const std::string &OutputFile,
322-
const LangOptions *LangOpts);
378+
/// Same as \c CompilerInvocation, but with copy-on-write optimization.
379+
class CowCompilerInvocation : public CompilerInvocationBase {
380+
public:
381+
CowCompilerInvocation() = default;
382+
CowCompilerInvocation(const CowCompilerInvocation &X)
383+
: CompilerInvocationBase(EmptyConstructor{}) {
384+
shallow_copy_assign(X);
385+
}
386+
CowCompilerInvocation(CowCompilerInvocation &&) = default;
387+
CowCompilerInvocation &operator=(const CowCompilerInvocation &X) {
388+
shallow_copy_assign(X);
389+
return *this;
390+
}
391+
~CowCompilerInvocation() = default;
392+
393+
CowCompilerInvocation(const CompilerInvocation &X)
394+
: CompilerInvocationBase(EmptyConstructor{}) {
395+
deep_copy_assign(X);
396+
}
397+
398+
// Const getters are inherited from the base class.
399+
400+
/// Mutable getters.
401+
/// @{
402+
LangOptions &getMutLangOpts();
403+
TargetOptions &getMutTargetOpts();
404+
DiagnosticOptions &getMutDiagnosticOpts();
405+
HeaderSearchOptions &getMutHeaderSearchOpts();
406+
PreprocessorOptions &getMutPreprocessorOpts();
407+
AnalyzerOptions &getMutAnalyzerOpts();
408+
MigratorOptions &getMutMigratorOpts();
409+
APINotesOptions &getMutAPINotesOpts();
410+
CASOptions &getMutCASOpts();
411+
CodeGenOptions &getMutCodeGenOpts();
412+
FileSystemOptions &getMutFileSystemOpts();
413+
FrontendOptions &getMutFrontendOpts();
414+
DependencyOutputOptions &getMutDependencyOutputOpts();
415+
PreprocessorOutputOptions &getMutPreprocessorOutputOpts();
416+
/// @}
323417
};
324418

325419
IntrusiveRefCntPtr<llvm::vfs::FileSystem> createVFSFromCompilerInvocation(

0 commit comments

Comments
 (0)