Source/JavaScriptCore/ChangeLog

 12019-05-03 Robin Morisset <rmorisset@apple.com>
 2
 3 [Air] highOrderAdjacents in AbstractColoringAllocator::conservativeHeuristic should be some kind of array
 4 https://bugs.webkit.org/show_bug.cgi?id=197305
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 Currently it is a HashSet, but it only ever holds at most registerCount() items. And linear search tends to be faster on such a small collection than hashing + searching in a HashSet.
 9 Further benefits include avoiding the allocation of the HashSet, not actually adding the nodes adjacent to V (since there are no duplicates in the adjacency lists).
 10
 11 This patch also contains a trivial optimization: if the remaining number of nodes to consider + the number of highOrderAdjacents already seen is smaller than registerCount() we can return true directly.
 12 Apart from that, the patch got some trivial cleanup of GraphColoringRegisterAllocation::allocateOnBank() (that for example was only logging the number of iterations for FP registers, and not the more interesting number for GP registers).
 13
 14 The time spent in the register allocator throughout JetStream2 on this MacBook Pro moves from 3767 / 3710 / 3785 ms to 3551 / 3454 / 3503 ms.
 15 So about a 6% speedup for that phase, and between 1 and 1.5% speedup for FTL/OMG compilation overall.
 16
 17 No new tests as there is no intended change to the code being generated, and this was already tested by running testb3 + JetStream2.
 18
 19 * b3/air/AirAllocateRegistersByGraphColoring.cpp:
 20
1212019-05-03 Devin Rousso <drousso@apple.com>
222
323 Web Inspector: Record actions performed on WebGL2RenderingContext

Source/JavaScriptCore/b3/air/AirAllocateRegistersByGraphColoring.cpp

@@protected:
192192 const auto& adjacentsOfU = m_adjacencyList[u];
193193 const auto& adjacentsOfV = m_adjacencyList[v];
194194
195  if (adjacentsOfU.size() + adjacentsOfV.size() < registerCount()) {
 195 Vector<IndexType, 100> highOrderAdjacents;
 196 RELEASE_ASSERT(registerCount() < 100);
 197 unsigned numCandidates = adjacentsOfU.size() + adjacentsOfV.size();
 198 if (numCandidates < registerCount()) {
196199 // Shortcut: if the total number of adjacents is less than the number of register, the condition is always met.
197200 return true;
198201 }
199202
200  HashSet<IndexType> highOrderAdjacents;
201 
202203 for (IndexType adjacentTmpIndex : adjacentsOfU) {
203204 ASSERT(adjacentTmpIndex != v);
204205 ASSERT(adjacentTmpIndex != u);
 206 numCandidates--;
205207 if (!hasBeenSimplified(adjacentTmpIndex) && m_degrees[adjacentTmpIndex] >= registerCount()) {
206  auto addResult = highOrderAdjacents.add(adjacentTmpIndex);
207  if (addResult.isNewEntry && highOrderAdjacents.size() >= registerCount())
 208 ASSERT(std::find(highOrderAdjacents.begin(), highOrderAdjacents.end(), adjacentTmpIndex) == highOrderAdjacents.end());
 209 highOrderAdjacents.uncheckedAppend(adjacentTmpIndex);
 210 if (highOrderAdjacents.size() >= registerCount())
208211 return false;
209  }
 212 } else if (highOrderAdjacents.size() + numCandidates < registerCount())
 213 return true;
210214 }
 215 ASSERT(numCandidates == adjacentsOfV.size());
 216
 217 auto iteratorEndHighOrderAdjacentsOfU = highOrderAdjacents.end();
211218 for (IndexType adjacentTmpIndex : adjacentsOfV) {
212219 ASSERT(adjacentTmpIndex != u);
213220 ASSERT(adjacentTmpIndex != v);
214  if (!hasBeenSimplified(adjacentTmpIndex) && m_degrees[adjacentTmpIndex] >= registerCount()) {
215  auto addResult = highOrderAdjacents.add(adjacentTmpIndex);
216  if (addResult.isNewEntry && highOrderAdjacents.size() >= registerCount())
 221 numCandidates--;
 222 if (!hasBeenSimplified(adjacentTmpIndex)
 223 && m_degrees[adjacentTmpIndex] >= registerCount()
 224 && std::find(highOrderAdjacents.begin(), iteratorEndHighOrderAdjacentsOfU, adjacentTmpIndex) == iteratorEndHighOrderAdjacentsOfU) {
 225 ASSERT(std::find(iteratorEndHighOrderAdjacentsOfU, highOrderAdjacents.end(), adjacentTmpIndex) == highOrderAdjacents.end());
 226 highOrderAdjacents.uncheckedAppend(adjacentTmpIndex);
 227 if (highOrderAdjacents.size() >= registerCount())
217228 return false;
218  }
 229 } else if (highOrderAdjacents.size() + numCandidates < registerCount())
 230 return true;
219231 }
220232
 233 ASSERT(!numCandidates);
221234 ASSERT(highOrderAdjacents.size() < registerCount());
222235 return true;
223236 }

@@protected:
10211034 }
10221035
10231036 // Low-degree vertex can always be colored: just pick any of the color taken by any
1024  // other adjacent verices.
 1037 // other adjacent vertices.
10251038 // The "Simplify" phase takes a low-degree out of the interference graph to simplify it.
10261039 void simplify()
10271040 {

@@public:
17891802 padInterference(m_code);
17901803
17911804 allocateOnBank<GP>();
1792  m_numIterations = 0;
17931805 allocateOnBank<FP>();
17941806
17951807 fixSpillsAfterTerminals(m_code);
1796 
1797  if (reportStats)
1798  dataLog("Num iterations = ", m_numIterations, "\n");
17991808 }
18001809
18011810private:

@@private:
18081817 // we should add the Tmp to unspillableTmps. That will help avoid relooping only to turn the
18091818 // Tmp into an unspillable Tmp.
18101819 // https://bugs.webkit.org/show_bug.cgi?id=152699
1811 
1812  while (true) {
1813  ++m_numIterations;
 1820
 1821 unsigned numIterations = 0;
 1822 bool done = false;
 1823
 1824 while (!done) {
 1825 ++numIterations;
18141826
18151827 if (traceDebug)
1816  dataLog("Code at iteration ", m_numIterations, ":\n", m_code);
 1828 dataLog("Code at iteration ", numIterations, ":\n", m_code);
18171829
18181830 // FIXME: One way to optimize this code is to remove the recomputation inside the fixpoint.
18191831 // We need to recompute because spilling adds tmps, but we could just update tmpWidth when we

@@private:
18221834 // spill code we emit. Since we currently recompute TmpWidth after spilling, the newly
18231835 // created Tmps may get narrower use/def widths. On the other hand, the spiller already
18241836 // selects which move instruction to use based on the original Tmp's widths, so it may not
1825  // matter than a subsequent iteration sees a coservative width for the new Tmps. Also, the
 1837 // matter than a subsequent iteration sees a conservative width for the new Tmps. Also, the
18261838 // recomputation may not actually be a performance problem; it's likely that a better way to
18271839 // improve performance of TmpWidth is to replace its HashMap with something else. It's
18281840 // possible that most of the TmpWidth overhead is from queries of TmpWidth rather than the

@@private:
18351847 if (!allocator.requiresSpilling()) {
18361848 this->assignRegistersToTmp<bank>(allocator);
18371849 if (traceDebug)
1838  dataLog("Successfull allocation at iteration ", m_numIterations, ":\n", m_code);
 1850 dataLog("Successfull allocation at iteration ", numIterations, ":\n", m_code);
18391851
18401852 return true;
18411853 }

@@private:
18431855 this->addSpillAndFill<bank>(allocator, unspillableTmps);
18441856 return false;
18451857 };
1846 
1847  bool done;
 1858
18481859 if (useIRC()) {
18491860 ColoringAllocator<bank, IRC> allocator(m_code, m_tmpWidth, m_useCounts, unspillableTmps);
18501861 done = doAllocation(allocator);

@@private:
18521863 ColoringAllocator<bank, Briggs> allocator(m_code, m_tmpWidth, m_useCounts, unspillableTmps);
18531864 done = doAllocation(allocator);
18541865 }
1855  if (done)
1856  return;
18571866 }
 1867 dataLogLnIf(reportStats, "Num iterations = ", numIterations, " for bank: ", bank);
18581868 }
18591869
18601870 template<Bank bank>

@@private:
21872197 Code& m_code;
21882198 TmpWidth m_tmpWidth;
21892199 UseCounts<Tmp>& m_useCounts;
2190  unsigned m_numIterations { 0 };
21912200};
21922201
21932202} // anonymous namespace