11e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block// Copyright 2011 the V8 project authors. All rights reserved.
21e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block// Redistribution and use in source and binary forms, with or without
31e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block// modification, are permitted provided that the following conditions are
41e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block// met:
51e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block//
61e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block//     * Redistributions of source code must retain the above copyright
71e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block//       notice, this list of conditions and the following disclaimer.
81e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block//     * Redistributions in binary form must reproduce the above
91e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block//       copyright notice, this list of conditions and the following
101e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block//       disclaimer in the documentation and/or other materials provided
111e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block//       with the distribution.
121e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block//     * Neither the name of Google Inc. nor the names of its
131e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block//       contributors may be used to endorse or promote products derived
141e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block//       from this software without specific prior written permission.
151e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block//
161e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
171e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
181e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
191e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
201e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
211e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
221e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
231e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
241e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
251e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
261e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
271e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
281e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block#include "v8.h"
291e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
301e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block#if defined(V8_TARGET_ARCH_X64)
311e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
321e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block#include "x64/lithium-gap-resolver-x64.h"
331e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block#include "x64/lithium-codegen-x64.h"
341e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
351e0659c275bb392c045087af4f6b0d7565cb3d77Steve Blocknamespace v8 {
361e0659c275bb392c045087af4f6b0d7565cb3d77Steve Blocknamespace internal {
371e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
381e0659c275bb392c045087af4f6b0d7565cb3d77Steve BlockLGapResolver::LGapResolver(LCodeGen* owner)
391e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    : cgen_(owner), moves_(32) {}
401e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
411e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
421e0659c275bb392c045087af4f6b0d7565cb3d77Steve Blockvoid LGapResolver::Resolve(LParallelMove* parallel_move) {
431e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  ASSERT(moves_.is_empty());
441e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Build up a worklist of moves.
451e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  BuildInitialMoveList(parallel_move);
461e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
471e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  for (int i = 0; i < moves_.length(); ++i) {
481e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    LMoveOperands move = moves_[i];
491e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    // Skip constants to perform them last.  They don't block other moves
501e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    // and skipping such moves with register destinations keeps those
511e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    // registers free for the whole algorithm.
521e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    if (!move.IsEliminated() && !move.source()->IsConstantOperand()) {
531e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      PerformMove(i);
541e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    }
551e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  }
561e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
571e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Perform the moves with constant sources.
581e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  for (int i = 0; i < moves_.length(); ++i) {
591e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    if (!moves_[i].IsEliminated()) {
601e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      ASSERT(moves_[i].source()->IsConstantOperand());
611e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      EmitMove(i);
621e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    }
631e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  }
641e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
651e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  moves_.Rewind(0);
661e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block}
671e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
681e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
691e0659c275bb392c045087af4f6b0d7565cb3d77Steve Blockvoid LGapResolver::BuildInitialMoveList(LParallelMove* parallel_move) {
701e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Perform a linear sweep of the moves to add them to the initial list of
711e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // moves to perform, ignoring any move that is redundant (the source is
721e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // the same as the destination, the destination is ignored and
731e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // unallocated, or the move was already eliminated).
741e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  const ZoneList<LMoveOperands>* moves = parallel_move->move_operands();
751e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  for (int i = 0; i < moves->length(); ++i) {
761e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    LMoveOperands move = moves->at(i);
771e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    if (!move.IsRedundant()) moves_.Add(move);
781e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  }
791e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  Verify();
801e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block}
811e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
821e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
831e0659c275bb392c045087af4f6b0d7565cb3d77Steve Blockvoid LGapResolver::PerformMove(int index) {
841e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Each call to this function performs a move and deletes it from the move
851e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // graph.  We first recursively perform any move blocking this one.  We
861e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // mark a move as "pending" on entry to PerformMove in order to detect
871e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // cycles in the move graph.  We use operand swaps to resolve cycles,
881e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // which means that a call to PerformMove could change any source operand
891e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // in the move graph.
901e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
911e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  ASSERT(!moves_[index].IsPending());
921e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  ASSERT(!moves_[index].IsRedundant());
931e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
941e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Clear this move's destination to indicate a pending move.  The actual
951e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // destination is saved in a stack-allocated local.  Recursion may allow
961e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // multiple moves to be pending.
971e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  ASSERT(moves_[index].source() != NULL);  // Or else it will look eliminated.
981e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  LOperand* destination = moves_[index].destination();
991e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  moves_[index].set_destination(NULL);
1001e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
1011e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Perform a depth-first traversal of the move graph to resolve
1021e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // dependencies.  Any unperformed, unpending move with a source the same
1031e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // as this one's destination blocks this one so recursively perform all
1041e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // such moves.
1051e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  for (int i = 0; i < moves_.length(); ++i) {
1061e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    LMoveOperands other_move = moves_[i];
1071e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    if (other_move.Blocks(destination) && !other_move.IsPending()) {
1081e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      // Though PerformMove can change any source operand in the move graph,
1091e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      // this call cannot create a blocking move via a swap (this loop does
1101e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      // not miss any).  Assume there is a non-blocking move with source A
1111e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      // and this move is blocked on source B and there is a swap of A and
1121e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      // B.  Then A and B must be involved in the same cycle (or they would
1131e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      // not be swapped).  Since this move's destination is B and there is
1141e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      // only a single incoming edge to an operand, this move must also be
1151e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      // involved in the same cycle.  In that case, the blocking move will
1161e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      // be created but will be "pending" when we return from PerformMove.
1171e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      PerformMove(i);
1181e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    }
1191e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  }
1201e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
1211e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // We are about to resolve this move and don't need it marked as
1221e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // pending, so restore its destination.
1231e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  moves_[index].set_destination(destination);
1241e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
1251e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // This move's source may have changed due to swaps to resolve cycles and
1261e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // so it may now be the last move in the cycle.  If so remove it.
1271e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  if (moves_[index].source()->Equals(destination)) {
1281e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    moves_[index].Eliminate();
1291e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    return;
1301e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  }
1311e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
1321e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // The move may be blocked on a (at most one) pending move, in which case
1331e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // we have a cycle.  Search for such a blocking move and perform a swap to
1341e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // resolve it.
1351e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  for (int i = 0; i < moves_.length(); ++i) {
1361e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    LMoveOperands other_move = moves_[i];
1371e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    if (other_move.Blocks(destination)) {
1381e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      ASSERT(other_move.IsPending());
1391e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      EmitSwap(index);
1401e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      return;
1411e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    }
1421e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  }
1431e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
1441e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // This move is not blocked.
1451e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  EmitMove(index);
1461e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block}
1471e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
1481e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
1491e0659c275bb392c045087af4f6b0d7565cb3d77Steve Blockvoid LGapResolver::Verify() {
1501e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block#ifdef ENABLE_SLOW_ASSERTS
1511e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // No operand should be the destination for more than one move.
1521e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  for (int i = 0; i < moves_.length(); ++i) {
1531e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    LOperand* destination = moves_[i].destination();
1541e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    for (int j = i + 1; j < moves_.length(); ++j) {
1551e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      SLOW_ASSERT(!destination->Equals(moves_[j].destination()));
1561e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    }
1571e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  }
1581e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block#endif
1591e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block}
1601e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
1611e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
1621e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block#define __ ACCESS_MASM(cgen_->masm())
1631e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
1641e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
1651e0659c275bb392c045087af4f6b0d7565cb3d77Steve Blockvoid LGapResolver::EmitMove(int index) {
1661e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  LOperand* source = moves_[index].source();
1671e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  LOperand* destination = moves_[index].destination();
1681e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
1691e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Dispatch on the source and destination operand kinds.  Not all
1701e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // combinations are possible.
1711e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  if (source->IsRegister()) {
1721e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    Register src = cgen_->ToRegister(source);
1731e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    if (destination->IsRegister()) {
1741e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      Register dst = cgen_->ToRegister(destination);
1751e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ movq(dst, src);
1761e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    } else {
1771e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      ASSERT(destination->IsStackSlot());
1781e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      Operand dst = cgen_->ToOperand(destination);
1791e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ movq(dst, src);
1801e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    }
1811e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
1821e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  } else if (source->IsStackSlot()) {
1831e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    Operand src = cgen_->ToOperand(source);
1841e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    if (destination->IsRegister()) {
1851e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      Register dst = cgen_->ToRegister(destination);
1861e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ movq(dst, src);
1871e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    } else {
1881e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      ASSERT(destination->IsStackSlot());
1891e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      Operand dst = cgen_->ToOperand(destination);
1901e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ movq(kScratchRegister, src);
1911e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ movq(dst, kScratchRegister);
1921e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    }
1931e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
1941e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  } else if (source->IsConstantOperand()) {
1951e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    LConstantOperand* constant_source = LConstantOperand::cast(source);
1961e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    if (destination->IsRegister()) {
1971e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      Register dst = cgen_->ToRegister(destination);
1981e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      if (cgen_->IsInteger32Constant(constant_source)) {
1991e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        __ movl(dst, Immediate(cgen_->ToInteger32(constant_source)));
2001e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      } else {
2013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        __ LoadObject(dst, cgen_->ToHandle(constant_source));
2021e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      }
2031e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    } else {
2041e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      ASSERT(destination->IsStackSlot());
2051e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      Operand dst = cgen_->ToOperand(destination);
2061e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      if (cgen_->IsInteger32Constant(constant_source)) {
2073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        // Zero top 32 bits of a 64 bit spill slot that holds a 32 bit untagged
2083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        // value.
2093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        __ movq(dst, Immediate(cgen_->ToInteger32(constant_source)));
2101e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      } else {
2113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        __ LoadObject(kScratchRegister, cgen_->ToHandle(constant_source));
2123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        __ movq(dst, kScratchRegister);
2131e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      }
2141e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    }
2151e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
2161e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  } else if (source->IsDoubleRegister()) {
2171e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    XMMRegister src = cgen_->ToDoubleRegister(source);
2181e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    if (destination->IsDoubleRegister()) {
219257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      __ movaps(cgen_->ToDoubleRegister(destination), src);
2201e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    } else {
2211e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      ASSERT(destination->IsDoubleStackSlot());
2221e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ movsd(cgen_->ToOperand(destination), src);
2231e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    }
2241e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  } else if (source->IsDoubleStackSlot()) {
2251e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    Operand src = cgen_->ToOperand(source);
2261e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    if (destination->IsDoubleRegister()) {
2271e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ movsd(cgen_->ToDoubleRegister(destination), src);
2281e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    } else {
2291e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      ASSERT(destination->IsDoubleStackSlot());
2301e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ movsd(xmm0, src);
2311e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      __ movsd(cgen_->ToOperand(destination), xmm0);
2321e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    }
2331e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  } else {
2341e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    UNREACHABLE();
2351e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  }
2361e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
2371e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  moves_[index].Eliminate();
2381e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block}
2391e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
2401e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
2411e0659c275bb392c045087af4f6b0d7565cb3d77Steve Blockvoid LGapResolver::EmitSwap(int index) {
2421e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  LOperand* source = moves_[index].source();
2431e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  LOperand* destination = moves_[index].destination();
2441e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
2451e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Dispatch on the source and destination operand kinds.  Not all
2461e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // combinations are possible.
2471e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  if (source->IsRegister() && destination->IsRegister()) {
2481e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    // Swap two general-purpose registers.
2491e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    Register src = cgen_->ToRegister(source);
2501e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    Register dst = cgen_->ToRegister(destination);
2511e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ xchg(dst, src);
2521e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
2531e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  } else if ((source->IsRegister() && destination->IsStackSlot()) ||
2541e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block             (source->IsStackSlot() && destination->IsRegister())) {
2551e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    // Swap a general-purpose register and a stack slot.
2561e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    Register reg =
2571e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        cgen_->ToRegister(source->IsRegister() ? source : destination);
2581e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    Operand mem =
2591e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        cgen_->ToOperand(source->IsRegister() ? destination : source);
2601e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ movq(kScratchRegister, mem);
2611e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ movq(mem, reg);
2621e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ movq(reg, kScratchRegister);
2631e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
2641e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  } else if ((source->IsStackSlot() && destination->IsStackSlot()) ||
2651e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      (source->IsDoubleStackSlot() && destination->IsDoubleStackSlot())) {
2661e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    // Swap two stack slots or two double stack slots.
2671e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    Operand src = cgen_->ToOperand(source);
2681e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    Operand dst = cgen_->ToOperand(destination);
2691e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ movsd(xmm0, src);
2701e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ movq(kScratchRegister, dst);
2711e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ movsd(dst, xmm0);
2721e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ movq(src, kScratchRegister);
2731e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
2741e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  } else if (source->IsDoubleRegister() && destination->IsDoubleRegister()) {
2751e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    // Swap two double registers.
2761e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    XMMRegister source_reg = cgen_->ToDoubleRegister(source);
2771e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    XMMRegister destination_reg = cgen_->ToDoubleRegister(destination);
278257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ movaps(xmm0, source_reg);
279257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ movaps(source_reg, destination_reg);
280257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    __ movaps(destination_reg, xmm0);
2811e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
2821e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  } else if (source->IsDoubleRegister() || destination->IsDoubleRegister()) {
2831e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    // Swap a double register and a double stack slot.
2841e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    ASSERT((source->IsDoubleRegister() && destination->IsDoubleStackSlot()) ||
2851e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block           (source->IsDoubleStackSlot() && destination->IsDoubleRegister()));
2861e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    XMMRegister reg = cgen_->ToDoubleRegister(source->IsDoubleRegister()
2871e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                                  ? source
2881e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                                  : destination);
2891e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    LOperand* other = source->IsDoubleRegister() ? destination : source;
2901e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    ASSERT(other->IsDoubleStackSlot());
2911e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    Operand other_operand = cgen_->ToOperand(other);
2921e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ movsd(xmm0, other_operand);
2931e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ movsd(other_operand, reg);
2941e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    __ movsd(reg, xmm0);
2951e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
2961e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  } else {
2971e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    // No other combinations are possible.
2981e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    UNREACHABLE();
2991e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  }
3001e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
3011e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // The swap of source and destination has executed a move from source to
3021e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // destination.
3031e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  moves_[index].Eliminate();
3041e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
3051e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // Any unperformed (including pending) move with a source of either
3061e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // this move's source or destination needs to have their source
3071e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  // changed to reflect the state of affairs after the swap.
3081e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  for (int i = 0; i < moves_.length(); ++i) {
3091e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    LMoveOperands other_move = moves_[i];
3101e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    if (other_move.Blocks(source)) {
3111e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      moves_[i].set_source(destination);
3121e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    } else if (other_move.Blocks(destination)) {
3131e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      moves_[i].set_source(source);
3141e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    }
3151e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  }
3161e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block}
3171e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
3181e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block#undef __
3191e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
3201e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block} }  // namespace v8::internal
3211e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
3221e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block#endif  // V8_TARGET_ARCH_X64
323