14e3d23aa1523718ea1fdf3a32516d2f9d81e84feNicolas Geoffray/*
24e3d23aa1523718ea1fdf3a32516d2f9d81e84feNicolas Geoffray * Copyright (C) 2014 The Android Open Source Project
34e3d23aa1523718ea1fdf3a32516d2f9d81e84feNicolas Geoffray *
44e3d23aa1523718ea1fdf3a32516d2f9d81e84feNicolas Geoffray * Licensed under the Apache License, Version 2.0 (the "License");
54e3d23aa1523718ea1fdf3a32516d2f9d81e84feNicolas Geoffray * you may not use this file except in compliance with the License.
64e3d23aa1523718ea1fdf3a32516d2f9d81e84feNicolas Geoffray * You may obtain a copy of the License at
74e3d23aa1523718ea1fdf3a32516d2f9d81e84feNicolas Geoffray *
84e3d23aa1523718ea1fdf3a32516d2f9d81e84feNicolas Geoffray *      http://www.apache.org/licenses/LICENSE-2.0
94e3d23aa1523718ea1fdf3a32516d2f9d81e84feNicolas Geoffray *
104e3d23aa1523718ea1fdf3a32516d2f9d81e84feNicolas Geoffray * Unless required by applicable law or agreed to in writing, software
114e3d23aa1523718ea1fdf3a32516d2f9d81e84feNicolas Geoffray * distributed under the License is distributed on an "AS IS" BASIS,
124e3d23aa1523718ea1fdf3a32516d2f9d81e84feNicolas Geoffray * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134e3d23aa1523718ea1fdf3a32516d2f9d81e84feNicolas Geoffray * See the License for the specific language governing permissions and
144e3d23aa1523718ea1fdf3a32516d2f9d81e84feNicolas Geoffray * limitations under the License.
154e3d23aa1523718ea1fdf3a32516d2f9d81e84feNicolas Geoffray */
164e3d23aa1523718ea1fdf3a32516d2f9d81e84feNicolas Geoffray
174e3d23aa1523718ea1fdf3a32516d2f9d81e84feNicolas Geoffray#ifndef ART_COMPILER_OPTIMIZING_PARALLEL_MOVE_RESOLVER_H_
184e3d23aa1523718ea1fdf3a32516d2f9d81e84feNicolas Geoffray#define ART_COMPILER_OPTIMIZING_PARALLEL_MOVE_RESOLVER_H_
194e3d23aa1523718ea1fdf3a32516d2f9d81e84feNicolas Geoffray
20225b6464a58ebe11c156144653f11a1c6607f4ebVladimir Marko#include "base/arena_containers.h"
210279ebb3efd653e6bb255470c99d26949c7bcd95Ian Rogers#include "base/value_object.h"
22ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu#include "locations.h"
2380afd02024d20e60b197d3adfbb43cc303cf29e0Vladimir Marko#include "primitive.h"
244e3d23aa1523718ea1fdf3a32516d2f9d81e84feNicolas Geoffray
254e3d23aa1523718ea1fdf3a32516d2f9d81e84feNicolas Geoffraynamespace art {
264e3d23aa1523718ea1fdf3a32516d2f9d81e84feNicolas Geoffray
274e3d23aa1523718ea1fdf3a32516d2f9d81e84feNicolas Geoffrayclass HParallelMove;
284e3d23aa1523718ea1fdf3a32516d2f9d81e84feNicolas Geoffrayclass MoveOperands;
294e3d23aa1523718ea1fdf3a32516d2f9d81e84feNicolas Geoffray
30ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu// Helper classes to resolve a set of parallel moves. Architecture dependent code generator must
31ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu// have their own subclass that implements corresponding virtual functions.
324e3d23aa1523718ea1fdf3a32516d2f9d81e84feNicolas Geoffrayclass ParallelMoveResolver : public ValueObject {
334e3d23aa1523718ea1fdf3a32516d2f9d81e84feNicolas Geoffray public:
34225b6464a58ebe11c156144653f11a1c6607f4ebVladimir Marko  explicit ParallelMoveResolver(ArenaAllocator* allocator)
35225b6464a58ebe11c156144653f11a1c6607f4ebVladimir Marko      : moves_(allocator->Adapter(kArenaAllocParallelMoveResolver)) {
36225b6464a58ebe11c156144653f11a1c6607f4ebVladimir Marko    moves_.reserve(32);
37225b6464a58ebe11c156144653f11a1c6607f4ebVladimir Marko  }
38aa037b52a2eef463dab7b3a7e3c7cb441d28533aNicolas Geoffray  virtual ~ParallelMoveResolver() {}
394e3d23aa1523718ea1fdf3a32516d2f9d81e84feNicolas Geoffray
404e3d23aa1523718ea1fdf3a32516d2f9d81e84feNicolas Geoffray  // Resolve a set of parallel moves, emitting assembler instructions.
41ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  virtual void EmitNativeCode(HParallelMove* parallel_move) = 0;
42ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu
43ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu protected:
44ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  // Build the initial list of moves.
45ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  void BuildInitialMoveList(HParallelMove* parallel_move);
46ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu
47225b6464a58ebe11c156144653f11a1c6607f4ebVladimir Marko  ArenaVector<MoveOperands*> moves_;
48ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu
49ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu private:
50ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  DISALLOW_COPY_AND_ASSIGN(ParallelMoveResolver);
51ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu};
52ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu
53ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu// This helper class uses swap to resolve dependencies and may emit swap.
54ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xuclass ParallelMoveResolverWithSwap : public ParallelMoveResolver {
55ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu public:
56ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  explicit ParallelMoveResolverWithSwap(ArenaAllocator* allocator)
57ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu      : ParallelMoveResolver(allocator) {}
58ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  virtual ~ParallelMoveResolverWithSwap() {}
59ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu
60ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  // Resolve a set of parallel moves, emitting assembler instructions.
61ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  void EmitNativeCode(HParallelMove* parallel_move) OVERRIDE;
624e3d23aa1523718ea1fdf3a32516d2f9d81e84feNicolas Geoffray
634e3d23aa1523718ea1fdf3a32516d2f9d81e84feNicolas Geoffray protected:
6486dbb9a12119273039ce272b41c809fa548b37b6Nicolas Geoffray  class ScratchRegisterScope : public ValueObject {
6586dbb9a12119273039ce272b41c809fa548b37b6Nicolas Geoffray   public:
66ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu    ScratchRegisterScope(ParallelMoveResolverWithSwap* resolver,
67e27f31a81636ad74bd3376ee39cf215941b85c0eNicolas Geoffray                         int blocked,
68e27f31a81636ad74bd3376ee39cf215941b85c0eNicolas Geoffray                         int if_scratch,
69e27f31a81636ad74bd3376ee39cf215941b85c0eNicolas Geoffray                         int number_of_registers);
7086dbb9a12119273039ce272b41c809fa548b37b6Nicolas Geoffray    ~ScratchRegisterScope();
7186dbb9a12119273039ce272b41c809fa548b37b6Nicolas Geoffray
7286dbb9a12119273039ce272b41c809fa548b37b6Nicolas Geoffray    int GetRegister() const { return reg_; }
7386dbb9a12119273039ce272b41c809fa548b37b6Nicolas Geoffray    bool IsSpilled() const { return spilled_; }
7486dbb9a12119273039ce272b41c809fa548b37b6Nicolas Geoffray
7586dbb9a12119273039ce272b41c809fa548b37b6Nicolas Geoffray   private:
76ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu    ParallelMoveResolverWithSwap* resolver_;
7786dbb9a12119273039ce272b41c809fa548b37b6Nicolas Geoffray    int reg_;
7886dbb9a12119273039ce272b41c809fa548b37b6Nicolas Geoffray    bool spilled_;
7986dbb9a12119273039ce272b41c809fa548b37b6Nicolas Geoffray  };
8086dbb9a12119273039ce272b41c809fa548b37b6Nicolas Geoffray
81ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  // Return true if the location can be scratched.
8286dbb9a12119273039ce272b41c809fa548b37b6Nicolas Geoffray  bool IsScratchLocation(Location loc);
8348c310c431b110f6ab54907da20c4fa39a8f76b8Nicolas Geoffray
8448c310c431b110f6ab54907da20c4fa39a8f76b8Nicolas Geoffray  // Allocate a scratch register for performing a move. The method will try to use
8548c310c431b110f6ab54907da20c4fa39a8f76b8Nicolas Geoffray  // a register that is the destination of a move, but that move has not been emitted yet.
86e27f31a81636ad74bd3376ee39cf215941b85c0eNicolas Geoffray  int AllocateScratchRegister(int blocked, int if_scratch, int register_count, bool* spilled);
8786dbb9a12119273039ce272b41c809fa548b37b6Nicolas Geoffray
884e3d23aa1523718ea1fdf3a32516d2f9d81e84feNicolas Geoffray  // Emit a move.
894e3d23aa1523718ea1fdf3a32516d2f9d81e84feNicolas Geoffray  virtual void EmitMove(size_t index) = 0;
904e3d23aa1523718ea1fdf3a32516d2f9d81e84feNicolas Geoffray
914e3d23aa1523718ea1fdf3a32516d2f9d81e84feNicolas Geoffray  // Execute a move by emitting a swap of two operands.
924e3d23aa1523718ea1fdf3a32516d2f9d81e84feNicolas Geoffray  virtual void EmitSwap(size_t index) = 0;
934e3d23aa1523718ea1fdf3a32516d2f9d81e84feNicolas Geoffray
9486dbb9a12119273039ce272b41c809fa548b37b6Nicolas Geoffray  virtual void SpillScratch(int reg) = 0;
9586dbb9a12119273039ce272b41c809fa548b37b6Nicolas Geoffray  virtual void RestoreScratch(int reg) = 0;
9686dbb9a12119273039ce272b41c809fa548b37b6Nicolas Geoffray
9786dbb9a12119273039ce272b41c809fa548b37b6Nicolas Geoffray  static constexpr int kNoRegister = -1;
9886dbb9a12119273039ce272b41c809fa548b37b6Nicolas Geoffray
994e3d23aa1523718ea1fdf3a32516d2f9d81e84feNicolas Geoffray private:
1004e3d23aa1523718ea1fdf3a32516d2f9d81e84feNicolas Geoffray  // Perform the move at the moves_ index in question (possibly requiring
1014e3d23aa1523718ea1fdf3a32516d2f9d81e84feNicolas Geoffray  // other moves to satisfy dependencies).
102f7a0c4e421b5edaad5b7a15bfff687da28d0b287Nicolas Geoffray  //
103f7a0c4e421b5edaad5b7a15bfff687da28d0b287Nicolas Geoffray  // Return whether another move in the dependency cycle needs to swap. This
1049021825d1e73998b99c81e89c73796f6f2845471Nicolas Geoffray  // is to handle 64bits swaps:
1059021825d1e73998b99c81e89c73796f6f2845471Nicolas Geoffray  // 1) In the case of register pairs, where we want the pair to swap first to avoid
1069021825d1e73998b99c81e89c73796f6f2845471Nicolas Geoffray  //    building pairs that are unexpected by the code generator. For example, if
1079021825d1e73998b99c81e89c73796f6f2845471Nicolas Geoffray  //    we were to swap R1 with R2, we would need to update all locations using
1089021825d1e73998b99c81e89c73796f6f2845471Nicolas Geoffray  //    R2 to R1. So a (R2,R3) pair register could become (R1,R3). We could make
1099021825d1e73998b99c81e89c73796f6f2845471Nicolas Geoffray  //    the code generator understand such pairs, but it's easier and cleaner to
1109021825d1e73998b99c81e89c73796f6f2845471Nicolas Geoffray  //    just not create such pairs and exchange pairs in priority.
1119021825d1e73998b99c81e89c73796f6f2845471Nicolas Geoffray  // 2) Even when the architecture does not have pairs, we must handle 64bits swaps
1129021825d1e73998b99c81e89c73796f6f2845471Nicolas Geoffray  //    first. Consider the case: (R0->R1) (R1->S) (S->R0), where 'S' is a single
1139021825d1e73998b99c81e89c73796f6f2845471Nicolas Geoffray  //    stack slot. If we end up swapping S and R0, S will only contain the low bits
1149021825d1e73998b99c81e89c73796f6f2845471Nicolas Geoffray  //    of R0. If R0->R1 is for a 64bits instruction, R1 will therefore not contain
1159021825d1e73998b99c81e89c73796f6f2845471Nicolas Geoffray  //    the right value.
116f7a0c4e421b5edaad5b7a15bfff687da28d0b287Nicolas Geoffray  MoveOperands* PerformMove(size_t index);
1174e3d23aa1523718ea1fdf3a32516d2f9d81e84feNicolas Geoffray
118ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  DISALLOW_COPY_AND_ASSIGN(ParallelMoveResolverWithSwap);
119ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu};
120ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu
121ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu// This helper class uses additional scratch registers to resolve dependencies. It supports all kind
122ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu// of dependency cycles and does not care about the register layout.
123ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xuclass ParallelMoveResolverNoSwap : public ParallelMoveResolver {
124ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu public:
125ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  explicit ParallelMoveResolverNoSwap(ArenaAllocator* allocator)
126225b6464a58ebe11c156144653f11a1c6607f4ebVladimir Marko      : ParallelMoveResolver(allocator),
127225b6464a58ebe11c156144653f11a1c6607f4ebVladimir Marko        scratches_(allocator->Adapter(kArenaAllocParallelMoveResolver)),
128225b6464a58ebe11c156144653f11a1c6607f4ebVladimir Marko        pending_moves_(allocator->Adapter(kArenaAllocParallelMoveResolver)),
129225b6464a58ebe11c156144653f11a1c6607f4ebVladimir Marko        allocator_(allocator) {
130225b6464a58ebe11c156144653f11a1c6607f4ebVladimir Marko    scratches_.reserve(32);
131225b6464a58ebe11c156144653f11a1c6607f4ebVladimir Marko    pending_moves_.reserve(8);
132225b6464a58ebe11c156144653f11a1c6607f4ebVladimir Marko  }
133ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  virtual ~ParallelMoveResolverNoSwap() {}
134ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu
135ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  // Resolve a set of parallel moves, emitting assembler instructions.
136ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  void EmitNativeCode(HParallelMove* parallel_move) OVERRIDE;
137ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu
138ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu protected:
139ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  // Called at the beginning of EmitNativeCode(). A subclass may put some architecture dependent
140ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  // initialization here.
141ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  virtual void PrepareForEmitNativeCode() = 0;
142ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu
143ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  // Called at the end of EmitNativeCode(). A subclass may put some architecture dependent cleanup
144ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  // here. All scratch locations will be removed after this call.
145ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  virtual void FinishEmitNativeCode() = 0;
146ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu
147ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  // Allocate a scratch location to perform a move from input kind of location. A subclass should
148ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  // implement this to get the best fit location. If there is no suitable physical register, it can
149ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  // also return a stack slot.
150ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  virtual Location AllocateScratchLocationFor(Location::Kind kind) = 0;
151ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu
152ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  // Called after a move which takes a scratch location as source. A subclass can defer the cleanup
153ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  // to FinishEmitNativeCode().
154ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  virtual void FreeScratchLocation(Location loc) = 0;
155ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu
156ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  // Emit a move.
157ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  virtual void EmitMove(size_t index) = 0;
158ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu
159ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  // Return a scratch location from the moves which exactly matches the kind.
160ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  // Return Location::NoLocation() if no matching scratch location can be found.
161ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  Location GetScratchLocation(Location::Kind kind);
162ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu
163ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  // Add a location to the scratch list which can be returned from GetScratchLocation() to resolve
164ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  // dependency cycles.
165ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  void AddScratchLocation(Location loc);
166ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu
167ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  // Remove a location from the scratch list.
168ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  void RemoveScratchLocation(Location loc);
169ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu
170ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  // List of scratch locations.
171225b6464a58ebe11c156144653f11a1c6607f4ebVladimir Marko  ArenaVector<Location> scratches_;
172ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu
173ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu private:
174ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  // Perform the move at the given index in `moves_` (possibly requiring other moves to satisfy
175ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  // dependencies).
176ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  void PerformMove(size_t index);
177ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu
178ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  void UpdateMoveSource(Location from, Location to);
179ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu
180ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  void AddPendingMove(Location source, Location destination, Primitive::Type type);
181ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu
182ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  void DeletePendingMove(MoveOperands* move);
183ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu
184ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  // Find a move that may be unblocked after (loc -> XXX) is performed.
185ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  MoveOperands* GetUnblockedPendingMove(Location loc);
186ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu
187ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  // Return true if the location is blocked by outstanding moves.
188ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  bool IsBlockedByMoves(Location loc);
189ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu
190ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  // Return the number of pending moves.
191ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  size_t GetNumberOfPendingMoves();
192ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu
193ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  // Additional pending moves which might be added to resolve dependency cycle.
194225b6464a58ebe11c156144653f11a1c6607f4ebVladimir Marko  ArenaVector<MoveOperands*> pending_moves_;
195ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu
196ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  // Used to allocate pending MoveOperands.
197ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  ArenaAllocator* const allocator_;
198ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu
199ad4450e5c3ffaa9566216cc6fafbf5c11186c467Zheng Xu  DISALLOW_COPY_AND_ASSIGN(ParallelMoveResolverNoSwap);
2004e3d23aa1523718ea1fdf3a32516d2f9d81e84feNicolas Geoffray};
2014e3d23aa1523718ea1fdf3a32516d2f9d81e84feNicolas Geoffray
2024e3d23aa1523718ea1fdf3a32516d2f9d81e84feNicolas Geoffray}  // namespace art
2034e3d23aa1523718ea1fdf3a32516d2f9d81e84feNicolas Geoffray
2044e3d23aa1523718ea1fdf3a32516d2f9d81e84feNicolas Geoffray#endif  // ART_COMPILER_OPTIMIZING_PARALLEL_MOVE_RESOLVER_H_
205