Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(297)

Side by Side Diff: src/compiler/gap-resolver.cc

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

Powered by Google App Engine
This is Rietveld 408576698