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