[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