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