blob: e5bcb12aecf9b361270d47a88a28daddb54e2bf8 [file] [log] [blame]
John McCall3dd706b2010-07-29 07:53:27 +00001#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>
John McCall62dc1f32010-07-29 08:14:41 +000017#include <llvm/Support/ErrorHandling.h>
John McCall3dd706b2010-07-29 07:53:27 +000018#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
25using 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.
31static 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
55static 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
63namespace {
64struct 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
75void 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
101class DiffConsumer : public DifferenceEngine::Consumer {
102private:
John McCall62dc1f32010-07-29 08:14:41 +0000103 raw_ostream &out;
John McCall3dd706b2010-07-29 07:53:27 +0000104 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()) {
John McCall62dc1f32010-07-29 08:14:41 +0000112 out << (isa<GlobalValue>(V) ? '@' : '%') << V->getName();
John McCall3dd706b2010-07-29 07:53:27 +0000113 return;
114 }
115 if (V->getType()->isVoidTy()) {
116 if (isa<StoreInst>(V)) {
John McCall62dc1f32010-07-29 08:14:41 +0000117 out << "store to ";
John McCall3dd706b2010-07-29 07:53:27 +0000118 printValue(cast<StoreInst>(V)->getPointerOperand(), isL);
119 } else if (isa<CallInst>(V)) {
John McCall62dc1f32010-07-29 08:14:41 +0000120 out << "call to ";
John McCall3dd706b2010-07-29 07:53:27 +0000121 printValue(cast<CallInst>(V)->getCalledValue(), isL);
122 } else if (isa<InvokeInst>(V)) {
John McCall62dc1f32010-07-29 08:14:41 +0000123 out << "invoke to ";
John McCall3dd706b2010-07-29 07:53:27 +0000124 printValue(cast<InvokeInst>(V)->getCalledValue(), isL);
125 } else {
John McCall62dc1f32010-07-29 08:14:41 +0000126 out << *V;
John McCall3dd706b2010-07-29 07:53:27 +0000127 }
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);
John McCall62dc1f32010-07-29 08:14:41 +0000139 out << '%' << ctxt.LNumbering[V];
John McCall3dd706b2010-07-29 07:53:27 +0000140 return;
141 } else {
142 if (ctxt.RNumbering.empty())
143 ComputeNumbering(cast<Function>(ctxt.R), ctxt.RNumbering);
John McCall62dc1f32010-07-29 08:14:41 +0000144 out << '%' << ctxt.RNumbering[V];
John McCall3dd706b2010-07-29 07:53:27 +0000145 return;
146 }
147 }
148
John McCall62dc1f32010-07-29 08:14:41 +0000149 out << "<anonymous>";
John McCall3dd706b2010-07-29 07:53:27 +0000150 }
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.
John McCall62dc1f32010-07-29 08:14:41 +0000159 if (Differences) out << "\n";
John McCall3dd706b2010-07-29 07:53:27 +0000160
161 Function *L = cast<Function>(I->L);
162 Function *R = cast<Function>(I->R);
163 if (L->getName() != R->getName())
John McCall62dc1f32010-07-29 08:14:41 +0000164 out << "in function " << L->getName() << " / " << R->getName() << ":\n";
John McCall3dd706b2010-07-29 07:53:27 +0000165 else
John McCall62dc1f32010-07-29 08:14:41 +0000166 out << "in function " << L->getName() << ":\n";
John McCall3dd706b2010-07-29 07:53:27 +0000167 } else if (isa<BasicBlock>(I->L)) {
168 BasicBlock *L = cast<BasicBlock>(I->L);
169 BasicBlock *R = cast<BasicBlock>(I->R);
John McCall62dc1f32010-07-29 08:14:41 +0000170 out << " in block ";
John McCall3dd706b2010-07-29 07:53:27 +0000171 printValue(L, true);
John McCall62dc1f32010-07-29 08:14:41 +0000172 out << " / ";
John McCall3dd706b2010-07-29 07:53:27 +0000173 printValue(R, false);
John McCall62dc1f32010-07-29 08:14:41 +0000174 out << ":\n";
John McCall3dd706b2010-07-29 07:53:27 +0000175 } else if (isa<Instruction>(I->L)) {
John McCall62dc1f32010-07-29 08:14:41 +0000176 out << " in instruction ";
John McCall3dd706b2010-07-29 07:53:27 +0000177 printValue(I->L, true);
John McCall62dc1f32010-07-29 08:14:41 +0000178 out << " / ";
John McCall3dd706b2010-07-29 07:53:27 +0000179 printValue(I->R, false);
John McCall62dc1f32010-07-29 08:14:41 +0000180 out << ":\n";
John McCall3dd706b2010-07-29 07:53:27 +0000181 }
182
183 I->Differences = true;
184 }
185 }
186
187 void indent() {
188 unsigned N = Indent;
John McCall62dc1f32010-07-29 08:14:41 +0000189 while (N--) out << ' ';
John McCall3dd706b2010-07-29 07:53:27 +0000190 }
191
192public:
193 DiffConsumer(Module *L, Module *R)
John McCall62dc1f32010-07-29 08:14:41 +0000194 : out(errs()), LModule(L), RModule(R), Differences(false), Indent(0) {}
John McCall3dd706b2010-07-29 07:53:27 +0000195
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();
John McCall62dc1f32010-07-29 08:14:41 +0000211 out << text << '\n';
John McCall3dd706b2010-07-29 07:53:27 +0000212 }
213
214 void logf(const DifferenceEngine::LogBuilder &Log) {
215 header();
216 indent();
217
John McCall62dc1f32010-07-29 08:14:41 +0000218 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';
John McCall3dd706b2010-07-29 07:53:27 +0000242 }
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:
John McCall62dc1f32010-07-29 08:14:41 +0000251 out << " ";
John McCall3dd706b2010-07-29 07:53:27 +0000252 Log.getLeft(I)->dump();
253 //printValue(Log.getLeft(I), true);
254 break;
255 case DifferenceEngine::DC_left:
John McCall62dc1f32010-07-29 08:14:41 +0000256 out << "< ";
John McCall3dd706b2010-07-29 07:53:27 +0000257 Log.getLeft(I)->dump();
258 //printValue(Log.getLeft(I), true);
259 break;
260 case DifferenceEngine::DC_right:
John McCall62dc1f32010-07-29 08:14:41 +0000261 out << "> ";
John McCall3dd706b2010-07-29 07:53:27 +0000262 Log.getRight(I)->dump();
263 //printValue(Log.getRight(I), false);
264 break;
265 }
John McCall62dc1f32010-07-29 08:14:41 +0000266 //out << "\n";
John McCall3dd706b2010-07-29 07:53:27 +0000267 }
268 }
269
270};
271}
272
273int 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}