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