llvm-diff.cpp revision 212793
1212793Sdim//===-- llvm-diff.cpp - Module comparator command-line driver ---*- C++ -*-===//
2212793Sdim//
3212793Sdim//                     The LLVM Compiler Infrastructure
4212793Sdim//
5212793Sdim// This file is distributed under the University of Illinois Open Source
6212793Sdim// License. See LICENSE.TXT for details.
7212793Sdim//
8212793Sdim//===----------------------------------------------------------------------===//
9212793Sdim//
10212793Sdim// This file defines the command-line driver for the difference engine.
11212793Sdim//
12212793Sdim//===----------------------------------------------------------------------===//
13212793Sdim
14212793Sdim#include "DifferenceEngine.h"
15212793Sdim
16212793Sdim#include "llvm/Instructions.h"
17212793Sdim#include "llvm/LLVMContext.h"
18212793Sdim#include "llvm/Module.h"
19212793Sdim#include "llvm/Type.h"
20212793Sdim#include "llvm/Assembly/Parser.h"
21212793Sdim#include "llvm/Bitcode/ReaderWriter.h"
22212793Sdim#include "llvm/ADT/DenseMap.h"
23212793Sdim#include "llvm/ADT/SmallVector.h"
24212793Sdim#include "llvm/ADT/StringRef.h"
25212793Sdim#include "llvm/Support/CommandLine.h"
26212793Sdim#include "llvm/Support/ErrorHandling.h"
27212793Sdim#include "llvm/Support/MemoryBuffer.h"
28212793Sdim#include "llvm/Support/raw_ostream.h"
29212793Sdim#include "llvm/Support/SourceMgr.h"
30212793Sdim
31212793Sdim#include <string>
32212793Sdim#include <utility>
33212793Sdim
34212793Sdim
35212793Sdimusing namespace llvm;
36212793Sdim
37212793Sdim/// Reads a module from a file.  If the filename ends in .ll, it is
38212793Sdim/// interpreted as an assembly file;  otherwise, it is interpreted as
39212793Sdim/// bitcode.  On error, messages are written to stderr and null is
40212793Sdim/// returned.
41212793Sdimstatic Module *ReadModule(LLVMContext &Context, StringRef Name) {
42212793Sdim  // LLVM assembly path.
43212793Sdim  if (Name.endswith(".ll")) {
44212793Sdim    SMDiagnostic Diag;
45212793Sdim    Module *M = ParseAssemblyFile(Name, Diag, Context);
46212793Sdim    if (M) return M;
47212793Sdim
48212793Sdim    Diag.Print("llvmdiff", errs());
49212793Sdim    return 0;
50212793Sdim  }
51212793Sdim
52212793Sdim  // Bitcode path.
53212793Sdim  MemoryBuffer *Buffer = MemoryBuffer::getFile(Name);
54212793Sdim
55212793Sdim  // ParseBitcodeFile takes ownership of the buffer if it succeeds.
56212793Sdim  std::string Error;
57212793Sdim  Module *M = ParseBitcodeFile(Buffer, Context, &Error);
58212793Sdim  if (M) return M;
59212793Sdim
60212793Sdim  errs() << "error parsing " << Name << ": " << Error;
61212793Sdim  delete Buffer;
62212793Sdim  return 0;
63212793Sdim}
64212793Sdim
65212793Sdimnamespace {
66212793Sdimstruct DiffContext {
67212793Sdim  DiffContext(Value *L, Value *R)
68212793Sdim    : L(L), R(R), Differences(false), IsFunction(isa<Function>(L)) {}
69212793Sdim  Value *L;
70212793Sdim  Value *R;
71212793Sdim  bool Differences;
72212793Sdim  bool IsFunction;
73212793Sdim  DenseMap<Value*,unsigned> LNumbering;
74212793Sdim  DenseMap<Value*,unsigned> RNumbering;
75212793Sdim};
76212793Sdim
77212793Sdimvoid ComputeNumbering(Function *F, DenseMap<Value*,unsigned> &Numbering) {
78212793Sdim  unsigned IN = 0;
79212793Sdim
80212793Sdim  // Arguments get the first numbers.
81212793Sdim  for (Function::arg_iterator
82212793Sdim         AI = F->arg_begin(), AE = F->arg_end(); AI != AE; ++AI)
83212793Sdim    if (!AI->hasName())
84212793Sdim      Numbering[&*AI] = IN++;
85212793Sdim
86212793Sdim  // Walk the basic blocks in order.
87212793Sdim  for (Function::iterator FI = F->begin(), FE = F->end(); FI != FE; ++FI) {
88212793Sdim    if (!FI->hasName())
89212793Sdim      Numbering[&*FI] = IN++;
90212793Sdim
91212793Sdim    // Walk the instructions in order.
92212793Sdim    for (BasicBlock::iterator BI = FI->begin(), BE = FI->end(); BI != BE; ++BI)
93212793Sdim      // void instructions don't get numbers.
94212793Sdim      if (!BI->hasName() && !BI->getType()->isVoidTy())
95212793Sdim        Numbering[&*BI] = IN++;
96212793Sdim  }
97212793Sdim
98212793Sdim  assert(!Numbering.empty() && "asked for numbering but numbering was no-op");
99212793Sdim}
100212793Sdim
101212793Sdimclass DiffConsumer : public DifferenceEngine::Consumer {
102212793Sdimprivate:
103212793Sdim  raw_ostream &out;
104212793Sdim  Module *LModule;
105212793Sdim  Module *RModule;
106212793Sdim  SmallVector<DiffContext, 5> contexts;
107212793Sdim  bool Differences;
108212793Sdim  unsigned Indent;
109212793Sdim
110212793Sdim  void printValue(Value *V, bool isL) {
111212793Sdim    if (V->hasName()) {
112212793Sdim      out << (isa<GlobalValue>(V) ? '@' : '%') << V->getName();
113212793Sdim      return;
114212793Sdim    }
115212793Sdim    if (V->getType()->isVoidTy()) {
116212793Sdim      if (isa<StoreInst>(V)) {
117212793Sdim        out << "store to ";
118212793Sdim        printValue(cast<StoreInst>(V)->getPointerOperand(), isL);
119212793Sdim      } else if (isa<CallInst>(V)) {
120212793Sdim        out << "call to ";
121212793Sdim        printValue(cast<CallInst>(V)->getCalledValue(), isL);
122212793Sdim      } else if (isa<InvokeInst>(V)) {
123212793Sdim        out << "invoke to ";
124212793Sdim        printValue(cast<InvokeInst>(V)->getCalledValue(), isL);
125212793Sdim      } else {
126212793Sdim        out << *V;
127212793Sdim      }
128212793Sdim      return;
129212793Sdim    }
130212793Sdim
131212793Sdim    unsigned N = contexts.size();
132212793Sdim    while (N > 0) {
133212793Sdim      --N;
134212793Sdim      DiffContext &ctxt = contexts[N];
135212793Sdim      if (!ctxt.IsFunction) continue;
136212793Sdim      if (isL) {
137212793Sdim        if (ctxt.LNumbering.empty())
138212793Sdim          ComputeNumbering(cast<Function>(ctxt.L), ctxt.LNumbering);
139212793Sdim        out << '%' << ctxt.LNumbering[V];
140212793Sdim        return;
141212793Sdim      } else {
142212793Sdim        if (ctxt.RNumbering.empty())
143212793Sdim          ComputeNumbering(cast<Function>(ctxt.R), ctxt.RNumbering);
144212793Sdim        out << '%' << ctxt.RNumbering[V];
145212793Sdim        return;
146212793Sdim      }
147212793Sdim    }
148212793Sdim
149212793Sdim    out << "<anonymous>";
150212793Sdim  }
151212793Sdim
152212793Sdim  void header() {
153212793Sdim    if (contexts.empty()) return;
154212793Sdim    for (SmallVectorImpl<DiffContext>::iterator
155212793Sdim           I = contexts.begin(), E = contexts.end(); I != E; ++I) {
156212793Sdim      if (I->Differences) continue;
157212793Sdim      if (isa<Function>(I->L)) {
158212793Sdim        // Extra newline between functions.
159212793Sdim        if (Differences) out << "\n";
160212793Sdim
161212793Sdim        Function *L = cast<Function>(I->L);
162212793Sdim        Function *R = cast<Function>(I->R);
163212793Sdim        if (L->getName() != R->getName())
164212793Sdim          out << "in function " << L->getName()
165212793Sdim              << " / " << R->getName() << ":\n";
166212793Sdim        else
167212793Sdim          out << "in function " << L->getName() << ":\n";
168212793Sdim      } else if (isa<BasicBlock>(I->L)) {
169212793Sdim        BasicBlock *L = cast<BasicBlock>(I->L);
170212793Sdim        BasicBlock *R = cast<BasicBlock>(I->R);
171212793Sdim        if (L->hasName() && R->hasName() && L->getName() == R->getName())
172212793Sdim          out << "  in block %" << L->getName() << ":\n";
173212793Sdim        else {
174212793Sdim          out << "  in block ";
175212793Sdim          printValue(L, true);
176212793Sdim          out << " / ";
177212793Sdim          printValue(R, false);
178212793Sdim          out << ":\n";
179212793Sdim        }
180212793Sdim      } else if (isa<Instruction>(I->L)) {
181212793Sdim        out << "    in instruction ";
182212793Sdim        printValue(I->L, true);
183212793Sdim        out << " / ";
184212793Sdim        printValue(I->R, false);
185212793Sdim        out << ":\n";
186212793Sdim      }
187212793Sdim
188212793Sdim      I->Differences = true;
189212793Sdim    }
190212793Sdim  }
191212793Sdim
192212793Sdim  void indent() {
193212793Sdim    unsigned N = Indent;
194212793Sdim    while (N--) out << ' ';
195212793Sdim  }
196212793Sdim
197212793Sdimpublic:
198212793Sdim  DiffConsumer(Module *L, Module *R)
199212793Sdim    : out(errs()), LModule(L), RModule(R), Differences(false), Indent(0) {}
200212793Sdim
201212793Sdim  bool hadDifferences() const { return Differences; }
202212793Sdim
203212793Sdim  void enterContext(Value *L, Value *R) {
204212793Sdim    contexts.push_back(DiffContext(L, R));
205212793Sdim    Indent += 2;
206212793Sdim  }
207212793Sdim  void exitContext() {
208212793Sdim    Differences |= contexts.back().Differences;
209212793Sdim    contexts.pop_back();
210212793Sdim    Indent -= 2;
211212793Sdim  }
212212793Sdim
213212793Sdim  void log(StringRef text) {
214212793Sdim    header();
215212793Sdim    indent();
216212793Sdim    out << text << '\n';
217212793Sdim  }
218212793Sdim
219212793Sdim  void logf(const DifferenceEngine::LogBuilder &Log) {
220212793Sdim    header();
221212793Sdim    indent();
222212793Sdim
223212793Sdim    unsigned arg = 0;
224212793Sdim
225212793Sdim    StringRef format = Log.getFormat();
226212793Sdim    while (true) {
227212793Sdim      size_t percent = format.find('%');
228212793Sdim      if (percent == StringRef::npos) {
229212793Sdim        out << format;
230212793Sdim        break;
231212793Sdim      }
232212793Sdim      assert(format[percent] == '%');
233212793Sdim
234212793Sdim      if (percent > 0) out << format.substr(0, percent);
235212793Sdim
236212793Sdim      switch (format[percent+1]) {
237212793Sdim      case '%': out << '%'; break;
238212793Sdim      case 'l': printValue(Log.getArgument(arg++), true); break;
239212793Sdim      case 'r': printValue(Log.getArgument(arg++), false); break;
240212793Sdim      default: llvm_unreachable("unknown format character");
241212793Sdim      }
242212793Sdim
243212793Sdim      format = format.substr(percent+2);
244212793Sdim    }
245212793Sdim
246212793Sdim    out << '\n';
247212793Sdim  }
248212793Sdim
249212793Sdim  void logd(const DifferenceEngine::DiffLogBuilder &Log) {
250212793Sdim    header();
251212793Sdim
252212793Sdim    for (unsigned I = 0, E = Log.getNumLines(); I != E; ++I) {
253212793Sdim      indent();
254212793Sdim      switch (Log.getLineKind(I)) {
255212793Sdim      case DifferenceEngine::DC_match:
256212793Sdim        out << "  ";
257212793Sdim        Log.getLeft(I)->dump();
258212793Sdim        //printValue(Log.getLeft(I), true);
259212793Sdim        break;
260212793Sdim      case DifferenceEngine::DC_left:
261212793Sdim        out << "< ";
262212793Sdim        Log.getLeft(I)->dump();
263212793Sdim        //printValue(Log.getLeft(I), true);
264212793Sdim        break;
265212793Sdim      case DifferenceEngine::DC_right:
266212793Sdim        out << "> ";
267212793Sdim        Log.getRight(I)->dump();
268212793Sdim        //printValue(Log.getRight(I), false);
269212793Sdim        break;
270212793Sdim      }
271212793Sdim      //out << "\n";
272212793Sdim    }
273212793Sdim  }
274212793Sdim
275212793Sdim};
276212793Sdim}
277212793Sdim
278212793Sdimstatic void diffGlobal(DifferenceEngine &Engine, Module *L, Module *R,
279212793Sdim                       StringRef Name) {
280212793Sdim  // Drop leading sigils from the global name.
281212793Sdim  if (Name.startswith("@")) Name = Name.substr(1);
282212793Sdim
283212793Sdim  Function *LFn = L->getFunction(Name);
284212793Sdim  Function *RFn = R->getFunction(Name);
285212793Sdim  if (LFn && RFn)
286212793Sdim    Engine.diff(LFn, RFn);
287212793Sdim  else if (!LFn && !RFn)
288212793Sdim    errs() << "No function named @" << Name << " in either module\n";
289212793Sdim  else if (!LFn)
290212793Sdim    errs() << "No function named @" << Name << " in left module\n";
291212793Sdim  else
292212793Sdim    errs() << "No function named @" << Name << " in right module\n";
293212793Sdim}
294212793Sdim
295212793Sdimcl::opt<std::string> LeftFilename(cl::Positional,
296212793Sdim                                  cl::desc("<first file>"),
297212793Sdim                                  cl::Required);
298212793Sdimcl::opt<std::string> RightFilename(cl::Positional,
299212793Sdim                                   cl::desc("<second file>"),
300212793Sdim                                   cl::Required);
301212793Sdimcl::list<std::string> GlobalsToCompare(cl::Positional,
302212793Sdim                                       cl::desc("<globals to compare>"));
303212793Sdim
304212793Sdimint main(int argc, char **argv) {
305212793Sdim  cl::ParseCommandLineOptions(argc, argv);
306212793Sdim
307212793Sdim  LLVMContext Context;
308212793Sdim
309212793Sdim  // Load both modules.  Die if that fails.
310212793Sdim  Module *LModule = ReadModule(Context, LeftFilename);
311212793Sdim  Module *RModule = ReadModule(Context, RightFilename);
312212793Sdim  if (!LModule || !RModule) return 1;
313212793Sdim
314212793Sdim  DiffConsumer Consumer(LModule, RModule);
315212793Sdim  DifferenceEngine Engine(Context, Consumer);
316212793Sdim
317212793Sdim  // If any global names were given, just diff those.
318212793Sdim  if (!GlobalsToCompare.empty()) {
319212793Sdim    for (unsigned I = 0, E = GlobalsToCompare.size(); I != E; ++I)
320212793Sdim      diffGlobal(Engine, LModule, RModule, GlobalsToCompare[I]);
321212793Sdim
322212793Sdim  // Otherwise, diff everything in the module.
323212793Sdim  } else {
324212793Sdim    Engine.diff(LModule, RModule);
325212793Sdim  }
326212793Sdim
327212793Sdim  delete LModule;
328212793Sdim  delete RModule;
329212793Sdim
330212793Sdim  return Consumer.hadDifferences();
331212793Sdim}
332