[llvm] r213824 - IR: Add Value::sortUseList()
Justin Bogner
mail at justinbogner.com
Wed Jul 23 18:41:19 PDT 2014
"Duncan P. N. Exon Smith" <dexonsmith at apple.com> writes:
> 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).
It should probably say Use::Prev here, for clarity.
> + 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
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
More information about the llvm-commits
mailing list