Check in a couple of changes that I apparently never committed:
[oota-llvm.git] / tools / llvm-diff / llvm-diff.cpp
1 //===-- llvm-diff.cpp - Module comparator command-line driver ---*- C++ -*-===//
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 file defines the command-line driver for the difference engine.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "DifferenceEngine.h"
15
16 #include "llvm/Instructions.h"
17 #include "llvm/LLVMContext.h"
18 #include "llvm/Module.h"
19 #include "llvm/Type.h"
20 #include "llvm/Assembly/Parser.h"
21 #include "llvm/Bitcode/ReaderWriter.h"
22 #include "llvm/ADT/DenseMap.h"
23 #include "llvm/ADT/SmallVector.h"
24 #include "llvm/ADT/StringRef.h"
25 #include "llvm/Support/CommandLine.h"
26 #include "llvm/Support/ErrorHandling.h"
27 #include "llvm/Support/MemoryBuffer.h"
28 #include "llvm/Support/raw_ostream.h"
29 #include "llvm/Support/SourceMgr.h"
30
31 #include <string>
32 #include <utility>
33
34
35 using namespace llvm;
36
37 /// Reads a module from a file.  If the filename ends in .ll, it is
38 /// interpreted as an assembly file;  otherwise, it is interpreted as
39 /// bitcode.  On error, messages are written to stderr and null is
40 /// returned.
41 static Module *ReadModule(LLVMContext &Context, StringRef Name) {
42   // LLVM assembly path.
43   if (Name.endswith(".ll")) {
44     SMDiagnostic Diag;
45     Module *M = ParseAssemblyFile(Name, Diag, Context);
46     if (M) return M;
47
48     Diag.Print("llvmdiff", errs());
49     return 0;
50   }
51
52   // Bitcode path.
53   MemoryBuffer *Buffer = MemoryBuffer::getFile(Name);
54
55   // ParseBitcodeFile takes ownership of the buffer if it succeeds.
56   std::string Error;
57   Module *M = ParseBitcodeFile(Buffer, Context, &Error);
58   if (M) return M;
59
60   errs() << "error parsing " << Name << ": " << Error;
61   delete Buffer;
62   return 0;
63 }
64
65 namespace {
66 struct DiffContext {
67   DiffContext(Value *L, Value *R)
68     : L(L), R(R), Differences(false), IsFunction(isa<Function>(L)) {}
69   Value *L;
70   Value *R;
71   bool Differences;
72   bool IsFunction;
73   DenseMap<Value*,unsigned> LNumbering;
74   DenseMap<Value*,unsigned> RNumbering;
75 };
76
77 void ComputeNumbering(Function *F, DenseMap<Value*,unsigned> &Numbering) {
78   unsigned IN = 0;
79
80   // Arguments get the first numbers.
81   for (Function::arg_iterator
82          AI = F->arg_begin(), AE = F->arg_end(); AI != AE; ++AI)
83     if (!AI->hasName())
84       Numbering[&*AI] = IN++;
85
86   // Walk the basic blocks in order.
87   for (Function::iterator FI = F->begin(), FE = F->end(); FI != FE; ++FI) {
88     if (!FI->hasName())
89       Numbering[&*FI] = IN++;
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()
165               << " / " << R->getName() << ":\n";
166         else
167           out << "in function " << L->getName() << ":\n";
168       } else if (isa<BasicBlock>(I->L)) {
169         BasicBlock *L = cast<BasicBlock>(I->L);
170         BasicBlock *R = cast<BasicBlock>(I->R);
171         if (L->hasName() && R->hasName() && L->getName() == R->getName())
172           out << "  in block %" << L->getName() << ":\n";
173         else {
174           out << "  in block ";
175           printValue(L, true);
176           out << " / ";
177           printValue(R, false);
178           out << ":\n";
179         }
180       } else if (isa<Instruction>(I->L)) {
181         out << "    in instruction ";
182         printValue(I->L, true);
183         out << " / ";
184         printValue(I->R, false);
185         out << ":\n";
186       }
187
188       I->Differences = true;
189     }
190   }
191
192   void indent() {
193     unsigned N = Indent;
194     while (N--) out << ' ';
195   }
196
197 public:
198   DiffConsumer(Module *L, Module *R)
199     : out(errs()), LModule(L), RModule(R), Differences(false), Indent(0) {}
200
201   bool hadDifferences() const { return Differences; }
202
203   void enterContext(Value *L, Value *R) {
204     contexts.push_back(DiffContext(L, R));
205     Indent += 2;
206   }
207   void exitContext() {
208     Differences |= contexts.back().Differences;
209     contexts.pop_back();
210     Indent -= 2;
211   }
212
213   void log(StringRef text) {
214     header();
215     indent();
216     out << text << '\n';
217   }
218
219   void logf(const DifferenceEngine::LogBuilder &Log) {
220     header();
221     indent();
222
223     unsigned arg = 0;
224
225     StringRef format = Log.getFormat();
226     while (true) {
227       size_t percent = format.find('%');
228       if (percent == StringRef::npos) {
229         out << format;
230         break;
231       }
232       assert(format[percent] == '%');
233
234       if (percent > 0) out << format.substr(0, percent);
235
236       switch (format[percent+1]) {
237       case '%': out << '%'; break;
238       case 'l': printValue(Log.getArgument(arg++), true); break;
239       case 'r': printValue(Log.getArgument(arg++), false); break;
240       default: llvm_unreachable("unknown format character");
241       }
242
243       format = format.substr(percent+2);
244     }
245
246     out << '\n';
247   }
248
249   void logd(const DifferenceEngine::DiffLogBuilder &Log) {
250     header();
251
252     for (unsigned I = 0, E = Log.getNumLines(); I != E; ++I) {
253       indent();
254       switch (Log.getLineKind(I)) {
255       case DifferenceEngine::DC_match:
256         out << "  ";
257         Log.getLeft(I)->dump();
258         //printValue(Log.getLeft(I), true);
259         break;
260       case DifferenceEngine::DC_left:
261         out << "< ";
262         Log.getLeft(I)->dump();
263         //printValue(Log.getLeft(I), true);
264         break;
265       case DifferenceEngine::DC_right:
266         out << "> ";
267         Log.getRight(I)->dump();
268         //printValue(Log.getRight(I), false);
269         break;
270       }
271       //out << "\n";
272     }
273   }
274   
275 };
276 }
277
278 static void diffGlobal(DifferenceEngine &Engine, Module *L, Module *R,
279                        StringRef Name) {
280   // Drop leading sigils from the global name.
281   if (Name.startswith("@")) Name = Name.substr(1);
282
283   Function *LFn = L->getFunction(Name);
284   Function *RFn = R->getFunction(Name);
285   if (LFn && RFn)
286     Engine.diff(LFn, RFn);
287   else if (!LFn && !RFn)
288     errs() << "No function named @" << Name << " in either module\n";
289   else if (!LFn)
290     errs() << "No function named @" << Name << " in left module\n";
291   else
292     errs() << "No function named @" << Name << " in right module\n";
293 }
294
295 cl::opt<std::string> LeftFilename(cl::Positional,
296                                   cl::desc("<first file>"),
297                                   cl::Required);
298 cl::opt<std::string> RightFilename(cl::Positional,
299                                    cl::desc("<second file>"),
300                                    cl::Required);
301 cl::list<std::string> GlobalsToCompare(cl::Positional,
302                                        cl::desc("<globals to compare>"));
303
304 int main(int argc, char **argv) {
305   cl::ParseCommandLineOptions(argc, argv);
306
307   LLVMContext Context;
308   
309   // Load both modules.  Die if that fails.
310   Module *LModule = ReadModule(Context, LeftFilename);
311   Module *RModule = ReadModule(Context, RightFilename);
312   if (!LModule || !RModule) return 1;
313
314   DiffConsumer Consumer(LModule, RModule);
315   DifferenceEngine Engine(Context, Consumer);
316
317   // If any global names were given, just diff those.
318   if (!GlobalsToCompare.empty()) {
319     for (unsigned I = 0, E = GlobalsToCompare.size(); I != E; ++I)
320       diffGlobal(Engine, LModule, RModule, GlobalsToCompare[I]);
321
322   // Otherwise, diff everything in the module.
323   } else {
324     Engine.diff(LModule, RModule);
325   }
326
327   delete LModule;
328   delete RModule;
329
330   return Consumer.hadDifferences();
331 }