3f6f3d86ce08db3a7dd4af0db42d706eb5398183
[oota-llvm.git] / tools / llvm-bcanalyzer / llvm-bcanalyzer.cpp
1 //===-- llvm-bcanalyzer.cpp - Byte Code Analyzer --------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file was developed by Reid Spencer and is distributed under the
6 // University of Illinois Open Source License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This tool may be invoked in the following manner:
11 //  llvm-bcanalyzer [options]      - Read LLVM bytecode from stdin
12 //  llvm-bcanalyzer [options] x.bc - Read LLVM bytecode from the x.bc file
13 //
14 //  Options:
15 //      --help      - Output information about command line switches
16 //      --nodetails - Don't print out detailed informaton about individual
17 //                    blocks and functions
18 //      --dump      - Dump low-level bytecode structure in readable format
19 //
20 // This tool provides analytical information about a bytecode file. It is
21 // intended as an aid to developers of bytecode reading and writing software. It
22 // produces on std::out a summary of the bytecode file that shows various
23 // statistics about the contents of the file. By default this information is
24 // detailed and contains information about individual bytecode blocks and the
25 // functions in the module. To avoid this more detailed output, use the
26 // -nodetails option to limit the output to just module level information.
27 // The tool is also able to print a bytecode file in a straight forward text
28 // format that shows the containment and relationships of the information in
29 // the bytecode file (-dump option).
30 //
31 //===----------------------------------------------------------------------===//
32
33 #include "llvm/Analysis/Verifier.h"
34 #include "llvm/Bitcode/BitstreamReader.h"
35 #include "llvm/Bitcode/LLVMBitCodes.h"
36 #include "llvm/Bytecode/Analyzer.h"
37 #include "llvm/Support/CommandLine.h"
38 #include "llvm/Support/Compressor.h"
39 #include "llvm/Support/ManagedStatic.h"
40 #include "llvm/Support/MemoryBuffer.h"
41 #include "llvm/System/Signals.h"
42 #include <fstream>
43 #include <iostream>
44 using namespace llvm;
45
46 static cl::opt<std::string>
47   InputFilename(cl::Positional, cl::desc("<input bytecode>"), cl::init("-"));
48
49 static cl::opt<std::string>
50   OutputFilename("-o", cl::init("-"), cl::desc("<output file>"));
51
52 static cl::opt<bool> NoDetails("nodetails", cl::desc("Skip detailed output"));
53 static cl::opt<bool> Dump("dump", cl::desc("Dump low level bytecode trace"));
54 static cl::opt<bool> Verify("verify", cl::desc("Progressively verify module"));
55
56 //===----------------------------------------------------------------------===//
57 // Bitcode specific analysis.
58 //===----------------------------------------------------------------------===//
59
60 static cl::opt<bool> Bitcode("bitcode", cl::desc("Read a bitcode file"));
61
62 /// CurStreamType - If we can sniff the flavor of this stream, we can produce 
63 /// better dump info.
64 static enum {
65   UnknownBitstream,
66   LLVMIRBitstream
67 } CurStreamType;
68
69
70 /// GetBlockName - Return a symbolic block name if known, otherwise return
71 /// empty.
72 static const char *GetBlockName(unsigned BlockID) {
73   if (CurStreamType != LLVMIRBitstream) return "";
74   
75   switch (BlockID) {
76   default:                          return "<unknown LLVM IR block ID>";
77   case bitc::MODULE_BLOCK_ID:       return "MODULE_BLOCK";
78   case bitc::TYPE_BLOCK_ID:         return "TYPE_BLOCK";
79   case bitc::CONSTANTS_BLOCK_ID:    return "CONSTANTS_BLOCK";
80   case bitc::FUNCTION_BLOCK_ID:     return "FUNCTION_BLOCK";
81   case bitc::TYPE_SYMTAB_BLOCK_ID:  return "TYPE_SYMTAB";
82   case bitc::VALUE_SYMTAB_BLOCK_ID: return "VALUE_SYMTAB";
83   }
84 }
85
86
87 struct PerBlockIDStats {
88   /// NumInstances - This the number of times this block ID has been seen.
89   unsigned NumInstances;
90   
91   /// NumBits - The total size in bits of all of these blocks.
92   uint64_t NumBits;
93   
94   /// NumSubBlocks - The total number of blocks these blocks contain.
95   unsigned NumSubBlocks;
96   
97   /// NumAbbrevs - The total number of abbreviations.
98   unsigned NumAbbrevs;
99   
100   /// NumRecords - The total number of records these blocks contain, and the 
101   /// number that are abbreviated.
102   unsigned NumRecords, NumAbbreviatedRecords;
103   
104   PerBlockIDStats()
105     : NumInstances(0), NumBits(0),
106       NumSubBlocks(0), NumAbbrevs(0), NumRecords(0), NumAbbreviatedRecords(0) {}
107 };
108
109 static std::map<unsigned, PerBlockIDStats> BlockIDStats;
110
111
112
113 /// Error - All bitcode analysis errors go through this function, making this a
114 /// good place to breakpoint if debugging.
115 static bool Error(const std::string &Err) {
116   std::cerr << Err << "\n";
117   return true;
118 }
119
120 /// ParseBlock - Read a block, updating statistics, etc.
121 static bool ParseBlock(BitstreamReader &Stream) {
122   uint64_t BlockBitStart = Stream.GetCurrentBitNo();
123   
124   unsigned BlockID = Stream.ReadSubBlockID();
125   
126   // Get the statistics for this BlockID.
127   PerBlockIDStats &BlockStats = BlockIDStats[BlockID];
128   
129   BlockStats.NumInstances++;
130   
131   if (Stream.EnterSubBlock())
132     return Error("Malformed block record");
133
134   SmallVector<uint64_t, 64> Record;
135
136   // Read all the records for this block.
137   while (1) {
138     if (Stream.AtEndOfStream())
139       return Error("Premature end of bitstream");
140
141     // Read the code for this record.
142     unsigned AbbrevID = Stream.ReadCode();
143     switch (AbbrevID) {
144     case bitc::END_BLOCK: {
145       if (Stream.ReadBlockEnd())
146         return Error("Error at end of block");
147       uint64_t BlockBitEnd = Stream.GetCurrentBitNo();
148       BlockStats.NumBits += BlockBitEnd-BlockBitStart;
149       return false;
150     } 
151     case bitc::ENTER_SUBBLOCK:
152       if (ParseBlock(Stream))
153         return true;
154       ++BlockStats.NumSubBlocks;
155       break;
156     case bitc::DEFINE_ABBREV:
157       Stream.ReadAbbrevRecord();
158       ++BlockStats.NumAbbrevs;
159       break;
160     default:
161       ++BlockStats.NumRecords;
162       if (AbbrevID != bitc::UNABBREV_RECORD)
163         ++BlockStats.NumAbbreviatedRecords;
164       
165       Record.clear();
166       unsigned Code = Stream.ReadRecord(AbbrevID, Record);
167       // TODO: Compute per-blockid/code stats.
168       Code = Code;
169       break;
170     }
171   }
172 }
173
174 static void PrintSize(double Bits) {
175   std::cerr << Bits << "b/" << Bits/8 << "B/" << Bits/32 << "W";
176 }
177
178
179 /// AnalyzeBitcode - Analyze the bitcode file specified by InputFilename.
180 static int AnalyzeBitcode() {
181   // Read the input file.
182   MemoryBuffer *Buffer;
183   if (InputFilename == "-")
184     Buffer = MemoryBuffer::getSTDIN();
185   else
186     Buffer = MemoryBuffer::getFile(&InputFilename[0], InputFilename.size());
187
188   if (Buffer == 0)
189     return Error("Error reading '" + InputFilename + "'.");
190   
191   if (Buffer->getBufferSize() & 3)
192     return Error("Bitcode stream should be a multiple of 4 bytes in length");
193   
194   unsigned char *BufPtr = (unsigned char *)Buffer->getBufferStart();
195   BitstreamReader Stream(BufPtr, BufPtr+Buffer->getBufferSize());
196
197   
198   // Read the stream signature.
199   char Signature[6];
200   Signature[0] = Stream.Read(8);
201   Signature[1] = Stream.Read(8);
202   Signature[2] = Stream.Read(4);
203   Signature[3] = Stream.Read(4);
204   Signature[4] = Stream.Read(4);
205   Signature[5] = Stream.Read(4);
206   
207   // Autodetect the file contents, if it is one we know.
208   CurStreamType = UnknownBitstream;
209   if (Signature[0] == 'B' && Signature[1] == 'C' &&
210       Signature[2] == 0x0 && Signature[3] == 0xC &&
211       Signature[4] == 0xE && Signature[5] == 0xD)
212     CurStreamType = LLVMIRBitstream;
213
214   unsigned NumTopBlocks = 0;
215   
216   // Parse the top-level structure.  We only allow blocks at the top-level.
217   while (!Stream.AtEndOfStream()) {
218     unsigned Code = Stream.ReadCode();
219     if (Code != bitc::ENTER_SUBBLOCK)
220       return Error("Invalid record at top-level");
221     
222     if (ParseBlock(Stream))
223       return true;
224     ++NumTopBlocks;
225   }
226   
227   // Print a summary of the read file.
228   std::cerr << "Summary of " << InputFilename << ":\n";
229   std::cerr << "         Total size: ";
230   PrintSize(Buffer->getBufferSize()*8);
231   std::cerr << "\n";
232   std::cerr << "        Stream type: ";
233   switch (CurStreamType) {
234   default: assert(0 && "Unknown bitstream type");
235   case UnknownBitstream: std::cerr << "unknown\n"; break;
236   case LLVMIRBitstream:  std::cerr << "LLVM IR\n"; break;
237   }
238   std::cerr << "  # Toplevel Blocks: " << NumTopBlocks << "\n";
239   std::cerr << "\n";
240
241   // Emit per-block stats.
242   std::cerr << "Per-block Summary:\n";
243   for (std::map<unsigned, PerBlockIDStats>::iterator I = BlockIDStats.begin(),
244        E = BlockIDStats.end(); I != E; ++I) {
245     std::cerr << "  Block ID #" << I->first;
246     const char *BlockName = GetBlockName(I->first);
247     if (BlockName[0])
248       std::cerr << " (" << BlockName << ")";
249     std::cerr << ":\n";
250     
251     const PerBlockIDStats &Stats = I->second;
252     std::cerr << "      Num Instances: " << Stats.NumInstances << "\n";
253     std::cerr << "         Total Size: ";
254     PrintSize(Stats.NumBits);
255     std::cerr << "\n";
256     std::cerr << "       Average Size: ";
257     PrintSize(Stats.NumBits/(double)Stats.NumInstances);
258     std::cerr << "\n";
259     std::cerr << "  Tot/Avg SubBlocks: " << Stats.NumSubBlocks << "/"
260               << Stats.NumSubBlocks/(double)Stats.NumInstances << "\n";
261     std::cerr << "    Tot/Avg Abbrevs: " << Stats.NumAbbrevs << "/"
262               << Stats.NumAbbrevs/(double)Stats.NumInstances << "\n";
263     std::cerr << "    Tot/Avg Records: " << Stats.NumRecords << "/"
264               << Stats.NumRecords/(double)Stats.NumInstances << "\n";
265     std::cerr << "      % Abbrev Recs: " << (Stats.NumAbbreviatedRecords/
266                  (double)Stats.NumRecords)*100 << "\n";
267     std::cerr << "\n";
268   }
269   return 0;
270 }
271
272
273 //===----------------------------------------------------------------------===//
274 // Bytecode specific analysis.
275 //===----------------------------------------------------------------------===//
276
277 int main(int argc, char **argv) {
278   llvm_shutdown_obj X;  // Call llvm_shutdown() on exit.
279   cl::ParseCommandLineOptions(argc, argv, " llvm-bcanalyzer file analyzer\n");
280   
281   sys::PrintStackTraceOnErrorSignal();
282   
283   if (Bitcode)
284     return AnalyzeBitcode();
285     
286   try {
287     std::ostream *Out = &std::cout;  // Default to printing to stdout...
288     std::string ErrorMessage;
289     BytecodeAnalysis bca;
290
291     /// Determine what to generate
292     bca.detailedResults = !NoDetails;
293     bca.progressiveVerify = Verify;
294
295     /// Analyze the bytecode file
296     Module* M = AnalyzeBytecodeFile(InputFilename, bca, 
297                                     Compressor::decompressToNewBuffer,
298                                     &ErrorMessage, (Dump?Out:0));
299
300     // All that bcanalyzer does is write the gathered statistics to the output
301     PrintBytecodeAnalysis(bca,*Out);
302
303     if (M && Verify) {
304       std::string verificationMsg;
305       if (verifyModule(*M, ReturnStatusAction, &verificationMsg))
306         std::cerr << "Final Verification Message: " << verificationMsg << "\n";
307     }
308
309     if (Out != &std::cout) {
310       ((std::ofstream*)Out)->close();
311       delete Out;
312     }
313     return 0;
314   } catch (const std::string& msg) {
315     std::cerr << argv[0] << ": " << msg << "\n";
316   } catch (...) {
317     std::cerr << argv[0] << ": Unexpected unknown exception occurred.\n";
318   }
319   return 1;
320 }