Skip to content

Commit 6a11557

Browse files
committed
[clang][modules] Avoid storing command-line macro definitions into implicitly built PCM files
With implicit modules, it's impossible to load a PCM file that was built using different command-line macro definitions. This is guaranteed by the fact that they contribute to the context hash. This means that we don't need to store those macros into PCM files for validation purposes. This patch avoids serializing them in those circumstances, since there's no other use for command-line macro definitions (besides "-module-file-info"). For a typical Apple project, this speeds up the dependency scan by 5.6% and shrinks the cache with scanning PCMs by 26%. Reviewed By: benlangmuir Differential Revision: https://reviews.llvm.org/D158136
1 parent 2041611 commit 6a11557

File tree

8 files changed

+148
-121
lines changed

8 files changed

+148
-121
lines changed

clang/include/clang/Serialization/ASTReader.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ class ASTReaderListener {
199199
/// \returns true to indicate the preprocessor options are invalid, or false
200200
/// otherwise.
201201
virtual bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts,
202-
bool Complain,
202+
bool ReadMacros, bool Complain,
203203
std::string &SuggestedPredefines) {
204204
return false;
205205
}
@@ -274,7 +274,7 @@ class ChainedASTReaderListener : public ASTReaderListener {
274274
StringRef SpecificModuleCachePath,
275275
bool Complain) override;
276276
bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts,
277-
bool Complain,
277+
bool ReadMacros, bool Complain,
278278
std::string &SuggestedPredefines) override;
279279

280280
void ReadCounter(const serialization::ModuleFile &M, unsigned Value) override;
@@ -304,7 +304,8 @@ class PCHValidator : public ASTReaderListener {
304304
bool AllowCompatibleDifferences) override;
305305
bool ReadDiagnosticOptions(IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts,
306306
bool Complain) override;
307-
bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts, bool Complain,
307+
bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts,
308+
bool ReadMacros, bool Complain,
308309
std::string &SuggestedPredefines) override;
309310
bool ReadHeaderSearchOptions(const HeaderSearchOptions &HSOpts,
310311
StringRef SpecificModuleCachePath,
@@ -325,7 +326,8 @@ class SimpleASTReaderListener : public ASTReaderListener {
325326
public:
326327
SimpleASTReaderListener(Preprocessor &PP) : PP(PP) {}
327328

328-
bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts, bool Complain,
329+
bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts,
330+
bool ReadMacros, bool Complain,
329331
std::string &SuggestedPredefines) override;
330332
};
331333

clang/include/clang/Serialization/ASTWriter.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,11 @@ class ASTWriter : public ASTDeserializationListener,
143143
/// file is up to date, but not otherwise.
144144
bool IncludeTimestamps;
145145

146+
/// Indicates whether the AST file being written is an implicit module.
147+
/// If that's the case, we may be able to skip writing some information that
148+
/// are guaranteed to be the same in the importer by the context hash.
149+
bool BuildingImplicitModule = false;
150+
146151
/// Indicates when the AST writing is actively performing
147152
/// serialization, rather than just queueing updates.
148153
bool WritingAST = false;
@@ -571,7 +576,7 @@ class ASTWriter : public ASTDeserializationListener,
571576
ASTWriter(llvm::BitstreamWriter &Stream, SmallVectorImpl<char> &Buffer,
572577
InMemoryModuleCache &ModuleCache,
573578
ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions,
574-
bool IncludeTimestamps = true);
579+
bool IncludeTimestamps = true, bool BuildingImplicitModule = false);
575580
~ASTWriter() override;
576581

577582
ASTContext &getASTContext() const {
@@ -809,6 +814,7 @@ class PCHGenerator : public SemaConsumer {
809814
std::shared_ptr<PCHBuffer> Buffer,
810815
ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions,
811816
bool AllowASTWithErrors = false, bool IncludeTimestamps = true,
817+
bool BuildingImplicitModule = false,
812818
bool ShouldCacheASTInMemory = false);
813819
~PCHGenerator() override;
814820

clang/lib/Frontend/ASTUnit.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -581,7 +581,8 @@ class ASTInfoCollector : public ASTReaderListener {
581581
return false;
582582
}
583583

584-
bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts, bool Complain,
584+
bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts,
585+
bool ReadMacros, bool Complain,
585586
std::string &SuggestedPredefines) override {
586587
this->PPOpts = PPOpts;
587588
return false;

clang/lib/Frontend/FrontendActions.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,8 @@ GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
141141
CI.getPreprocessor(), CI.getModuleCache(), OutputFile, Sysroot, Buffer,
142142
FrontendOpts.ModuleFileExtensions,
143143
CI.getPreprocessorOpts().AllowPCHWithCompilerErrors,
144-
FrontendOpts.IncludeTimestamps, +CI.getLangOpts().CacheGeneratedPCH));
144+
FrontendOpts.IncludeTimestamps, FrontendOpts.BuildingImplicitModule,
145+
+CI.getLangOpts().CacheGeneratedPCH));
145146
Consumers.push_back(CI.getPCHContainerWriter().CreatePCHContainerGenerator(
146147
CI, std::string(InFile), OutputFile, std::move(OS), Buffer));
147148

@@ -204,6 +205,7 @@ GenerateModuleAction::CreateASTConsumer(CompilerInstance &CI,
204205
/*IncludeTimestamps=*/
205206
+CI.getFrontendOpts().BuildingImplicitModule &&
206207
+CI.getFrontendOpts().IncludeTimestamps,
208+
/*BuildingImplicitModule=*/+CI.getFrontendOpts().BuildingImplicitModule,
207209
/*ShouldCacheASTInMemory=*/
208210
+CI.getFrontendOpts().BuildingImplicitModule));
209211
Consumers.push_back(CI.getPCHContainerWriter().CreatePCHContainerGenerator(
@@ -660,15 +662,15 @@ namespace {
660662
}
661663

662664
bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts,
663-
bool Complain,
665+
bool ReadMacros, bool Complain,
664666
std::string &SuggestedPredefines) override {
665667
Out.indent(2) << "Preprocessor options:\n";
666668
DUMP_BOOLEAN(PPOpts.UsePredefines,
667669
"Uses compiler/target-specific predefines [-undef]");
668670
DUMP_BOOLEAN(PPOpts.DetailedRecord,
669671
"Uses detailed preprocessing record (for indexing)");
670672

671-
if (!PPOpts.Macros.empty()) {
673+
if (ReadMacros) {
672674
Out.indent(4) << "Predefined macros:\n";
673675
}
674676

clang/lib/Serialization/ASTReader.cpp

Lines changed: 99 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -208,11 +208,12 @@ bool ChainedASTReaderListener::ReadHeaderSearchOptions(
208208
}
209209

210210
bool ChainedASTReaderListener::ReadPreprocessorOptions(
211-
const PreprocessorOptions &PPOpts, bool Complain,
211+
const PreprocessorOptions &PPOpts, bool ReadMacros, bool Complain,
212212
std::string &SuggestedPredefines) {
213-
return First->ReadPreprocessorOptions(PPOpts, Complain,
213+
return First->ReadPreprocessorOptions(PPOpts, ReadMacros, Complain,
214214
SuggestedPredefines) ||
215-
Second->ReadPreprocessorOptions(PPOpts, Complain, SuggestedPredefines);
215+
Second->ReadPreprocessorOptions(PPOpts, ReadMacros, Complain,
216+
SuggestedPredefines);
216217
}
217218

218219
void ChainedASTReaderListener::ReadCounter(const serialization::ModuleFile &M,
@@ -658,92 +659,95 @@ enum OptionValidation {
658659
/// are no differences in the options between the two.
659660
static bool checkPreprocessorOptions(
660661
const PreprocessorOptions &PPOpts,
661-
const PreprocessorOptions &ExistingPPOpts, DiagnosticsEngine *Diags,
662-
FileManager &FileMgr, std::string &SuggestedPredefines,
663-
const LangOptions &LangOpts,
662+
const PreprocessorOptions &ExistingPPOpts, bool ReadMacros,
663+
DiagnosticsEngine *Diags, FileManager &FileMgr,
664+
std::string &SuggestedPredefines, const LangOptions &LangOpts,
664665
OptionValidation Validation = OptionValidateContradictions) {
665-
// Check macro definitions.
666-
MacroDefinitionsMap ASTFileMacros;
667-
collectMacroDefinitions(PPOpts, ASTFileMacros);
668-
MacroDefinitionsMap ExistingMacros;
669-
SmallVector<StringRef, 4> ExistingMacroNames;
670-
collectMacroDefinitions(ExistingPPOpts, ExistingMacros, &ExistingMacroNames);
671-
672-
// Use a line marker to enter the <command line> file, as the defines and
673-
// undefines here will have come from the command line.
674-
SuggestedPredefines += "# 1 \"<command line>\" 1\n";
675-
676-
for (unsigned I = 0, N = ExistingMacroNames.size(); I != N; ++I) {
677-
// Dig out the macro definition in the existing preprocessor options.
678-
StringRef MacroName = ExistingMacroNames[I];
679-
std::pair<StringRef, bool> Existing = ExistingMacros[MacroName];
680-
681-
// Check whether we know anything about this macro name or not.
682-
llvm::StringMap<std::pair<StringRef, bool /*IsUndef*/>>::iterator Known =
683-
ASTFileMacros.find(MacroName);
684-
if (Validation == OptionValidateNone || Known == ASTFileMacros.end()) {
685-
if (Validation == OptionValidateStrictMatches) {
686-
// If strict matches are requested, don't tolerate any extra defines on
687-
// the command line that are missing in the AST file.
666+
if (ReadMacros) {
667+
// Check macro definitions.
668+
MacroDefinitionsMap ASTFileMacros;
669+
collectMacroDefinitions(PPOpts, ASTFileMacros);
670+
MacroDefinitionsMap ExistingMacros;
671+
SmallVector<StringRef, 4> ExistingMacroNames;
672+
collectMacroDefinitions(ExistingPPOpts, ExistingMacros,
673+
&ExistingMacroNames);
674+
675+
// Use a line marker to enter the <command line> file, as the defines and
676+
// undefines here will have come from the command line.
677+
SuggestedPredefines += "# 1 \"<command line>\" 1\n";
678+
679+
for (unsigned I = 0, N = ExistingMacroNames.size(); I != N; ++I) {
680+
// Dig out the macro definition in the existing preprocessor options.
681+
StringRef MacroName = ExistingMacroNames[I];
682+
std::pair<StringRef, bool> Existing = ExistingMacros[MacroName];
683+
684+
// Check whether we know anything about this macro name or not.
685+
llvm::StringMap<std::pair<StringRef, bool /*IsUndef*/>>::iterator Known =
686+
ASTFileMacros.find(MacroName);
687+
if (Validation == OptionValidateNone || Known == ASTFileMacros.end()) {
688+
if (Validation == OptionValidateStrictMatches) {
689+
// If strict matches are requested, don't tolerate any extra defines
690+
// on the command line that are missing in the AST file.
691+
if (Diags) {
692+
Diags->Report(diag::err_pch_macro_def_undef) << MacroName << true;
693+
}
694+
return true;
695+
}
696+
// FIXME: Check whether this identifier was referenced anywhere in the
697+
// AST file. If so, we should reject the AST file. Unfortunately, this
698+
// information isn't in the control block. What shall we do about it?
699+
700+
if (Existing.second) {
701+
SuggestedPredefines += "#undef ";
702+
SuggestedPredefines += MacroName.str();
703+
SuggestedPredefines += '\n';
704+
} else {
705+
SuggestedPredefines += "#define ";
706+
SuggestedPredefines += MacroName.str();
707+
SuggestedPredefines += ' ';
708+
SuggestedPredefines += Existing.first.str();
709+
SuggestedPredefines += '\n';
710+
}
711+
continue;
712+
}
713+
714+
// If the macro was defined in one but undef'd in the other, we have a
715+
// conflict.
716+
if (Existing.second != Known->second.second) {
688717
if (Diags) {
689-
Diags->Report(diag::err_pch_macro_def_undef) << MacroName << true;
718+
Diags->Report(diag::err_pch_macro_def_undef)
719+
<< MacroName << Known->second.second;
690720
}
691721
return true;
692722
}
693-
// FIXME: Check whether this identifier was referenced anywhere in the
694-
// AST file. If so, we should reject the AST file. Unfortunately, this
695-
// information isn't in the control block. What shall we do about it?
696-
697-
if (Existing.second) {
698-
SuggestedPredefines += "#undef ";
699-
SuggestedPredefines += MacroName.str();
700-
SuggestedPredefines += '\n';
701-
} else {
702-
SuggestedPredefines += "#define ";
703-
SuggestedPredefines += MacroName.str();
704-
SuggestedPredefines += ' ';
705-
SuggestedPredefines += Existing.first.str();
706-
SuggestedPredefines += '\n';
723+
724+
// If the macro was #undef'd in both, or if the macro bodies are
725+
// identical, it's fine.
726+
if (Existing.second || Existing.first == Known->second.first) {
727+
ASTFileMacros.erase(Known);
728+
continue;
707729
}
708-
continue;
709-
}
710730

711-
// If the macro was defined in one but undef'd in the other, we have a
712-
// conflict.
713-
if (Existing.second != Known->second.second) {
731+
// The macro bodies differ; complain.
714732
if (Diags) {
715-
Diags->Report(diag::err_pch_macro_def_undef)
716-
<< MacroName << Known->second.second;
733+
Diags->Report(diag::err_pch_macro_def_conflict)
734+
<< MacroName << Known->second.first << Existing.first;
717735
}
718736
return true;
719737
}
720738

721-
// If the macro was #undef'd in both, or if the macro bodies are identical,
722-
// it's fine.
723-
if (Existing.second || Existing.first == Known->second.first) {
724-
ASTFileMacros.erase(Known);
725-
continue;
726-
}
727-
728-
// The macro bodies differ; complain.
729-
if (Diags) {
730-
Diags->Report(diag::err_pch_macro_def_conflict)
731-
<< MacroName << Known->second.first << Existing.first;
732-
}
733-
return true;
734-
}
735-
736-
// Leave the <command line> file and return to <built-in>.
737-
SuggestedPredefines += "# 1 \"<built-in>\" 2\n";
739+
// Leave the <command line> file and return to <built-in>.
740+
SuggestedPredefines += "# 1 \"<built-in>\" 2\n";
738741

739-
if (Validation == OptionValidateStrictMatches) {
740-
// If strict matches are requested, don't tolerate any extra defines in
741-
// the AST file that are missing on the command line.
742-
for (const auto &MacroName : ASTFileMacros.keys()) {
743-
if (Diags) {
744-
Diags->Report(diag::err_pch_macro_def_undef) << MacroName << false;
742+
if (Validation == OptionValidateStrictMatches) {
743+
// If strict matches are requested, don't tolerate any extra defines in
744+
// the AST file that are missing on the command line.
745+
for (const auto &MacroName : ASTFileMacros.keys()) {
746+
if (Diags) {
747+
Diags->Report(diag::err_pch_macro_def_undef) << MacroName << false;
748+
}
749+
return true;
745750
}
746-
return true;
747751
}
748752
}
749753

@@ -805,24 +809,22 @@ static bool checkPreprocessorOptions(
805809
}
806810

807811
bool PCHValidator::ReadPreprocessorOptions(const PreprocessorOptions &PPOpts,
808-
bool Complain,
812+
bool ReadMacros, bool Complain,
809813
std::string &SuggestedPredefines) {
810814
const PreprocessorOptions &ExistingPPOpts = PP.getPreprocessorOpts();
811815

812-
return checkPreprocessorOptions(PPOpts, ExistingPPOpts,
813-
Complain? &Reader.Diags : nullptr,
814-
PP.getFileManager(),
815-
SuggestedPredefines,
816-
PP.getLangOpts());
816+
return checkPreprocessorOptions(
817+
PPOpts, ExistingPPOpts, ReadMacros, Complain ? &Reader.Diags : nullptr,
818+
PP.getFileManager(), SuggestedPredefines, PP.getLangOpts());
817819
}
818820

819821
bool SimpleASTReaderListener::ReadPreprocessorOptions(
820-
const PreprocessorOptions &PPOpts,
821-
bool Complain,
822-
std::string &SuggestedPredefines) {
823-
return checkPreprocessorOptions(PPOpts, PP.getPreprocessorOpts(), nullptr,
824-
PP.getFileManager(), SuggestedPredefines,
825-
PP.getLangOpts(), OptionValidateNone);
822+
const PreprocessorOptions &PPOpts, bool ReadMacros, bool Complain,
823+
std::string &SuggestedPredefines) {
824+
return checkPreprocessorOptions(PPOpts, PP.getPreprocessorOpts(), ReadMacros,
825+
nullptr, PP.getFileManager(),
826+
SuggestedPredefines, PP.getLangOpts(),
827+
OptionValidateNone);
826828
}
827829

828830
/// Check the header search options deserialized from the control block
@@ -5274,10 +5276,10 @@ namespace {
52745276
}
52755277

52765278
bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts,
5277-
bool Complain,
5279+
bool ReadMacros, bool Complain,
52785280
std::string &SuggestedPredefines) override {
52795281
return checkPreprocessorOptions(
5280-
PPOpts, ExistingPPOpts, /*Diags=*/nullptr, FileMgr,
5282+
PPOpts, ExistingPPOpts, ReadMacros, /*Diags=*/nullptr, FileMgr,
52815283
SuggestedPredefines, ExistingLangOpts,
52825284
StrictOptionMatches ? OptionValidateStrictMatches
52835285
: OptionValidateContradictions);
@@ -6048,10 +6050,13 @@ bool ASTReader::ParsePreprocessorOptions(const RecordData &Record,
60486050
unsigned Idx = 0;
60496051

60506052
// Macro definitions/undefs
6051-
for (unsigned N = Record[Idx++]; N; --N) {
6052-
std::string Macro = ReadString(Record, Idx);
6053-
bool IsUndef = Record[Idx++];
6054-
PPOpts.Macros.push_back(std::make_pair(Macro, IsUndef));
6053+
bool ReadMacros = Record[Idx++];
6054+
if (ReadMacros) {
6055+
for (unsigned N = Record[Idx++]; N; --N) {
6056+
std::string Macro = ReadString(Record, Idx);
6057+
bool IsUndef = Record[Idx++];
6058+
PPOpts.Macros.push_back(std::make_pair(Macro, IsUndef));
6059+
}
60556060
}
60566061

60576062
// Includes
@@ -6070,7 +6075,7 @@ bool ASTReader::ParsePreprocessorOptions(const RecordData &Record,
60706075
PPOpts.ObjCXXARCStandardLibrary =
60716076
static_cast<ObjCXXARCStandardLibraryKind>(Record[Idx++]);
60726077
SuggestedPredefines.clear();
6073-
return Listener.ReadPreprocessorOptions(PPOpts, Complain,
6078+
return Listener.ReadPreprocessorOptions(PPOpts, ReadMacros, Complain,
60746079
SuggestedPredefines);
60756080
}
60766081

0 commit comments

Comments
 (0)