<div dir="ltr"><div>First, I agree with Chandler about not worrying unless this is in the profile.</div><div><br></div><div>However, if this really does need to be optimized....</div><div><br></div>Crazy idea: would it be possible to store just a single int's worth of RNG seed for each use list?<div>
<br></div><div>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.</div>
<div>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:</div>
<div>Low 4 bits: number of elements (the "size")</div><div>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.</div>
<div>(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) </div><div><br></div><div><br></div><div>
-- Sean Silva</div></div><div class="gmail_extra"><br><br><div class="gmail_quote">On Mon, Jul 28, 2014 at 4:41 PM, Duncan P. N. Exon Smith <span dir="ltr"><<a href="mailto:dexonsmith@apple.com" target="_blank">dexonsmith@apple.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: dexonsmith<br>
Date: Mon Jul 28 17:41:50 2014<br>
New Revision: 214135<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=214135&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=214135&view=rev</a><br>
Log:<br>
IR: Optimize size of use-list order shuffle vectors<br>
<br>
Since we're storing lots of these, save two-pointers per vector with a<br>
custom type rather than using the relatively heavy `SmallVector`.<br>
<br>
Part of PR5680.<br>
<br>
Modified:<br>
    llvm/trunk/include/llvm/IR/UseListOrder.h<br>
    llvm/trunk/lib/Bitcode/Writer/ValueEnumerator.cpp<br>
<br>
Modified: llvm/trunk/include/llvm/IR/UseListOrder.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/UseListOrder.h?rev=214135&r1=214134&r2=214135&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/UseListOrder.h?rev=214135&r1=214134&r2=214135&view=diff</a><br>

==============================================================================<br>
--- llvm/trunk/include/llvm/IR/UseListOrder.h (original)<br>
+++ llvm/trunk/include/llvm/IR/UseListOrder.h Mon Jul 28 17:41:50 2014<br>
@@ -25,11 +25,58 @@ class Module;<br>
 class Function;<br>
 class Value;<br>
<br>
+/// \brief Structure to hold a use-list shuffle vector.<br>
+///<br>
+/// Stores most use-lists locally, but large use-lists use an extra heap entry.<br>
+/// Costs two fewer pointers than the equivalent \a SmallVector.<br>
+class UseListShuffleVector {<br>
+  unsigned Size;<br>
+  union {<br>
+    unsigned *Ptr;<br>
+    unsigned Array[6];<br>
+  } Storage;<br>
+<br>
+  bool isSmall() const { return Size <= 6; }<br>
+  unsigned *data() { return isSmall() ? Storage.Array : Storage.Ptr; }<br>
+  const unsigned *data() const {<br>
+    return isSmall() ? Storage.Array : Storage.Ptr;<br>
+  }<br>
+<br>
+public:<br>
+  UseListShuffleVector() : Size(0) {}<br>
+  UseListShuffleVector(UseListShuffleVector &&X) {<br>
+    std::memcpy(this, &X, sizeof(UseListShuffleVector));<br>
+    X.Size = 0;<br>
+  }<br>
+  explicit UseListShuffleVector(size_t Size) : Size(Size) {<br>
+    if (!isSmall())<br>
+      Storage.Ptr = new unsigned[Size];<br>
+  }<br>
+  ~UseListShuffleVector() {<br>
+    if (!isSmall())<br>
+      delete Storage.Ptr;<br>
+  }<br>
+<br>
+  typedef unsigned *iterator;<br>
+  typedef const unsigned *const_iterator;<br>
+<br>
+  size_t size() const { return Size; }<br>
+  iterator begin() { return data(); }<br>
+  iterator end() { return begin() + size(); }<br>
+  const_iterator begin() const { return data(); }<br>
+  const_iterator end() const { return begin() + size(); }<br>
+  unsigned &operator[](size_t I) { return data()[I]; }<br>
+  unsigned operator[](size_t I) const { return data()[I]; }<br>
+};<br>
+<br>
 /// \brief Structure to hold a use-list order.<br>
 struct UseListOrder {<br>
-  const Function *F;<br>
   const Value *V;<br>
-  SmallVector<unsigned, 8> Shuffle;<br>
+  const Function *F;<br>
+  UseListShuffleVector Shuffle;<br>
+<br>
+  UseListOrder(const Value *V, const Function *F, size_t ShuffleSize)<br>
+      : V(V), F(F), Shuffle(ShuffleSize) {}<br>
 };<br>
<br>
 typedef std::vector<UseListOrder> UseListOrderStack;<br>
<br>
Modified: llvm/trunk/lib/Bitcode/Writer/ValueEnumerator.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Bitcode/Writer/ValueEnumerator.cpp?rev=214135&r1=214134&r2=214135&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Bitcode/Writer/ValueEnumerator.cpp?rev=214135&r1=214134&r2=214135&view=diff</a><br>

==============================================================================<br>
--- llvm/trunk/lib/Bitcode/Writer/ValueEnumerator.cpp (original)<br>
+++ llvm/trunk/lib/Bitcode/Writer/ValueEnumerator.cpp Mon Jul 28 17:41:50 2014<br>
@@ -133,12 +133,11 @@ static void predictValueUseListOrderImpl<br>
     return;<br>
<br>
   // Store the shuffle.<br>
-  UseListOrder O;<br>
-  O.V = V;<br>
-  O.F = F;<br>
-  for (auto &I : List)<br>
-    O.Shuffle.push_back(I.second);<br>
-  Stack.push_back(O);<br>
+  UseListOrder O(V, F, List.size());<br>
+  assert(List.size() == O.Shuffle.size() && "Wrong size");<br>
+  for (size_t I = 0, E = List.size(); I != E; ++I)<br>
+    O.Shuffle[I] = List[I].second;<br>
+  Stack.emplace_back(std::move(O));<br>
 }<br>
<br>
 static void predictValueUseListOrder(const Value *V, const Function *F,<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@cs.uiuc.edu">llvm-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits</a><br>
</blockquote></div><br></div>