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