bool MoveResolver::resolve() { resetState(); orderedMoves_.clear(); InlineList<PendingMove> stack; // This is a depth-first-search without recursion, which tries to find // cycles in a list of moves. // // Algorithm. // // S = Traversal stack. // P = Pending move list. // O = Ordered list of moves. // // As long as there are pending moves in P: // Let |root| be any pending move removed from P // Add |root| to the traversal stack. // As long as S is not empty: // Let |L| be the most recent move added to S. // // Find any pending move M whose source is L's destination, thus // preventing L's move until M has completed. // // If a move M was found, // Remove M from the pending list. // If M's destination is |root|, // Annotate M and |root| as cycles. // Add M to S. // do not Add M to O, since M may have other conflictors in P that have not yet been processed. // Otherwise, // Add M to S. // Otherwise, // Remove L from S. // Add L to O. // while (!pending_.empty()) { PendingMove* pm = pending_.popBack(); // Add this pending move to the cycle detection stack. stack.pushBack(pm); while (!stack.empty()) { PendingMove* blocking = findBlockingMove(stack.peekBack()); if (blocking) { PendingMoveIterator stackiter = stack.begin(); PendingMove* cycled = findCycledMove(&stackiter, stack.end(), blocking); if (cycled) { // Find the cycle's start. // We annotate cycles at each move in the cycle, and // assert that we do not find two cycles in one move chain // traversal (which would indicate two moves to the same // destination). // Since there can be more than one cycle, find them all. do { cycled->setCycleEnd(curCycles_); cycled = findCycledMove(&stackiter, stack.end(), blocking); } while (cycled); blocking->setCycleBegin(pm->type(), curCycles_); curCycles_++; pending_.remove(blocking); stack.pushBack(blocking); } else { // This is a new link in the move chain, so keep // searching for a cycle. pending_.remove(blocking); stack.pushBack(blocking); } } else { // Otherwise, pop the last move on the search stack because it's // complete and not participating in a cycle. The resulting // move can safely be added to the ordered move list. PendingMove* done = stack.popBack(); if (!addOrderedMove(*done)) return false; movePool_.free(done); } } // If the current queue is empty, it is certain that there are // all previous cycles cannot conflict with future cycles, // so re-set the counter of pending cycles, while keeping a high-water mark. if (numCycles_ < curCycles_) numCycles_ = curCycles_; curCycles_ = 0; } return true; }
bool MoveResolver::resolve() { resetState(); orderedMoves_.clear(); InlineList<PendingMove> stack; // This is a depth-first-search without recursion, which tries to find // cycles in a list of moves. The output is not entirely optimal for cases // where a source has multiple destinations, i.e.: // [stack0] -> A // [stack0] -> B // // These moves may not occur next to each other in the list, making it // harder for the emitter to optimize memory to memory traffic. However, we // expect duplicate sources to be rare in greedy allocation, and indicative // of an error in LSRA. // // Algorithm. // // S = Traversal stack. // P = Pending move list. // O = Ordered list of moves. // // As long as there are pending moves in P: // Let |root| be any pending move removed from P // Add |root| to the traversal stack. // As long as S is not empty: // Let |L| be the most recent move added to S. // // Find any pending move M whose source is L's destination, thus // preventing L's move until M has completed. // // If a move M was found, // Remove M from the pending list. // If M's destination is |root|, // Annotate M and |root| as cycles. // Add M to S. // do not Add M to O, since M may have other conflictors in P that have not yet been processed. // Otherwise, // Add M to S. // Otherwise, // Remove L from S. // Add L to O. // while (!pending_.empty()) { PendingMove *pm = pending_.popBack(); // Add this pending move to the cycle detection stack. stack.pushBack(pm); while (!stack.empty()) { PendingMove *blocking = findBlockingMove(stack.peekBack()); if (blocking) { if (blocking->to() == pm->from()) { // We annotate cycles at each move in the cycle, and // assert that we do not find two cycles in one move chain // traversal (which would indicate two moves to the same // destination). pm->setInCycle(); blocking->setInCycle(); hasCycles_ = true; pending_.remove(blocking); stack.pushBack(blocking); } else { // This is a new link in the move chain, so keep // searching for a cycle. pending_.remove(blocking); stack.pushBack(blocking); } } else { // Otherwise, pop the last move on the search stack because it's // complete and not participating in a cycle. The resulting // move can safely be added to the ordered move list. PendingMove *done = stack.popBack(); if (!orderedMoves_.append(*done)) return false; movePool_.free(done); } } } return true; }