[llvm] r213824 - IR: Add Value::sortUseList()

Duncan P. N. Exon Smith dexonsmith at apple.com
Wed Jul 23 17:53:19 PDT 2014


Author: dexonsmith
Date: Wed Jul 23 19:53:19 2014
New Revision: 213824

URL: http://llvm.org/viewvc/llvm-project?rev=213824&view=rev
Log:
IR: Add Value::sortUseList()

Add `Value::sortUseList()`, templated on the comparison function to use.

The sort is an iterative merge sort that uses a binomial vector of
already-merged lists to limit the size overhead to `O(1)`.

This is part of PR5680.

Added:
    llvm/trunk/unittests/IR/UseTest.cpp
Modified:
    llvm/trunk/include/llvm/IR/Value.h
    llvm/trunk/unittests/IR/CMakeLists.txt

Modified: llvm/trunk/include/llvm/IR/Value.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/Value.h?rev=213824&r1=213823&r2=213824&view=diff
==============================================================================
--- llvm/trunk/include/llvm/IR/Value.h (original)
+++ llvm/trunk/include/llvm/IR/Value.h Wed Jul 23 19:53:19 2014
@@ -456,6 +456,34 @@ public:
     VTy = Ty;
   }
 
+  /// \brief Sort the use-list.
+  ///
+  /// Sorts the Value's use-list by Cmp using a stable mergesort.  Cmp is
+  /// expected to compare two \a Use references.
+  template <class Compare> void sortUseList(Compare Cmp);
+
+private:
+  /// \brief Merge two lists together.
+  ///
+  /// Merges \c L and \c R using \c Cmp.  To enable stable sorts, always pushes
+  /// "equal" items from L before items from R.
+  ///
+  /// \return the first element in the list.
+  ///
+  /// \note Completely ignores \a Prev (doesn't read, doesn't update).
+  template <class Compare>
+  static Use *mergeUseLists(Use *L, Use *R, Compare Cmp) {
+    Use *Merged;
+    mergeUseListsImpl(L, R, &Merged, Cmp);
+    return Merged;
+  }
+
+  /// \brief Tail-recursive helper for \a mergeUseLists().
+  ///
+  /// \param[out] Next the first element in the list.
+  template <class Compare>
+  static void mergeUseListsImpl(Use *L, Use *R, Use **Next, Compare Cmp);
+
 protected:
   unsigned short getSubclassDataFromValue() const { return SubclassData; }
   void setValueSubclassData(unsigned short D) { SubclassData = D; }
@@ -472,6 +500,91 @@ void Use::set(Value *V) {
   if (V) V->addUse(*this);
 }
 
+template <class Compare> void Value::sortUseList(Compare Cmp) {
+  if (!UseList || !UseList->Next)
+    // No need to sort 0 or 1 uses.
+    return;
+
+  // Note: this function completely ignores Prev pointers until the end when
+  // they're fixed en masse.
+
+  // Create a binomial vector of sorted lists, visiting uses one at a time and
+  // merging lists as necessary.
+  const unsigned MaxSlots = 32;
+  Use *Slots[MaxSlots];
+
+  // Collect the first use, turning it into a single-item list.
+  Use *Next = UseList->Next;
+  UseList->Next = nullptr;
+  unsigned NumSlots = 1;
+  Slots[0] = UseList;
+
+  // Collect all but the last use.
+  while (Next->Next) {
+    Use *Current = Next;
+    Next = Current->Next;
+
+    // Turn Current into a single-item list.
+    Current->Next = nullptr;
+
+    // Save Current in the first available slot, merging on collisions.
+    unsigned I;
+    for (I = 0; I < NumSlots; ++I) {
+      if (!Slots[I])
+        break;
+
+      // Merge two lists, doubling the size of Current and emptying slot I.
+      //
+      // Since the uses in Slots[I] originally preceded those in Current, send
+      // Slots[I] in as the left parameter to maintain a stable sort.
+      Current = mergeUseLists(Slots[I], Current, Cmp);
+      Slots[I] = nullptr;
+    }
+    // Check if this is a new slot.
+    if (I == NumSlots) {
+      ++NumSlots;
+      assert(NumSlots <= MaxSlots && "Use list bigger than 2^32");
+    }
+
+    // Found an open slot.
+    Slots[I] = Current;
+  }
+
+  // Merge all the lists together.
+  assert(Next && "Expected one more Use");
+  assert(!Next->Next && "Expected only one Use");
+  UseList = Next;
+  for (unsigned I = 0; I < NumSlots; ++I)
+    if (Slots[I])
+      // Since the uses in Slots[I] originally preceded those in UseList, send
+      // Slots[I] in as the left parameter to maintain a stable sort.
+      UseList = mergeUseLists(Slots[I], UseList, Cmp);
+
+  // Fix the Prev pointers.
+  for (Use *I = UseList, **Prev = &UseList; I; I = I->Next) {
+    I->setPrev(Prev);
+    Prev = &I->Next;
+  }
+}
+
+template <class Compare>
+void Value::mergeUseListsImpl(Use *L, Use *R, Use **Next, Compare Cmp) {
+  if (!L) {
+    *Next = R;
+    return;
+  }
+  if (!R) {
+    *Next = L;
+    return;
+  }
+  if (Cmp(*R, *L)) {
+    *Next = R;
+    mergeUseListsImpl(L, R->Next, &R->Next, Cmp);
+    return;
+  }
+  *Next = L;
+  mergeUseListsImpl(L->Next, R, &L->Next, Cmp);
+};
 
 // isa - Provide some specializations of isa so that we don't have to include
 // the subtype header files to test to see if the value is a subclass...

Modified: llvm/trunk/unittests/IR/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/IR/CMakeLists.txt?rev=213824&r1=213823&r2=213824&view=diff
==============================================================================
--- llvm/trunk/unittests/IR/CMakeLists.txt (original)
+++ llvm/trunk/unittests/IR/CMakeLists.txt Wed Jul 23 19:53:19 2014
@@ -21,6 +21,7 @@ set(IRSources
   PatternMatch.cpp
   TypeBuilderTest.cpp
   TypesTest.cpp
+  UseTest.cpp
   UserTest.cpp
   ValueHandleTest.cpp
   ValueMapTest.cpp

Added: llvm/trunk/unittests/IR/UseTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/IR/UseTest.cpp?rev=213824&view=auto
==============================================================================
--- llvm/trunk/unittests/IR/UseTest.cpp (added)
+++ llvm/trunk/unittests/IR/UseTest.cpp Wed Jul 23 19:53:19 2014
@@ -0,0 +1,62 @@
+//===- llvm/unittest/IR/UseTest.cpp - Use unit tests ----------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/AsmParser/Parser.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/User.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/Support/SourceMgr.h"
+#include "gtest/gtest.h"
+using namespace llvm;
+
+namespace {
+
+TEST(UseTest, sort) {
+  LLVMContext C;
+
+  const char *ModuleString = "define void @f(i32 %x) {\n"
+                             "entry:\n"
+                             "  %v0 = add i32 %x, 0\n"
+                             "  %v2 = add i32 %x, 2\n"
+                             "  %v5 = add i32 %x, 5\n"
+                             "  %v1 = add i32 %x, 1\n"
+                             "  %v3 = add i32 %x, 3\n"
+                             "  %v7 = add i32 %x, 7\n"
+                             "  %v6 = add i32 %x, 6\n"
+                             "  %v4 = add i32 %x, 4\n"
+                             "  ret void\n"
+                             "}\n";
+  SMDiagnostic Err;
+  Module *M = ParseAssemblyString(ModuleString, nullptr, Err, C);
+  Function *F = M->getFunction("f");
+  ASSERT_TRUE(F);
+  ASSERT_TRUE(F->arg_begin() != F->arg_end());
+  Argument &X = *F->arg_begin();
+  ASSERT_EQ("x", X.getName());
+
+  X.sortUseList([](const Use &L, const Use &R) {
+    return L.getUser()->getName() < R.getUser()->getName();
+  });
+  unsigned I = 0;
+  for (User *U : X.users())
+    EXPECT_EQ("v" + std::to_string(I++), U->getName());
+  ASSERT_EQ(8u, I);
+
+  X.sortUseList([](const Use &L, const Use &R) {
+    return L.getUser()->getName() > R.getUser()->getName();
+  });
+  I = 0;
+  for (User *U : X.users())
+    EXPECT_EQ("v" + std::to_string((7 - I++)), U->getName());
+  ASSERT_EQ(8u, I);
+}
+
+} // end anonymous namespace





More information about the llvm-commits mailing list