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