Make the deserialization of macro definitions lazy, so that we can

load identifiers without loading their corresponding macro
definitions. This is likely to improve PCH performance slightly, and
reduces deserialization stack depth considerably when using
preprocessor metaprogramming.

llvm-svn: 117750
This commit is contained in:
Douglas Gregor 2010-10-30 00:23:06 +00:00
parent 6a16b2f10c
commit 5ef9e33137
6 changed files with 93 additions and 3 deletions

View File

@ -71,7 +71,7 @@ class IdentifierInfo {
void operator=(const IdentifierInfo&); // NONASSIGNABLE.
friend class IdentifierTable;
public:
IdentifierInfo();

View File

@ -27,6 +27,9 @@ public:
/// \brief Read the set of macros defined by this external macro source.
virtual void ReadDefinedMacros() = 0;
/// \brief Read the definition for the given macro.
virtual void LoadMacroDefinition(IdentifierInfo *II) = 0;
};
}

View File

@ -262,6 +262,8 @@ private: // Cached tokens state.
/// allocation.
MacroInfoChain *MICache;
MacroInfo *getInfoForMacro(IdentifierInfo *II) const;
public:
Preprocessor(Diagnostic &diags, const LangOptions &opts,
const TargetInfo &target,
@ -335,7 +337,10 @@ public:
/// getMacroInfo - Given an identifier, return the MacroInfo it is #defined to
/// or null if it isn't #define'd.
MacroInfo *getMacroInfo(IdentifierInfo *II) const {
return II->hasMacroDefinition() ? Macros.find(II)->second : 0;
if (!II->hasMacroDefinition())
return 0;
return getInfoForMacro(II);
}
/// setMacroInfo - Specify a macro for this identifier.

View File

@ -488,6 +488,11 @@ private:
/// \brief The macro definitions we have already loaded.
llvm::SmallVector<MacroDefinition *, 16> MacroDefinitionsLoaded;
/// \brief Mapping from identifiers that represent macros whose definitions
/// have not yet been deserialized to the global offset where the macro
/// record resides.
llvm::DenseMap<IdentifierInfo *, uint64_t> UnreadMacroRecordOffsets;
/// \name CodeGen-relevant special data
/// \brief Fields containing data that is relevant to CodeGen.
//@{
@ -1145,9 +1150,22 @@ public:
/// \brief Reads the macro record located at the given offset.
void ReadMacroRecord(PerFileData &F, uint64_t Offset);
/// \brief Note that the identifier is a macro whose record will be loaded
/// from the given AST file at the given (file-local) offset.
void SetIdentifierIsMacro(IdentifierInfo *II, PerFileData &F,
uint64_t Offset);
/// \brief Read the set of macros defined by this external macro source.
virtual void ReadDefinedMacros();
/// \brief Read the macro definition for this identifier.
virtual void LoadMacroDefinition(IdentifierInfo *II);
/// \brief Read the macro definition corresponding to this iterator
/// into the unread macro record offsets table.
void LoadMacroDefinition(
llvm::DenseMap<IdentifierInfo *, uint64_t>::iterator Pos);
/// \brief Retrieve the macro definition with the given ID.
MacroDefinition *getMacroDefinition(serialization::MacroID ID);

View File

@ -20,12 +20,27 @@
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/LexDiagnostic.h"
#include "clang/Lex/CodeCompletionHandler.h"
#include "clang/Lex/ExternalPreprocessorSource.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/raw_ostream.h"
#include <cstdio>
#include <ctime>
using namespace clang;
MacroInfo *Preprocessor::getInfoForMacro(IdentifierInfo *II) const {
assert(II->hasMacroDefinition() && "Identifier is not a macro!");
llvm::DenseMap<IdentifierInfo*, MacroInfo*>::const_iterator Pos
= Macros.find(II);
if (Pos == Macros.end()) {
// Load this macro from the external source.
getExternalSource()->LoadMacroDefinition(II);
Pos = Macros.find(II);
}
assert(Pos != Macros.end() && "Identifier macro info is missing!");
return Pos->second;
}
/// setMacroInfo - Specify a macro for this identifier.
///
void Preprocessor::setMacroInfo(IdentifierInfo *II, MacroInfo *MI) {

View File

@ -682,7 +682,7 @@ public:
// definition.
if (hasMacroDefinition) {
uint32_t Offset = ReadUnalignedLE32(d);
Reader.ReadMacroRecord(F, Offset);
Reader.SetIdentifierIsMacro(II, F, Offset);
DataLen -= 4;
}
@ -1568,6 +1568,22 @@ void ASTReader::ReadMacroRecord(PerFileData &F, uint64_t Offset) {
}
}
void ASTReader::SetIdentifierIsMacro(IdentifierInfo *II, PerFileData &F,
uint64_t Offset) {
// Note that this identifier has a macro definition.
II->setHasMacroDefinition(true);
// Adjust the offset based on our position in the chain.
for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
if (Chain[I] == &F)
break;
Offset += Chain[I]->SizeInBits;
}
UnreadMacroRecordOffsets[II] = Offset;
}
void ASTReader::ReadDefinedMacros() {
for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
PerFileData &F = *Chain[N - I - 1];
@ -1629,6 +1645,39 @@ void ASTReader::ReadDefinedMacros() {
}
}
}
// Drain the unread macro-record offsets map.
while (!UnreadMacroRecordOffsets.empty())
LoadMacroDefinition(UnreadMacroRecordOffsets.begin());
}
void ASTReader::LoadMacroDefinition(
llvm::DenseMap<IdentifierInfo *, uint64_t>::iterator Pos) {
assert(Pos != UnreadMacroRecordOffsets.end() && "Unknown macro definition");
PerFileData *F = 0;
uint64_t Offset = Pos->second;
UnreadMacroRecordOffsets.erase(Pos);
for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
if (Offset < Chain[I]->SizeInBits) {
F = Chain[I];
break;
}
Offset -= Chain[I]->SizeInBits;
}
if (!F) {
Error("Malformed macro record offset");
return;
}
ReadMacroRecord(*F, Offset);
}
void ASTReader::LoadMacroDefinition(IdentifierInfo *II) {
llvm::DenseMap<IdentifierInfo *, uint64_t>::iterator Pos
= UnreadMacroRecordOffsets.find(II);
LoadMacroDefinition(Pos);
}
MacroDefinition *ASTReader::getMacroDefinition(MacroID ID) {