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