1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef ART_COMPILER_OPTIMIZING_PARALLEL_MOVE_RESOLVER_H_ 18 #define ART_COMPILER_OPTIMIZING_PARALLEL_MOVE_RESOLVER_H_ 19 20 #include "base/arena_containers.h" 21 #include "base/macros.h" 22 #include "base/value_object.h" 23 #include "data_type.h" 24 #include "locations.h" 25 26 namespace art HIDDEN { 27 28 class HParallelMove; 29 class MoveOperands; 30 31 // Helper classes to resolve a set of parallel moves. Architecture dependent code generator must 32 // have their own subclass that implements corresponding virtual functions. 33 class ParallelMoveResolver : public ValueObject { 34 public: ParallelMoveResolver(ArenaAllocator * allocator)35 explicit ParallelMoveResolver(ArenaAllocator* allocator) 36 : moves_(allocator->Adapter(kArenaAllocParallelMoveResolver)) { 37 moves_.reserve(32); 38 } ~ParallelMoveResolver()39 virtual ~ParallelMoveResolver() {} 40 41 // Resolve a set of parallel moves, emitting assembler instructions. 42 virtual void EmitNativeCode(HParallelMove* parallel_move) = 0; 43 44 protected: 45 // Build the initial list of moves. 46 void BuildInitialMoveList(HParallelMove* parallel_move); 47 48 ArenaVector<MoveOperands*> moves_; 49 50 private: 51 DISALLOW_COPY_AND_ASSIGN(ParallelMoveResolver); 52 }; 53 54 // This helper class uses swap to resolve dependencies and may emit swap. 55 class ParallelMoveResolverWithSwap : public ParallelMoveResolver { 56 public: ParallelMoveResolverWithSwap(ArenaAllocator * allocator)57 explicit ParallelMoveResolverWithSwap(ArenaAllocator* allocator) 58 : ParallelMoveResolver(allocator) {} ~ParallelMoveResolverWithSwap()59 virtual ~ParallelMoveResolverWithSwap() {} 60 61 // Resolve a set of parallel moves, emitting assembler instructions. 62 void EmitNativeCode(HParallelMove* parallel_move) override; 63 64 protected: 65 class ScratchRegisterScope : public ValueObject { 66 public: 67 ScratchRegisterScope(ParallelMoveResolverWithSwap* resolver, 68 int blocked, 69 int if_scratch, 70 int number_of_registers); 71 ~ScratchRegisterScope(); 72 GetRegister()73 int GetRegister() const { return reg_; } IsSpilled()74 bool IsSpilled() const { return spilled_; } 75 76 private: 77 ParallelMoveResolverWithSwap* resolver_; 78 int reg_; 79 bool spilled_; 80 }; 81 82 // Return true if the location can be scratched. 83 bool IsScratchLocation(Location loc); 84 85 // Allocate a scratch register for performing a move. The method will try to use 86 // a register that is the destination of a move, but that move has not been emitted yet. 87 int AllocateScratchRegister(int blocked, int if_scratch, int register_count, bool* spilled); 88 89 // Emit a move. 90 virtual void EmitMove(size_t index) = 0; 91 92 // Execute a move by emitting a swap of two operands. 93 virtual void EmitSwap(size_t index) = 0; 94 95 virtual void SpillScratch(int reg) = 0; 96 virtual void RestoreScratch(int reg) = 0; 97 98 static constexpr int kNoRegister = -1; 99 100 private: 101 // Perform the move at the moves_ index in question (possibly requiring 102 // other moves to satisfy dependencies). 103 // 104 // Return whether another move in the dependency cycle needs to swap. This 105 // is to handle 64bits swaps: 106 // 1) In the case of register pairs, where we want the pair to swap first to avoid 107 // building pairs that are unexpected by the code generator. For example, if 108 // we were to swap R1 with R2, we would need to update all locations using 109 // R2 to R1. So a (R2,R3) pair register could become (R1,R3). We could make 110 // the code generator understand such pairs, but it's easier and cleaner to 111 // just not create such pairs and exchange pairs in priority. 112 // 2) Even when the architecture does not have pairs, we must handle 64bits swaps 113 // first. Consider the case: (R0->R1) (R1->S) (S->R0), where 'S' is a single 114 // stack slot. If we end up swapping S and R0, S will only contain the low bits 115 // of R0. If R0->R1 is for a 64bits instruction, R1 will therefore not contain 116 // the right value. 117 MoveOperands* PerformMove(size_t index); 118 119 DISALLOW_COPY_AND_ASSIGN(ParallelMoveResolverWithSwap); 120 }; 121 122 // This helper class uses additional scratch registers to resolve dependencies. It supports all kind 123 // of dependency cycles and does not care about the register layout. 124 class ParallelMoveResolverNoSwap : public ParallelMoveResolver { 125 public: ParallelMoveResolverNoSwap(ArenaAllocator * allocator)126 explicit ParallelMoveResolverNoSwap(ArenaAllocator* allocator) 127 : ParallelMoveResolver(allocator), 128 scratches_(allocator->Adapter(kArenaAllocParallelMoveResolver)), 129 pending_moves_(allocator->Adapter(kArenaAllocParallelMoveResolver)), 130 allocator_(allocator) { 131 scratches_.reserve(32); 132 pending_moves_.reserve(8); 133 } ~ParallelMoveResolverNoSwap()134 virtual ~ParallelMoveResolverNoSwap() {} 135 136 // Resolve a set of parallel moves, emitting assembler instructions. 137 void EmitNativeCode(HParallelMove* parallel_move) override; 138 139 protected: 140 // Called at the beginning of EmitNativeCode(). A subclass may put some architecture dependent 141 // initialization here. 142 virtual void PrepareForEmitNativeCode() = 0; 143 144 // Called at the end of EmitNativeCode(). A subclass may put some architecture dependent cleanup 145 // here. All scratch locations will be removed after this call. 146 virtual void FinishEmitNativeCode() = 0; 147 148 // Allocate a scratch location to perform a move from input kind of location. A subclass should 149 // implement this to get the best fit location. If there is no suitable physical register, it can 150 // also return a stack slot. 151 virtual Location AllocateScratchLocationFor(Location::Kind kind) = 0; 152 153 // Called after a move which takes a scratch location as source. A subclass can defer the cleanup 154 // to FinishEmitNativeCode(). 155 virtual void FreeScratchLocation(Location loc) = 0; 156 157 // Emit a move. 158 virtual void EmitMove(size_t index) = 0; 159 160 // Return a scratch location from the moves which exactly matches the kind. 161 // Return Location::NoLocation() if no matching scratch location can be found. 162 Location GetScratchLocation(Location::Kind kind); 163 164 // Add a location to the scratch list which can be returned from GetScratchLocation() to resolve 165 // dependency cycles. 166 void AddScratchLocation(Location loc); 167 168 // Remove a location from the scratch list. 169 void RemoveScratchLocation(Location loc); 170 171 // List of scratch locations. 172 ArenaVector<Location> scratches_; 173 174 private: 175 // Perform the move at the given index in `moves_` (possibly requiring other moves to satisfy 176 // dependencies). 177 void PerformMove(size_t index); 178 179 void UpdateMoveSource(Location from, Location to); 180 181 void AddPendingMove(Location source, Location destination, DataType::Type type); 182 183 void DeletePendingMove(MoveOperands* move); 184 185 // Find a move that may be unblocked after (loc -> XXX) is performed. 186 MoveOperands* GetUnblockedPendingMove(Location loc); 187 188 // Return true if the location is blocked by outstanding moves. 189 bool IsBlockedByMoves(Location loc); 190 191 // Return the number of pending moves. 192 size_t GetNumberOfPendingMoves(); 193 194 // Additional pending moves which might be added to resolve dependency cycle. 195 ArenaVector<MoveOperands*> pending_moves_; 196 197 // Used to allocate pending MoveOperands. 198 ArenaAllocator* const allocator_; 199 200 DISALLOW_COPY_AND_ASSIGN(ParallelMoveResolverNoSwap); 201 }; 202 203 } // namespace art 204 205 #endif // ART_COMPILER_OPTIMIZING_PARALLEL_MOVE_RESOLVER_H_ 206