llvm-diff.cpp revision 212793
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
35using 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.
41static 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
65namespace {
66struct 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
77void 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
101class DiffConsumer : public DifferenceEngine::Consumer {
102private:
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
197public:
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
278static 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
295cl::opt<std::string> LeftFilename(cl::Positional,
296                                  cl::desc("<first file>"),
297                                  cl::Required);
298cl::opt<std::string> RightFilename(cl::Positional,
299                                   cl::desc("<second file>"),
300                                   cl::Required);
301cl::list<std::string> GlobalsToCompare(cl::Positional,
302                                       cl::desc("<globals to compare>"));
303
304int 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}
332