1b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// Copyright 2014 the V8 project authors. All rights reserved.
2b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// found in the LICENSE file.
4b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
5b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/compiler/gap-resolver.h"
6b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
7b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include <algorithm>
8b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include <functional>
9b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include <set>
10b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
11b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochnamespace v8 {
12b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochnamespace internal {
13b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochnamespace compiler {
14b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
15014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochnamespace {
16014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
17c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch#define REP_BIT(rep) (1 << static_cast<int>(rep))
18c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch
19c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdochconst int kFloat32Bit = REP_BIT(MachineRepresentation::kFloat32);
20c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdochconst int kFloat64Bit = REP_BIT(MachineRepresentation::kFloat64);
21c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch
22014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochinline bool Blocks(MoveOperands* move, InstructionOperand destination) {
23c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  return !move->IsEliminated() && move->source().InterferesWith(destination);
24b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
25b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
26c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch// Splits a FP move between two location operands into the equivalent series of
27c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch// moves between smaller sub-operands, e.g. a double move to two single moves.
28c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch// This helps reduce the number of cycles that would normally occur under FP
29c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch// aliasing, and makes swaps much easier to implement.
30c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen MurdochMoveOperands* Split(MoveOperands* move, MachineRepresentation smaller_rep,
31c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch                    ParallelMove* moves) {
32c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  DCHECK(!kSimpleFPAliasing);
33c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  // Splitting is only possible when the slot size is the same as float size.
34c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  DCHECK_EQ(kPointerSize, kFloatSize);
35c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  const LocationOperand& src_loc = LocationOperand::cast(move->source());
36c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  const LocationOperand& dst_loc = LocationOperand::cast(move->destination());
37c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  MachineRepresentation dst_rep = dst_loc.representation();
38c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  DCHECK_NE(smaller_rep, dst_rep);
39c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  auto src_kind = src_loc.location_kind();
40c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  auto dst_kind = dst_loc.location_kind();
41c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch
42c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  int aliases =
43c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch      1 << (ElementSizeLog2Of(dst_rep) - ElementSizeLog2Of(smaller_rep));
44c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  int base = -1;
45c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  USE(base);
46c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  DCHECK_EQ(aliases, RegisterConfiguration::Turbofan()->GetAliases(
47c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch                         dst_rep, 0, smaller_rep, &base));
48c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch
49c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  int src_index = -1;
50c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  int slot_size = (1 << ElementSizeLog2Of(smaller_rep)) / kPointerSize;
51c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  int src_step = 1;
52c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  if (src_kind == LocationOperand::REGISTER) {
53c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    src_index = src_loc.register_code() * aliases;
54c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  } else {
55c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    src_index = src_loc.index();
56c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    // For operands that occuply multiple slots, the index refers to the last
57c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    // slot. On little-endian architectures, we start at the high slot and use a
58c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    // negative step so that register-to-slot moves are in the correct order.
59c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    src_step = -slot_size;
60c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  }
61c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  int dst_index = -1;
62c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  int dst_step = 1;
63c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  if (dst_kind == LocationOperand::REGISTER) {
64c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    dst_index = dst_loc.register_code() * aliases;
65c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  } else {
66c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    dst_index = dst_loc.index();
67c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    dst_step = -slot_size;
68c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  }
69b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
70c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  // Reuse 'move' for the first fragment. It is not pending.
71c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  move->set_source(AllocatedOperand(src_kind, smaller_rep, src_index));
72c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  move->set_destination(AllocatedOperand(dst_kind, smaller_rep, dst_index));
73c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  // Add the remaining fragment moves.
74c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  for (int i = 1; i < aliases; ++i) {
75c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    src_index += src_step;
76c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    dst_index += dst_step;
77c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    moves->AddMove(AllocatedOperand(src_kind, smaller_rep, src_index),
78c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch                   AllocatedOperand(dst_kind, smaller_rep, dst_index));
79c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  }
80c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  // Return the first fragment.
81c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  return move;
82c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch}
83b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
84014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}  // namespace
85b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
86c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdochvoid GapResolver::Resolve(ParallelMove* moves) {
87c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  // Clear redundant moves, and collect FP move representations if aliasing
88c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  // is non-simple.
89c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  int reps = 0;
90c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  for (size_t i = 0; i < moves->size();) {
91c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    MoveOperands* move = (*moves)[i];
92c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    if (move->IsRedundant()) {
93c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch      (*moves)[i] = moves->back();
94c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch      moves->pop_back();
95c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch      continue;
96c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    }
97c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    i++;
98c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    if (!kSimpleFPAliasing && move->destination().IsFPRegister()) {
99c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch      reps |=
100c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch          REP_BIT(LocationOperand::cast(move->destination()).representation());
101c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    }
102c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  }
103c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch
104c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  if (!kSimpleFPAliasing) {
105c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    if (reps && !base::bits::IsPowerOfTwo32(reps)) {
106c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch      // Start with the smallest FP moves, so we never encounter smaller moves
107c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch      // in the middle of a cycle of larger moves.
108c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch      if ((reps & kFloat32Bit) != 0) {
109c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch        split_rep_ = MachineRepresentation::kFloat32;
110c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch        for (size_t i = 0; i < moves->size(); ++i) {
111c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch          auto move = (*moves)[i];
112c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch          if (!move->IsEliminated() && move->destination().IsFloatRegister())
113c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch            PerformMove(moves, move);
114c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch        }
115c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch      }
116c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch      if ((reps & kFloat64Bit) != 0) {
117c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch        split_rep_ = MachineRepresentation::kFloat64;
118c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch        for (size_t i = 0; i < moves->size(); ++i) {
119c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch          auto move = (*moves)[i];
120c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch          if (!move->IsEliminated() && move->destination().IsDoubleRegister())
121c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch            PerformMove(moves, move);
122c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch        }
123c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch      }
124c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    }
125c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    split_rep_ = MachineRepresentation::kSimd128;
126c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  }
127014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
128c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  for (size_t i = 0; i < moves->size(); ++i) {
129c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    auto move = (*moves)[i];
130014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if (!move->IsEliminated()) PerformMove(moves, move);
131b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
132b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
133b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
134c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdochvoid GapResolver::PerformMove(ParallelMove* moves, MoveOperands* move) {
135b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Each call to this function performs a move and deletes it from the move
136b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // graph.  We first recursively perform any move blocking this one.  We mark a
137b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // move as "pending" on entry to PerformMove in order to detect cycles in the
138b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // move graph.  We use operand swaps to resolve cycles, which means that a
139b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // call to PerformMove could change any source operand in the move graph.
140b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(!move->IsPending());
141b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(!move->IsRedundant());
142b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
143b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Clear this move's destination to indicate a pending move.  The actual
144b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // destination is saved on the side.
145c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  InstructionOperand source = move->source();
146c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  DCHECK(!source.IsInvalid());  // Or else it will look eliminated.
147014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  InstructionOperand destination = move->destination();
148014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  move->SetPending();
149b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
150c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  // We may need to split moves between FP locations differently.
151c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  bool is_fp_loc_move = !kSimpleFPAliasing && destination.IsFPLocationOperand();
152c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch
153b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Perform a depth-first traversal of the move graph to resolve dependencies.
154b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Any unperformed, unpending move with a source the same as this one's
155b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // destination blocks this one so recursively perform all such moves.
156c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  for (size_t i = 0; i < moves->size(); ++i) {
157c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    auto other = (*moves)[i];
158c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    if (other->IsEliminated()) continue;
159c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    if (other->IsPending()) continue;
160c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    if (other->source().InterferesWith(destination)) {
161c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch      if (!kSimpleFPAliasing && is_fp_loc_move &&
162c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch          LocationOperand::cast(other->source()).representation() >
163c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch              split_rep_) {
164c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch        // 'other' must also be an FP location move. Break it into fragments
165c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch        // of the same size as 'move'. 'other' is set to one of the fragments,
166c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch        // and the rest are appended to 'moves'.
167c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch        other = Split(other, split_rep_, moves);
168c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch        // 'other' may not block destination now.
169c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch        if (!other->source().InterferesWith(destination)) continue;
170c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch      }
171b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      // Though PerformMove can change any source operand in the move graph,
172b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      // this call cannot create a blocking move via a swap (this loop does not
173b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      // miss any).  Assume there is a non-blocking move with source A and this
174b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      // move is blocked on source B and there is a swap of A and B.  Then A and
175b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      // B must be involved in the same cycle (or they would not be swapped).
176b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      // Since this move's destination is B and there is only a single incoming
177b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      // edge to an operand, this move must also be involved in the same cycle.
178b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      // In that case, the blocking move will be created but will be "pending"
179b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      // when we return from PerformMove.
180b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      PerformMove(moves, other);
181b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
182b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
183b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
184b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // This move's source may have changed due to swaps to resolve cycles and so
185b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // it may now be the last move in the cycle.  If so remove it.
186c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  source = move->source();
187c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  if (source.EqualsCanonicalized(destination)) {
188b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    move->Eliminate();
189b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    return;
190b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
191b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
192c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  // We are about to resolve this move and don't need it marked as pending, so
193c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  // restore its destination.
194c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  move->set_destination(destination);
195c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch
196b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // The move may be blocked on a (at most one) pending move, in which case we
197b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // have a cycle.  Search for such a blocking move and perform a swap to
198b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // resolve it.
199014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  auto blocker = std::find_if(moves->begin(), moves->end(),
200014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                              std::bind2nd(std::ptr_fun(&Blocks), destination));
201b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if (blocker == moves->end()) {
202b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // The easy case: This move is not blocked.
203014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    assembler_->AssembleMove(&source, &destination);
204b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    move->Eliminate();
205b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    return;
206b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
207b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
208b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Ensure source is a register or both are stack slots, to limit swap cases.
209bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  if (source.IsStackSlot() || source.IsFPStackSlot()) {
210b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    std::swap(source, destination);
211b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
212014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  assembler_->AssembleSwap(&source, &destination);
213b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  move->Eliminate();
214b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
215c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  // Update outstanding moves whose source may now have been moved.
216c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  if (!kSimpleFPAliasing && is_fp_loc_move) {
217c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    // We may have to split larger moves.
218c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    for (size_t i = 0; i < moves->size(); ++i) {
219c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch      auto other = (*moves)[i];
220c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch      if (other->IsEliminated()) continue;
221c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch      if (source.InterferesWith(other->source())) {
222c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch        if (LocationOperand::cast(other->source()).representation() >
223c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch            split_rep_) {
224c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch          other = Split(other, split_rep_, moves);
225c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch          if (!source.InterferesWith(other->source())) continue;
226c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch        }
227c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch        other->set_source(destination);
228c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch      } else if (destination.InterferesWith(other->source())) {
229c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch        if (LocationOperand::cast(other->source()).representation() >
230c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch            split_rep_) {
231c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch          other = Split(other, split_rep_, moves);
232c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch          if (!destination.InterferesWith(other->source())) continue;
233c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch        }
234c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch        other->set_source(source);
235c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch      }
236c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    }
237c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  } else {
238c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    for (auto other : *moves) {
239c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch      if (other->IsEliminated()) continue;
240c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch      if (source.EqualsCanonicalized(other->source())) {
241c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch        other->set_source(destination);
242c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch      } else if (destination.EqualsCanonicalized(other->source())) {
243c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch        other->set_source(source);
244c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch      }
245b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
246b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
247b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
248014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}  // namespace compiler
249014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}  // namespace internal
250014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}  // namespace v8
251