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 35 using 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. 41 static 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 65 namespace { 66 struct 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 } 77 78 static void ComputeNumbering(Function *F, DenseMap<Value*,unsigned> &Numbering){ 79 unsigned IN = 0; 80 81 // Arguments get the first numbers. 82 for (Function::arg_iterator 83 AI = F->arg_begin(), AE = F->arg_end(); AI != AE; ++AI) 84 if (!AI->hasName()) 85 Numbering[&*AI] = IN++; 86 87 // Walk the basic blocks in order. 88 for (Function::iterator FI = F->begin(), FE = F->end(); FI != FE; ++FI) { 89 if (!FI->hasName()) 90 Numbering[&*FI] = IN++; 91 92 // Walk the instructions in order. 93 for (BasicBlock::iterator BI = FI->begin(), BE = FI->end(); BI != BE; ++BI) 94 // void instructions don't get numbers. 95 if (!BI->hasName() && !BI->getType()->isVoidTy()) 96 Numbering[&*BI] = IN++; 97 } 98 99 assert(!Numbering.empty() && "asked for numbering but numbering was no-op"); 100 } 101 102 namespace { 103 class DiffConsumer : public DifferenceEngine::Consumer { 104 private: 105 raw_ostream &out; 106 Module *LModule; 107 Module *RModule; 108 SmallVector<DiffContext, 5> contexts; 109 bool Differences; 110 unsigned Indent; 111 112 void printValue(Value *V, bool isL) { 113 if (V->hasName()) { 114 out << (isa<GlobalValue>(V) ? '@' : '%') << V->getName(); 115 return; 116 } 117 if (V->getType()->isVoidTy()) { 118 if (isa<StoreInst>(V)) { 119 out << "store to "; 120 printValue(cast<StoreInst>(V)->getPointerOperand(), isL); 121 } else if (isa<CallInst>(V)) { 122 out << "call to "; 123 printValue(cast<CallInst>(V)->getCalledValue(), isL); 124 } else if (isa<InvokeInst>(V)) { 125 out << "invoke to "; 126 printValue(cast<InvokeInst>(V)->getCalledValue(), isL); 127 } else { 128 out << *V; 129 } 130 return; 131 } 132 133 unsigned N = contexts.size(); 134 while (N > 0) { 135 --N; 136 DiffContext &ctxt = contexts[N]; 137 if (!ctxt.IsFunction) continue; 138 if (isL) { 139 if (ctxt.LNumbering.empty()) 140 ComputeNumbering(cast<Function>(ctxt.L), ctxt.LNumbering); 141 out << '%' << ctxt.LNumbering[V]; 142 return; 143 } else { 144 if (ctxt.RNumbering.empty()) 145 ComputeNumbering(cast<Function>(ctxt.R), ctxt.RNumbering); 146 out << '%' << ctxt.RNumbering[V]; 147 return; 148 } 149 } 150 151 out << "<anonymous>"; 152 } 153 154 void header() { 155 if (contexts.empty()) return; 156 for (SmallVectorImpl<DiffContext>::iterator 157 I = contexts.begin(), E = contexts.end(); I != E; ++I) { 158 if (I->Differences) continue; 159 if (isa<Function>(I->L)) { 160 // Extra newline between functions. 161 if (Differences) out << "\n"; 162 163 Function *L = cast<Function>(I->L); 164 Function *R = cast<Function>(I->R); 165 if (L->getName() != R->getName()) 166 out << "in function " << L->getName() 167 << " / " << R->getName() << ":\n"; 168 else 169 out << "in function " << L->getName() << ":\n"; 170 } else if (isa<BasicBlock>(I->L)) { 171 BasicBlock *L = cast<BasicBlock>(I->L); 172 BasicBlock *R = cast<BasicBlock>(I->R); 173 if (L->hasName() && R->hasName() && L->getName() == R->getName()) 174 out << " in block %" << L->getName() << ":\n"; 175 else { 176 out << " in block "; 177 printValue(L, true); 178 out << " / "; 179 printValue(R, false); 180 out << ":\n"; 181 } 182 } else if (isa<Instruction>(I->L)) { 183 out << " in instruction "; 184 printValue(I->L, true); 185 out << " / "; 186 printValue(I->R, false); 187 out << ":\n"; 188 } 189 190 I->Differences = true; 191 } 192 } 193 194 void indent() { 195 unsigned N = Indent; 196 while (N--) out << ' '; 197 } 198 199 public: 200 DiffConsumer(Module *L, Module *R) 201 : out(errs()), LModule(L), RModule(R), Differences(false), Indent(0) {} 202 203 bool hadDifferences() const { return Differences; } 204 205 void enterContext(Value *L, Value *R) { 206 contexts.push_back(DiffContext(L, R)); 207 Indent += 2; 208 } 209 void exitContext() { 210 Differences |= contexts.back().Differences; 211 contexts.pop_back(); 212 Indent -= 2; 213 } 214 215 void log(StringRef text) { 216 header(); 217 indent(); 218 out << text << '\n'; 219 } 220 221 void logf(const DifferenceEngine::LogBuilder &Log) { 222 header(); 223 indent(); 224 225 unsigned arg = 0; 226 227 StringRef format = Log.getFormat(); 228 while (true) { 229 size_t percent = format.find('%'); 230 if (percent == StringRef::npos) { 231 out << format; 232 break; 233 } 234 assert(format[percent] == '%'); 235 236 if (percent > 0) out << format.substr(0, percent); 237 238 switch (format[percent+1]) { 239 case '%': out << '%'; break; 240 case 'l': printValue(Log.getArgument(arg++), true); break; 241 case 'r': printValue(Log.getArgument(arg++), false); break; 242 default: llvm_unreachable("unknown format character"); 243 } 244 245 format = format.substr(percent+2); 246 } 247 248 out << '\n'; 249 } 250 251 void logd(const DifferenceEngine::DiffLogBuilder &Log) { 252 header(); 253 254 for (unsigned I = 0, E = Log.getNumLines(); I != E; ++I) { 255 indent(); 256 switch (Log.getLineKind(I)) { 257 case DifferenceEngine::DC_match: 258 out << " "; 259 Log.getLeft(I)->dump(); 260 //printValue(Log.getLeft(I), true); 261 break; 262 case DifferenceEngine::DC_left: 263 out << "< "; 264 Log.getLeft(I)->dump(); 265 //printValue(Log.getLeft(I), true); 266 break; 267 case DifferenceEngine::DC_right: 268 out << "> "; 269 Log.getRight(I)->dump(); 270 //printValue(Log.getRight(I), false); 271 break; 272 } 273 //out << "\n"; 274 } 275 } 276 277 }; 278 } // end anonymous namespace 279 280 static void diffGlobal(DifferenceEngine &Engine, Module *L, Module *R, 281 StringRef Name) { 282 // Drop leading sigils from the global name. 283 if (Name.startswith("@")) Name = Name.substr(1); 284 285 Function *LFn = L->getFunction(Name); 286 Function *RFn = R->getFunction(Name); 287 if (LFn && RFn) 288 Engine.diff(LFn, RFn); 289 else if (!LFn && !RFn) 290 errs() << "No function named @" << Name << " in either module\n"; 291 else if (!LFn) 292 errs() << "No function named @" << Name << " in left module\n"; 293 else 294 errs() << "No function named @" << Name << " in right module\n"; 295 } 296 297 static cl::opt<std::string> LeftFilename(cl::Positional, 298 cl::desc("<first file>"), 299 cl::Required); 300 static cl::opt<std::string> RightFilename(cl::Positional, 301 cl::desc("<second file>"), 302 cl::Required); 303 static cl::list<std::string> GlobalsToCompare(cl::Positional, 304 cl::desc("<globals to compare>")); 305 306 int main(int argc, char **argv) { 307 cl::ParseCommandLineOptions(argc, argv); 308 309 LLVMContext Context; 310 311 // Load both modules. Die if that fails. 312 Module *LModule = ReadModule(Context, LeftFilename); 313 Module *RModule = ReadModule(Context, RightFilename); 314 if (!LModule || !RModule) return 1; 315 316 DiffConsumer Consumer(LModule, RModule); 317 DifferenceEngine Engine(Context, Consumer); 318 319 // If any global names were given, just diff those. 320 if (!GlobalsToCompare.empty()) { 321 for (unsigned I = 0, E = GlobalsToCompare.size(); I != E; ++I) 322 diffGlobal(Engine, LModule, RModule, GlobalsToCompare[I]); 323 324 // Otherwise, diff everything in the module. 325 } else { 326 Engine.diff(LModule, RModule); 327 } 328 329 delete LModule; 330 delete RModule; 331 332 return Consumer.hadDifferences(); 333 } 334