106f32e7eSjoerg //===- verify-uselistorder.cpp - The LLVM Modular Optimizer ---------------===//
206f32e7eSjoerg //
306f32e7eSjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406f32e7eSjoerg // See https://llvm.org/LICENSE.txt for license information.
506f32e7eSjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606f32e7eSjoerg //
706f32e7eSjoerg //===----------------------------------------------------------------------===//
806f32e7eSjoerg //
906f32e7eSjoerg // Verify that use-list order can be serialized correctly.  After reading the
1006f32e7eSjoerg // provided IR, this tool shuffles the use-lists and then writes and reads to a
1106f32e7eSjoerg // separate Module whose use-list orders are compared to the original.
1206f32e7eSjoerg //
1306f32e7eSjoerg // The shuffles are deterministic, but guarantee that use-lists will change.
1406f32e7eSjoerg // The algorithm per iteration is as follows:
1506f32e7eSjoerg //
1606f32e7eSjoerg //  1. Seed the random number generator.  The seed is different for each
1706f32e7eSjoerg //     shuffle.  Shuffle 0 uses default+0, shuffle 1 uses default+1, and so on.
1806f32e7eSjoerg //
1906f32e7eSjoerg //  2. Visit every Value in a deterministic order.
2006f32e7eSjoerg //
2106f32e7eSjoerg //  3. Assign a random number to each Use in the Value's use-list in order.
2206f32e7eSjoerg //
2306f32e7eSjoerg //  4. If the numbers are already in order, reassign numbers until they aren't.
2406f32e7eSjoerg //
2506f32e7eSjoerg //  5. Sort the use-list using Value::sortUseList(), which is a stable sort.
2606f32e7eSjoerg //
2706f32e7eSjoerg //===----------------------------------------------------------------------===//
2806f32e7eSjoerg 
2906f32e7eSjoerg #include "llvm/ADT/DenseMap.h"
3006f32e7eSjoerg #include "llvm/ADT/DenseSet.h"
3106f32e7eSjoerg #include "llvm/AsmParser/Parser.h"
3206f32e7eSjoerg #include "llvm/Bitcode/BitcodeReader.h"
3306f32e7eSjoerg #include "llvm/Bitcode/BitcodeWriter.h"
3406f32e7eSjoerg #include "llvm/IR/LLVMContext.h"
3506f32e7eSjoerg #include "llvm/IR/Module.h"
3606f32e7eSjoerg #include "llvm/IR/UseListOrder.h"
3706f32e7eSjoerg #include "llvm/IR/Verifier.h"
3806f32e7eSjoerg #include "llvm/IRReader/IRReader.h"
3906f32e7eSjoerg #include "llvm/Support/CommandLine.h"
4006f32e7eSjoerg #include "llvm/Support/Debug.h"
4106f32e7eSjoerg #include "llvm/Support/ErrorHandling.h"
4206f32e7eSjoerg #include "llvm/Support/FileSystem.h"
4306f32e7eSjoerg #include "llvm/Support/FileUtilities.h"
4406f32e7eSjoerg #include "llvm/Support/InitLLVM.h"
4506f32e7eSjoerg #include "llvm/Support/MemoryBuffer.h"
4606f32e7eSjoerg #include "llvm/Support/SourceMgr.h"
4706f32e7eSjoerg #include "llvm/Support/SystemUtils.h"
4806f32e7eSjoerg #include "llvm/Support/raw_ostream.h"
4906f32e7eSjoerg #include <random>
5006f32e7eSjoerg #include <vector>
5106f32e7eSjoerg 
5206f32e7eSjoerg using namespace llvm;
5306f32e7eSjoerg 
5406f32e7eSjoerg #define DEBUG_TYPE "uselistorder"
5506f32e7eSjoerg 
5606f32e7eSjoerg static cl::opt<std::string> InputFilename(cl::Positional,
5706f32e7eSjoerg                                           cl::desc("<input bitcode file>"),
5806f32e7eSjoerg                                           cl::init("-"),
5906f32e7eSjoerg                                           cl::value_desc("filename"));
6006f32e7eSjoerg 
6106f32e7eSjoerg static cl::opt<bool> SaveTemps("save-temps", cl::desc("Save temp files"),
6206f32e7eSjoerg                                cl::init(false));
6306f32e7eSjoerg 
6406f32e7eSjoerg static cl::opt<unsigned>
6506f32e7eSjoerg     NumShuffles("num-shuffles",
6606f32e7eSjoerg                 cl::desc("Number of times to shuffle and verify use-lists"),
6706f32e7eSjoerg                 cl::init(1));
6806f32e7eSjoerg 
6906f32e7eSjoerg namespace {
7006f32e7eSjoerg 
7106f32e7eSjoerg struct TempFile {
7206f32e7eSjoerg   std::string Filename;
7306f32e7eSjoerg   FileRemover Remover;
7406f32e7eSjoerg   bool init(const std::string &Ext);
7506f32e7eSjoerg   bool writeBitcode(const Module &M) const;
7606f32e7eSjoerg   bool writeAssembly(const Module &M) const;
7706f32e7eSjoerg   std::unique_ptr<Module> readBitcode(LLVMContext &Context) const;
7806f32e7eSjoerg   std::unique_ptr<Module> readAssembly(LLVMContext &Context) const;
7906f32e7eSjoerg };
8006f32e7eSjoerg 
8106f32e7eSjoerg struct ValueMapping {
8206f32e7eSjoerg   DenseMap<const Value *, unsigned> IDs;
8306f32e7eSjoerg   std::vector<const Value *> Values;
8406f32e7eSjoerg 
8506f32e7eSjoerg   /// Construct a value mapping for module.
8606f32e7eSjoerg   ///
8706f32e7eSjoerg   /// Creates mapping from every value in \c M to an ID.  This mapping includes
8806f32e7eSjoerg   /// un-referencable values.
8906f32e7eSjoerg   ///
9006f32e7eSjoerg   /// Every \a Value that gets serialized in some way should be represented
9106f32e7eSjoerg   /// here.  The order needs to be deterministic, but it's unnecessary to match
9206f32e7eSjoerg   /// the value-ids in the bitcode writer.
9306f32e7eSjoerg   ///
9406f32e7eSjoerg   /// All constants that are referenced by other values are included in the
9506f32e7eSjoerg   /// mapping, but others -- which wouldn't be serialized -- are not.
9606f32e7eSjoerg   ValueMapping(const Module &M);
9706f32e7eSjoerg 
9806f32e7eSjoerg   /// Map a value.
9906f32e7eSjoerg   ///
10006f32e7eSjoerg   /// Maps a value.  If it's a constant, maps all of its operands first.
10106f32e7eSjoerg   void map(const Value *V);
lookup__anon83443d680111::ValueMapping10206f32e7eSjoerg   unsigned lookup(const Value *V) const { return IDs.lookup(V); }
10306f32e7eSjoerg };
10406f32e7eSjoerg 
10506f32e7eSjoerg } // end namespace
10606f32e7eSjoerg 
init(const std::string & Ext)10706f32e7eSjoerg bool TempFile::init(const std::string &Ext) {
10806f32e7eSjoerg   SmallVector<char, 64> Vector;
10906f32e7eSjoerg   LLVM_DEBUG(dbgs() << " - create-temp-file\n");
11006f32e7eSjoerg   if (auto EC = sys::fs::createTemporaryFile("uselistorder", Ext, Vector)) {
11106f32e7eSjoerg     errs() << "verify-uselistorder: error: " << EC.message() << "\n";
11206f32e7eSjoerg     return true;
11306f32e7eSjoerg   }
11406f32e7eSjoerg   assert(!Vector.empty());
11506f32e7eSjoerg 
11606f32e7eSjoerg   Filename.assign(Vector.data(), Vector.data() + Vector.size());
11706f32e7eSjoerg   Remover.setFile(Filename, !SaveTemps);
11806f32e7eSjoerg   if (SaveTemps)
11906f32e7eSjoerg     outs() << " - filename = " << Filename << "\n";
12006f32e7eSjoerg   return false;
12106f32e7eSjoerg }
12206f32e7eSjoerg 
writeBitcode(const Module & M) const12306f32e7eSjoerg bool TempFile::writeBitcode(const Module &M) const {
12406f32e7eSjoerg   LLVM_DEBUG(dbgs() << " - write bitcode\n");
12506f32e7eSjoerg   std::error_code EC;
12606f32e7eSjoerg   raw_fd_ostream OS(Filename, EC, sys::fs::OF_None);
12706f32e7eSjoerg   if (EC) {
12806f32e7eSjoerg     errs() << "verify-uselistorder: error: " << EC.message() << "\n";
12906f32e7eSjoerg     return true;
13006f32e7eSjoerg   }
13106f32e7eSjoerg 
13206f32e7eSjoerg   WriteBitcodeToFile(M, OS, /* ShouldPreserveUseListOrder */ true);
13306f32e7eSjoerg   return false;
13406f32e7eSjoerg }
13506f32e7eSjoerg 
writeAssembly(const Module & M) const13606f32e7eSjoerg bool TempFile::writeAssembly(const Module &M) const {
13706f32e7eSjoerg   LLVM_DEBUG(dbgs() << " - write assembly\n");
13806f32e7eSjoerg   std::error_code EC;
139*da58b97aSjoerg   raw_fd_ostream OS(Filename, EC, sys::fs::OF_TextWithCRLF);
14006f32e7eSjoerg   if (EC) {
14106f32e7eSjoerg     errs() << "verify-uselistorder: error: " << EC.message() << "\n";
14206f32e7eSjoerg     return true;
14306f32e7eSjoerg   }
14406f32e7eSjoerg 
14506f32e7eSjoerg   M.print(OS, nullptr, /* ShouldPreserveUseListOrder */ true);
14606f32e7eSjoerg   return false;
14706f32e7eSjoerg }
14806f32e7eSjoerg 
readBitcode(LLVMContext & Context) const14906f32e7eSjoerg std::unique_ptr<Module> TempFile::readBitcode(LLVMContext &Context) const {
15006f32e7eSjoerg   LLVM_DEBUG(dbgs() << " - read bitcode\n");
15106f32e7eSjoerg   ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOr =
15206f32e7eSjoerg       MemoryBuffer::getFile(Filename);
15306f32e7eSjoerg   if (!BufferOr) {
15406f32e7eSjoerg     errs() << "verify-uselistorder: error: " << BufferOr.getError().message()
15506f32e7eSjoerg            << "\n";
15606f32e7eSjoerg     return nullptr;
15706f32e7eSjoerg   }
15806f32e7eSjoerg 
15906f32e7eSjoerg   MemoryBuffer *Buffer = BufferOr.get().get();
16006f32e7eSjoerg   Expected<std::unique_ptr<Module>> ModuleOr =
16106f32e7eSjoerg       parseBitcodeFile(Buffer->getMemBufferRef(), Context);
16206f32e7eSjoerg   if (!ModuleOr) {
16306f32e7eSjoerg     logAllUnhandledErrors(ModuleOr.takeError(), errs(),
16406f32e7eSjoerg                           "verify-uselistorder: error: ");
16506f32e7eSjoerg     return nullptr;
16606f32e7eSjoerg   }
16706f32e7eSjoerg   return std::move(ModuleOr.get());
16806f32e7eSjoerg }
16906f32e7eSjoerg 
readAssembly(LLVMContext & Context) const17006f32e7eSjoerg std::unique_ptr<Module> TempFile::readAssembly(LLVMContext &Context) const {
17106f32e7eSjoerg   LLVM_DEBUG(dbgs() << " - read assembly\n");
17206f32e7eSjoerg   SMDiagnostic Err;
17306f32e7eSjoerg   std::unique_ptr<Module> M = parseAssemblyFile(Filename, Err, Context);
17406f32e7eSjoerg   if (!M.get())
17506f32e7eSjoerg     Err.print("verify-uselistorder", errs());
17606f32e7eSjoerg   return M;
17706f32e7eSjoerg }
17806f32e7eSjoerg 
ValueMapping(const Module & M)17906f32e7eSjoerg ValueMapping::ValueMapping(const Module &M) {
18006f32e7eSjoerg   // Every value should be mapped, including things like void instructions and
18106f32e7eSjoerg   // basic blocks that are kept out of the ValueEnumerator.
18206f32e7eSjoerg   //
18306f32e7eSjoerg   // The current mapping order makes it easier to debug the tables.  It happens
18406f32e7eSjoerg   // to be similar to the ID mapping when writing ValueEnumerator, but they
18506f32e7eSjoerg   // aren't (and needn't be) in sync.
18606f32e7eSjoerg 
18706f32e7eSjoerg   // Globals.
18806f32e7eSjoerg   for (const GlobalVariable &G : M.globals())
18906f32e7eSjoerg     map(&G);
19006f32e7eSjoerg   for (const GlobalAlias &A : M.aliases())
19106f32e7eSjoerg     map(&A);
19206f32e7eSjoerg   for (const GlobalIFunc &IF : M.ifuncs())
19306f32e7eSjoerg     map(&IF);
19406f32e7eSjoerg   for (const Function &F : M)
19506f32e7eSjoerg     map(&F);
19606f32e7eSjoerg 
19706f32e7eSjoerg   // Constants used by globals.
19806f32e7eSjoerg   for (const GlobalVariable &G : M.globals())
19906f32e7eSjoerg     if (G.hasInitializer())
20006f32e7eSjoerg       map(G.getInitializer());
20106f32e7eSjoerg   for (const GlobalAlias &A : M.aliases())
20206f32e7eSjoerg     map(A.getAliasee());
20306f32e7eSjoerg   for (const GlobalIFunc &IF : M.ifuncs())
20406f32e7eSjoerg     map(IF.getResolver());
20506f32e7eSjoerg   for (const Function &F : M) {
20606f32e7eSjoerg     if (F.hasPrefixData())
20706f32e7eSjoerg       map(F.getPrefixData());
20806f32e7eSjoerg     if (F.hasPrologueData())
20906f32e7eSjoerg       map(F.getPrologueData());
21006f32e7eSjoerg     if (F.hasPersonalityFn())
21106f32e7eSjoerg       map(F.getPersonalityFn());
21206f32e7eSjoerg   }
21306f32e7eSjoerg 
21406f32e7eSjoerg   // Function bodies.
21506f32e7eSjoerg   for (const Function &F : M) {
21606f32e7eSjoerg     for (const Argument &A : F.args())
21706f32e7eSjoerg       map(&A);
21806f32e7eSjoerg     for (const BasicBlock &BB : F)
21906f32e7eSjoerg       map(&BB);
22006f32e7eSjoerg     for (const BasicBlock &BB : F)
22106f32e7eSjoerg       for (const Instruction &I : BB)
22206f32e7eSjoerg         map(&I);
22306f32e7eSjoerg 
22406f32e7eSjoerg     // Constants used by instructions.
22506f32e7eSjoerg     for (const BasicBlock &BB : F)
22606f32e7eSjoerg       for (const Instruction &I : BB)
227*da58b97aSjoerg         for (const Value *Op : I.operands()) {
228*da58b97aSjoerg           // Look through a metadata wrapper.
229*da58b97aSjoerg           if (const auto *MAV = dyn_cast<MetadataAsValue>(Op))
230*da58b97aSjoerg             if (const auto *VAM = dyn_cast<ValueAsMetadata>(MAV->getMetadata()))
231*da58b97aSjoerg               Op = VAM->getValue();
232*da58b97aSjoerg 
23306f32e7eSjoerg           if ((isa<Constant>(Op) && !isa<GlobalValue>(*Op)) ||
23406f32e7eSjoerg               isa<InlineAsm>(Op))
23506f32e7eSjoerg             map(Op);
23606f32e7eSjoerg         }
23706f32e7eSjoerg   }
238*da58b97aSjoerg }
23906f32e7eSjoerg 
map(const Value * V)24006f32e7eSjoerg void ValueMapping::map(const Value *V) {
24106f32e7eSjoerg   if (IDs.lookup(V))
24206f32e7eSjoerg     return;
24306f32e7eSjoerg 
24406f32e7eSjoerg   if (auto *C = dyn_cast<Constant>(V))
24506f32e7eSjoerg     if (!isa<GlobalValue>(C))
24606f32e7eSjoerg       for (const Value *Op : C->operands())
24706f32e7eSjoerg         map(Op);
24806f32e7eSjoerg 
24906f32e7eSjoerg   Values.push_back(V);
25006f32e7eSjoerg   IDs[V] = Values.size();
25106f32e7eSjoerg }
25206f32e7eSjoerg 
25306f32e7eSjoerg #ifndef NDEBUG
dumpMapping(const ValueMapping & VM)25406f32e7eSjoerg static void dumpMapping(const ValueMapping &VM) {
25506f32e7eSjoerg   dbgs() << "value-mapping (size = " << VM.Values.size() << "):\n";
25606f32e7eSjoerg   for (unsigned I = 0, E = VM.Values.size(); I != E; ++I) {
25706f32e7eSjoerg     dbgs() << " - id = " << I << ", value = ";
25806f32e7eSjoerg     VM.Values[I]->dump();
25906f32e7eSjoerg   }
26006f32e7eSjoerg }
26106f32e7eSjoerg 
debugValue(const ValueMapping & M,unsigned I,StringRef Desc)26206f32e7eSjoerg static void debugValue(const ValueMapping &M, unsigned I, StringRef Desc) {
26306f32e7eSjoerg   const Value *V = M.Values[I];
26406f32e7eSjoerg   dbgs() << " - " << Desc << " value = ";
26506f32e7eSjoerg   V->dump();
26606f32e7eSjoerg   for (const Use &U : V->uses()) {
26706f32e7eSjoerg     dbgs() << "   => use: op = " << U.getOperandNo()
26806f32e7eSjoerg            << ", user-id = " << M.IDs.lookup(U.getUser()) << ", user = ";
26906f32e7eSjoerg     U.getUser()->dump();
27006f32e7eSjoerg   }
27106f32e7eSjoerg }
27206f32e7eSjoerg 
debugUserMismatch(const ValueMapping & L,const ValueMapping & R,unsigned I)27306f32e7eSjoerg static void debugUserMismatch(const ValueMapping &L, const ValueMapping &R,
27406f32e7eSjoerg                               unsigned I) {
27506f32e7eSjoerg   dbgs() << " - fail: user mismatch: ID = " << I << "\n";
27606f32e7eSjoerg   debugValue(L, I, "LHS");
27706f32e7eSjoerg   debugValue(R, I, "RHS");
27806f32e7eSjoerg 
27906f32e7eSjoerg   dbgs() << "\nlhs-";
28006f32e7eSjoerg   dumpMapping(L);
28106f32e7eSjoerg   dbgs() << "\nrhs-";
28206f32e7eSjoerg   dumpMapping(R);
28306f32e7eSjoerg }
28406f32e7eSjoerg 
debugSizeMismatch(const ValueMapping & L,const ValueMapping & R)28506f32e7eSjoerg static void debugSizeMismatch(const ValueMapping &L, const ValueMapping &R) {
28606f32e7eSjoerg   dbgs() << " - fail: map size: " << L.Values.size()
28706f32e7eSjoerg          << " != " << R.Values.size() << "\n";
28806f32e7eSjoerg   dbgs() << "\nlhs-";
28906f32e7eSjoerg   dumpMapping(L);
29006f32e7eSjoerg   dbgs() << "\nrhs-";
29106f32e7eSjoerg   dumpMapping(R);
29206f32e7eSjoerg }
29306f32e7eSjoerg #endif
29406f32e7eSjoerg 
matches(const ValueMapping & LM,const ValueMapping & RM)29506f32e7eSjoerg static bool matches(const ValueMapping &LM, const ValueMapping &RM) {
29606f32e7eSjoerg   LLVM_DEBUG(dbgs() << "compare value maps\n");
29706f32e7eSjoerg   if (LM.Values.size() != RM.Values.size()) {
29806f32e7eSjoerg     LLVM_DEBUG(debugSizeMismatch(LM, RM));
29906f32e7eSjoerg     return false;
30006f32e7eSjoerg   }
30106f32e7eSjoerg 
30206f32e7eSjoerg   // This mapping doesn't include dangling constant users, since those don't
30306f32e7eSjoerg   // get serialized.  However, checking if users are constant and calling
30406f32e7eSjoerg   // isConstantUsed() on every one is very expensive.  Instead, just check if
30506f32e7eSjoerg   // the user is mapped.
30606f32e7eSjoerg   auto skipUnmappedUsers =
30706f32e7eSjoerg       [&](Value::const_use_iterator &U, Value::const_use_iterator E,
30806f32e7eSjoerg           const ValueMapping &M) {
30906f32e7eSjoerg     while (U != E && !M.lookup(U->getUser()))
31006f32e7eSjoerg       ++U;
31106f32e7eSjoerg   };
31206f32e7eSjoerg 
31306f32e7eSjoerg   // Iterate through all values, and check that both mappings have the same
31406f32e7eSjoerg   // users.
31506f32e7eSjoerg   for (unsigned I = 0, E = LM.Values.size(); I != E; ++I) {
31606f32e7eSjoerg     const Value *L = LM.Values[I];
31706f32e7eSjoerg     const Value *R = RM.Values[I];
31806f32e7eSjoerg     auto LU = L->use_begin(), LE = L->use_end();
31906f32e7eSjoerg     auto RU = R->use_begin(), RE = R->use_end();
32006f32e7eSjoerg     skipUnmappedUsers(LU, LE, LM);
32106f32e7eSjoerg     skipUnmappedUsers(RU, RE, RM);
32206f32e7eSjoerg 
32306f32e7eSjoerg     while (LU != LE) {
32406f32e7eSjoerg       if (RU == RE) {
32506f32e7eSjoerg         LLVM_DEBUG(debugUserMismatch(LM, RM, I));
32606f32e7eSjoerg         return false;
32706f32e7eSjoerg       }
32806f32e7eSjoerg       if (LM.lookup(LU->getUser()) != RM.lookup(RU->getUser())) {
32906f32e7eSjoerg         LLVM_DEBUG(debugUserMismatch(LM, RM, I));
33006f32e7eSjoerg         return false;
33106f32e7eSjoerg       }
33206f32e7eSjoerg       if (LU->getOperandNo() != RU->getOperandNo()) {
33306f32e7eSjoerg         LLVM_DEBUG(debugUserMismatch(LM, RM, I));
33406f32e7eSjoerg         return false;
33506f32e7eSjoerg       }
33606f32e7eSjoerg       skipUnmappedUsers(++LU, LE, LM);
33706f32e7eSjoerg       skipUnmappedUsers(++RU, RE, RM);
33806f32e7eSjoerg     }
33906f32e7eSjoerg     if (RU != RE) {
34006f32e7eSjoerg       LLVM_DEBUG(debugUserMismatch(LM, RM, I));
34106f32e7eSjoerg       return false;
34206f32e7eSjoerg     }
34306f32e7eSjoerg   }
34406f32e7eSjoerg 
34506f32e7eSjoerg   return true;
34606f32e7eSjoerg }
34706f32e7eSjoerg 
verifyAfterRoundTrip(const Module & M,std::unique_ptr<Module> OtherM)34806f32e7eSjoerg static void verifyAfterRoundTrip(const Module &M,
34906f32e7eSjoerg                                  std::unique_ptr<Module> OtherM) {
35006f32e7eSjoerg   if (!OtherM)
35106f32e7eSjoerg     report_fatal_error("parsing failed");
35206f32e7eSjoerg   if (verifyModule(*OtherM, &errs()))
35306f32e7eSjoerg     report_fatal_error("verification failed");
35406f32e7eSjoerg   if (!matches(ValueMapping(M), ValueMapping(*OtherM)))
35506f32e7eSjoerg     report_fatal_error("use-list order changed");
35606f32e7eSjoerg }
35706f32e7eSjoerg 
verifyBitcodeUseListOrder(const Module & M)35806f32e7eSjoerg static void verifyBitcodeUseListOrder(const Module &M) {
35906f32e7eSjoerg   TempFile F;
36006f32e7eSjoerg   if (F.init("bc"))
36106f32e7eSjoerg     report_fatal_error("failed to initialize bitcode file");
36206f32e7eSjoerg 
36306f32e7eSjoerg   if (F.writeBitcode(M))
36406f32e7eSjoerg     report_fatal_error("failed to write bitcode");
36506f32e7eSjoerg 
36606f32e7eSjoerg   LLVMContext Context;
36706f32e7eSjoerg   verifyAfterRoundTrip(M, F.readBitcode(Context));
36806f32e7eSjoerg }
36906f32e7eSjoerg 
verifyAssemblyUseListOrder(const Module & M)37006f32e7eSjoerg static void verifyAssemblyUseListOrder(const Module &M) {
37106f32e7eSjoerg   TempFile F;
37206f32e7eSjoerg   if (F.init("ll"))
37306f32e7eSjoerg     report_fatal_error("failed to initialize assembly file");
37406f32e7eSjoerg 
37506f32e7eSjoerg   if (F.writeAssembly(M))
37606f32e7eSjoerg     report_fatal_error("failed to write assembly");
37706f32e7eSjoerg 
37806f32e7eSjoerg   LLVMContext Context;
37906f32e7eSjoerg   verifyAfterRoundTrip(M, F.readAssembly(Context));
38006f32e7eSjoerg }
38106f32e7eSjoerg 
verifyUseListOrder(const Module & M)38206f32e7eSjoerg static void verifyUseListOrder(const Module &M) {
38306f32e7eSjoerg   outs() << "verify bitcode\n";
38406f32e7eSjoerg   verifyBitcodeUseListOrder(M);
38506f32e7eSjoerg   outs() << "verify assembly\n";
38606f32e7eSjoerg   verifyAssemblyUseListOrder(M);
38706f32e7eSjoerg }
38806f32e7eSjoerg 
shuffleValueUseLists(Value * V,std::minstd_rand0 & Gen,DenseSet<Value * > & Seen)38906f32e7eSjoerg static void shuffleValueUseLists(Value *V, std::minstd_rand0 &Gen,
39006f32e7eSjoerg                                  DenseSet<Value *> &Seen) {
39106f32e7eSjoerg   if (!Seen.insert(V).second)
39206f32e7eSjoerg     return;
39306f32e7eSjoerg 
39406f32e7eSjoerg   if (auto *C = dyn_cast<Constant>(V))
39506f32e7eSjoerg     if (!isa<GlobalValue>(C))
39606f32e7eSjoerg       for (Value *Op : C->operands())
39706f32e7eSjoerg         shuffleValueUseLists(Op, Gen, Seen);
39806f32e7eSjoerg 
39906f32e7eSjoerg   if (V->use_empty() || std::next(V->use_begin()) == V->use_end())
40006f32e7eSjoerg     // Nothing to shuffle for 0 or 1 users.
40106f32e7eSjoerg     return;
40206f32e7eSjoerg 
40306f32e7eSjoerg   // Generate random numbers between 10 and 99, which will line up nicely in
40406f32e7eSjoerg   // debug output.  We're not worried about collisons here.
40506f32e7eSjoerg   LLVM_DEBUG(dbgs() << "V = "; V->dump());
40606f32e7eSjoerg   std::uniform_int_distribution<short> Dist(10, 99);
40706f32e7eSjoerg   SmallDenseMap<const Use *, short, 16> Order;
40806f32e7eSjoerg   auto compareUses =
40906f32e7eSjoerg       [&Order](const Use &L, const Use &R) { return Order[&L] < Order[&R]; };
41006f32e7eSjoerg   do {
41106f32e7eSjoerg     for (const Use &U : V->uses()) {
41206f32e7eSjoerg       auto I = Dist(Gen);
41306f32e7eSjoerg       Order[&U] = I;
41406f32e7eSjoerg       LLVM_DEBUG(dbgs() << " - order: " << I << ", op = " << U.getOperandNo()
41506f32e7eSjoerg                         << ", U = ";
41606f32e7eSjoerg                  U.getUser()->dump());
41706f32e7eSjoerg     }
41806f32e7eSjoerg   } while (std::is_sorted(V->use_begin(), V->use_end(), compareUses));
41906f32e7eSjoerg 
42006f32e7eSjoerg   LLVM_DEBUG(dbgs() << " => shuffle\n");
42106f32e7eSjoerg   V->sortUseList(compareUses);
42206f32e7eSjoerg 
42306f32e7eSjoerg   LLVM_DEBUG({
42406f32e7eSjoerg     for (const Use &U : V->uses()) {
42506f32e7eSjoerg       dbgs() << " - order: " << Order.lookup(&U)
42606f32e7eSjoerg              << ", op = " << U.getOperandNo() << ", U = ";
42706f32e7eSjoerg       U.getUser()->dump();
42806f32e7eSjoerg     }
42906f32e7eSjoerg   });
43006f32e7eSjoerg }
43106f32e7eSjoerg 
reverseValueUseLists(Value * V,DenseSet<Value * > & Seen)43206f32e7eSjoerg static void reverseValueUseLists(Value *V, DenseSet<Value *> &Seen) {
43306f32e7eSjoerg   if (!Seen.insert(V).second)
43406f32e7eSjoerg     return;
43506f32e7eSjoerg 
43606f32e7eSjoerg   if (auto *C = dyn_cast<Constant>(V))
43706f32e7eSjoerg     if (!isa<GlobalValue>(C))
43806f32e7eSjoerg       for (Value *Op : C->operands())
43906f32e7eSjoerg         reverseValueUseLists(Op, Seen);
44006f32e7eSjoerg 
44106f32e7eSjoerg   if (V->use_empty() || std::next(V->use_begin()) == V->use_end())
44206f32e7eSjoerg     // Nothing to shuffle for 0 or 1 users.
44306f32e7eSjoerg     return;
44406f32e7eSjoerg 
44506f32e7eSjoerg   LLVM_DEBUG({
44606f32e7eSjoerg     dbgs() << "V = ";
44706f32e7eSjoerg     V->dump();
44806f32e7eSjoerg     for (const Use &U : V->uses()) {
44906f32e7eSjoerg       dbgs() << " - order: op = " << U.getOperandNo() << ", U = ";
45006f32e7eSjoerg       U.getUser()->dump();
45106f32e7eSjoerg     }
45206f32e7eSjoerg     dbgs() << " => reverse\n";
45306f32e7eSjoerg   });
45406f32e7eSjoerg 
45506f32e7eSjoerg   V->reverseUseList();
45606f32e7eSjoerg 
45706f32e7eSjoerg   LLVM_DEBUG({
45806f32e7eSjoerg     for (const Use &U : V->uses()) {
45906f32e7eSjoerg       dbgs() << " - order: op = " << U.getOperandNo() << ", U = ";
46006f32e7eSjoerg       U.getUser()->dump();
46106f32e7eSjoerg     }
46206f32e7eSjoerg   });
46306f32e7eSjoerg }
46406f32e7eSjoerg 
46506f32e7eSjoerg template <class Changer>
changeUseLists(Module & M,Changer changeValueUseList)46606f32e7eSjoerg static void changeUseLists(Module &M, Changer changeValueUseList) {
46706f32e7eSjoerg   // Visit every value that would be serialized to an IR file.
46806f32e7eSjoerg   //
46906f32e7eSjoerg   // Globals.
47006f32e7eSjoerg   for (GlobalVariable &G : M.globals())
47106f32e7eSjoerg     changeValueUseList(&G);
47206f32e7eSjoerg   for (GlobalAlias &A : M.aliases())
47306f32e7eSjoerg     changeValueUseList(&A);
47406f32e7eSjoerg   for (GlobalIFunc &IF : M.ifuncs())
47506f32e7eSjoerg     changeValueUseList(&IF);
47606f32e7eSjoerg   for (Function &F : M)
47706f32e7eSjoerg     changeValueUseList(&F);
47806f32e7eSjoerg 
47906f32e7eSjoerg   // Constants used by globals.
48006f32e7eSjoerg   for (GlobalVariable &G : M.globals())
48106f32e7eSjoerg     if (G.hasInitializer())
48206f32e7eSjoerg       changeValueUseList(G.getInitializer());
48306f32e7eSjoerg   for (GlobalAlias &A : M.aliases())
48406f32e7eSjoerg     changeValueUseList(A.getAliasee());
48506f32e7eSjoerg   for (GlobalIFunc &IF : M.ifuncs())
48606f32e7eSjoerg     changeValueUseList(IF.getResolver());
48706f32e7eSjoerg   for (Function &F : M) {
48806f32e7eSjoerg     if (F.hasPrefixData())
48906f32e7eSjoerg       changeValueUseList(F.getPrefixData());
49006f32e7eSjoerg     if (F.hasPrologueData())
49106f32e7eSjoerg       changeValueUseList(F.getPrologueData());
49206f32e7eSjoerg     if (F.hasPersonalityFn())
49306f32e7eSjoerg       changeValueUseList(F.getPersonalityFn());
49406f32e7eSjoerg   }
49506f32e7eSjoerg 
49606f32e7eSjoerg   // Function bodies.
49706f32e7eSjoerg   for (Function &F : M) {
49806f32e7eSjoerg     for (Argument &A : F.args())
49906f32e7eSjoerg       changeValueUseList(&A);
50006f32e7eSjoerg     for (BasicBlock &BB : F)
50106f32e7eSjoerg       changeValueUseList(&BB);
50206f32e7eSjoerg     for (BasicBlock &BB : F)
50306f32e7eSjoerg       for (Instruction &I : BB)
50406f32e7eSjoerg         changeValueUseList(&I);
50506f32e7eSjoerg 
50606f32e7eSjoerg     // Constants used by instructions.
50706f32e7eSjoerg     for (BasicBlock &BB : F)
50806f32e7eSjoerg       for (Instruction &I : BB)
509*da58b97aSjoerg         for (Value *Op : I.operands()) {
510*da58b97aSjoerg           // Look through a metadata wrapper.
511*da58b97aSjoerg           if (auto *MAV = dyn_cast<MetadataAsValue>(Op))
512*da58b97aSjoerg             if (auto *VAM = dyn_cast<ValueAsMetadata>(MAV->getMetadata()))
513*da58b97aSjoerg               Op = VAM->getValue();
51406f32e7eSjoerg           if ((isa<Constant>(Op) && !isa<GlobalValue>(*Op)) ||
51506f32e7eSjoerg               isa<InlineAsm>(Op))
51606f32e7eSjoerg             changeValueUseList(Op);
51706f32e7eSjoerg         }
518*da58b97aSjoerg   }
51906f32e7eSjoerg 
52006f32e7eSjoerg   if (verifyModule(M, &errs()))
52106f32e7eSjoerg     report_fatal_error("verification failed");
52206f32e7eSjoerg }
52306f32e7eSjoerg 
shuffleUseLists(Module & M,unsigned SeedOffset)52406f32e7eSjoerg static void shuffleUseLists(Module &M, unsigned SeedOffset) {
52506f32e7eSjoerg   std::minstd_rand0 Gen(std::minstd_rand0::default_seed + SeedOffset);
52606f32e7eSjoerg   DenseSet<Value *> Seen;
52706f32e7eSjoerg   changeUseLists(M, [&](Value *V) { shuffleValueUseLists(V, Gen, Seen); });
52806f32e7eSjoerg   LLVM_DEBUG(dbgs() << "\n");
52906f32e7eSjoerg }
53006f32e7eSjoerg 
reverseUseLists(Module & M)53106f32e7eSjoerg static void reverseUseLists(Module &M) {
53206f32e7eSjoerg   DenseSet<Value *> Seen;
53306f32e7eSjoerg   changeUseLists(M, [&](Value *V) { reverseValueUseLists(V, Seen); });
53406f32e7eSjoerg   LLVM_DEBUG(dbgs() << "\n");
53506f32e7eSjoerg }
53606f32e7eSjoerg 
main(int argc,char ** argv)53706f32e7eSjoerg int main(int argc, char **argv) {
53806f32e7eSjoerg   InitLLVM X(argc, argv);
53906f32e7eSjoerg 
54006f32e7eSjoerg   // Enable debug stream buffering.
54106f32e7eSjoerg   EnableDebugBuffering = true;
54206f32e7eSjoerg 
54306f32e7eSjoerg   LLVMContext Context;
54406f32e7eSjoerg 
54506f32e7eSjoerg   cl::ParseCommandLineOptions(argc, argv,
54606f32e7eSjoerg                               "llvm tool to verify use-list order\n");
54706f32e7eSjoerg 
54806f32e7eSjoerg   SMDiagnostic Err;
54906f32e7eSjoerg 
55006f32e7eSjoerg   // Load the input module...
55106f32e7eSjoerg   std::unique_ptr<Module> M = parseIRFile(InputFilename, Err, Context);
55206f32e7eSjoerg 
55306f32e7eSjoerg   if (!M.get()) {
55406f32e7eSjoerg     Err.print(argv[0], errs());
55506f32e7eSjoerg     return 1;
55606f32e7eSjoerg   }
55706f32e7eSjoerg   if (verifyModule(*M, &errs())) {
55806f32e7eSjoerg     errs() << argv[0] << ": " << InputFilename
55906f32e7eSjoerg            << ": error: input module is broken!\n";
56006f32e7eSjoerg     return 1;
56106f32e7eSjoerg   }
56206f32e7eSjoerg 
56306f32e7eSjoerg   // Verify the use lists now and after reversing them.
56406f32e7eSjoerg   outs() << "*** verify-uselistorder ***\n";
56506f32e7eSjoerg   verifyUseListOrder(*M);
56606f32e7eSjoerg   outs() << "reverse\n";
56706f32e7eSjoerg   reverseUseLists(*M);
56806f32e7eSjoerg   verifyUseListOrder(*M);
56906f32e7eSjoerg 
57006f32e7eSjoerg   for (unsigned I = 0, E = NumShuffles; I != E; ++I) {
57106f32e7eSjoerg     outs() << "\n";
57206f32e7eSjoerg 
57306f32e7eSjoerg     // Shuffle with a different (deterministic) seed each time.
57406f32e7eSjoerg     outs() << "shuffle (" << I + 1 << " of " << E << ")\n";
57506f32e7eSjoerg     shuffleUseLists(*M, I);
57606f32e7eSjoerg 
57706f32e7eSjoerg     // Verify again before and after reversing.
57806f32e7eSjoerg     verifyUseListOrder(*M);
57906f32e7eSjoerg     outs() << "reverse\n";
58006f32e7eSjoerg     reverseUseLists(*M);
58106f32e7eSjoerg     verifyUseListOrder(*M);
58206f32e7eSjoerg   }
58306f32e7eSjoerg 
58406f32e7eSjoerg   return 0;
58506f32e7eSjoerg }
586