blob: 7c2a5d66c3ba976fd951076d7a33260864183fd2 [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>
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
24using 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.
30static 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
54static 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
62namespace {
63struct 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
74void 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
100class DiffConsumer : public DifferenceEngine::Consumer {
101private:
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
190public:
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
252int 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}