1 #include <string> 2 #include <utility> 3 4 #include <llvm/ADT/StringRef.h> 5 #include <llvm/ADT/SmallVector.h> 6 #include <llvm/ADT/DenseMap.h> 7 8 // Required to parse .ll files. 9 #include <llvm/Support/SourceMgr.h> 10 #include <llvm/Assembly/Parser.h> 11 12 // Required to parse .bc files. 13 #include <llvm/Support/MemoryBuffer.h> 14 #include <llvm/Bitcode/ReaderWriter.h> 15 16 #include <llvm/Support/raw_ostream.h> 17 #include <llvm/Support/ErrorHandling.h> 18 #include <llvm/LLVMContext.h> 19 #include <llvm/Module.h> 20 #include <llvm/Type.h> 21 #include <llvm/Instructions.h> 22 23 #include "DifferenceEngine.h" 24 25 using namespace llvm; 26 27 /// Reads a module from a file. If the filename ends in .ll, it is 28 /// interpreted as an assembly file; otherwise, it is interpreted as 29 /// bitcode. On error, messages are written to stderr and null is 30 /// returned. 31 static Module *ReadModule(LLVMContext &Context, StringRef Name) { 32 // LLVM assembly path. 33 if (Name.endswith(".ll")) { 34 SMDiagnostic Diag; 35 Module *M = ParseAssemblyFile(Name, Diag, Context); 36 if (M) return M; 37 38 Diag.Print("llvmdiff", errs()); 39 return 0; 40 } 41 42 // Bitcode path. 43 MemoryBuffer *Buffer = MemoryBuffer::getFile(Name); 44 45 // ParseBitcodeFile takes ownership of the buffer if it succeeds. 46 std::string Error; 47 Module *M = ParseBitcodeFile(Buffer, Context, &Error); 48 if (M) return M; 49 50 errs() << "error parsing " << Name << ": " << Error; 51 delete Buffer; 52 return 0; 53 } 54 55 static int usage() { 56 errs() << "expected usage:\n"; 57 errs() << " llvm-diff oldmodule.ll newmodule.ll [function list]\n"; 58 errs() << "Assembly or bitcode modules may be used interchangeably.\n"; 59 errs() << "If no functions are provided, all functions will be compared.\n"; 60 return 1; 61 } 62 63 namespace { 64 struct DiffContext { 65 DiffContext(Value *L, Value *R) 66 : L(L), R(R), Differences(false), IsFunction(isa<Function>(L)) {} 67 Value *L; 68 Value *R; 69 bool Differences; 70 bool IsFunction; 71 DenseMap<Value*,unsigned> LNumbering; 72 DenseMap<Value*,unsigned> RNumbering; 73 }; 74 75 void ComputeNumbering(Function *F, DenseMap<Value*,unsigned> &Numbering) { 76 unsigned BBN = 0; 77 unsigned IN = 0; 78 79 // Arguments get the first numbers. 80 for (Function::arg_iterator 81 AI = F->arg_begin(), AE = F->arg_end(); AI != AE; ++AI) 82 if (!AI->hasName()) 83 Numbering[&*AI] = IN++; 84 85 // Walk the basic blocks in order. 86 for (Function::iterator FI = F->begin(), FE = F->end(); FI != FE; ++FI) { 87 // Basic blocks have their own 'namespace'. 88 if (!FI->hasName()) 89 Numbering[&*FI] = BBN++; 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 101 class DiffConsumer : public DifferenceEngine::Consumer { 102 private: 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() << " / " << R->getName() << ":\n"; 165 else 166 out << "in function " << L->getName() << ":\n"; 167 } else if (isa<BasicBlock>(I->L)) { 168 BasicBlock *L = cast<BasicBlock>(I->L); 169 BasicBlock *R = cast<BasicBlock>(I->R); 170 out << " in block "; 171 printValue(L, true); 172 out << " / "; 173 printValue(R, false); 174 out << ":\n"; 175 } else if (isa<Instruction>(I->L)) { 176 out << " in instruction "; 177 printValue(I->L, true); 178 out << " / "; 179 printValue(I->R, false); 180 out << ":\n"; 181 } 182 183 I->Differences = true; 184 } 185 } 186 187 void indent() { 188 unsigned N = Indent; 189 while (N--) out << ' '; 190 } 191 192 public: 193 DiffConsumer(Module *L, Module *R) 194 : out(errs()), LModule(L), RModule(R), Differences(false), Indent(0) {} 195 196 bool hadDifferences() const { return Differences; } 197 198 void enterContext(Value *L, Value *R) { 199 contexts.push_back(DiffContext(L, R)); 200 Indent += 2; 201 } 202 void exitContext() { 203 Differences |= contexts.back().Differences; 204 contexts.pop_back(); 205 Indent -= 2; 206 } 207 208 void log(StringRef text) { 209 header(); 210 indent(); 211 out << text << '\n'; 212 } 213 214 void logf(const DifferenceEngine::LogBuilder &Log) { 215 header(); 216 indent(); 217 218 unsigned arg = 0; 219 220 StringRef format = Log.getFormat(); 221 while (true) { 222 size_t percent = format.find('%'); 223 if (percent == StringRef::npos) { 224 out << format; 225 break; 226 } 227 assert(format[percent] == '%'); 228 229 if (percent > 0) out << format.substr(0, percent); 230 231 switch (format[percent+1]) { 232 case '%': out << '%'; break; 233 case 'l': printValue(Log.getArgument(arg++), true); break; 234 case 'r': printValue(Log.getArgument(arg++), false); break; 235 default: llvm_unreachable("unknown format character"); 236 } 237 238 format = format.substr(percent+2); 239 } 240 241 out << '\n'; 242 } 243 244 void logd(const DifferenceEngine::DiffLogBuilder &Log) { 245 header(); 246 247 for (unsigned I = 0, E = Log.getNumLines(); I != E; ++I) { 248 indent(); 249 switch (Log.getLineKind(I)) { 250 case DifferenceEngine::DC_match: 251 out << " "; 252 Log.getLeft(I)->dump(); 253 //printValue(Log.getLeft(I), true); 254 break; 255 case DifferenceEngine::DC_left: 256 out << "< "; 257 Log.getLeft(I)->dump(); 258 //printValue(Log.getLeft(I), true); 259 break; 260 case DifferenceEngine::DC_right: 261 out << "> "; 262 Log.getRight(I)->dump(); 263 //printValue(Log.getRight(I), false); 264 break; 265 } 266 //out << "\n"; 267 } 268 } 269 270 }; 271 } 272 273 int main(int argc, const char **argv) { 274 if (argc < 3) return usage(); 275 276 // Don't make StringRef locals like this at home. 277 StringRef LModuleFile = argv[1]; 278 StringRef RModuleFile = argv[2]; 279 280 LLVMContext Context; 281 282 // Load both modules. Die if that fails. 283 Module *LModule = ReadModule(Context, LModuleFile); 284 Module *RModule = ReadModule(Context, RModuleFile); 285 if (!LModule || !RModule) return 1; 286 287 DiffConsumer Consumer(LModule, RModule); 288 DifferenceEngine Engine(Context, Consumer); 289 290 // If any function names were given, just diff those. 291 const char **FnNames = argv + 3; 292 unsigned NumFnNames = argc - 3; 293 if (NumFnNames) { 294 for (unsigned I = 0; I != NumFnNames; ++I) { 295 StringRef FnName = FnNames[I]; 296 297 // Drop leading sigils from the function name. 298 if (FnName.startswith("@")) FnName = FnName.substr(1); 299 300 Function *LFn = LModule->getFunction(FnName); 301 Function *RFn = RModule->getFunction(FnName); 302 if (LFn && RFn) 303 Engine.diff(LFn, RFn); 304 else { 305 if (!LFn && !RFn) 306 errs() << "No function named @" << FnName << " in either module\n"; 307 else if (!LFn) 308 errs() << "No function named @" << FnName << " in left module\n"; 309 else 310 errs() << "No function named @" << FnName << " in right module\n"; 311 } 312 } 313 } else { 314 // Otherwise, diff all functions in the modules. 315 Engine.diff(LModule, RModule); 316 } 317 318 delete LModule; 319 delete RModule; 320 321 return Consumer.hadDifferences(); 322 } 323