Cache the result of errs() and implement formatted logging.
[oota-llvm.git] / tools / llvm-diff / llvm-diff.cpp
1 #include <string>
2 #include <utility>
3
4 #include <llvm/ADT/StringRef.h>
5 #include <llvm/ADT/SmallVector.h>
6 #include <llvm/ADT/DenseMap.h>
7
8 // Required to parse .ll files.
9 #include <llvm/Support/SourceMgr.h>
10 #include <llvm/Assembly/Parser.h>
11
12 // Required to parse .bc files.
13 #include <llvm/Support/MemoryBuffer.h>
14 #include <llvm/Bitcode/ReaderWriter.h>
15
16 #include <llvm/Support/raw_ostream.h>
17 #include <llvm/Support/ErrorHandling.h>
18 #include <llvm/LLVMContext.h>
19 #include <llvm/Module.h>
20 #include <llvm/Type.h>
21 #include <llvm/Instructions.h>
22
23 #include "DifferenceEngine.h"
24
25 using namespace llvm;
26
27 /// Reads a module from a file.  If the filename ends in .ll, it is
28 /// interpreted as an assembly file;  otherwise, it is interpreted as
29 /// bitcode.  On error, messages are written to stderr and null is
30 /// returned.
31 static Module *ReadModule(LLVMContext &Context, StringRef Name) {
32   // LLVM assembly path.
33   if (Name.endswith(".ll")) {
34     SMDiagnostic Diag;
35     Module *M = ParseAssemblyFile(Name, Diag, Context);
36     if (M) return M;
37
38     Diag.Print("llvmdiff", errs());
39     return 0;
40   }
41
42   // Bitcode path.
43   MemoryBuffer *Buffer = MemoryBuffer::getFile(Name);
44
45   // ParseBitcodeFile takes ownership of the buffer if it succeeds.
46   std::string Error;
47   Module *M = ParseBitcodeFile(Buffer, Context, &Error);
48   if (M) return M;
49
50   errs() << "error parsing " << Name << ": " << Error;
51   delete Buffer;
52   return 0;
53 }
54
55 static int usage() {
56   errs() << "expected usage:\n";
57   errs() << "  llvm-diff oldmodule.ll newmodule.ll [function list]\n";
58   errs() << "Assembly or bitcode modules may be used interchangeably.\n";
59   errs() << "If no functions are provided, all functions will be compared.\n";
60   return 1;
61 }
62
63 namespace {
64 struct DiffContext {
65   DiffContext(Value *L, Value *R)
66     : L(L), R(R), Differences(false), IsFunction(isa<Function>(L)) {}
67   Value *L;
68   Value *R;
69   bool Differences;
70   bool IsFunction;
71   DenseMap<Value*,unsigned> LNumbering;
72   DenseMap<Value*,unsigned> RNumbering;
73 };
74
75 void ComputeNumbering(Function *F, DenseMap<Value*,unsigned> &Numbering) {
76   unsigned BBN = 0;
77   unsigned IN = 0;
78
79   // Arguments get the first numbers.
80   for (Function::arg_iterator
81          AI = F->arg_begin(), AE = F->arg_end(); AI != AE; ++AI)
82     if (!AI->hasName())
83       Numbering[&*AI] = IN++;
84
85   // Walk the basic blocks in order.
86   for (Function::iterator FI = F->begin(), FE = F->end(); FI != FE; ++FI) {
87     // Basic blocks have their own 'namespace'.
88     if (!FI->hasName())
89       Numbering[&*FI] = BBN++;
90
91     // Walk the instructions in order.
92     for (BasicBlock::iterator BI = FI->begin(), BE = FI->end(); BI != BE; ++BI)
93       // void instructions don't get numbers.
94       if (!BI->hasName() && !BI->getType()->isVoidTy())
95         Numbering[&*BI] = IN++;
96   }
97
98   assert(!Numbering.empty() && "asked for numbering but numbering was no-op");
99 }
100
101 class DiffConsumer : public DifferenceEngine::Consumer {
102 private:
103   raw_ostream &out;
104   Module *LModule;
105   Module *RModule;
106   SmallVector<DiffContext, 5> contexts;
107   bool Differences;
108   unsigned Indent;
109
110   void printValue(Value *V, bool isL) {
111     if (V->hasName()) {
112       out << (isa<GlobalValue>(V) ? '@' : '%') << V->getName();
113       return;
114     }
115     if (V->getType()->isVoidTy()) {
116       if (isa<StoreInst>(V)) {
117         out << "store to ";
118         printValue(cast<StoreInst>(V)->getPointerOperand(), isL);
119       } else if (isa<CallInst>(V)) {
120         out << "call to ";
121         printValue(cast<CallInst>(V)->getCalledValue(), isL);
122       } else if (isa<InvokeInst>(V)) {
123         out << "invoke to ";
124         printValue(cast<InvokeInst>(V)->getCalledValue(), isL);
125       } else {
126         out << *V;
127       }
128       return;
129     }
130
131     unsigned N = contexts.size();
132     while (N > 0) {
133       --N;
134       DiffContext &ctxt = contexts[N];
135       if (!ctxt.IsFunction) continue;
136       if (isL) {
137         if (ctxt.LNumbering.empty())
138           ComputeNumbering(cast<Function>(ctxt.L), ctxt.LNumbering);
139         out << '%' << ctxt.LNumbering[V];
140         return;
141       } else {
142         if (ctxt.RNumbering.empty())
143           ComputeNumbering(cast<Function>(ctxt.R), ctxt.RNumbering);
144         out << '%' << ctxt.RNumbering[V];
145         return;
146       }
147     }
148
149     out << "<anonymous>";
150   }
151
152   void header() {
153     if (contexts.empty()) return;
154     for (SmallVectorImpl<DiffContext>::iterator
155            I = contexts.begin(), E = contexts.end(); I != E; ++I) {
156       if (I->Differences) continue;
157       if (isa<Function>(I->L)) {
158         // Extra newline between functions.
159         if (Differences) out << "\n";
160
161         Function *L = cast<Function>(I->L);
162         Function *R = cast<Function>(I->R);
163         if (L->getName() != R->getName())
164           out << "in function " << L->getName() << " / " << R->getName() << ":\n";
165         else
166           out << "in function " << L->getName() << ":\n";
167       } else if (isa<BasicBlock>(I->L)) {
168         BasicBlock *L = cast<BasicBlock>(I->L);
169         BasicBlock *R = cast<BasicBlock>(I->R);
170         out << "  in block ";
171         printValue(L, true);
172         out << " / ";
173         printValue(R, false);
174         out << ":\n";
175       } else if (isa<Instruction>(I->L)) {
176         out << "    in instruction ";
177         printValue(I->L, true);
178         out << " / ";
179         printValue(I->R, false);
180         out << ":\n";
181       }
182
183       I->Differences = true;
184     }
185   }
186
187   void indent() {
188     unsigned N = Indent;
189     while (N--) out << ' ';
190   }
191
192 public:
193   DiffConsumer(Module *L, Module *R)
194     : out(errs()), LModule(L), RModule(R), Differences(false), Indent(0) {}
195
196   bool hadDifferences() const { return Differences; }
197
198   void enterContext(Value *L, Value *R) {
199     contexts.push_back(DiffContext(L, R));
200     Indent += 2;
201   }
202   void exitContext() {
203     Differences |= contexts.back().Differences;
204     contexts.pop_back();
205     Indent -= 2;
206   }
207
208   void log(StringRef text) {
209     header();
210     indent();
211     out << text << '\n';
212   }
213
214   void logf(const DifferenceEngine::LogBuilder &Log) {
215     header();
216     indent();
217
218     unsigned arg = 0;
219
220     StringRef format = Log.getFormat();
221     while (true) {
222       size_t percent = format.find('%');
223       if (percent == StringRef::npos) {
224         out << format;
225         break;
226       }
227       assert(format[percent] == '%');
228
229       if (percent > 0) out << format.substr(0, percent);
230
231       switch (format[percent+1]) {
232       case '%': out << '%'; break;
233       case 'l': printValue(Log.getArgument(arg++), true); break;
234       case 'r': printValue(Log.getArgument(arg++), false); break;
235       default: llvm_unreachable("unknown format character");
236       }
237
238       format = format.substr(percent+2);
239     }
240
241     out << '\n';
242   }
243
244   void logd(const DifferenceEngine::DiffLogBuilder &Log) {
245     header();
246
247     for (unsigned I = 0, E = Log.getNumLines(); I != E; ++I) {
248       indent();
249       switch (Log.getLineKind(I)) {
250       case DifferenceEngine::DC_match:
251         out << "  ";
252         Log.getLeft(I)->dump();
253         //printValue(Log.getLeft(I), true);
254         break;
255       case DifferenceEngine::DC_left:
256         out << "< ";
257         Log.getLeft(I)->dump();
258         //printValue(Log.getLeft(I), true);
259         break;
260       case DifferenceEngine::DC_right:
261         out << "> ";
262         Log.getRight(I)->dump();
263         //printValue(Log.getRight(I), false);
264         break;
265       }
266       //out << "\n";
267     }
268   }
269   
270 };
271 }
272
273 int main(int argc, const char **argv) {
274   if (argc < 3) return usage();
275
276   // Don't make StringRef locals like this at home.
277   StringRef LModuleFile = argv[1];
278   StringRef RModuleFile = argv[2];
279
280   LLVMContext Context;
281   
282   // Load both modules.  Die if that fails.
283   Module *LModule = ReadModule(Context, LModuleFile);
284   Module *RModule = ReadModule(Context, RModuleFile);
285   if (!LModule || !RModule) return 1;
286
287   DiffConsumer Consumer(LModule, RModule);
288   DifferenceEngine Engine(Context, Consumer);
289
290   // If any function names were given, just diff those.
291   const char **FnNames = argv + 3;
292   unsigned NumFnNames = argc - 3;
293   if (NumFnNames) {
294     for (unsigned I = 0; I != NumFnNames; ++I) {
295       StringRef FnName = FnNames[I];
296
297       // Drop leading sigils from the function name.
298       if (FnName.startswith("@")) FnName = FnName.substr(1);
299
300       Function *LFn = LModule->getFunction(FnName);
301       Function *RFn = RModule->getFunction(FnName);
302       if (LFn && RFn)
303         Engine.diff(LFn, RFn);
304       else {
305         if (!LFn && !RFn)
306           errs() << "No function named @" << FnName << " in either module\n";
307         else if (!LFn)
308           errs() << "No function named @" << FnName << " in left module\n";
309         else
310           errs() << "No function named @" << FnName << " in right module\n";
311       }
312     }
313   } else {
314     // Otherwise, diff all functions in the modules.
315     Engine.diff(LModule, RModule);
316   }
317
318   delete LModule;
319   delete RModule;
320
321   return Consumer.hadDifferences();
322 }