Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(177)

Side by Side Diff: lib/Bitcode/NaCl/Analysis/NaClBitcodeAnalyzer.cpp

Issue 939073008: Rebased PNaCl localmods in LLVM to 223109 (Closed)
Patch Set: undo localmod Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 //===-- NaClBitcodeAnalyzer.cpp - Bitcode Analyzer ------------------------===//
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 #define DEBUG_TYPE "nacl-bitcode-analyzer"
11
12 #include "llvm/ADT/STLExtras.h"
13 #include "llvm/ADT/Twine.h"
14 #include "llvm/Bitcode/NaCl/NaClAnalyzerBlockDist.h"
15 #include "llvm/Bitcode/NaCl/NaClBitcodeAnalyzer.h"
16 #include "llvm/Bitcode/NaCl/NaClBitcodeHeader.h"
17 #include "llvm/Bitcode/NaCl/NaClBitcodeParser.h"
18 #include "llvm/Bitcode/NaCl/NaClBitstreamReader.h"
19 #include "llvm/Bitcode/NaCl/NaClLLVMBitCodes.h"
20 #include "llvm/Bitcode/NaCl/NaClReaderWriter.h"
21 #include "llvm/Support/Debug.h"
22 #include "llvm/Support/Format.h"
23 #include "llvm/Support/MemoryBuffer.h"
24 #include "llvm/Support/raw_ostream.h"
25 #include <algorithm>
26 #include <map>
27 #include <system_error>
28
29 // TODO(kschimpf): Separate out into two bitcode parsers, one for
30 // dumping records, and one for collecting distribution stats for
31 // printing. This should simplify the code.
32
33 /// Error - All bitcode analysis errors go through this function, making this a
34 /// good place to breakpoint if debugging.
35 static bool Error(const llvm::Twine &Err) {
36 llvm::errs() << Err << "\n";
37 return true;
38 }
39
40 namespace llvm {
41
42 // Parses all bitcode blocks, and collects distribution of records in
43 // each block. Also dumps bitcode structure if specified (via global
44 // variables).
45 class PNaClBitcodeAnalyzerParser : public NaClBitcodeParser {
46 public:
47 PNaClBitcodeAnalyzerParser(NaClBitstreamCursor &Cursor,
48 raw_ostream &OS,
49 const AnalysisDumpOptions &DumpOptions,
50 NaClBitcodeDist *Dist)
51 : NaClBitcodeParser(Cursor),
52 IndentLevel(0),
53 OS(OS),
54 DumpOptions(DumpOptions),
55 Dist(Dist),
56 AbbrevListener(this)
57 {
58 SetListener(&AbbrevListener);
59 }
60
61 virtual ~PNaClBitcodeAnalyzerParser() {}
62
63 virtual bool Error(const std::string &Message) {
64 // Use local error routine so that all errors are treated uniformly.
65 return ::Error(Message);
66 }
67
68 virtual bool ParseBlock(unsigned BlockID);
69
70 // Returns the string defining the indentation to use with respect
71 // to the current indent level.
72 const std::string &GetIndentation() {
73 size_t Size = IndentationCache.size();
74 if (IndentLevel >= Size) {
75 IndentationCache.resize(IndentLevel+1);
76 for (size_t i = Size; i <= IndentLevel; ++i) {
77 IndentationCache[i] = std::string(i*2, ' ');
78 }
79 }
80 return IndentationCache[IndentLevel];
81 }
82
83 // Keeps track of current indentation level based on block nesting.
84 unsigned IndentLevel;
85 // The output stream to print to.
86 raw_ostream &OS;
87 // The dump options to use.
88 const AnalysisDumpOptions &DumpOptions;
89 // The bitcode distribution map (if defined) to update.
90 NaClBitcodeDist *Dist;
91
92 private:
93 // The set of cached, indentation strings. Used for indenting
94 // records when dumping.
95 std::vector<std::string> IndentationCache;
96 // Listener used to get abbreviations as they are read.
97 NaClBitcodeParserListener AbbrevListener;
98 };
99
100 // Parses a bitcode block, and collects distribution of records in that block.
101 // Also dumps bitcode structure if specified (via global variables).
102 class PNaClBitcodeAnalyzerBlockParser : public NaClBitcodeParser {
103 public:
104 // Parses top-level block.
105 PNaClBitcodeAnalyzerBlockParser(
106 unsigned BlockID,
107 PNaClBitcodeAnalyzerParser *Parser)
108 : NaClBitcodeParser(BlockID, Parser) {
109 Initialize(BlockID, Parser);
110 }
111
112 virtual ~PNaClBitcodeAnalyzerBlockParser() {
113 if (Context->Dist) Context->Dist->AddBlock(GetBlock());
114 }
115
116 // *****************************************************
117 // This subsection Defines an XML generator for the dump.
118 // Tag. TagName, Attribute
119 // *****************************************************
120
121 private:
122 // The tag name for an element.
123 std::string TagName;
124 // The number of attributes associated with a tag.
125 unsigned NumTagAttributes;
126 // The number of (indexed attribute) operands associated with a tag.
127 unsigned NumTagOperands;
128
129 protected:
130
131 /// Initializes internal data used to emit an XML tag.
132 void InitializeEmitTag() {
133 TagName.clear();
134 NumTagAttributes = 0;
135 NumTagOperands = 0;
136 }
137
138 /// Emits the start of an XML start tag.
139 void EmitBeginStartTag() {
140 InitializeEmitTag();
141 Context->OS << Indent << "<";
142 }
143
144 /// Emit the start of an XML end tag.
145 void EmitBeginEndTag() {
146 InitializeEmitTag();
147 Context->OS << Indent << "</";
148 }
149
150 /// Emits the end of an empty-element XML tag.
151 void EmitEndTag() {
152 Context->OS << "/>\n";
153 }
154
155 /// Emits the End of a start/end tag for an XML element.
156 void EmitEndElementTag() {
157 Context->OS << ">\n";
158 }
159
160 /// Emits the tag name for an XML tag.
161 void EmitTagName(const std::string &ElmtName) {
162 TagName = ElmtName;
163 Context->OS << ElmtName;
164 }
165
166 /// Emits the "name=" portion of an XML tag attribute.
167 raw_ostream &EmitAttributePrefix(const std::string &AttributeName) {
168 WrapOperandsLine();
169 Context->OS << " " << AttributeName << "=";
170 ++NumTagAttributes;
171 return Context->OS;
172 }
173
174 /// Emits a string-valued XML attribute of an XML tag.
175 void EmitStringAttribute(const char *AttributeName, const std::string &Str) {
176 EmitAttributePrefix(AttributeName) << "'" << Str << "'";
177 }
178
179 /// Emits a string-valued XML attribute of an XML tag.
180 void EmitStringAttribute(const char *AttributeName, const char*Str) {
181 std::string StrStr(Str);
182 EmitStringAttribute(AttributeName, StrStr);
183 }
184
185 /// Emits an unsigned integer-valued XML attribute of an XML tag.
186 void EmitAttribute(const char *AttributeName, uint64_t Value) {
187 EmitAttributePrefix(AttributeName) << Value;
188 }
189
190 /// Emits the "opN=" portion of an XML tag (indexable) operand attribute.
191 raw_ostream &EmitOperandPrefix() {
192 std::string OpName;
193 raw_string_ostream OpNameStrm(OpName);
194 OpNameStrm << "op" << NumTagOperands;
195 ++NumTagOperands;
196 return EmitAttributePrefix(OpNameStrm.str());
197 }
198
199 /// Adds line wrap if more than "OpsPerLine" XML tag attributes are
200 /// emitted on the current line.
201 void WrapOperandsLine() {
202 if (Context->DumpOptions.OpsPerLine) {
203 if (NumTagAttributes &&
204 (NumTagAttributes % Context->DumpOptions.OpsPerLine) == 0) {
205 raw_ostream &OS = Context->OS;
206 // Last operand crossed width boundary, add newline and indent.
207 OS << "\n" << Indent << " ";
208 for (unsigned J = 0, SZ = TagName.size(); J < SZ; ++J)
209 OS << " ";
210 }
211 }
212 }
213
214 // ********************************************************
215 // This section defines how to parse the block and generate
216 // the corresponding XML.
217 // ********************************************************
218
219 // Parses nested blocks.
220 PNaClBitcodeAnalyzerBlockParser(
221 unsigned BlockID,
222 PNaClBitcodeAnalyzerBlockParser *EnclosingBlock)
223 : NaClBitcodeParser(BlockID, EnclosingBlock),
224 Context(EnclosingBlock->Context) {
225 Initialize(BlockID, EnclosingBlock->Context);
226 }
227
228 // Initialize data associated with a block.
229 void Initialize(unsigned BlockID, PNaClBitcodeAnalyzerParser *Parser) {
230 InitializeEmitTag();
231 Context = Parser;
232 if (Context->DumpOptions.DumpRecords) {
233 Indent = Parser->GetIndentation();
234 }
235 NumWords = 0;
236 }
237
238 // Increment the indentation level for dumping.
239 void IncrementIndent() {
240 Context->IndentLevel++;
241 Indent = Context->GetIndentation();
242 }
243
244 // Increment the indentation level for dumping.
245 void DecrementIndent() {
246 Context->IndentLevel--;
247 Indent = Context->GetIndentation();
248 }
249
250 virtual bool Error(const std::string &Message) {
251 // Use local error routine so that all errors are treated uniformly.
252 return ::Error(Message);
253 }
254
255 // Called once the block has been entered by the bitstream reader.
256 // Argument NumWords is set to the number of words in the
257 // corresponding block.
258 virtual void EnterBlock(unsigned NumberWords) {
259 NumWords = NumberWords;
260 if (Context->DumpOptions.DumpRecords) {
261 unsigned BlockID = GetBlockID();
262 EmitBeginStartTag();
263 EmitEnterBlockTagName(BlockID);
264 if (Context->DumpOptions.DumpDetails) {
265 EmitAttribute("NumWords", NumWords);
266 EmitAttribute("BlockCodeSize", Record.GetCursor().getAbbrevIDWidth());
267 }
268 if (!Context->DumpOptions.DumpDetails &&
269 naclbitc::BLOCKINFO_BLOCK_ID == GetBlockID()) {
270 EmitEndTag();
271 } else {
272 EmitEndElementTag();
273 IncrementIndent();
274 }
275 }
276 }
277
278 // Called when the corresponding EndBlock of the block being parsed
279 // is found.
280 virtual void ExitBlock() {
281 if (Context->DumpOptions.DumpRecords) {
282 if (!Context->DumpOptions.DumpDetails &&
283 naclbitc::BLOCKINFO_BLOCK_ID == GetBlockID())
284 return;
285 DecrementIndent();
286 EmitBeginEndTag();
287 EmitExitBlockTagName(Record.GetBlockID());
288 EmitEndElementTag();
289 }
290 }
291
292 virtual void SetBID() {
293 if (!(Context->DumpOptions.DumpRecords &&
294 Context->DumpOptions.DumpDetails)) {
295 return;
296 }
297 EmitBeginStartTag();
298 EmitCodeTagName(naclbitc::BLOCKINFO_CODE_SETBID,
299 naclbitc::BLOCKINFO_BLOCK_ID);
300 EmitStringAttribute("block",
301 NaClBitcodeBlockDist::GetName(Record.GetValues()[0]));
302 EmitEndTag();
303 }
304
305 virtual void ProcessAbbreviation(unsigned BlockID,
306 NaClBitCodeAbbrev *Abbrev,
307 bool IsLocal) {
308 if (Context->DumpOptions.DumpDetails) {
309 EmitAbbreviation(Abbrev);
310 }
311 }
312
313 // Process the last read record in the block.
314 virtual void ProcessRecord() {
315 // Increment the # occurrences of this code.
316 if (Context->Dist) Context->Dist->AddRecord(Record);
317
318 if (Context->DumpOptions.DumpRecords) {
319 EmitBeginStartTag();
320 EmitCodeTagName(Record.GetCode(), GetBlockID(), Record.GetEntryID());
321 const NaClBitcodeRecord::RecordVector &Values = Record.GetValues();
322 for (unsigned i = 0, e = Values.size(); i != e; ++i) {
323 EmitOperandPrefix() << (int64_t)Values[i];
324 }
325 EmitEndTag();
326 }
327 }
328
329 virtual bool ParseBlock(unsigned BlockID) {
330 PNaClBitcodeAnalyzerBlockParser Parser(BlockID, this);
331 return Parser.ParseThisBlock();
332 }
333
334 private:
335 /// Defines the indent level of the block being parsed.
336 std::string Indent;
337 /// Defines the number of (32-bit) words the block occupies in
338 /// the bitstream.
339 unsigned NumWords;
340 /// Refers to global parsing context.
341 PNaClBitcodeAnalyzerParser *Context;
342
343 protected:
344
345 /// Emit the given abbreviation as an XML tag.
346 void EmitAbbreviation(const NaClBitCodeAbbrev *Abbrev) {
347 EmitBeginStartTag();
348 EmitTagName("DEFINE_ABBREV");
349 if (Context->DumpOptions.DumpDetails) {
350 EmitStringAttribute("abbrev", "DEFINE_ABBREV");
351 }
352 for (unsigned I = 0, IEnd = Abbrev->getNumOperandInfos(); I != IEnd; ++I) {
353 EmitAbbreviationOp(Abbrev->getOperandInfo(I));
354 }
355 EmitEndTag();
356 }
357
358 /// Emit the given abbreviation operand as an XML tag attribute.
359 void EmitAbbreviationOp(const NaClBitCodeAbbrevOp &Op) {
360 EmitOperandPrefix()
361 << "'" << NaClBitCodeAbbrevOp::getEncodingName(Op.getEncoding());
362 if (Op.hasValue()) {
363 Context->OS << "(" << Op.getValue() << ")";
364 }
365 Context->OS << "'";
366 }
367
368 /// Emits the symbolic name of the record code as the XML tag name.
369 void EmitCodeTagName(
370 unsigned CodeID, unsigned BlockID,
371 unsigned AbbreviationID = naclbitc::UNABBREV_RECORD) {
372 EmitTagName(NaClBitcodeCodeDist::GetCodeName(CodeID, BlockID));
373 if (Context->DumpOptions.DumpDetails) {
374 if (AbbreviationID == naclbitc::UNABBREV_RECORD) {
375 EmitStringAttribute("abbrev", "UNABBREVIATED");
376 } else {
377 EmitAttribute("abbrev", AbbreviationID);
378 }
379 }
380 }
381
382 /// Emits the symbolic name of the block as the XML tag name.
383 void EmitEnterBlockTagName(unsigned BlockID) {
384 EmitTagName(NaClBitcodeBlockDist::GetName(BlockID));
385 if (Context->DumpOptions.DumpDetails)
386 EmitStringAttribute("abbrev", "ENTER_SUBBLOCK");
387 }
388
389 /// Emits the symbolic name of the block as the the XML tag name.
390 void EmitExitBlockTagName(unsigned BlockID) {
391 EmitTagName(NaClBitcodeBlockDist::GetName(BlockID));
392 if (Context->DumpOptions.DumpDetails)
393 EmitStringAttribute("abbrev", "END_BLOCK");
394 }
395 };
396
397 bool PNaClBitcodeAnalyzerParser::ParseBlock(unsigned BlockID) {
398 PNaClBitcodeAnalyzerBlockParser Parser(BlockID, this);
399 return Parser.ParseThisBlock();
400 }
401
402 static void PrintSize(uint64_t Bits, raw_ostream &OS) {
403 OS << format("%lub/%.2fB/%luW", (unsigned long)Bits,
404 (double)Bits/8, (unsigned long)(Bits/32));
405 }
406
407 int AnalyzeBitcodeInBuffer(const std::unique_ptr<MemoryBuffer> &Buf,
408 raw_ostream &OS,
409 const AnalysisDumpOptions &DumpOptions) {
410 DEBUG(dbgs() << "-> AnalyzeBitcodeInBuffer\n");
411
412 if (Buf->getBufferSize() & 3)
413 return Error("Bitcode stream should be a multiple of 4 bytes in length");
414
415 const unsigned char *BufPtr = (const unsigned char *)Buf->getBufferStart();
416 const unsigned char *EndBufPtr = BufPtr + Buf->getBufferSize();
417
418 NaClBitcodeHeader Header;
419 if (Header.Read(BufPtr, EndBufPtr))
420 return Error("Invalid PNaCl bitcode header");
421
422 if (!Header.IsSupported())
423 errs() << "Warning: " << Header.Unsupported() << "\n";
424
425 if (!Header.IsReadable())
426 Error("Bitcode file is not readable");
427
428 NaClBitstreamReader StreamFile(BufPtr, EndBufPtr);
429 NaClBitstreamCursor Stream(StreamFile);
430
431 unsigned NumTopBlocks = 0;
432
433 // Print out header information.
434 for (size_t i = 0, limit = Header.NumberFields(); i < limit; ++i) {
435 OS << Header.GetField(i)->Contents() << "\n";
436 }
437 if (Header.NumberFields()) OS << "\n";
438
439 // Parse the top-level structure. We only allow blocks at the top-level.
440 NaClAnalyzerBlockDistElement DistSentinel(0, DumpOptions.OrderBlocksByID);
441 NaClAnalyzerBlockDist Dist(DistSentinel);
442 PNaClBitcodeAnalyzerParser Parser(Stream, OS, DumpOptions, &Dist);
443 while (!Stream.AtEndOfStream()) {
444 ++NumTopBlocks;
445 if (Parser.Parse()) return 1;
446 }
447
448 if (DumpOptions.DumpRecords) return 0;
449
450 uint64_t BufferSizeBits = (EndBufPtr-BufPtr)*CHAR_BIT;
451 // Print a summary
452 OS << "Total size: ";
453 PrintSize(BufferSizeBits, OS);
454 OS << "\n";
455 OS << "# Toplevel Blocks: " << NumTopBlocks << "\n";
456 OS << "\n";
457
458 if (Parser.Dist) Parser.Dist->Print(OS);
459
460 DEBUG(dbgs() << "<- AnalyzeBitcode\n");
461 return 0;
462 }
463
464 int AnalyzeBitcodeInFile(const StringRef &InputFilename, raw_ostream &OS,
465 const AnalysisDumpOptions &DumpOptions) {
466 ErrorOr<std::unique_ptr<MemoryBuffer>> ErrOrFile =
467 MemoryBuffer::getFileOrSTDIN(InputFilename);
468 if (std::error_code EC = ErrOrFile.getError())
469 return Error(Twine("Error reading '") + InputFilename + "': " +
470 EC.message());
471
472 return AnalyzeBitcodeInBuffer(ErrOrFile.get(), OS, DumpOptions);
473 }
474
475 } // namespace llvm
OLDNEW
« no previous file with comments | « lib/Bitcode/NaCl/Analysis/NaClBitcodeAbbrevDist.cpp ('k') | lib/Bitcode/NaCl/Analysis/NaClBitcodeBitsAndAbbrevsDist.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698