verify-uselistorder: Make the verification logic easier to reuse
[oota-llvm.git] / tools / verify-uselistorder / verify-uselistorder.cpp
1 //===- verify-uselistorder.cpp - The LLVM Modular Optimizer ---------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // Verify that use-list order can be serialized correctly.  After reading the
11 // provided IR, this tool shuffles the use-lists and then writes and reads to a
12 // separate Module whose use-list orders are compared to the original.
13 //
14 // The shuffles are deterministic and somewhat naive.  On a given shuffle, some
15 // use-lists will not change at all.  The algorithm per iteration is as follows:
16 //
17 //  1. Seed the random number generator.  The seed is different for each
18 //     shuffle.  Shuffle 0 uses default+0, shuffle 1 uses default+1, and so on.
19 //
20 //  2. Visit every Value in a deterministic order.
21 //
22 //  3. Assign a random number to each Use in the Value's use-list in order.
23 //
24 //  4. Sort the use-list using Value::sortUseList(), which is a stable sort.
25 //
26 // Shuffling a larger number of times provides a better statistical guarantee
27 // that each use-list has changed at least once.
28 //
29 //===----------------------------------------------------------------------===//
30
31 #include "llvm/ADT/DenseMap.h"
32 #include "llvm/AsmParser/Parser.h"
33 #include "llvm/Bitcode/ReaderWriter.h"
34 #include "llvm/IR/LLVMContext.h"
35 #include "llvm/IR/Module.h"
36 #include "llvm/IR/UseListOrder.h"
37 #include "llvm/IRReader/IRReader.h"
38 #include "llvm/Support/CommandLine.h"
39 #include "llvm/Support/Debug.h"
40 #include "llvm/Support/ErrorHandling.h"
41 #include "llvm/Support/FileSystem.h"
42 #include "llvm/Support/FileUtilities.h"
43 #include "llvm/Support/ManagedStatic.h"
44 #include "llvm/Support/MemoryBuffer.h"
45 #include "llvm/Support/PrettyStackTrace.h"
46 #include "llvm/Support/Signals.h"
47 #include "llvm/Support/SourceMgr.h"
48 #include "llvm/Support/SystemUtils.h"
49
50 using namespace llvm;
51
52 #define DEBUG_TYPE "use-list-order"
53
54 static cl::opt<std::string> InputFilename(cl::Positional,
55                                           cl::desc("<input bitcode file>"),
56                                           cl::init("-"),
57                                           cl::value_desc("filename"));
58
59 static cl::opt<bool> SaveTemps("save-temps", cl::desc("Save temp files"),
60                                cl::init(false));
61
62 static cl::opt<unsigned>
63     NumShuffles("num-shuffles",
64                 cl::desc("Number of times to shuffle and verify use-lists"),
65                 cl::init(5));
66
67 namespace {
68
69 struct TempFile {
70   std::string Filename;
71   FileRemover Remover;
72   bool init(const std::string &Ext);
73   bool writeBitcode(const Module &M) const;
74   bool writeAssembly(const Module &M) const;
75   std::unique_ptr<Module> readBitcode(LLVMContext &Context) const;
76   std::unique_ptr<Module> readAssembly(LLVMContext &Context) const;
77 };
78
79 struct ValueMapping {
80   DenseMap<const Value *, unsigned> IDs;
81   std::vector<const Value *> Values;
82
83   /// \brief Construct a value mapping for module.
84   ///
85   /// Creates mapping from every value in \c M to an ID.  This mapping includes
86   /// un-referencable values.
87   ///
88   /// Every \a Value that gets serialized in some way should be represented
89   /// here.  The order needs to be deterministic, but it's unnecessary to match
90   /// the value-ids in the bitcode writer.
91   ///
92   /// All constants that are referenced by other values are included in the
93   /// mapping, but others -- which wouldn't be serialized -- are not.
94   ValueMapping(const Module &M);
95
96   /// \brief Map a value.
97   ///
98   /// Maps a value.  If it's a constant, maps all of its operands first.
99   void map(const Value *V);
100   unsigned lookup(const Value *V) const { return IDs.lookup(V); }
101 };
102
103 } // end namespace
104
105 bool TempFile::init(const std::string &Ext) {
106   SmallVector<char, 64> Vector;
107   DEBUG(dbgs() << " - create-temp-file\n");
108   if (auto EC = sys::fs::createTemporaryFile("use-list-order", Ext, Vector)) {
109     (void)EC;
110     DEBUG(dbgs() << "error: " << EC.message() << "\n");
111     return true;
112   }
113   assert(!Vector.empty());
114
115   Filename.assign(Vector.data(), Vector.data() + Vector.size());
116   Remover.setFile(Filename, !SaveTemps);
117   DEBUG(dbgs() << " - filename = " << Filename << "\n");
118   return false;
119 }
120
121 bool TempFile::writeBitcode(const Module &M) const {
122   DEBUG(dbgs() << " - write bitcode\n");
123   std::string ErrorInfo;
124   raw_fd_ostream OS(Filename.c_str(), ErrorInfo, sys::fs::F_None);
125   if (!ErrorInfo.empty()) {
126     DEBUG(dbgs() << "error: " << ErrorInfo << "\n");
127     return true;
128   }
129
130   WriteBitcodeToFile(&M, OS);
131   return false;
132 }
133
134 bool TempFile::writeAssembly(const Module &M) const {
135   DEBUG(dbgs() << " - write assembly\n");
136   std::string ErrorInfo;
137   raw_fd_ostream OS(Filename.c_str(), ErrorInfo, sys::fs::F_Text);
138   if (!ErrorInfo.empty()) {
139     DEBUG(dbgs() << "error: " << ErrorInfo << "\n");
140     return true;
141   }
142
143   OS << M;
144   return false;
145 }
146
147 std::unique_ptr<Module> TempFile::readBitcode(LLVMContext &Context) const {
148   DEBUG(dbgs() << " - read bitcode\n");
149   ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOr =
150       MemoryBuffer::getFile(Filename);
151   if (!BufferOr) {
152     DEBUG(dbgs() << "error: " << BufferOr.getError().message() << "\n");
153     return nullptr;
154   }
155
156   MemoryBuffer *Buffer = BufferOr.get().get();
157   ErrorOr<Module *> ModuleOr = parseBitcodeFile(Buffer, Context);
158   if (!ModuleOr) {
159     DEBUG(dbgs() << "error: " << ModuleOr.getError().message() << "\n");
160     return nullptr;
161   }
162   return std::unique_ptr<Module>(ModuleOr.get());
163 }
164
165 std::unique_ptr<Module> TempFile::readAssembly(LLVMContext &Context) const {
166   DEBUG(dbgs() << " - read assembly\n");
167   SMDiagnostic Err;
168   std::unique_ptr<Module> M(ParseAssemblyFile(Filename, Err, Context));
169   if (!M.get())
170     DEBUG(dbgs() << "error: "; Err.print("verify-use-list-order", dbgs()));
171   return M;
172 }
173
174 ValueMapping::ValueMapping(const Module &M) {
175   // Every value should be mapped, including things like void instructions and
176   // basic blocks that are kept out of the ValueEnumerator.
177   //
178   // The current mapping order makes it easier to debug the tables.  It happens
179   // to be similar to the ID mapping when writing ValueEnumerator, but they
180   // aren't (and needn't be) in sync.
181
182   // Globals.
183   for (const GlobalVariable &G : M.globals())
184     map(&G);
185   for (const GlobalAlias &A : M.aliases())
186     map(&A);
187   for (const Function &F : M)
188     map(&F);
189
190   // Constants used by globals.
191   for (const GlobalVariable &G : M.globals())
192     if (G.hasInitializer())
193       map(G.getInitializer());
194   for (const GlobalAlias &A : M.aliases())
195     map(A.getAliasee());
196   for (const Function &F : M)
197     if (F.hasPrefixData())
198       map(F.getPrefixData());
199
200   // Function bodies.
201   for (const Function &F : M) {
202     for (const Argument &A : F.args())
203       map(&A);
204     for (const BasicBlock &BB : F)
205       map(&BB);
206     for (const BasicBlock &BB : F)
207       for (const Instruction &I : BB)
208         map(&I);
209
210     // Constants used by instructions.
211     for (const BasicBlock &BB : F)
212       for (const Instruction &I : BB)
213         for (const Value *Op : I.operands())
214           if ((isa<Constant>(Op) && !isa<GlobalValue>(*Op)) ||
215               isa<InlineAsm>(Op))
216             map(Op);
217   }
218 }
219
220 void ValueMapping::map(const Value *V) {
221   if (IDs.lookup(V))
222     return;
223
224   if (auto *C = dyn_cast<Constant>(V))
225     if (!isa<GlobalValue>(C))
226       for (const Value *Op : C->operands())
227         map(Op);
228
229   Values.push_back(V);
230   IDs[V] = Values.size();
231 }
232
233 #ifndef NDEBUG
234 static void dumpMapping(const ValueMapping &VM) {
235   dbgs() << "value-mapping (size = " << VM.Values.size() << "):\n";
236   for (unsigned I = 0, E = VM.Values.size(); I != E; ++I) {
237     dbgs() << " - id = " << I << ", value = ";
238     VM.Values[I]->dump();
239   }
240 }
241
242 static void debugValue(const ValueMapping &M, unsigned I, StringRef Desc) {
243   const Value *V = M.Values[I];
244   dbgs() << " - " << Desc << " value = ";
245   V->dump();
246   for (const Use &U : V->uses()) {
247     dbgs() << "   => use: op = " << U.getOperandNo()
248            << ", user-id = " << M.IDs.lookup(U.getUser()) << ", user = ";
249     U.getUser()->dump();
250   }
251 }
252
253 static void debugUserMismatch(const ValueMapping &L, const ValueMapping &R,
254                               unsigned I) {
255   dbgs() << " - fail: user mismatch: ID = " << I << "\n";
256   debugValue(L, I, "LHS");
257   debugValue(R, I, "RHS");
258
259   dbgs() << "\nlhs-";
260   dumpMapping(L);
261   dbgs() << "\nrhs-";
262   dumpMapping(R);
263 }
264
265 static void debugSizeMismatch(const ValueMapping &L, const ValueMapping &R) {
266   dbgs() << " - fail: map size: " << L.Values.size()
267          << " != " << R.Values.size() << "\n";
268   dbgs() << "\nlhs-";
269   dumpMapping(L);
270   dbgs() << "\nrhs-";
271   dumpMapping(R);
272 }
273 #endif
274
275 static bool matches(const ValueMapping &LM, const ValueMapping &RM) {
276   DEBUG(dbgs() << "compare value maps\n");
277   if (LM.Values.size() != RM.Values.size()) {
278     DEBUG(debugSizeMismatch(LM, RM));
279     return false;
280   }
281
282   // This mapping doesn't include dangling constant users, since those don't
283   // get serialized.  However, checking if users are constant and calling
284   // isConstantUsed() on every one is very expensive.  Instead, just check if
285   // the user is mapped.
286   auto skipUnmappedUsers =
287       [&](Value::const_use_iterator &U, Value::const_use_iterator E,
288           const ValueMapping &M) {
289     while (U != E && !M.lookup(U->getUser()))
290       ++U;
291   };
292
293   // Iterate through all values, and check that both mappings have the same
294   // users.
295   for (unsigned I = 0, E = LM.Values.size(); I != E; ++I) {
296     const Value *L = LM.Values[I];
297     const Value *R = RM.Values[I];
298     auto LU = L->use_begin(), LE = L->use_end();
299     auto RU = R->use_begin(), RE = R->use_end();
300     skipUnmappedUsers(LU, LE, LM);
301     skipUnmappedUsers(RU, RE, RM);
302
303     while (LU != LE) {
304       if (RU == RE) {
305         DEBUG(debugUserMismatch(LM, RM, I));
306         return false;
307       }
308       if (LM.lookup(LU->getUser()) != RM.lookup(RU->getUser())) {
309         DEBUG(debugUserMismatch(LM, RM, I));
310         return false;
311       }
312       if (LU->getOperandNo() != RU->getOperandNo()) {
313         DEBUG(debugUserMismatch(LM, RM, I));
314         return false;
315       }
316       skipUnmappedUsers(++LU, LE, LM);
317       skipUnmappedUsers(++RU, RE, RM);
318     }
319     if (RU != RE) {
320       DEBUG(debugUserMismatch(LM, RM, I));
321       return false;
322     }
323   }
324
325   return true;
326 }
327
328 static bool verifyBitcodeUseListOrder(const Module &M) {
329   DEBUG(dbgs() << "*** verify-use-list-order: bitcode ***\n");
330   TempFile F;
331   if (F.init("bc"))
332     return false;
333
334   if (F.writeBitcode(M))
335     return false;
336
337   LLVMContext Context;
338   std::unique_ptr<Module> OtherM = F.readBitcode(Context);
339   if (!OtherM)
340     return false;
341
342   return matches(ValueMapping(M), ValueMapping(*OtherM));
343 }
344
345 static bool verifyAssemblyUseListOrder(const Module &M) {
346   DEBUG(dbgs() << "*** verify-use-list-order: assembly ***\n");
347   TempFile F;
348   if (F.init("ll"))
349     return false;
350
351   if (F.writeAssembly(M))
352     return false;
353
354   LLVMContext Context;
355   std::unique_ptr<Module> OtherM = F.readAssembly(Context);
356   if (!OtherM)
357     return false;
358
359   return matches(ValueMapping(M), ValueMapping(*OtherM));
360 }
361
362 static void verifyUseListOrder(const Module &M) {
363   if (!verifyBitcodeUseListOrder(M))
364     report_fatal_error("bitcode use-list order changed");
365
366   if (shouldPreserveAssemblyUseListOrder())
367     if (!verifyAssemblyUseListOrder(M))
368       report_fatal_error("assembly use-list order changed");
369 }
370
371 int main(int argc, char **argv) {
372   sys::PrintStackTraceOnErrorSignal();
373   llvm::PrettyStackTraceProgram X(argc, argv);
374
375   // Enable debug stream buffering.
376   EnableDebugBuffering = true;
377
378   llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
379   LLVMContext &Context = getGlobalContext();
380
381   cl::ParseCommandLineOptions(argc, argv,
382                               "llvm tool to verify use-list order\n");
383
384   SMDiagnostic Err;
385
386   // Load the input module...
387   std::unique_ptr<Module> M;
388   M.reset(ParseIRFile(InputFilename, Err, Context));
389
390   if (!M.get()) {
391     Err.print(argv[0], errs());
392     return 1;
393   }
394
395   DEBUG(dbgs() << "*** verify-use-list-order ***\n");
396   if (!shouldPreserveBitcodeUseListOrder()) {
397     // Can't verify if order isn't preserved.
398     DEBUG(dbgs() << "warning: cannot verify bitcode; "
399                     "try -preserve-bc-use-list-order\n");
400     return 0;
401   }
402
403   for (unsigned I = 0, E = NumShuffles; I != E; ++I) {
404     DEBUG(dbgs() << "*** iteration: " << I << " ***\n");
405
406     // Shuffle with a different seed each time so that use-lists that aren't
407     // modified the first time are likely to be modified the next time.
408     shuffleUseLists(*M, I);
409     verifyUseListOrder(*M);
410   }
411
412   return 0;
413 }