[llvm] r214135 - IR: Optimize size of use-list order shuffle vectors

Sean Silva chisophugis at gmail.com
Tue Jul 29 10:19:28 PDT 2014


First, I agree with Chandler about not worrying unless this is in the
profile.

However, if this really does need to be optimized....

Crazy idea: would it be possible to store just a single int's worth of RNG
seed for each use list?

A less crazy idea: a vector of indices is an extremely memory-inefficient
way to store permutations. For example, there are 12! permutations of 12
elements, and 12! is less than 2^32. Similarly, there are 20! permutations
of 20 elements and 20! < 2^64. Therefore your "small" case could
theoretically be just a single `unsigned` from a storage perspective.
A slightly memory-suboptimal but simple and cpu-friendly way to store the
permutations in an integer would be to bit-pack the indices, using just as
many bits for the indices as necessary. For example, suppose you were just
allowed a single uint64. You could use the following arrangement to store
permutations of up to 15 elements:
Low 4 bits: number of elements (the "size")
Each 4 bits after that: an index. Since we use 4 bits to store it, size()
is at most 15, thus each index fits in 4 bits. 4 * 15 = 60, so that is just
enough room for up to 15 elements.
(there is actually room for quite a bit of out-of-band data; if size() <
15, then you have entire unused indices at the top and so you have 4*(15 -
size()) bits available)


-- Sean Silva


On Mon, Jul 28, 2014 at 4:41 PM, Duncan P. N. Exon Smith <
dexonsmith at apple.com> wrote:

> Author: dexonsmith
> Date: Mon Jul 28 17:41:50 2014
> New Revision: 214135
>
> URL: http://llvm.org/viewvc/llvm-project?rev=214135&view=rev
> Log:
> IR: Optimize size of use-list order shuffle vectors
>
> Since we're storing lots of these, save two-pointers per vector with a
> custom type rather than using the relatively heavy `SmallVector`.
>
> Part of PR5680.
>
> Modified:
>     llvm/trunk/include/llvm/IR/UseListOrder.h
>     llvm/trunk/lib/Bitcode/Writer/ValueEnumerator.cpp
>
> Modified: llvm/trunk/include/llvm/IR/UseListOrder.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/UseListOrder.h?rev=214135&r1=214134&r2=214135&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm/IR/UseListOrder.h (original)
> +++ llvm/trunk/include/llvm/IR/UseListOrder.h Mon Jul 28 17:41:50 2014
> @@ -25,11 +25,58 @@ class Module;
>  class Function;
>  class Value;
>
> +/// \brief Structure to hold a use-list shuffle vector.
> +///
> +/// Stores most use-lists locally, but large use-lists use an extra heap
> entry.
> +/// Costs two fewer pointers than the equivalent \a SmallVector.
> +class UseListShuffleVector {
> +  unsigned Size;
> +  union {
> +    unsigned *Ptr;
> +    unsigned Array[6];
> +  } Storage;
> +
> +  bool isSmall() const { return Size <= 6; }
> +  unsigned *data() { return isSmall() ? Storage.Array : Storage.Ptr; }
> +  const unsigned *data() const {
> +    return isSmall() ? Storage.Array : Storage.Ptr;
> +  }
> +
> +public:
> +  UseListShuffleVector() : Size(0) {}
> +  UseListShuffleVector(UseListShuffleVector &&X) {
> +    std::memcpy(this, &X, sizeof(UseListShuffleVector));
> +    X.Size = 0;
> +  }
> +  explicit UseListShuffleVector(size_t Size) : Size(Size) {
> +    if (!isSmall())
> +      Storage.Ptr = new unsigned[Size];
> +  }
> +  ~UseListShuffleVector() {
> +    if (!isSmall())
> +      delete Storage.Ptr;
> +  }
> +
> +  typedef unsigned *iterator;
> +  typedef const unsigned *const_iterator;
> +
> +  size_t size() const { return Size; }
> +  iterator begin() { return data(); }
> +  iterator end() { return begin() + size(); }
> +  const_iterator begin() const { return data(); }
> +  const_iterator end() const { return begin() + size(); }
> +  unsigned &operator[](size_t I) { return data()[I]; }
> +  unsigned operator[](size_t I) const { return data()[I]; }
> +};
> +
>  /// \brief Structure to hold a use-list order.
>  struct UseListOrder {
> -  const Function *F;
>    const Value *V;
> -  SmallVector<unsigned, 8> Shuffle;
> +  const Function *F;
> +  UseListShuffleVector Shuffle;
> +
> +  UseListOrder(const Value *V, const Function *F, size_t ShuffleSize)
> +      : V(V), F(F), Shuffle(ShuffleSize) {}
>  };
>
>  typedef std::vector<UseListOrder> UseListOrderStack;
>
> Modified: llvm/trunk/lib/Bitcode/Writer/ValueEnumerator.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Bitcode/Writer/ValueEnumerator.cpp?rev=214135&r1=214134&r2=214135&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/Bitcode/Writer/ValueEnumerator.cpp (original)
> +++ llvm/trunk/lib/Bitcode/Writer/ValueEnumerator.cpp Mon Jul 28 17:41:50
> 2014
> @@ -133,12 +133,11 @@ static void predictValueUseListOrderImpl
>      return;
>
>    // Store the shuffle.
> -  UseListOrder O;
> -  O.V = V;
> -  O.F = F;
> -  for (auto &I : List)
> -    O.Shuffle.push_back(I.second);
> -  Stack.push_back(O);
> +  UseListOrder O(V, F, List.size());
> +  assert(List.size() == O.Shuffle.size() && "Wrong size");
> +  for (size_t I = 0, E = List.size(); I != E; ++I)
> +    O.Shuffle[I] = List[I].second;
> +  Stack.emplace_back(std::move(O));
>  }
>
>  static void predictValueUseListOrder(const Value *V, const Function *F,
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20140729/fd24c108/attachment.html>


More information about the llvm-commits mailing list