blob: c64797ec3835aee01dc3ebe0e232e15b746032de [file] [log] [blame]
Ted Kremenek85888962008-10-21 00:54:44 +00001//===--- CacheTokens.cpp - Caching of lexer tokens for PCH support --------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This provides a possible implementation of PCH support for Clang that is
11// based on caching lexed tokens and identifiers.
12//
13//===----------------------------------------------------------------------===//
14
15#include "clang.h"
16#include "clang/Basic/FileManager.h"
17#include "clang/Basic/SourceManager.h"
18#include "clang/Basic/IdentifierTable.h"
19#include "clang/Basic/Diagnostic.h"
20#include "clang/Lex/Lexer.h"
21#include "clang/Lex/Preprocessor.h"
Ted Kremenekbe295332009-01-08 02:44:06 +000022#include "llvm/ADT/StringMap.h"
Ted Kremenek85888962008-10-21 00:54:44 +000023#include "llvm/Support/MemoryBuffer.h"
24#include "llvm/Support/raw_ostream.h"
Ted Kremenekfc7e2ea2008-12-02 19:44:08 +000025#include "llvm/System/Path.h"
Ted Kremenekb978c662009-01-08 01:17:37 +000026#include "llvm/Support/Compiler.h"
Ted Kremenek72b1b152009-01-15 18:47:46 +000027#include "llvm/Support/Streams.h"
Ted Kremenek85888962008-10-21 00:54:44 +000028
29using namespace clang;
30
Ted Kremenekfc7e2ea2008-12-02 19:44:08 +000031typedef uint32_t Offset;
32
Ted Kremenekbe295332009-01-08 02:44:06 +000033namespace {
34class VISIBILITY_HIDDEN PCHEntry {
35 Offset TokenData, PPCondData;
Ted Kremenekbe295332009-01-08 02:44:06 +000036
37public:
38 PCHEntry() {}
39
Ted Kremenek277faca2009-01-27 00:01:05 +000040 PCHEntry(Offset td, Offset ppcd)
41 : TokenData(td), PPCondData(ppcd) {}
Ted Kremenekbe295332009-01-08 02:44:06 +000042
Ted Kremenek277faca2009-01-27 00:01:05 +000043 Offset getTokenOffset() const { return TokenData; }
Ted Kremenekbe295332009-01-08 02:44:06 +000044 Offset getPPCondTableOffset() const { return PPCondData; }
Ted Kremenek277faca2009-01-27 00:01:05 +000045};
Ted Kremenekbe295332009-01-08 02:44:06 +000046
Ted Kremenek277faca2009-01-27 00:01:05 +000047class OffsetOpt {
48 bool valid;
49 Offset off;
50public:
51 OffsetOpt() : valid(false) {}
52 bool hasOffset() const { return valid; }
53 Offset getOffset() const { assert(valid); return off; }
54 void setOffset(Offset o) { off = o; valid = true; }
Ted Kremenekbe295332009-01-08 02:44:06 +000055};
56} // end anonymous namespace
57
58typedef llvm::DenseMap<const FileEntry*, PCHEntry> PCHMap;
Ted Kremenekfc7e2ea2008-12-02 19:44:08 +000059typedef llvm::DenseMap<const IdentifierInfo*,uint32_t> IDMap;
Ted Kremenek277faca2009-01-27 00:01:05 +000060typedef llvm::StringMap<OffsetOpt, llvm::BumpPtrAllocator> CachedStrsTy;
Ted Kremenek85888962008-10-21 00:54:44 +000061
Ted Kremenekb978c662009-01-08 01:17:37 +000062namespace {
63class VISIBILITY_HIDDEN PTHWriter {
64 IDMap IM;
65 llvm::raw_fd_ostream& Out;
66 Preprocessor& PP;
67 uint32_t idcount;
68 PCHMap PM;
Ted Kremenekbe295332009-01-08 02:44:06 +000069 CachedStrsTy CachedStrs;
Ted Kremenek277faca2009-01-27 00:01:05 +000070 Offset CurStrOffset;
71 std::vector<llvm::StringMapEntry<OffsetOpt>*> StrEntries;
Ted Kremenek8f174e12008-12-23 02:52:12 +000072
Ted Kremenekb978c662009-01-08 01:17:37 +000073 //// Get the persistent id for the given IdentifierInfo*.
74 uint32_t ResolveID(const IdentifierInfo* II);
Ted Kremenekfc7e2ea2008-12-02 19:44:08 +000075
Ted Kremenekb978c662009-01-08 01:17:37 +000076 /// Emit a token to the PTH file.
77 void EmitToken(const Token& T);
78
79 void Emit8(uint32_t V) {
80 Out << (unsigned char)(V);
81 }
82
83 void Emit16(uint32_t V) {
84 Out << (unsigned char)(V);
85 Out << (unsigned char)(V >> 8);
86 assert((V >> 16) == 0);
87 }
88
89 void Emit24(uint32_t V) {
90 Out << (unsigned char)(V);
91 Out << (unsigned char)(V >> 8);
92 Out << (unsigned char)(V >> 16);
93 assert((V >> 24) == 0);
94 }
95
96 void Emit32(uint32_t V) {
97 Out << (unsigned char)(V);
98 Out << (unsigned char)(V >> 8);
99 Out << (unsigned char)(V >> 16);
100 Out << (unsigned char)(V >> 24);
101 }
102
103 void EmitBuf(const char* I, const char* E) {
104 for ( ; I != E ; ++I) Out << *I;
105 }
106
Ted Kremenek293b4af2009-01-15 01:26:25 +0000107 std::pair<Offset,std::pair<Offset, Offset> > EmitIdentifierTable();
Ted Kremenekb978c662009-01-08 01:17:37 +0000108 Offset EmitFileTable();
Ted Kremenekbe295332009-01-08 02:44:06 +0000109 PCHEntry LexTokens(Lexer& L);
Ted Kremenek277faca2009-01-27 00:01:05 +0000110 Offset EmitCachedSpellings();
Ted Kremenekbe295332009-01-08 02:44:06 +0000111
Ted Kremenekb978c662009-01-08 01:17:37 +0000112public:
113 PTHWriter(llvm::raw_fd_ostream& out, Preprocessor& pp)
Ted Kremenek277faca2009-01-27 00:01:05 +0000114 : Out(out), PP(pp), idcount(0), CurStrOffset(0) {}
Ted Kremenekb978c662009-01-08 01:17:37 +0000115
116 void GeneratePTH();
117};
118} // end anonymous namespace
119
120uint32_t PTHWriter::ResolveID(const IdentifierInfo* II) {
Ted Kremenekfc7e2ea2008-12-02 19:44:08 +0000121 // Null IdentifierInfo's map to the persistent ID 0.
122 if (!II)
123 return 0;
124
Ted Kremenek85888962008-10-21 00:54:44 +0000125 IDMap::iterator I = IM.find(II);
126
127 if (I == IM.end()) {
Ted Kremenekb978c662009-01-08 01:17:37 +0000128 IM[II] = ++idcount; // Pre-increment since '0' is reserved for NULL.
129 return idcount;
Ted Kremenek85888962008-10-21 00:54:44 +0000130 }
131
Ted Kremenekfc7e2ea2008-12-02 19:44:08 +0000132 return I->second; // We've already added 1.
Ted Kremenek85888962008-10-21 00:54:44 +0000133}
134
Ted Kremenekb978c662009-01-08 01:17:37 +0000135void PTHWriter::EmitToken(const Token& T) {
Ted Kremenek7b78b7c2009-01-19 23:13:15 +0000136 Emit32(((uint32_t) T.getKind()) |
137 (((uint32_t) T.getFlags()) << 8) |
138 (((uint32_t) T.getLength()) << 16));
Ted Kremenek277faca2009-01-27 00:01:05 +0000139
Chris Lattner47246be2009-01-26 19:29:26 +0000140 // Literals (strings, numbers, characters) get cached spellings.
141 if (T.isLiteral()) {
142 // FIXME: This uses the slow getSpelling(). Perhaps we do better
143 // in the future? This only slows down PTH generation.
144 const std::string &spelling = PP.getSpelling(T);
145 const char* s = spelling.c_str();
146
147 // Get the string entry.
Ted Kremenek277faca2009-01-27 00:01:05 +0000148 llvm::StringMapEntry<OffsetOpt> *E =
149 &CachedStrs.GetOrCreateValue(s, s+spelling.size());
150
151 if (!E->getValue().hasOffset()) {
152 E->getValue().setOffset(CurStrOffset);
153 StrEntries.push_back(E);
154 CurStrOffset += spelling.size() + 1;
155 }
156
157 Emit32(E->getValue().getOffset());
Ted Kremenekb978c662009-01-08 01:17:37 +0000158 }
Ted Kremenek277faca2009-01-27 00:01:05 +0000159 else
160 Emit32(ResolveID(T.getIdentifierInfo()));
161
Chris Lattner52c29082009-01-27 06:27:13 +0000162 Emit32(PP.getSourceManager().getFileOffset(T.getLocation()));
Ted Kremenek85888962008-10-21 00:54:44 +0000163}
164
Ted Kremenekb978c662009-01-08 01:17:37 +0000165namespace {
166struct VISIBILITY_HIDDEN IDData {
Ted Kremenekfa59aad2008-11-26 23:58:26 +0000167 const IdentifierInfo* II;
168 uint32_t FileOffset;
Ted Kremenek293b4af2009-01-15 01:26:25 +0000169};
170
171class VISIBILITY_HIDDEN CompareIDDataIndex {
172 IDData* Table;
173public:
174 CompareIDDataIndex(IDData* table) : Table(table) {}
175
176 bool operator()(unsigned i, unsigned j) const {
Ted Kremenek72b1b152009-01-15 18:47:46 +0000177 const IdentifierInfo* II_i = Table[i].II;
178 const IdentifierInfo* II_j = Table[j].II;
179
180 unsigned i_len = II_i->getLength();
181 unsigned j_len = II_j->getLength();
182
183 if (i_len > j_len)
184 return false;
185
186 if (i_len < j_len)
187 return true;
188
189 // Otherwise, compare the strings themselves!
190 return strncmp(II_i->getName(), II_j->getName(), i_len) < 0;
Ted Kremenek293b4af2009-01-15 01:26:25 +0000191 }
Ted Kremenekfa59aad2008-11-26 23:58:26 +0000192};
Ted Kremenekb978c662009-01-08 01:17:37 +0000193}
Ted Kremeneka3d764c2008-11-26 03:36:26 +0000194
Ted Kremenek293b4af2009-01-15 01:26:25 +0000195std::pair<Offset,std::pair<Offset,Offset> >
196PTHWriter::EmitIdentifierTable() {
197 llvm::BumpPtrAllocator Alloc;
Ted Kremenekfa59aad2008-11-26 23:58:26 +0000198
199 // Build an inverse map from persistent IDs -> IdentifierInfo*.
Ted Kremenek293b4af2009-01-15 01:26:25 +0000200 IDData* IIDMap = Alloc.Allocate<IDData>(idcount);
Ted Kremenek85888962008-10-21 00:54:44 +0000201
Ted Kremenekfa59aad2008-11-26 23:58:26 +0000202 // Generate mapping from persistent IDs -> IdentifierInfo*.
Ted Kremenekb978c662009-01-08 01:17:37 +0000203 for (IDMap::iterator I=IM.begin(), E=IM.end(); I!=E; ++I) {
Ted Kremenekfc7e2ea2008-12-02 19:44:08 +0000204 // Decrement by 1 because we are using a vector for the lookup and
205 // 0 is reserved for NULL.
206 assert(I->second > 0);
Ted Kremenek293b4af2009-01-15 01:26:25 +0000207 assert(I->second-1 < idcount);
208 unsigned idx = I->second-1;
209 IIDMap[idx].II = I->first;
210 }
Ted Kremenekfa59aad2008-11-26 23:58:26 +0000211
Ted Kremenek293b4af2009-01-15 01:26:25 +0000212 // We want to write out the strings in lexical order to support binary
213 // search of strings to identifiers. Create such a table.
214 unsigned *LexicalOrder = Alloc.Allocate<unsigned>(idcount);
215 for (unsigned i = 0; i < idcount ; ++i ) LexicalOrder[i] = i;
216 std::sort(LexicalOrder, LexicalOrder+idcount, CompareIDDataIndex(IIDMap));
217
218 // Write out the lexically-sorted table of persistent ids.
219 Offset LexicalOff = Out.tell();
220 for (unsigned i = 0; i < idcount ; ++i) Emit32(LexicalOrder[i]);
221
222 // Write out the string data itself.
Ted Kremenekfc7e2ea2008-12-02 19:44:08 +0000223 Offset DataOff = Out.tell();
Ted Kremenek6183e482008-12-03 01:16:39 +0000224
Ted Kremenek293b4af2009-01-15 01:26:25 +0000225 for (unsigned i = 0; i < idcount; ++i) {
226 IDData& d = IIDMap[i];
227 d.FileOffset = Out.tell(); // Record the location for this data.
228 unsigned len = d.II->getLength(); // Write out the string length.
Ted Kremenekb978c662009-01-08 01:17:37 +0000229 Emit32(len);
Ted Kremenek293b4af2009-01-15 01:26:25 +0000230 const char* buf = d.II->getName(); // Write out the string data.
Ted Kremenek72b1b152009-01-15 18:47:46 +0000231 EmitBuf(buf, buf+len);
232 // Emit a null character for those clients expecting that IdentifierInfo
233 // strings are null terminated.
234 Emit8('\0');
Ted Kremenek85888962008-10-21 00:54:44 +0000235 }
Ted Kremeneka3d764c2008-11-26 03:36:26 +0000236
Ted Kremenekfa59aad2008-11-26 23:58:26 +0000237 // Now emit the table mapping from persistent IDs to PTH file offsets.
Ted Kremenekfc7e2ea2008-12-02 19:44:08 +0000238 Offset IDOff = Out.tell();
Ted Kremenek293b4af2009-01-15 01:26:25 +0000239 Emit32(idcount); // Emit the number of identifiers.
240 for (unsigned i = 0 ; i < idcount; ++i) Emit32(IIDMap[i].FileOffset);
Ted Kremenek6183e482008-12-03 01:16:39 +0000241
Ted Kremenek293b4af2009-01-15 01:26:25 +0000242 return std::make_pair(DataOff, std::make_pair(IDOff, LexicalOff));
Ted Kremenek85888962008-10-21 00:54:44 +0000243}
244
Ted Kremenekb978c662009-01-08 01:17:37 +0000245Offset PTHWriter::EmitFileTable() {
246 // Determine the offset where this table appears in the PTH file.
Ted Kremenekfc7e2ea2008-12-02 19:44:08 +0000247 Offset off = (Offset) Out.tell();
Ted Kremenekb978c662009-01-08 01:17:37 +0000248
Ted Kremenekfa59aad2008-11-26 23:58:26 +0000249 // Output the size of the table.
Ted Kremenekb978c662009-01-08 01:17:37 +0000250 Emit32(PM.size());
Ted Kremenekfa59aad2008-11-26 23:58:26 +0000251
252 for (PCHMap::iterator I=PM.begin(), E=PM.end(); I!=E; ++I) {
Ted Kremenekfa59aad2008-11-26 23:58:26 +0000253 const FileEntry* FE = I->first;
Ted Kremenek8dffd9b2008-12-04 22:36:44 +0000254 const char* Name = FE->getName();
255 unsigned size = strlen(Name);
Ted Kremenekb978c662009-01-08 01:17:37 +0000256 Emit32(size);
257 EmitBuf(Name, Name+size);
Ted Kremenekbe295332009-01-08 02:44:06 +0000258 Emit32(I->second.getTokenOffset());
259 Emit32(I->second.getPPCondTableOffset());
Ted Kremenekfa59aad2008-11-26 23:58:26 +0000260 }
261
Ted Kremeneka3d764c2008-11-26 03:36:26 +0000262 return off;
263}
264
Ted Kremenekbe295332009-01-08 02:44:06 +0000265PCHEntry PTHWriter::LexTokens(Lexer& L) {
Ted Kremenek7b78b7c2009-01-19 23:13:15 +0000266 // Pad 0's so that we emit tokens to a 4-byte alignment.
267 // This speed up reading them back in.
268 Offset off = (Offset) Out.tell();
269 for (unsigned Pad = off % 4 ; Pad != 0 ; --Pad, ++off) Emit8(0);
Ted Kremenekfb645b62008-12-11 23:36:38 +0000270
271 // Keep track of matching '#if' ... '#endif'.
272 typedef std::vector<std::pair<Offset, unsigned> > PPCondTable;
273 PPCondTable PPCond;
Ted Kremenekdad7b342008-12-12 18:31:09 +0000274 std::vector<unsigned> PPStartCond;
Ted Kremeneke5680f32008-12-23 01:30:52 +0000275 bool ParsingPreprocessorDirective = false;
Ted Kremeneka3d764c2008-11-26 03:36:26 +0000276 Token Tok;
277
278 do {
279 L.LexFromRawLexer(Tok);
280
Ted Kremeneke5680f32008-12-23 01:30:52 +0000281 if ((Tok.isAtStartOfLine() || Tok.is(tok::eof)) &&
282 ParsingPreprocessorDirective) {
283 // Insert an eom token into the token cache. It has the same
284 // position as the next token that is not on the same line as the
285 // preprocessor directive. Observe that we continue processing
286 // 'Tok' when we exit this branch.
287 Token Tmp = Tok;
288 Tmp.setKind(tok::eom);
289 Tmp.clearFlag(Token::StartOfLine);
290 Tmp.setIdentifierInfo(0);
Ted Kremenekb978c662009-01-08 01:17:37 +0000291 EmitToken(Tmp);
Ted Kremeneke5680f32008-12-23 01:30:52 +0000292 ParsingPreprocessorDirective = false;
293 }
294
Ted Kremeneka3d764c2008-11-26 03:36:26 +0000295 if (Tok.is(tok::identifier)) {
296 Tok.setIdentifierInfo(PP.LookUpIdentifierInfo(Tok));
Ted Kremeneke5680f32008-12-23 01:30:52 +0000297 continue;
Ted Kremeneka3d764c2008-11-26 03:36:26 +0000298 }
Ted Kremeneke5680f32008-12-23 01:30:52 +0000299
300 if (Tok.is(tok::hash) && Tok.isAtStartOfLine()) {
Ted Kremeneka3d764c2008-11-26 03:36:26 +0000301 // Special processing for #include. Store the '#' token and lex
302 // the next token.
Ted Kremeneke5680f32008-12-23 01:30:52 +0000303 assert(!ParsingPreprocessorDirective);
Ted Kremenekfb645b62008-12-11 23:36:38 +0000304 Offset HashOff = (Offset) Out.tell();
Ted Kremenekb978c662009-01-08 01:17:37 +0000305 EmitToken(Tok);
Ted Kremenekdad7b342008-12-12 18:31:09 +0000306
307 // Get the next token.
Ted Kremeneka3d764c2008-11-26 03:36:26 +0000308 L.LexFromRawLexer(Tok);
Ted Kremeneke5680f32008-12-23 01:30:52 +0000309
310 assert(!Tok.isAtStartOfLine());
Ted Kremeneka3d764c2008-11-26 03:36:26 +0000311
312 // Did we see 'include'/'import'/'include_next'?
313 if (!Tok.is(tok::identifier))
314 continue;
315
316 IdentifierInfo* II = PP.LookUpIdentifierInfo(Tok);
317 Tok.setIdentifierInfo(II);
318 tok::PPKeywordKind K = II->getPPKeywordID();
319
Ted Kremeneke5680f32008-12-23 01:30:52 +0000320 assert(K != tok::pp_not_keyword);
321 ParsingPreprocessorDirective = true;
322
323 switch (K) {
324 default:
325 break;
326 case tok::pp_include:
327 case tok::pp_import:
328 case tok::pp_include_next: {
Ted Kremeneka3d764c2008-11-26 03:36:26 +0000329 // Save the 'include' token.
Ted Kremenekb978c662009-01-08 01:17:37 +0000330 EmitToken(Tok);
Ted Kremeneka3d764c2008-11-26 03:36:26 +0000331 // Lex the next token as an include string.
332 L.setParsingPreprocessorDirective(true);
333 L.LexIncludeFilename(Tok);
334 L.setParsingPreprocessorDirective(false);
Ted Kremeneke5680f32008-12-23 01:30:52 +0000335 assert(!Tok.isAtStartOfLine());
Ted Kremeneka3d764c2008-11-26 03:36:26 +0000336 if (Tok.is(tok::identifier))
337 Tok.setIdentifierInfo(PP.LookUpIdentifierInfo(Tok));
Ted Kremeneke5680f32008-12-23 01:30:52 +0000338
339 break;
Ted Kremeneka3d764c2008-11-26 03:36:26 +0000340 }
Ted Kremeneke5680f32008-12-23 01:30:52 +0000341 case tok::pp_if:
342 case tok::pp_ifdef:
343 case tok::pp_ifndef: {
Ted Kremenekfb645b62008-12-11 23:36:38 +0000344 // Ad an entry for '#if' and friends. We initially set the target index
345 // to 0. This will get backpatched when we hit #endif.
346 PPStartCond.push_back(PPCond.size());
Ted Kremenekdad7b342008-12-12 18:31:09 +0000347 PPCond.push_back(std::make_pair(HashOff, 0U));
Ted Kremeneke5680f32008-12-23 01:30:52 +0000348 break;
Ted Kremenekfb645b62008-12-11 23:36:38 +0000349 }
Ted Kremeneke5680f32008-12-23 01:30:52 +0000350 case tok::pp_endif: {
Ted Kremenekfb645b62008-12-11 23:36:38 +0000351 // Add an entry for '#endif'. We set the target table index to itself.
Ted Kremenekdad7b342008-12-12 18:31:09 +0000352 // This will later be set to zero when emitting to the PTH file. We
353 // use 0 for uninitialized indices because that is easier to debug.
Ted Kremenekfb645b62008-12-11 23:36:38 +0000354 unsigned index = PPCond.size();
Ted Kremenekfb645b62008-12-11 23:36:38 +0000355 // Backpatch the opening '#if' entry.
Ted Kremenekdad7b342008-12-12 18:31:09 +0000356 assert(!PPStartCond.empty());
357 assert(PPCond.size() > PPStartCond.back());
Ted Kremenekfb645b62008-12-11 23:36:38 +0000358 assert(PPCond[PPStartCond.back()].second == 0);
359 PPCond[PPStartCond.back()].second = index;
360 PPStartCond.pop_back();
Ted Kremenekdad7b342008-12-12 18:31:09 +0000361 // Add the new entry to PPCond.
362 PPCond.push_back(std::make_pair(HashOff, index));
Ted Kremeneke5680f32008-12-23 01:30:52 +0000363 break;
Ted Kremenekfb645b62008-12-11 23:36:38 +0000364 }
Ted Kremeneke5680f32008-12-23 01:30:52 +0000365 case tok::pp_elif:
366 case tok::pp_else: {
367 // Add an entry for #elif or #else.
Ted Kremenekdad7b342008-12-12 18:31:09 +0000368 // This serves as both a closing and opening of a conditional block.
369 // This means that its entry will get backpatched later.
Ted Kremenekfb645b62008-12-11 23:36:38 +0000370 unsigned index = PPCond.size();
Ted Kremenekfb645b62008-12-11 23:36:38 +0000371 // Backpatch the previous '#if' entry.
Ted Kremenekdad7b342008-12-12 18:31:09 +0000372 assert(!PPStartCond.empty());
373 assert(PPCond.size() > PPStartCond.back());
Ted Kremenekfb645b62008-12-11 23:36:38 +0000374 assert(PPCond[PPStartCond.back()].second == 0);
375 PPCond[PPStartCond.back()].second = index;
376 PPStartCond.pop_back();
377 // Now add '#elif' as a new block opening.
Ted Kremenekdad7b342008-12-12 18:31:09 +0000378 PPCond.push_back(std::make_pair(HashOff, 0U));
379 PPStartCond.push_back(index);
Ted Kremeneke5680f32008-12-23 01:30:52 +0000380 break;
381 }
Ted Kremenekfb645b62008-12-11 23:36:38 +0000382 }
Ted Kremeneka3d764c2008-11-26 03:36:26 +0000383 }
384 }
Ted Kremenekb978c662009-01-08 01:17:37 +0000385 while (EmitToken(Tok), Tok.isNot(tok::eof));
386
Ted Kremenekdad7b342008-12-12 18:31:09 +0000387 assert(PPStartCond.empty() && "Error: imblanced preprocessor conditionals.");
Ted Kremenekb978c662009-01-08 01:17:37 +0000388
Ted Kremenekfb645b62008-12-11 23:36:38 +0000389 // Next write out PPCond.
390 Offset PPCondOff = (Offset) Out.tell();
Ted Kremenekdad7b342008-12-12 18:31:09 +0000391
392 // Write out the size of PPCond so that clients can identifer empty tables.
Ted Kremenekb978c662009-01-08 01:17:37 +0000393 Emit32(PPCond.size());
Ted Kremenekfc7e2ea2008-12-02 19:44:08 +0000394
Ted Kremenekdad7b342008-12-12 18:31:09 +0000395 for (unsigned i = 0, e = PPCond.size(); i!=e; ++i) {
Ted Kremenekb978c662009-01-08 01:17:37 +0000396 Emit32(PPCond[i].first - off);
Ted Kremenekdad7b342008-12-12 18:31:09 +0000397 uint32_t x = PPCond[i].second;
398 assert(x != 0 && "PPCond entry not backpatched.");
399 // Emit zero for #endifs. This allows us to do checking when
400 // we read the PTH file back in.
Ted Kremenekb978c662009-01-08 01:17:37 +0000401 Emit32(x == i ? 0 : x);
Ted Kremenekfb645b62008-12-11 23:36:38 +0000402 }
403
Ted Kremenek277faca2009-01-27 00:01:05 +0000404 return PCHEntry(off, PPCondOff);
Ted Kremenekbe295332009-01-08 02:44:06 +0000405}
406
Ted Kremenek277faca2009-01-27 00:01:05 +0000407Offset PTHWriter::EmitCachedSpellings() {
408 // Write each cached strings to the PTH file.
409 Offset SpellingsOff = Out.tell();
410
411 for (std::vector<llvm::StringMapEntry<OffsetOpt>*>::iterator
412 I = StrEntries.begin(), E = StrEntries.end(); I!=E; ++I) {
Ted Kremenekbe295332009-01-08 02:44:06 +0000413
Ted Kremenek277faca2009-01-27 00:01:05 +0000414 const char* data = (*I)->getKeyData();
415 EmitBuf(data, data + (*I)->getKeyLength());
416 Emit8('\0');
Ted Kremenekbe295332009-01-08 02:44:06 +0000417 }
418
Ted Kremenek277faca2009-01-27 00:01:05 +0000419 return SpellingsOff;
Ted Kremeneka3d764c2008-11-26 03:36:26 +0000420}
Ted Kremenek85888962008-10-21 00:54:44 +0000421
Ted Kremenekb978c662009-01-08 01:17:37 +0000422void PTHWriter::GeneratePTH() {
Ted Kremeneke1b64982009-01-26 21:43:14 +0000423 // Generate the prologue.
424 Out << "cfe-pth";
Ted Kremenek67d15052009-01-26 21:50:21 +0000425 Emit32(PTHManager::Version);
Ted Kremeneke1b64982009-01-26 21:43:14 +0000426 Offset JumpOffset = Out.tell();
427 Emit32(0);
428
Ted Kremenek85888962008-10-21 00:54:44 +0000429 // Iterate over all the files in SourceManager. Create a lexer
430 // for each file and cache the tokens.
Chris Lattnerc6fe32a2009-01-17 03:48:08 +0000431 SourceManager &SM = PP.getSourceManager();
432 const LangOptions &LOpts = PP.getLangOptions();
Ted Kremenek85888962008-10-21 00:54:44 +0000433
Chris Lattnerc6fe32a2009-01-17 03:48:08 +0000434 for (SourceManager::fileinfo_iterator I = SM.fileinfo_begin(),
435 E = SM.fileinfo_end(); I != E; ++I) {
436 const SrcMgr::ContentCache &C = *I;
437 const FileEntry *FE = C.Entry;
Ted Kremenekfc7e2ea2008-12-02 19:44:08 +0000438
439 // FIXME: Handle files with non-absolute paths.
440 llvm::sys::Path P(FE->getName());
441 if (!P.isAbsolute())
442 continue;
Ted Kremenek85888962008-10-21 00:54:44 +0000443
Chris Lattner5c263852009-01-17 03:49:48 +0000444 assert(!PM.count(FE) && "fileinfo's are not uniqued on FileEntry?");
Ted Kremeneka3d764c2008-11-26 03:36:26 +0000445
Chris Lattnerc6fe32a2009-01-17 03:48:08 +0000446 const llvm::MemoryBuffer *B = C.getBuffer();
Ted Kremeneka3d764c2008-11-26 03:36:26 +0000447 if (!B) continue;
Ted Kremenekfb645b62008-12-11 23:36:38 +0000448
Chris Lattner2b2453a2009-01-17 06:22:33 +0000449 FileID FID = SM.createFileID(FE, SourceLocation(), SrcMgr::C_User);
Chris Lattner025c3a62009-01-17 07:35:14 +0000450 Lexer L(FID, SM, LOpts);
Ted Kremenekb978c662009-01-08 01:17:37 +0000451 PM[FE] = LexTokens(L);
Daniel Dunbar31309ab2008-11-26 02:18:33 +0000452 }
Ted Kremeneka3d764c2008-11-26 03:36:26 +0000453
454 // Write out the identifier table.
Ted Kremenek293b4af2009-01-15 01:26:25 +0000455 const std::pair<Offset, std::pair<Offset,Offset> >& IdTableOff
456 = EmitIdentifierTable();
Ted Kremenek85888962008-10-21 00:54:44 +0000457
Ted Kremenekbe295332009-01-08 02:44:06 +0000458 // Write out the cached strings table.
Ted Kremenek277faca2009-01-27 00:01:05 +0000459 Offset SpellingOff = EmitCachedSpellings();
Ted Kremenekbe295332009-01-08 02:44:06 +0000460
Ted Kremeneka3d764c2008-11-26 03:36:26 +0000461 // Write out the file table.
Ted Kremenekb978c662009-01-08 01:17:37 +0000462 Offset FileTableOff = EmitFileTable();
Ted Kremeneka3d764c2008-11-26 03:36:26 +0000463
464 // Finally, write out the offset table at the end.
Ted Kremeneke1b64982009-01-26 21:43:14 +0000465 Offset JumpTargetOffset = Out.tell();
Ted Kremenekb978c662009-01-08 01:17:37 +0000466 Emit32(IdTableOff.first);
Ted Kremenek293b4af2009-01-15 01:26:25 +0000467 Emit32(IdTableOff.second.first);
468 Emit32(IdTableOff.second.second);
Ted Kremenekb978c662009-01-08 01:17:37 +0000469 Emit32(FileTableOff);
Ted Kremenek277faca2009-01-27 00:01:05 +0000470 Emit32(SpellingOff);
Ted Kremeneke1b64982009-01-26 21:43:14 +0000471
472 // Now write the offset in the prologue.
473 Out.seek(JumpOffset);
474 Emit32(JumpTargetOffset);
Ted Kremenekb978c662009-01-08 01:17:37 +0000475}
476
477void clang::CacheTokens(Preprocessor& PP, const std::string& OutFile) {
478 // Lex through the entire file. This will populate SourceManager with
479 // all of the header information.
480 Token Tok;
481 PP.EnterMainSourceFile();
482 do { PP.Lex(Tok); } while (Tok.isNot(tok::eof));
483
484 // Open up the PTH file.
485 std::string ErrMsg;
486 llvm::raw_fd_ostream Out(OutFile.c_str(), true, ErrMsg);
487
488 if (!ErrMsg.empty()) {
489 llvm::errs() << "PTH error: " << ErrMsg << "\n";
490 return;
491 }
492
493 // Create the PTHWriter and generate the PTH file.
494 PTHWriter PW(Out, PP);
495 PW.GeneratePTH();
Ted Kremenek85888962008-10-21 00:54:44 +0000496}