⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 286053 in webkit


Ignore:
Timestamp:
Nov 19, 2021, 1:38:27 AM (5 years ago)
Author:
rmorisset@apple.com
Message:

AirFixObviousSpills should be optimized
https://bugs.webkit.org/show_bug.cgi?id=228052

Reviewed by Yusuke Suzuki.

There were two problems with AirFixObviousSpills:

  • merge() had a quadratic blow-up, as for each element in a vector, it was searching it in a different vector.
  • it would visit blocks even when their state at head had not changed.

I fixed the first problem by making sure that the vectors are sorted before calling merge, and making use of that invariant in the search of the vectors
(see filterVectorAgainst)
This reduced the total time spent in that phase from 390ms to 230ms, and the worst case time spent in that phase for one function from 100ms to 30ms (all of the results in this Changelog are for JetStream2 on a M1 MBP).

I fixed the second problem even more easily by adding a m_shouldVisit BitVector. I also moved the m_wasVisited boolean that was in State to a m_notBottom BitVector for simplicity and symmetry.
That change further reduced the total/max time from 230ms/30ms to 140ms/16ms.

  • b3/air/AirFixObviousSpills.cpp:
Location:
trunk/Source/JavaScriptCore
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r286045 r286053  
     12021-11-19  Robin Morisset  <rmorisset@apple.com>
     2
     3        AirFixObviousSpills should be optimized
     4        https://bugs.webkit.org/show_bug.cgi?id=228052
     5
     6        Reviewed by Yusuke Suzuki.
     7
     8        There were two problems with AirFixObviousSpills:
     9        - merge() had a quadratic blow-up, as for each element in a vector, it was searching it in a different vector.
     10        - it would visit blocks even when their state at head had not changed.
     11
     12        I fixed the first problem by making sure that the vectors are sorted before calling merge, and making use of that invariant in the search of the vectors
     13        (see filterVectorAgainst)
     14        This reduced the total time spent in that phase from 390ms to 230ms, and the worst case time spent in that phase for one function from 100ms to 30ms (all of the results in this Changelog are for JetStream2 on a M1 MBP).
     15
     16        I fixed the second problem even more easily by adding a m_shouldVisit BitVector. I also moved the m_wasVisited boolean that was in State to a m_notBottom BitVector for simplicity and symmetry.
     17        That change further reduced the total/max time from 230ms/30ms to 140ms/16ms.
     18
     19        * b3/air/AirFixObviousSpills.cpp:
     20
    1212021-11-18  Robin Morisset  <rmorisset@apple.com>
    222
  • trunk/Source/JavaScriptCore/b3/air/AirFixObviousSpills.cpp

    r278253 r286053  
    4949        : m_code(code)
    5050        , m_atHead(code.size())
     51        , m_notBottom(code.size())
     52        , m_shouldVisit(code.size())
    5153    {
    5254    }
     
    6466    void computeAliases()
    6567    {
    66         m_atHead[m_code[0]].wasVisited = true;
     68        m_notBottom.quickSet(0);
     69        m_shouldVisit.quickSet(0);
    6770       
    6871        bool changed = true;
     
    7073            changed = false;
    7174           
    72             for (BasicBlock* block : m_code) {
     75            for (unsigned blockIndex : m_shouldVisit) {
     76                m_shouldVisit.quickClear(blockIndex);
     77                BasicBlock* block = m_code[blockIndex];
     78                ASSERT(m_notBottom.quickGet(blockIndex));
    7379                m_block = block;
    7480                m_state = m_atHead[block];
    75                 if (!m_state.wasVisited)
    76                     continue;
    7781
    7882                if (AirFixObviousSpillsInternal::verbose)
     
    8286                    executeInst();
    8387
     88                // Before we call merge we must make sure that the two states are sorted.
     89                m_state.sort();
     90
    8491                for (BasicBlock* successor : block->successorBlocks()) {
     92                    unsigned successorIndex = successor->index();
    8593                    State& toState = m_atHead[successor];
    86                     if (toState.wasVisited)
    87                         changed |= toState.merge(m_state);
    88                     else {
     94                    if (m_notBottom.quickGet(successorIndex)) {
     95                        bool changedAtSuccessorHead = toState.merge(m_state);
     96                        if (changedAtSuccessorHead) {
     97                            changed = true;
     98                            m_shouldVisit.quickSet(successorIndex);
     99                        }
     100                    } else { // The state at head of successor is bottom
    89101                        toState = m_state;
    90102                        changed = true;
     103                        m_notBottom.quickSet(successorIndex);
     104                        m_shouldVisit.quickSet(successorIndex);
    91105                    }
    92106                }
     
    100114            m_block = block;
    101115            m_state = m_atHead[block];
    102             RELEASE_ASSERT(m_state.wasVisited);
     116            RELEASE_ASSERT(m_notBottom.quickGet(block->index()));
    103117
    104118            for (m_instIndex = 0; m_instIndex < block->size(); ++m_instIndex) {
     
    342356        }
    343357
     358        bool operator<(const RegConst& other) const
     359        {
     360            return reg < other.reg || (reg == other.reg && constant < other.constant);
     361        }
     362
    344363        void dump(PrintStream& out) const
    345364        {
     
    379398                && reg == other.reg
    380399                && mode == other.mode;
     400        }
     401
     402        bool operator<(const RegSlot& other) const
     403        {
     404            // We ignore `mode` on purpose, see merge() for how we deal with it.
     405            return slot < other.slot || (slot == other.slot && reg < other.reg);
    381406        }
    382407
     
    424449        }
    425450
     451        bool operator<(const SlotConst& other) const
     452        {
     453            return slot < other.slot || (slot == other.slot && constant < other.constant);
     454        }
     455
    426456        void dump(PrintStream& out) const
    427457        {
     
    436466        void addAlias(const RegConst& newAlias)
    437467        {
    438             return regConst.append(newAlias);
     468            regConst.append(newAlias);
     469#if ASSERT_ENABLED
     470            m_isSorted = false;
     471#endif
    439472        }
    440473        void addAlias(const RegSlot& newAlias)
    441474        {
    442             return regSlot.append(newAlias);
     475            regSlot.append(newAlias);
     476#if ASSERT_ENABLED
     477            m_isSorted = false;
     478#endif
    443479        }
    444480        void addAlias(const SlotConst& newAlias)
    445481        {
    446             return slotConst.append(newAlias);
     482            slotConst.append(newAlias);
     483#if ASSERT_ENABLED
     484            m_isSorted = false;
     485#endif
    447486        }
    448487       
     
    545584        }
    546585
     586        void sort()
     587        {
     588            std::sort(regConst.begin(), regConst.end(), [] (const RegConst& a, const RegConst& b) {
     589                return a < b;
     590            });
     591            std::sort(slotConst.begin(), slotConst.end(), [] (const SlotConst& a, const SlotConst& b) {
     592                return a < b;
     593            });
     594            std::sort(regSlot.begin(), regSlot.end(), [] (const RegSlot& a, const RegSlot& b) {
     595                return a < b;
     596            });
     597#if ASSERT_ENABLED
     598            m_isSorted = true;
     599#endif
     600        }
     601
     602        // Takes two sorted vectors, for each element in the first, it looks for the first element in the second which is not smaller.
     603        // If such an element exist, call f on both the element from the first vector and this element.
     604        // Remove the element from the first vector unless f returned true (so f says whether to keep the element)
     605        // Returns true if any element has been removed.
     606        template<typename T, typename Func>
     607        static bool filterVectorAgainst(Vector<T>& own, const Vector<T>& other, Func f)
     608        {
     609            const T* it = other.begin();
     610            const T* end = other.end();
     611            return !!own.removeAllMatching(
     612                [&] (T& alias) {
     613                    it = std::find_if_not(it, end, [&] (const T& otherAlias) {
     614                        return otherAlias < alias;
     615                    });
     616                    if (it == end)
     617                        return true;
     618                    return !f(alias, *it);
     619            });
     620        }
     621
    547622        bool merge(const State& other)
    548623        {
     624            ASSERT(m_isSorted);
     625            ASSERT(other.m_isSorted);
    549626            bool changed = false;
    550            
    551             changed |= !!regConst.removeAllMatching(
    552                 [&] (RegConst& alias) -> bool {
    553                     const RegConst* otherAlias = other.getRegConst(alias.reg);
    554                     if (!otherAlias)
    555                         return true;
    556                     if (alias.constant != otherAlias->constant)
    557                         return true;
     627
     628            changed |= filterVectorAgainst(regConst, other.regConst, [](RegConst& a, const RegConst& b) { return a == b; });
     629            changed |= filterVectorAgainst(slotConst, other.slotConst, [](SlotConst& a, const SlotConst& b) { return a == b; });
     630            changed |= filterVectorAgainst(regSlot, other.regSlot, [&](RegSlot& alias, const RegSlot& otherAlias) {
     631                if (alias.reg != otherAlias.reg || alias.slot != otherAlias.slot)
    558632                    return false;
    559                 });
    560 
    561             changed |= !!slotConst.removeAllMatching(
    562                 [&] (SlotConst& alias) -> bool {
    563                     const SlotConst* otherAlias = other.getSlotConst(alias.slot);
    564                     if (!otherAlias)
    565                         return true;
    566                     if (alias.constant != otherAlias->constant)
    567                         return true;
    568                     return false;
    569                 });
    570 
    571             changed |= !!regSlot.removeAllMatching(
    572                 [&] (RegSlot& alias) -> bool {
    573                     const RegSlot* otherAlias = other.getRegSlot(alias.reg, alias.slot);
    574                     if (!otherAlias)
    575                         return true;
    576                     if (alias.mode != RegSlot::Match32 && alias.mode != otherAlias->mode) {
    577                         alias.mode = RegSlot::Match32;
    578                         changed = true;
    579                     }
    580                     return false;
    581                 });
     633                if (alias.mode != RegSlot::Match32 && alias.mode != otherAlias.mode) {
     634                    alias.mode = RegSlot::Match32;
     635                    changed = true;
     636                }
     637                return true;
     638            });
    582639
    583640            return changed;
     
    588645            out.print(
    589646                "{regConst = [", listDump(regConst), "], slotConst = [", listDump(slotConst),
    590                 "], regSlot = [", listDump(regSlot), "], wasVisited = ", wasVisited, "}");
     647                "], regSlot = [", listDump(regSlot), "]}");
    591648        }
    592649
     
    594651        Vector<SlotConst> slotConst;
    595652        Vector<RegSlot> regSlot;
    596         bool wasVisited { false };
     653#if ASSERT_ENABLED
     654        bool m_isSorted { true };
     655#endif
    597656    };
    598657
     
    600659    IndexMap<BasicBlock*, State> m_atHead;
    601660    State m_state;
     661    BitVector m_notBottom;
     662    BitVector m_shouldVisit;
    602663    BasicBlock* m_block { nullptr };
    603664    unsigned m_instIndex { 0 };
Note: See TracChangeset for help on using the changeset viewer.