Move -verify-use-list-order into llvm-uselistorder
authorDuncan P. N. Exon Smith <dexonsmith@apple.com>
Fri, 25 Jul 2014 17:13:03 +0000 (17:13 +0000)
committerDuncan P. N. Exon Smith <dexonsmith@apple.com>
Fri, 25 Jul 2014 17:13:03 +0000 (17:13 +0000)
Ugh.  Turns out not even transformation passes link in how to read IR.
I sincerely believe the buildbots will finally agree with my system
after this though.  (I don't really understand why all of this has been
working on my system, but not on all the buildbots.)

Create a new tool called llvm-uselistorder to use for verifying use-list
order.  For now, just dump everything from the (now defunct)
-verify-use-list-order pass into the tool.

This might be a better way to test use-list order anyway.

Part of PR5680.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@213957 91177308-0d34-0410-b5e6-96231b3b80d8

14 files changed:
include/llvm/InitializePasses.h
include/llvm/LinkAllPasses.h
include/llvm/Transforms/IPO.h
lib/Transforms/IPO/CMakeLists.txt
lib/Transforms/IPO/IPO.cpp
lib/Transforms/IPO/VerifyUseListOrder.cpp [deleted file]
test/Bitcode/use-list-order.ll
test/CMakeLists.txt
test/lit.cfg
tools/CMakeLists.txt
tools/llvm-uselistorder/CMakeLists.txt [new file with mode: 0644]
tools/llvm-uselistorder/LLVMBuild.txt [new file with mode: 0644]
tools/llvm-uselistorder/Makefile [new file with mode: 0644]
tools/llvm-uselistorder/llvm-uselistorder.cpp [new file with mode: 0644]

index ae036b462ab2e6ed82bca2bc5dcd4266be6bf9da..20074f0a5d5df42c5f7300831815370fc0ae5d3a 100644 (file)
@@ -268,7 +268,6 @@ void initializeUnifyFunctionExitNodesPass(PassRegistry&);
 void initializeUnreachableBlockElimPass(PassRegistry&);
 void initializeUnreachableMachineBlockElimPass(PassRegistry&);
 void initializeVerifierLegacyPassPass(PassRegistry&);
-void initializeVerifyUseListOrderPass(PassRegistry&);
 void initializeVirtRegMapPass(PassRegistry&);
 void initializeVirtRegRewriterPass(PassRegistry&);
 void initializeInstSimplifierPass(PassRegistry&);
index ec695c8b79cdbbbaf99540ef718e86078dcf0f54..b7f832dcee9986e8ea52b319b155731dfc67298d 100644 (file)
@@ -161,7 +161,6 @@ namespace {
       (void) llvm::createPartiallyInlineLibCallsPass();
       (void) llvm::createScalarizerPass();
       (void) llvm::createSeparateConstOffsetFromGEPPass();
-      (void) llvm::createVerifyUseListOrderPass();
 
       (void)new llvm::IntervalPartition();
       (void)new llvm::FindUsedTypes();
index ca6d5144fc41261b6782c4bbabd2e017a520cd76..ce1a7d6a5230a3ca4e7c409bd9a1d75a4a79d3d6 100644 (file)
@@ -118,11 +118,6 @@ ModulePass *createInternalizePass(ArrayRef<const char *> ExportList);
 /// createInternalizePass - Same as above, but with an empty exportList.
 ModulePass *createInternalizePass();
 
-/// \brief Verify that use-list order doesn't change after shuffling.
-///
-/// \note This is a transformation, since the use-list order changes.
-ModulePass *createVerifyUseListOrderPass();
-
 //===----------------------------------------------------------------------===//
 /// createDeadArgEliminationPass - This pass removes arguments from functions
 /// which are not used by the body of the function.
index 070ecfdc1437071ed78e2f13d8336ca3532ed9b0..90c1c33e6dca7945ac9d040b5bd4e903253c6240 100644 (file)
@@ -20,7 +20,6 @@ add_llvm_library(LLVMipo
   PruneEH.cpp
   StripDeadPrototypes.cpp
   StripSymbols.cpp
-  VerifyUseListOrder.cpp
   )
 
 add_dependencies(LLVMipo intrinsics_gen)
index 5dce2d6b407a7d0f8f6eedb00242b0cfed26163c..b4d31d8d6fc25b85fb0a4bd8c48f522d830f760a 100644 (file)
@@ -44,7 +44,6 @@ void llvm::initializeIPO(PassRegistry &Registry) {
   initializeStripDebugDeclarePass(Registry);
   initializeStripDeadDebugInfoPass(Registry);
   initializeStripNonDebugSymbolsPass(Registry);
-  initializeVerifyUseListOrderPass(Registry);
   initializeBarrierNoopPass(Registry);
 }
 
diff --git a/lib/Transforms/IPO/VerifyUseListOrder.cpp b/lib/Transforms/IPO/VerifyUseListOrder.cpp
deleted file mode 100644 (file)
index 16a88e3..0000000
+++ /dev/null
@@ -1,370 +0,0 @@
-//===- VerifyUseListOrder.cpp - Use List Order Verifier ---------*- C++ -*-===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Pass to verify use-list order doesn't change after serialization.
-//
-// Despite it being a verifier, this pass *does* transform the module, since it
-// shuffles the use-list of every value.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Transforms/IPO.h"
-
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/AsmParser/Parser.h"
-#include "llvm/Bitcode/ReaderWriter.h"
-#include "llvm/IR/LLVMContext.h"
-#include "llvm/IR/Module.h"
-#include "llvm/IR/UseListOrder.h"
-#include "llvm/Pass.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/FileUtilities.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/SourceMgr.h"
-
-using namespace llvm;
-
-#define DEBUG_TYPE "use-list-order"
-
-namespace {
-
-struct TempFile {
-  std::string Filename;
-  FileRemover Remover;
-  bool init(const std::string &Ext);
-  bool writeBitcode(const Module &M) const;
-  bool writeAssembly(const Module &M) const;
-  std::unique_ptr<Module> readBitcode(LLVMContext &Context) const;
-  std::unique_ptr<Module> readAssembly(LLVMContext &Context) const;
-};
-
-struct ValueMapping {
-  DenseMap<const Value *, unsigned> IDs;
-  std::vector<const Value *> Values;
-
-  /// \brief Construct a value mapping for module.
-  ///
-  /// Creates mapping from every value in \c M to an ID.  This mapping includes
-  /// un-referencable values.
-  ///
-  /// Every \a Value that gets serialized in some way should be represented
-  /// here.  The order needs to be deterministic, but it's unnecessary to match
-  /// the value-ids in the bitcode writer.
-  ///
-  /// All constants that are referenced by other values are included in the
-  /// mapping, but others -- which wouldn't be serialized -- are not.
-  ValueMapping(const Module &M);
-
-  /// \brief Map a value.
-  ///
-  /// Maps a value.  If it's a constant, maps all of its operands first.
-  void map(const Value *V);
-  unsigned lookup(const Value *V) const { return IDs.lookup(V); }
-};
-
-} // end namespace
-
-bool TempFile::init(const std::string &Ext) {
-  SmallVector<char, 64> Vector;
-  DEBUG(dbgs() << " - create-temp-file\n");
-  if (auto EC = sys::fs::createTemporaryFile("use-list-order", Ext, Vector)) {
-    (void)EC;
-    DEBUG(dbgs() << "error: " << EC.message() << "\n");
-    return true;
-  }
-  assert(!Vector.empty());
-
-  Filename.assign(Vector.data(), Vector.data() + Vector.size());
-  Remover.setFile(Filename);
-  DEBUG(dbgs() << " - filename = " << Filename << "\n");
-  return false;
-}
-
-bool TempFile::writeBitcode(const Module &M) const {
-  DEBUG(dbgs() << " - write bitcode\n");
-  std::string ErrorInfo;
-  raw_fd_ostream OS(Filename.c_str(), ErrorInfo, sys::fs::F_None);
-  if (!ErrorInfo.empty()) {
-    DEBUG(dbgs() << "error: " << ErrorInfo << "\n");
-    return true;
-  }
-
-  WriteBitcodeToFile(&M, OS);
-  return false;
-}
-
-bool TempFile::writeAssembly(const Module &M) const {
-  DEBUG(dbgs() << " - write assembly\n");
-  std::string ErrorInfo;
-  raw_fd_ostream OS(Filename.c_str(), ErrorInfo, sys::fs::F_Text);
-  if (!ErrorInfo.empty()) {
-    DEBUG(dbgs() << "error: " << ErrorInfo << "\n");
-    return true;
-  }
-
-  OS << M;
-  return false;
-}
-
-std::unique_ptr<Module> TempFile::readBitcode(LLVMContext &Context) const {
-  DEBUG(dbgs() << " - read bitcode\n");
-  ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOr =
-      MemoryBuffer::getFile(Filename);
-  if (!BufferOr) {
-    DEBUG(dbgs() << "error: " << BufferOr.getError().message() << "\n");
-    return nullptr;
-  }
-
-  std::unique_ptr<MemoryBuffer> Buffer = std::move(BufferOr.get());
-  ErrorOr<Module *> ModuleOr = parseBitcodeFile(Buffer.release(), Context);
-  if (!ModuleOr) {
-    DEBUG(dbgs() << "error: " << ModuleOr.getError().message() << "\n");
-    return nullptr;
-  }
-  return std::unique_ptr<Module>(ModuleOr.get());
-}
-
-std::unique_ptr<Module> TempFile::readAssembly(LLVMContext &Context) const {
-  DEBUG(dbgs() << " - read assembly\n");
-  SMDiagnostic Err;
-  std::unique_ptr<Module> M(ParseAssemblyFile(Filename, Err, Context));
-  if (!M.get())
-    DEBUG(dbgs() << "error: "; Err.print("verify-use-list-order", dbgs()));
-  return M;
-}
-
-ValueMapping::ValueMapping(const Module &M) {
-  // Every value should be mapped, including things like void instructions and
-  // basic blocks that are kept out of the ValueEnumerator.
-  //
-  // The current mapping order makes it easier to debug the tables.  It happens
-  // to be similar to the ID mapping when writing ValueEnumerator, but they
-  // aren't (and needn't be) in sync.
-
-  // Globals.
-  for (const GlobalVariable &G : M.globals())
-    map(&G);
-  for (const GlobalAlias &A : M.aliases())
-    map(&A);
-  for (const Function &F : M)
-    map(&F);
-
-  // Constants used by globals.
-  for (const GlobalVariable &G : M.globals())
-    if (G.hasInitializer())
-      map(G.getInitializer());
-  for (const GlobalAlias &A : M.aliases())
-    map(A.getAliasee());
-  for (const Function &F : M)
-    if (F.hasPrefixData())
-      map(F.getPrefixData());
-
-  // Function bodies.
-  for (const Function &F : M) {
-    for (const Argument &A : F.args())
-      map(&A);
-    for (const BasicBlock &BB : F)
-      map(&BB);
-    for (const BasicBlock &BB : F)
-      for (const Instruction &I : BB)
-        map(&I);
-
-    // Constants used by instructions.
-    for (const BasicBlock &BB : F)
-      for (const Instruction &I : BB)
-        for (const Value *Op : I.operands())
-          if ((isa<Constant>(Op) && !isa<GlobalValue>(*Op)) ||
-              isa<InlineAsm>(Op))
-            map(Op);
-  }
-}
-
-void ValueMapping::map(const Value *V) {
-  if (IDs.lookup(V))
-    return;
-
-  if (auto *C = dyn_cast<Constant>(V))
-    if (!isa<GlobalValue>(C))
-      for (const Value *Op : C->operands())
-        map(Op);
-
-  Values.push_back(V);
-  IDs[V] = Values.size();
-}
-
-#ifndef NDEBUG
-static void dumpMapping(const ValueMapping &VM) {
-  dbgs() << "value-mapping (size = " << VM.Values.size() << "):\n";
-  for (unsigned I = 0, E = VM.Values.size(); I != E; ++I) {
-    dbgs() << " - id = " << I << ", value = ";
-    VM.Values[I]->dump();
-  }
-}
-
-static void debugValue(const ValueMapping &M, unsigned I, StringRef Desc) {
-  const Value *V = M.Values[I];
-  dbgs() << " - " << Desc << " value = ";
-  V->dump();
-  for (const Use &U : V->uses()) {
-    dbgs() << "   => use: op = " << U.getOperandNo()
-           << ", user-id = " << M.IDs.lookup(U.getUser()) << ", user = ";
-    U.getUser()->dump();
-  }
-}
-
-static void debugUserMismatch(const ValueMapping &L, const ValueMapping &R,
-                              unsigned I) {
-  dbgs() << " - fail: user mismatch: ID = " << I << "\n";
-  debugValue(L, I, "LHS");
-  debugValue(R, I, "RHS");
-
-  dbgs() << "\nlhs-";
-  dumpMapping(L);
-  dbgs() << "\nrhs-";
-  dumpMapping(R);
-}
-
-static void debugSizeMismatch(const ValueMapping &L, const ValueMapping &R) {
-  dbgs() << " - fail: map size: " << L.Values.size()
-         << " != " << R.Values.size() << "\n";
-  dbgs() << "\nlhs-";
-  dumpMapping(L);
-  dbgs() << "\nrhs-";
-  dumpMapping(R);
-}
-#endif
-
-static bool matches(const ValueMapping &LM, const ValueMapping &RM) {
-  DEBUG(dbgs() << "compare value maps\n");
-  if (LM.Values.size() != RM.Values.size()) {
-    DEBUG(debugSizeMismatch(LM, RM));
-    return false;
-  }
-
-  // This mapping doesn't include dangling constant users, since those don't
-  // get serialized.  However, checking if users are constant and calling
-  // isConstantUsed() on every one is very expensive.  Instead, just check if
-  // the user is mapped.
-  auto skipUnmappedUsers =
-      [&](Value::const_use_iterator &U, Value::const_use_iterator E,
-          const ValueMapping &M) {
-    while (U != E && !M.lookup(U->getUser()))
-      ++U;
-  };
-
-  // Iterate through all values, and check that both mappings have the same
-  // users.
-  for (unsigned I = 0, E = LM.Values.size(); I != E; ++I) {
-    const Value *L = LM.Values[I];
-    const Value *R = RM.Values[I];
-    auto LU = L->use_begin(), LE = L->use_end();
-    auto RU = R->use_begin(), RE = R->use_end();
-    skipUnmappedUsers(LU, LE, LM);
-    skipUnmappedUsers(RU, RE, RM);
-
-    while (LU != LE) {
-      if (RU == RE) {
-        DEBUG(debugUserMismatch(LM, RM, I));
-        return false;
-      }
-      if (LM.lookup(LU->getUser()) != RM.lookup(RU->getUser())) {
-        DEBUG(debugUserMismatch(LM, RM, I));
-        return false;
-      }
-      if (LU->getOperandNo() != RU->getOperandNo()) {
-        DEBUG(debugUserMismatch(LM, RM, I));
-        return false;
-      }
-      skipUnmappedUsers(++LU, LE, LM);
-      skipUnmappedUsers(++RU, RE, RM);
-    }
-    if (RU != RE) {
-      DEBUG(debugUserMismatch(LM, RM, I));
-      return false;
-    }
-  }
-
-  return true;
-}
-
-static bool verifyBitcodeUseListOrder(const Module &M) {
-  DEBUG(dbgs() << "*** verify-use-list-order: bitcode ***\n");
-  TempFile F;
-  if (F.init("bc"))
-    return false;
-
-  if (F.writeBitcode(M))
-    return false;
-
-  LLVMContext Context;
-  std::unique_ptr<Module> OtherM = F.readBitcode(Context);
-  if (!OtherM)
-    return false;
-
-  return matches(ValueMapping(M), ValueMapping(*OtherM));
-}
-
-static bool verifyAssemblyUseListOrder(const Module &M) {
-  DEBUG(dbgs() << "*** verify-use-list-order: assembly ***\n");
-  TempFile F;
-  if (F.init("ll"))
-    return false;
-
-  if (F.writeAssembly(M))
-    return false;
-
-  LLVMContext Context;
-  std::unique_ptr<Module> OtherM = F.readAssembly(Context);
-  if (!OtherM)
-    return false;
-
-  return matches(ValueMapping(M), ValueMapping(*OtherM));
-}
-
-namespace {
-class VerifyUseListOrder : public ModulePass {
-public:
-  static char ID;
-  VerifyUseListOrder();
-  bool runOnModule(Module &M) override;
-};
-} // end anonymous namespace
-
-char VerifyUseListOrder::ID = 0;
-INITIALIZE_PASS(VerifyUseListOrder, "verify-use-list-order",
-                "Verify Use List Order", false, false)
-VerifyUseListOrder::VerifyUseListOrder() : ModulePass(ID) {
-  initializeVerifyUseListOrderPass(*PassRegistry::getPassRegistry());
-}
-
-bool VerifyUseListOrder::runOnModule(Module &M) {
-  DEBUG(dbgs() << "*** verify-use-list-order ***\n");
-  if (!shouldPreserveBitcodeUseListOrder()) {
-    // Can't verify if order isn't preserved.
-    DEBUG(dbgs() << "warning: cannot verify bitcode; "
-                    "try -preserve-bc-use-list-order\n");
-    return false;
-  }
-
-  shuffleUseLists(M);
-  if (!verifyBitcodeUseListOrder(M))
-    report_fatal_error("bitcode use-list order changed");
-
-  if (shouldPreserveBitcodeUseListOrder())
-    if (!verifyAssemblyUseListOrder(M))
-      report_fatal_error("assembly use-list order changed");
-
-  return true;
-}
-
-ModulePass *llvm::createVerifyUseListOrderPass() {
-  return new VerifyUseListOrder;
-}
index 6d87dedee5171c5b96e58ce3e3cdb3294d24a2fd..aef526403c6acbe4a471dd04b515ff79c267f809 100644 (file)
@@ -1,4 +1,4 @@
-; RUN: opt -S < %s -preserve-bc-use-list-order -verify-use-list-order
+; RUN: llvm-uselistorder < %s -preserve-bc-use-list-order
 ; XFAIL: *
 
 @a = global [4 x i1] [i1 0, i1 1, i1 0, i1 1]
index 928b87a778cc04df7f9db384152d5503ea85bad3..59a17b1950680d1481bcd622076fa84b6fa08593 100644 (file)
@@ -44,6 +44,7 @@ set(LLVM_TEST_DEPENDS
           llvm-rtdyld
           llvm-symbolizer
           llvm-tblgen
+          llvm-uselistorder
           llvm-vtabledump
           macho-dump
           opt
index 99c05a794893ab8d4252e77f6bf6d6bc468247f2..2b9b2d9a7d05b2f137892aa02f2ddbc5114f8087 100644 (file)
@@ -228,6 +228,7 @@ for pattern in [r"\bbugpoint\b(?!-)",
                 r"\bllvm-rtdyld\b",
                 r"\bllvm-size\b",
                 r"\bllvm-tblgen\b",
+                r"\bllvm-uselistorder\b",
                 r"\bllvm-vtabledump\b",
                 r"\bllvm-c-test\b",
                 r"\bmacho-dump\b",
index acc4eb12860ee07ab0f4da7b89fcf84eba73325a..ef8095b688e1cf17654a08160b93b8e4a1bd3807 100644 (file)
@@ -43,6 +43,8 @@ add_llvm_tool_subdirectory(llvm-bcanalyzer)
 add_llvm_tool_subdirectory(llvm-stress)
 add_llvm_tool_subdirectory(llvm-mcmarkup)
 
+add_llvm_tool_subdirectory(llvm-uselistorder)
+
 add_llvm_tool_subdirectory(llvm-symbolizer)
 
 add_llvm_tool_subdirectory(llvm-c-test)
diff --git a/tools/llvm-uselistorder/CMakeLists.txt b/tools/llvm-uselistorder/CMakeLists.txt
new file mode 100644 (file)
index 0000000..21c46e9
--- /dev/null
@@ -0,0 +1,9 @@
+set(LLVM_LINK_COMPONENTS
+  Support
+  IRReader
+  BitWriter
+  )
+
+add_llvm_tool(llvm-uselistorder
+  llvm-uselistorder.cpp
+  )
diff --git a/tools/llvm-uselistorder/LLVMBuild.txt b/tools/llvm-uselistorder/LLVMBuild.txt
new file mode 100644 (file)
index 0000000..b9d6f10
--- /dev/null
@@ -0,0 +1,22 @@
+;===- ./tools/llvm-uselistorder/LLVMBuild.txt ------------------*- Conf -*--===;
+;
+;                     The LLVM Compiler Infrastructure
+;
+; This file is distributed under the University of Illinois Open Source
+; License. See LICENSE.TXT for details.
+;
+;===------------------------------------------------------------------------===;
+;
+; This is an LLVMBuild description file for the components in this subdirectory.
+;
+; For more information on the LLVMBuild system, please see:
+;
+;   http://llvm.org/docs/LLVMBuild.html
+;
+;===------------------------------------------------------------------------===;
+
+[component_0]
+type = Tool
+name = llvm-uselistorder
+parent = Tools
+required_libraries = IRReader BitWriter Support
diff --git a/tools/llvm-uselistorder/Makefile b/tools/llvm-uselistorder/Makefile
new file mode 100644 (file)
index 0000000..b9fc34b
--- /dev/null
@@ -0,0 +1,17 @@
+##===- tools/llvm-uselistorder/Makefile --------------------*- Makefile -*-===##
+#
+#                     The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL := ../..
+TOOLNAME := llvm-uselistorder
+LINK_COMPONENTS := support irreader bitwriter
+
+# This tool has no plugins, optimize startup time.
+TOOL_NO_EXPORTS := 1
+
+include $(LEVEL)/Makefile.common
diff --git a/tools/llvm-uselistorder/llvm-uselistorder.cpp b/tools/llvm-uselistorder/llvm-uselistorder.cpp
new file mode 100644 (file)
index 0000000..1d5a3d9
--- /dev/null
@@ -0,0 +1,379 @@
+//===- opt.cpp - The LLVM Modular Optimizer -------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Optimizations may be specified an arbitrary number of times on the command
+// line, They are run in the order specified.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/AsmParser/Parser.h"
+#include "llvm/Bitcode/ReaderWriter.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/UseListOrder.h"
+#include "llvm/IRReader/IRReader.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/FileUtilities.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/SystemUtils.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "use-list-order"
+
+static cl::opt<std::string> InputFilename(cl::Positional,
+                                          cl::desc("<input bitcode file>"),
+                                          cl::init("-"),
+                                          cl::value_desc("filename"));
+
+namespace {
+
+struct TempFile {
+  std::string Filename;
+  FileRemover Remover;
+  bool init(const std::string &Ext);
+  bool writeBitcode(const Module &M) const;
+  bool writeAssembly(const Module &M) const;
+  std::unique_ptr<Module> readBitcode(LLVMContext &Context) const;
+  std::unique_ptr<Module> readAssembly(LLVMContext &Context) const;
+};
+
+struct ValueMapping {
+  DenseMap<const Value *, unsigned> IDs;
+  std::vector<const Value *> Values;
+
+  /// \brief Construct a value mapping for module.
+  ///
+  /// Creates mapping from every value in \c M to an ID.  This mapping includes
+  /// un-referencable values.
+  ///
+  /// Every \a Value that gets serialized in some way should be represented
+  /// here.  The order needs to be deterministic, but it's unnecessary to match
+  /// the value-ids in the bitcode writer.
+  ///
+  /// All constants that are referenced by other values are included in the
+  /// mapping, but others -- which wouldn't be serialized -- are not.
+  ValueMapping(const Module &M);
+
+  /// \brief Map a value.
+  ///
+  /// Maps a value.  If it's a constant, maps all of its operands first.
+  void map(const Value *V);
+  unsigned lookup(const Value *V) const { return IDs.lookup(V); }
+};
+
+} // end namespace
+
+bool TempFile::init(const std::string &Ext) {
+  SmallVector<char, 64> Vector;
+  DEBUG(dbgs() << " - create-temp-file\n");
+  if (auto EC = sys::fs::createTemporaryFile("use-list-order", Ext, Vector)) {
+    (void)EC;
+    DEBUG(dbgs() << "error: " << EC.message() << "\n");
+    return true;
+  }
+  assert(!Vector.empty());
+
+  Filename.assign(Vector.data(), Vector.data() + Vector.size());
+  Remover.setFile(Filename);
+  DEBUG(dbgs() << " - filename = " << Filename << "\n");
+  return false;
+}
+
+bool TempFile::writeBitcode(const Module &M) const {
+  DEBUG(dbgs() << " - write bitcode\n");
+  std::string ErrorInfo;
+  raw_fd_ostream OS(Filename.c_str(), ErrorInfo, sys::fs::F_None);
+  if (!ErrorInfo.empty()) {
+    DEBUG(dbgs() << "error: " << ErrorInfo << "\n");
+    return true;
+  }
+
+  WriteBitcodeToFile(&M, OS);
+  return false;
+}
+
+bool TempFile::writeAssembly(const Module &M) const {
+  DEBUG(dbgs() << " - write assembly\n");
+  std::string ErrorInfo;
+  raw_fd_ostream OS(Filename.c_str(), ErrorInfo, sys::fs::F_Text);
+  if (!ErrorInfo.empty()) {
+    DEBUG(dbgs() << "error: " << ErrorInfo << "\n");
+    return true;
+  }
+
+  OS << M;
+  return false;
+}
+
+std::unique_ptr<Module> TempFile::readBitcode(LLVMContext &Context) const {
+  DEBUG(dbgs() << " - read bitcode\n");
+  ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOr =
+      MemoryBuffer::getFile(Filename);
+  if (!BufferOr) {
+    DEBUG(dbgs() << "error: " << BufferOr.getError().message() << "\n");
+    return nullptr;
+  }
+
+  std::unique_ptr<MemoryBuffer> Buffer = std::move(BufferOr.get());
+  ErrorOr<Module *> ModuleOr = parseBitcodeFile(Buffer.release(), Context);
+  if (!ModuleOr) {
+    DEBUG(dbgs() << "error: " << ModuleOr.getError().message() << "\n");
+    return nullptr;
+  }
+  return std::unique_ptr<Module>(ModuleOr.get());
+}
+
+std::unique_ptr<Module> TempFile::readAssembly(LLVMContext &Context) const {
+  DEBUG(dbgs() << " - read assembly\n");
+  SMDiagnostic Err;
+  std::unique_ptr<Module> M(ParseAssemblyFile(Filename, Err, Context));
+  if (!M.get())
+    DEBUG(dbgs() << "error: "; Err.print("verify-use-list-order", dbgs()));
+  return M;
+}
+
+ValueMapping::ValueMapping(const Module &M) {
+  // Every value should be mapped, including things like void instructions and
+  // basic blocks that are kept out of the ValueEnumerator.
+  //
+  // The current mapping order makes it easier to debug the tables.  It happens
+  // to be similar to the ID mapping when writing ValueEnumerator, but they
+  // aren't (and needn't be) in sync.
+
+  // Globals.
+  for (const GlobalVariable &G : M.globals())
+    map(&G);
+  for (const GlobalAlias &A : M.aliases())
+    map(&A);
+  for (const Function &F : M)
+    map(&F);
+
+  // Constants used by globals.
+  for (const GlobalVariable &G : M.globals())
+    if (G.hasInitializer())
+      map(G.getInitializer());
+  for (const GlobalAlias &A : M.aliases())
+    map(A.getAliasee());
+  for (const Function &F : M)
+    if (F.hasPrefixData())
+      map(F.getPrefixData());
+
+  // Function bodies.
+  for (const Function &F : M) {
+    for (const Argument &A : F.args())
+      map(&A);
+    for (const BasicBlock &BB : F)
+      map(&BB);
+    for (const BasicBlock &BB : F)
+      for (const Instruction &I : BB)
+        map(&I);
+
+    // Constants used by instructions.
+    for (const BasicBlock &BB : F)
+      for (const Instruction &I : BB)
+        for (const Value *Op : I.operands())
+          if ((isa<Constant>(Op) && !isa<GlobalValue>(*Op)) ||
+              isa<InlineAsm>(Op))
+            map(Op);
+  }
+}
+
+void ValueMapping::map(const Value *V) {
+  if (IDs.lookup(V))
+    return;
+
+  if (auto *C = dyn_cast<Constant>(V))
+    if (!isa<GlobalValue>(C))
+      for (const Value *Op : C->operands())
+        map(Op);
+
+  Values.push_back(V);
+  IDs[V] = Values.size();
+}
+
+#ifndef NDEBUG
+static void dumpMapping(const ValueMapping &VM) {
+  dbgs() << "value-mapping (size = " << VM.Values.size() << "):\n";
+  for (unsigned I = 0, E = VM.Values.size(); I != E; ++I) {
+    dbgs() << " - id = " << I << ", value = ";
+    VM.Values[I]->dump();
+  }
+}
+
+static void debugValue(const ValueMapping &M, unsigned I, StringRef Desc) {
+  const Value *V = M.Values[I];
+  dbgs() << " - " << Desc << " value = ";
+  V->dump();
+  for (const Use &U : V->uses()) {
+    dbgs() << "   => use: op = " << U.getOperandNo()
+           << ", user-id = " << M.IDs.lookup(U.getUser()) << ", user = ";
+    U.getUser()->dump();
+  }
+}
+
+static void debugUserMismatch(const ValueMapping &L, const ValueMapping &R,
+                              unsigned I) {
+  dbgs() << " - fail: user mismatch: ID = " << I << "\n";
+  debugValue(L, I, "LHS");
+  debugValue(R, I, "RHS");
+
+  dbgs() << "\nlhs-";
+  dumpMapping(L);
+  dbgs() << "\nrhs-";
+  dumpMapping(R);
+}
+
+static void debugSizeMismatch(const ValueMapping &L, const ValueMapping &R) {
+  dbgs() << " - fail: map size: " << L.Values.size()
+         << " != " << R.Values.size() << "\n";
+  dbgs() << "\nlhs-";
+  dumpMapping(L);
+  dbgs() << "\nrhs-";
+  dumpMapping(R);
+}
+#endif
+
+static bool matches(const ValueMapping &LM, const ValueMapping &RM) {
+  DEBUG(dbgs() << "compare value maps\n");
+  if (LM.Values.size() != RM.Values.size()) {
+    DEBUG(debugSizeMismatch(LM, RM));
+    return false;
+  }
+
+  // This mapping doesn't include dangling constant users, since those don't
+  // get serialized.  However, checking if users are constant and calling
+  // isConstantUsed() on every one is very expensive.  Instead, just check if
+  // the user is mapped.
+  auto skipUnmappedUsers =
+      [&](Value::const_use_iterator &U, Value::const_use_iterator E,
+          const ValueMapping &M) {
+    while (U != E && !M.lookup(U->getUser()))
+      ++U;
+  };
+
+  // Iterate through all values, and check that both mappings have the same
+  // users.
+  for (unsigned I = 0, E = LM.Values.size(); I != E; ++I) {
+    const Value *L = LM.Values[I];
+    const Value *R = RM.Values[I];
+    auto LU = L->use_begin(), LE = L->use_end();
+    auto RU = R->use_begin(), RE = R->use_end();
+    skipUnmappedUsers(LU, LE, LM);
+    skipUnmappedUsers(RU, RE, RM);
+
+    while (LU != LE) {
+      if (RU == RE) {
+        DEBUG(debugUserMismatch(LM, RM, I));
+        return false;
+      }
+      if (LM.lookup(LU->getUser()) != RM.lookup(RU->getUser())) {
+        DEBUG(debugUserMismatch(LM, RM, I));
+        return false;
+      }
+      if (LU->getOperandNo() != RU->getOperandNo()) {
+        DEBUG(debugUserMismatch(LM, RM, I));
+        return false;
+      }
+      skipUnmappedUsers(++LU, LE, LM);
+      skipUnmappedUsers(++RU, RE, RM);
+    }
+    if (RU != RE) {
+      DEBUG(debugUserMismatch(LM, RM, I));
+      return false;
+    }
+  }
+
+  return true;
+}
+
+static bool verifyBitcodeUseListOrder(const Module &M) {
+  DEBUG(dbgs() << "*** verify-use-list-order: bitcode ***\n");
+  TempFile F;
+  if (F.init("bc"))
+    return false;
+
+  if (F.writeBitcode(M))
+    return false;
+
+  LLVMContext Context;
+  std::unique_ptr<Module> OtherM = F.readBitcode(Context);
+  if (!OtherM)
+    return false;
+
+  return matches(ValueMapping(M), ValueMapping(*OtherM));
+}
+
+static bool verifyAssemblyUseListOrder(const Module &M) {
+  DEBUG(dbgs() << "*** verify-use-list-order: assembly ***\n");
+  TempFile F;
+  if (F.init("ll"))
+    return false;
+
+  if (F.writeAssembly(M))
+    return false;
+
+  LLVMContext Context;
+  std::unique_ptr<Module> OtherM = F.readAssembly(Context);
+  if (!OtherM)
+    return false;
+
+  return matches(ValueMapping(M), ValueMapping(*OtherM));
+}
+
+int main(int argc, char **argv) {
+  sys::PrintStackTraceOnErrorSignal();
+  llvm::PrettyStackTraceProgram X(argc, argv);
+
+  // Enable debug stream buffering.
+  EnableDebugBuffering = true;
+
+  llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
+  LLVMContext &Context = getGlobalContext();
+
+  cl::ParseCommandLineOptions(argc, argv,
+                              "llvm tool to verify use-list order\n");
+
+  SMDiagnostic Err;
+
+  // Load the input module...
+  std::unique_ptr<Module> M;
+  M.reset(ParseIRFile(InputFilename, Err, Context));
+
+  if (!M.get()) {
+    Err.print(argv[0], errs());
+    return 1;
+  }
+
+  DEBUG(dbgs() << "*** verify-use-list-order ***\n");
+  if (!shouldPreserveBitcodeUseListOrder()) {
+    // Can't verify if order isn't preserved.
+    DEBUG(dbgs() << "warning: cannot verify bitcode; "
+                    "try -preserve-bc-use-list-order\n");
+    return 0;
+  }
+
+  shuffleUseLists(*M);
+  if (!verifyBitcodeUseListOrder(*M))
+    report_fatal_error("bitcode use-list order changed");
+
+  if (shouldPreserveBitcodeUseListOrder())
+    if (!verifyAssemblyUseListOrder(*M))
+      report_fatal_error("assembly use-list order changed");
+
+  return 0;
+}