mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-11-01 15:11:24 +00:00
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. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@213824 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
ec6e535168
commit
5092384bd3
@ -456,6 +456,34 @@ public:
|
|||||||
VTy = Ty;
|
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:
|
protected:
|
||||||
unsigned short getSubclassDataFromValue() const { return SubclassData; }
|
unsigned short getSubclassDataFromValue() const { return SubclassData; }
|
||||||
void setValueSubclassData(unsigned short D) { SubclassData = D; }
|
void setValueSubclassData(unsigned short D) { SubclassData = D; }
|
||||||
@ -472,6 +500,91 @@ void Use::set(Value *V) {
|
|||||||
if (V) V->addUse(*this);
|
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
|
// 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...
|
// the subtype header files to test to see if the value is a subclass...
|
||||||
|
@ -21,6 +21,7 @@ set(IRSources
|
|||||||
PatternMatch.cpp
|
PatternMatch.cpp
|
||||||
TypeBuilderTest.cpp
|
TypeBuilderTest.cpp
|
||||||
TypesTest.cpp
|
TypesTest.cpp
|
||||||
|
UseTest.cpp
|
||||||
UserTest.cpp
|
UserTest.cpp
|
||||||
ValueHandleTest.cpp
|
ValueHandleTest.cpp
|
||||||
ValueMapTest.cpp
|
ValueMapTest.cpp
|
||||||
|
62
unittests/IR/UseTest.cpp
Normal file
62
unittests/IR/UseTest.cpp
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user