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