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 void ComputeNumbering(Function *F, DenseMap<Value*,unsigned> &Numbering) { 78 unsigned BBN = 0; 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 // Basic blocks have their own 'namespace'. 90 if (!FI->hasName()) 91 Numbering[&*FI] = BBN++; 92 93 // Walk the instructions in order. 94 for (BasicBlock::iterator BI = FI->begin(), BE = FI->end(); BI != BE; ++BI) 95 // void instructions don't get numbers. 96 if (!BI->hasName() && !BI->getType()->isVoidTy()) 97 Numbering[&*BI] = IN++; 98 } 99 100 assert(!Numbering.empty() && "asked for numbering but numbering was no-op"); 101 } 102 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() << " / " << R->getName() << ":\n"; 167 else 168 out << "in function " << L->getName() << ":\n"; 169 } else if (isa<BasicBlock>(I->L)) { 170 BasicBlock *L = cast<BasicBlock>(I->L); 171 BasicBlock *R = cast<BasicBlock>(I->R); 172 out << " in block "; 173 printValue(L, true); 174 out << " / "; 175 printValue(R, false); 176 out << ":\n"; 177 } else if (isa<Instruction>(I->L)) { 178 out << " in instruction "; 179 printValue(I->L, true); 180 out << " / "; 181 printValue(I->R, false); 182 out << ":\n"; 183 } 184 185 I->Differences = true; 186 } 187 } 188 189 void indent() { 190 unsigned N = Indent; 191 while (N--) out << ' '; 192 } 193 194 public: 195 DiffConsumer(Module *L, Module *R) 196 : out(errs()), LModule(L), RModule(R), Differences(false), Indent(0) {} 197 198 bool hadDifferences() const { return Differences; } 199 200 void enterContext(Value *L, Value *R) { 201 contexts.push_back(DiffContext(L, R)); 202 Indent += 2; 203 } 204 void exitContext() { 205 Differences |= contexts.back().Differences; 206 contexts.pop_back(); 207 Indent -= 2; 208 } 209 210 void log(StringRef text) { 211 header(); 212 indent(); 213 out << text << '\n'; 214 } 215 216 void logf(const DifferenceEngine::LogBuilder &Log) { 217 header(); 218 indent(); 219 220 unsigned arg = 0; 221 222 StringRef format = Log.getFormat(); 223 while (true) { 224 size_t percent = format.find('%'); 225 if (percent == StringRef::npos) { 226 out << format; 227 break; 228 } 229 assert(format[percent] == '%'); 230 231 if (percent > 0) out << format.substr(0, percent); 232 233 switch (format[percent+1]) { 234 case '%': out << '%'; break; 235 case 'l': printValue(Log.getArgument(arg++), true); break; 236 case 'r': printValue(Log.getArgument(arg++), false); break; 237 default: llvm_unreachable("unknown format character"); 238 } 239 240 format = format.substr(percent+2); 241 } 242 243 out << '\n'; 244 } 245 246 void logd(const DifferenceEngine::DiffLogBuilder &Log) { 247 header(); 248 249 for (unsigned I = 0, E = Log.getNumLines(); I != E; ++I) { 250 indent(); 251 switch (Log.getLineKind(I)) { 252 case DifferenceEngine::DC_match: 253 out << " "; 254 Log.getLeft(I)->dump(); 255 //printValue(Log.getLeft(I), true); 256 break; 257 case DifferenceEngine::DC_left: 258 out << "< "; 259 Log.getLeft(I)->dump(); 260 //printValue(Log.getLeft(I), true); 261 break; 262 case DifferenceEngine::DC_right: 263 out << "> "; 264 Log.getRight(I)->dump(); 265 //printValue(Log.getRight(I), false); 266 break; 267 } 268 //out << "\n"; 269 } 270 } 271 272 }; 273 } 274 275 static void diffGlobal(DifferenceEngine &Engine, Module *L, Module *R, 276 StringRef Name) { 277 // Drop leading sigils from the global name. 278 if (Name.startswith("@")) Name = Name.substr(1); 279 280 Function *LFn = L->getFunction(Name); 281 Function *RFn = R->getFunction(Name); 282 if (LFn && RFn) 283 Engine.diff(LFn, RFn); 284 else if (!LFn && !RFn) 285 errs() << "No function named @" << Name << " in either module\n"; 286 else if (!LFn) 287 errs() << "No function named @" << Name << " in left module\n"; 288 else 289 errs() << "No function named @" << Name << " in right module\n"; 290 } 291 292 cl::opt<std::string> LeftFilename(cl::Positional, cl::desc("<first file>"), cl::Required); 293 cl::opt<std::string> RightFilename(cl::Positional, cl::desc("<second file>"), cl::Required); 294 cl::list<std::string> GlobalsToCompare(cl::Positional, cl::desc("<globals to compare>")); 295 296 int main(int argc, char **argv) { 297 cl::ParseCommandLineOptions(argc, argv); 298 299 LLVMContext Context; 300 301 // Load both modules. Die if that fails. 302 Module *LModule = ReadModule(Context, LeftFilename); 303 Module *RModule = ReadModule(Context, RightFilename); 304 if (!LModule || !RModule) return 1; 305 306 DiffConsumer Consumer(LModule, RModule); 307 DifferenceEngine Engine(Context, Consumer); 308 309 // If any global names were given, just diff those. 310 if (!GlobalsToCompare.empty()) { 311 for (unsigned I = 0, E = GlobalsToCompare.size(); I != E; ++I) 312 diffGlobal(Engine, LModule, RModule, GlobalsToCompare[I]); 313 314 // Otherwise, diff everything in the module. 315 } else { 316 Engine.diff(LModule, RModule); 317 } 318 319 delete LModule; 320 delete RModule; 321 322 return Consumer.hadDifferences(); 323 } 324