js/src/jit/MoveResolver.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/src/jit/MoveResolver.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,140 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99:
     1.6 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#include "jit/MoveResolver.h"
    1.11 +
    1.12 +using namespace js;
    1.13 +using namespace js::jit;
    1.14 +
    1.15 +MoveResolver::MoveResolver()
    1.16 +  : hasCycles_(false)
    1.17 +{
    1.18 +}
    1.19 +
    1.20 +void
    1.21 +MoveResolver::resetState()
    1.22 +{
    1.23 +    hasCycles_ = false;
    1.24 +}
    1.25 +
    1.26 +bool
    1.27 +MoveResolver::addMove(const MoveOperand &from, const MoveOperand &to, MoveOp::Type type)
    1.28 +{
    1.29 +    // Assert that we're not doing no-op moves.
    1.30 +    JS_ASSERT(!(from == to));
    1.31 +    PendingMove *pm = movePool_.allocate();
    1.32 +    if (!pm)
    1.33 +        return false;
    1.34 +    new (pm) PendingMove(from, to, type);
    1.35 +    pending_.pushBack(pm);
    1.36 +    return true;
    1.37 +}
    1.38 +
    1.39 +// Given move (A -> B), this function attempts to find any move (B -> *) in the
    1.40 +// pending move list, and returns the first one.
    1.41 +MoveResolver::PendingMove *
    1.42 +MoveResolver::findBlockingMove(const PendingMove *last)
    1.43 +{
    1.44 +    for (PendingMoveIterator iter = pending_.begin(); iter != pending_.end(); iter++) {
    1.45 +        PendingMove *other = *iter;
    1.46 +
    1.47 +        if (other->from() == last->to()) {
    1.48 +            // We now have pairs in the form (A -> X) (X -> y). The second pair
    1.49 +            // blocks the move in the first pair, so return it.
    1.50 +            return other;
    1.51 +        }
    1.52 +    }
    1.53 +
    1.54 +    // No blocking moves found.
    1.55 +    return nullptr;
    1.56 +}
    1.57 +
    1.58 +bool
    1.59 +MoveResolver::resolve()
    1.60 +{
    1.61 +    resetState();
    1.62 +    orderedMoves_.clear();
    1.63 +
    1.64 +    InlineList<PendingMove> stack;
    1.65 +
    1.66 +    // This is a depth-first-search without recursion, which tries to find
    1.67 +    // cycles in a list of moves. The output is not entirely optimal for cases
    1.68 +    // where a source has multiple destinations, i.e.:
    1.69 +    //      [stack0] -> A
    1.70 +    //      [stack0] -> B
    1.71 +    //
    1.72 +    // These moves may not occur next to each other in the list, making it
    1.73 +    // harder for the emitter to optimize memory to memory traffic. However, we
    1.74 +    // expect duplicate sources to be rare in greedy allocation, and indicative
    1.75 +    // of an error in LSRA.
    1.76 +    //
    1.77 +    // Algorithm.
    1.78 +    //
    1.79 +    // S = Traversal stack.
    1.80 +    // P = Pending move list.
    1.81 +    // O = Ordered list of moves.
    1.82 +    //
    1.83 +    // As long as there are pending moves in P:
    1.84 +    //      Let |root| be any pending move removed from P
    1.85 +    //      Add |root| to the traversal stack.
    1.86 +    //      As long as S is not empty:
    1.87 +    //          Let |L| be the most recent move added to S.
    1.88 +    //
    1.89 +    //          Find any pending move M whose source is L's destination, thus
    1.90 +    //          preventing L's move until M has completed.
    1.91 +    //
    1.92 +    //          If a move M was found,
    1.93 +    //              Remove M from the pending list.
    1.94 +    //              If M's destination is |root|,
    1.95 +    //                  Annotate M and |root| as cycles.
    1.96 +    //                  Add M to S.
    1.97 +    //                  do not Add M to O, since M may have other conflictors in P that have not yet been processed.
    1.98 +    //              Otherwise,
    1.99 +    //                  Add M to S.
   1.100 +    //         Otherwise,
   1.101 +    //              Remove L from S.
   1.102 +    //              Add L to O.
   1.103 +    //
   1.104 +    while (!pending_.empty()) {
   1.105 +        PendingMove *pm = pending_.popBack();
   1.106 +
   1.107 +        // Add this pending move to the cycle detection stack.
   1.108 +        stack.pushBack(pm);
   1.109 +
   1.110 +        while (!stack.empty()) {
   1.111 +            PendingMove *blocking = findBlockingMove(stack.peekBack());
   1.112 +
   1.113 +            if (blocking) {
   1.114 +                if (blocking->to() == pm->from()) {
   1.115 +                    // We annotate cycles at each move in the cycle, and
   1.116 +                    // assert that we do not find two cycles in one move chain
   1.117 +                    // traversal (which would indicate two moves to the same
   1.118 +                    // destination).
   1.119 +                    pm->setCycleEnd();
   1.120 +                    blocking->setCycleBegin(pm->type());
   1.121 +                    hasCycles_ = true;
   1.122 +                    pending_.remove(blocking);
   1.123 +                    stack.pushBack(blocking);
   1.124 +                } else {
   1.125 +                    // This is a new link in the move chain, so keep
   1.126 +                    // searching for a cycle.
   1.127 +                    pending_.remove(blocking);
   1.128 +                    stack.pushBack(blocking);
   1.129 +                }
   1.130 +            } else {
   1.131 +                // Otherwise, pop the last move on the search stack because it's
   1.132 +                // complete and not participating in a cycle. The resulting
   1.133 +                // move can safely be added to the ordered move list.
   1.134 +                PendingMove *done = stack.popBack();
   1.135 +                if (!orderedMoves_.append(*done))
   1.136 +                    return false;
   1.137 +                movePool_.free(done);
   1.138 +            }
   1.139 +        }
   1.140 +    }
   1.141 +
   1.142 +    return true;
   1.143 +}

mercurial