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