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

Side by Side Diff: src/compiler/bytecode-analysis.cc

Issue 2558093005: [turbofan] Add and use bytecode loop assigment analysis (Closed)
Patch Set: Use assignment analysis in PrepareForLoop Created 4 years 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 2016 the V8 project authors. All rights reserved. 1 // Copyright 2016 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/bytecode-analysis.h" 5 #include "src/compiler/bytecode-analysis.h"
6 6
7 #include "src/interpreter/bytecode-array-iterator.h" 7 #include "src/interpreter/bytecode-array-iterator.h"
8 #include "src/interpreter/bytecode-array-random-iterator.h" 8 #include "src/interpreter/bytecode-array-random-iterator.h"
9 #include "src/objects-inl.h" 9 #include "src/objects-inl.h"
10 10
11 namespace v8 { 11 namespace v8 {
12 namespace internal { 12 namespace internal {
13 namespace compiler { 13 namespace compiler {
14 14
15 using namespace interpreter; 15 using namespace interpreter;
16 16
17 BytecodeLoopAssignments::BytecodeLoopAssignments(int parameter_count,
18 int register_count, Zone* zone)
19 : parameter_count_(parameter_count),
20 bit_vector_(new (zone)
21 BitVector(parameter_count + register_count, zone)) {}
22
23 void BytecodeLoopAssignments::Add(interpreter::Register r) {
24 if (r.is_parameter()) {
25 bit_vector_->Add(r.ToParameterIndex(parameter_count_));
26 } else {
27 bit_vector_->Add(parameter_count_ + r.index());
28 }
29 }
30
31 void BytecodeLoopAssignments::AddPair(interpreter::Register r) {
32 if (r.is_parameter()) {
33 DCHECK(interpreter::Register(r.index() + 1).is_parameter());
34 bit_vector_->Add(r.ToParameterIndex(parameter_count_));
35 bit_vector_->Add(r.ToParameterIndex(parameter_count_) + 1);
36 } else {
37 DCHECK(!interpreter::Register(r.index() + 1).is_parameter());
38 bit_vector_->Add(parameter_count_ + r.index());
39 bit_vector_->Add(parameter_count_ + r.index() + 1);
40 }
41 }
42
43 void BytecodeLoopAssignments::AddTriple(interpreter::Register r) {
44 if (r.is_parameter()) {
45 DCHECK(interpreter::Register(r.index() + 1).is_parameter());
46 DCHECK(interpreter::Register(r.index() + 2).is_parameter());
47 bit_vector_->Add(r.ToParameterIndex(parameter_count_));
48 bit_vector_->Add(r.ToParameterIndex(parameter_count_) + 1);
49 bit_vector_->Add(r.ToParameterIndex(parameter_count_) + 2);
50 } else {
51 DCHECK(!interpreter::Register(r.index() + 1).is_parameter());
52 DCHECK(!interpreter::Register(r.index() + 2).is_parameter());
53 bit_vector_->Add(parameter_count_ + r.index());
54 bit_vector_->Add(parameter_count_ + r.index() + 1);
55 bit_vector_->Add(parameter_count_ + r.index() + 2);
56 }
57 }
58
59 void BytecodeLoopAssignments::AddAll() { bit_vector_->AddAll(); }
60
61 void BytecodeLoopAssignments::Union(const BytecodeLoopAssignments& other) {
62 bit_vector_->Union(*other.bit_vector_);
63 }
64
65 bool BytecodeLoopAssignments::ContainsParameter(int index) const {
66 DCHECK_GE(index, 0);
67 DCHECK_LT(index, parameter_count_);
68 return bit_vector_->Contains(index);
69 }
70
71 bool BytecodeLoopAssignments::ContainsLocal(int index) const {
72 DCHECK_GE(index, 0);
73 DCHECK_LT(index, bit_vector_->length() - parameter_count_);
74 return bit_vector_->Contains(parameter_count_ + index);
75 }
76
17 BytecodeAnalysis::BytecodeAnalysis(Handle<BytecodeArray> bytecode_array, 77 BytecodeAnalysis::BytecodeAnalysis(Handle<BytecodeArray> bytecode_array,
18 Zone* zone, bool do_liveness_analysis) 78 Zone* zone, bool do_liveness_analysis)
19 : bytecode_array_(bytecode_array), 79 : bytecode_array_(bytecode_array),
20 do_liveness_analysis_(do_liveness_analysis), 80 do_liveness_analysis_(do_liveness_analysis),
21 zone_(zone), 81 zone_(zone),
22 loop_stack_(zone), 82 loop_stack_(zone),
23 loop_end_index_queue_(zone), 83 loop_end_index_queue_(zone),
24 end_to_header_(zone), 84 end_to_header_(zone),
25 header_to_parent_(zone), 85 header_to_info_(zone),
26 liveness_map_(bytecode_array->length(), zone) {} 86 liveness_map_(bytecode_array->length(), zone) {}
27 87
28 namespace { 88 namespace {
29 89
30 void UpdateInLiveness(Bytecode bytecode, BytecodeLivenessState& in_liveness, 90 void UpdateInLiveness(Bytecode bytecode, BytecodeLivenessState& in_liveness,
31 const BytecodeArrayAccessor& accessor) { 91 const BytecodeArrayAccessor& accessor) {
32 int num_operands = Bytecodes::NumberOfOperands(bytecode); 92 int num_operands = Bytecodes::NumberOfOperands(bytecode);
33 const OperandType* operand_types = Bytecodes::GetOperandTypes(bytecode); 93 const OperandType* operand_types = Bytecodes::GetOperandTypes(bytecode);
34 AccumulatorUse accumulator_use = Bytecodes::GetAccumulatorUse(bytecode); 94 AccumulatorUse accumulator_use = Bytecodes::GetAccumulatorUse(bytecode);
35 95
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
138 int handler_offset = 198 int handler_offset =
139 table->LookupRange(current_offset, &handler_context, nullptr); 199 table->LookupRange(current_offset, &handler_context, nullptr);
140 200
141 if (handler_offset != -1) { 201 if (handler_offset != -1) {
142 out_liveness.Union(*liveness_map.GetInLiveness(handler_offset)); 202 out_liveness.Union(*liveness_map.GetInLiveness(handler_offset));
143 out_liveness.MarkRegisterLive(handler_context); 203 out_liveness.MarkRegisterLive(handler_context);
144 } 204 }
145 } 205 }
146 } 206 }
147 207
208 void UpdateAssignments(Bytecode bytecode, BytecodeLoopAssignments& assignments,
209 const BytecodeArrayAccessor& accessor) {
210 int num_operands = Bytecodes::NumberOfOperands(bytecode);
211 const OperandType* operand_types = Bytecodes::GetOperandTypes(bytecode);
212
213 for (int i = 0; i < num_operands; ++i) {
214 switch (operand_types[i]) {
215 case OperandType::kRegOut: {
216 assignments.Add(accessor.GetRegisterOperand(i));
217 break;
218 }
219 case OperandType::kRegOutPair: {
220 assignments.AddPair(accessor.GetRegisterOperand(i));
221 break;
222 }
223 case OperandType::kRegOutTriple: {
224 assignments.AddTriple(accessor.GetRegisterOperand(i));
225 break;
226 }
227 default:
228 DCHECK(!Bytecodes::IsRegisterOutputOperandType(operand_types[i]));
229 break;
230 }
231 }
232 }
233
148 } // namespace 234 } // namespace
149 235
150 void BytecodeAnalysis::Analyze() { 236 void BytecodeAnalysis::Analyze(BailoutId osr_bailout_id) {
151 loop_stack_.push(-1); 237 loop_stack_.push({-1, nullptr});
152 238
153 BytecodeLivenessState* next_bytecode_in_liveness = nullptr; 239 BytecodeLivenessState* next_bytecode_in_liveness = nullptr;
154 240
241 bool is_osr_loop = false;
242 int osr_loop_end_offset =
243 osr_bailout_id.IsNone() ? -1 : osr_bailout_id.ToInt();
244
155 BytecodeArrayRandomIterator iterator(bytecode_array(), zone()); 245 BytecodeArrayRandomIterator iterator(bytecode_array(), zone());
156 for (iterator.GoToEnd(); iterator.IsValid(); --iterator) { 246 for (iterator.GoToEnd(); iterator.IsValid(); --iterator) {
157 Bytecode bytecode = iterator.current_bytecode(); 247 Bytecode bytecode = iterator.current_bytecode();
158 int current_offset = iterator.current_offset(); 248 int current_offset = iterator.current_offset();
159 249
160 if (bytecode == Bytecode::kJumpLoop) { 250 if (bytecode == Bytecode::kJumpLoop) {
161 // Every byte up to and including the last byte within the backwards jump 251 // Every byte up to and including the last byte within the backwards jump
162 // instruction is considered part of the loop, set loop end accordingly. 252 // instruction is considered part of the loop, set loop end accordingly.
163 int loop_end = current_offset + iterator.current_bytecode_size(); 253 int loop_end = current_offset + iterator.current_bytecode_size();
164 PushLoop(iterator.GetJumpTargetOffset(), loop_end); 254 PushLoop(iterator.GetJumpTargetOffset(), loop_end);
165 255
256 is_osr_loop = (current_offset == osr_loop_end_offset);
257 if (is_osr_loop) {
258 loop_stack_.top().loop_info->assignments().AddAll();
259 }
260
166 // Save the index so that we can do another pass later. 261 // Save the index so that we can do another pass later.
167 if (do_liveness_analysis_) { 262 if (do_liveness_analysis_) {
168 loop_end_index_queue_.push_back(iterator.current_index()); 263 loop_end_index_queue_.push_back(iterator.current_index());
169 } 264 }
170 } else if (current_offset == loop_stack_.top()) { 265 } else {
171 loop_stack_.pop(); 266 if (loop_stack_.size() > 1 && !is_osr_loop) {
267 // TODO(leszeks): Ideally, we'd only set values that were assigned in
268 // the loop *and* are live when the loop exits. However, this requires
269 // tracking the out-liveness of *all* loop exits, which is not
270 // information we currently have.
271 UpdateAssignments(bytecode, loop_stack_.top().loop_info->assignments(),
272 iterator);
273 }
274
275 if (current_offset == loop_stack_.top().header_offset) {
276 LoopStackEntry entry = loop_stack_.top();
277 loop_stack_.pop();
278 if (loop_stack_.size() > 1) {
279 // Propagate inner loop assignments to outer loop.
280 loop_stack_.top().loop_info->assignments().Union(
281 entry.loop_info->assignments());
282 }
283 }
172 } 284 }
173 285
174 if (do_liveness_analysis_) { 286 if (do_liveness_analysis_) {
175 BytecodeLiveness& liveness = liveness_map_.InitializeLiveness( 287 BytecodeLiveness& liveness = liveness_map_.InitializeLiveness(
176 current_offset, bytecode_array()->register_count(), zone()); 288 current_offset, bytecode_array()->register_count(), zone());
177 289
178 UpdateOutLiveness(bytecode, *liveness.out, next_bytecode_in_liveness, 290 UpdateOutLiveness(bytecode, *liveness.out, next_bytecode_in_liveness,
179 iterator, liveness_map_); 291 iterator, liveness_map_);
180 liveness.in->CopyFrom(*liveness.out); 292 liveness.in->CopyFrom(*liveness.out);
181 UpdateInLiveness(bytecode, *liveness.in, iterator); 293 UpdateInLiveness(bytecode, *liveness.in, iterator);
182 294
183 next_bytecode_in_liveness = liveness.in; 295 next_bytecode_in_liveness = liveness.in;
184 } 296 }
185 } 297 }
186 298
187 DCHECK_EQ(loop_stack_.size(), 1u); 299 DCHECK_EQ(loop_stack_.size(), 1u);
188 DCHECK_EQ(loop_stack_.top(), -1); 300 DCHECK_EQ(loop_stack_.top().header_offset, -1);
189 301
190 if (!do_liveness_analysis_) return; 302 if (!do_liveness_analysis_) return;
191 303
192 // At this point, every bytecode has a valid in and out liveness, except for 304 // At this point, every bytecode has a valid in and out liveness, except for
193 // propagating liveness across back edges (i.e. JumpLoop). Subsequent liveness 305 // propagating liveness across back edges (i.e. JumpLoop). Subsequent liveness
194 // analysis iterations can only add additional liveness bits that are pulled 306 // analysis iterations can only add additional liveness bits that are pulled
195 // across these back edges. 307 // across these back edges.
196 // 308 //
197 // Furthermore, a loop header's in-liveness can only change based on any 309 // Furthermore, a loop header's in-liveness can only change based on any
198 // bytecodes *after* the loop end -- it cannot change as a result of the 310 // bytecodes *after* the loop end -- it cannot change as a result of the
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
252 // can't change, we need only to update the out-liveness. 364 // can't change, we need only to update the out-liveness.
253 UpdateOutLiveness(iterator.current_bytecode(), *header_liveness.out, 365 UpdateOutLiveness(iterator.current_bytecode(), *header_liveness.out,
254 next_bytecode_in_liveness, iterator, liveness_map_); 366 next_bytecode_in_liveness, iterator, liveness_map_);
255 } 367 }
256 368
257 DCHECK(LivenessIsValid()); 369 DCHECK(LivenessIsValid());
258 } 370 }
259 371
260 void BytecodeAnalysis::PushLoop(int loop_header, int loop_end) { 372 void BytecodeAnalysis::PushLoop(int loop_header, int loop_end) {
261 DCHECK(loop_header < loop_end); 373 DCHECK(loop_header < loop_end);
262 DCHECK(loop_stack_.top() < loop_header); 374 DCHECK(loop_stack_.top().header_offset < loop_header);
263 DCHECK(end_to_header_.find(loop_end) == end_to_header_.end()); 375 DCHECK(end_to_header_.find(loop_end) == end_to_header_.end());
264 DCHECK(header_to_parent_.find(loop_header) == header_to_parent_.end()); 376 DCHECK(header_to_info_.find(loop_header) == header_to_info_.end());
265 377
266 end_to_header_.insert(ZoneMap<int, int>::value_type(loop_end, loop_header)); 378 int parent_offset = loop_stack_.top().header_offset;
267 header_to_parent_.insert( 379
268 ZoneMap<int, int>::value_type(loop_header, loop_stack_.top())); 380 end_to_header_.insert({loop_end, loop_header});
269 loop_stack_.push(loop_header); 381 auto it = header_to_info_.insert(
382 {loop_header, LoopInfo(parent_offset, bytecode_array_->parameter_count(),
383 bytecode_array_->register_count(), zone_)});
384 // Get the loop info pointer from the output of insert.
385 LoopInfo* loop_info = &it.first->second;
386
387 loop_stack_.push({loop_header, loop_info});
270 } 388 }
271 389
272 bool BytecodeAnalysis::IsLoopHeader(int offset) const { 390 bool BytecodeAnalysis::IsLoopHeader(int offset) const {
273 return header_to_parent_.find(offset) != header_to_parent_.end(); 391 return header_to_info_.find(offset) != header_to_info_.end();
274 } 392 }
275 393
276 int BytecodeAnalysis::GetLoopOffsetFor(int offset) const { 394 int BytecodeAnalysis::GetLoopOffsetFor(int offset) const {
277 auto loop_end_to_header = end_to_header_.upper_bound(offset); 395 auto loop_end_to_header = end_to_header_.upper_bound(offset);
278 // If there is no next end => offset is not in a loop. 396 // If there is no next end => offset is not in a loop.
279 if (loop_end_to_header == end_to_header_.end()) { 397 if (loop_end_to_header == end_to_header_.end()) {
280 return -1; 398 return -1;
281 } 399 }
282 // If the header preceeds the offset, this is the loop 400 // If the header preceeds the offset, this is the loop
283 // 401 //
284 // .> header <--loop_end_to_header 402 // .> header <--loop_end_to_header
285 // | 403 // |
286 // | <--offset 404 // | <--offset
287 // | 405 // |
288 // `- end 406 // `- end
289 if (loop_end_to_header->second <= offset) { 407 if (loop_end_to_header->second <= offset) {
290 return loop_end_to_header->second; 408 return loop_end_to_header->second;
291 } 409 }
292 // Otherwise there is a (potentially nested) loop after this offset. 410 // Otherwise there is a (potentially nested) loop after this offset.
293 // 411 //
294 // <--offset 412 // <--offset
295 // 413 //
296 // .> header 414 // .> header
297 // | 415 // |
298 // | .> header <--loop_end_to_header 416 // | .> header <--loop_end_to_header
299 // | | 417 // | |
300 // | `- end 418 // | `- end
301 // | 419 // |
302 // `- end 420 // `- end
303 // We just return the parent of the next loop header (might be -1). 421 // We just return the parent of the next loop (might be -1).
304 DCHECK(header_to_parent_.upper_bound(offset) != header_to_parent_.end()); 422 DCHECK(header_to_info_.upper_bound(offset) != header_to_info_.end());
305 423
306 return header_to_parent_.upper_bound(offset)->second; 424 return header_to_info_.upper_bound(offset)->second.parent_offset();
307 } 425 }
308 426
309 int BytecodeAnalysis::GetParentLoopFor(int header_offset) const { 427 const LoopInfo& BytecodeAnalysis::GetLoopInfoFor(int header_offset) const {
310 DCHECK(IsLoopHeader(header_offset)); 428 DCHECK(IsLoopHeader(header_offset));
311 429
312 return header_to_parent_.find(header_offset)->second; 430 return header_to_info_.find(header_offset)->second;
313 } 431 }
314 432
315 const BytecodeLivenessState* BytecodeAnalysis::GetInLivenessFor( 433 const BytecodeLivenessState* BytecodeAnalysis::GetInLivenessFor(
316 int offset) const { 434 int offset) const {
317 if (!do_liveness_analysis_) return nullptr; 435 if (!do_liveness_analysis_) return nullptr;
318 436
319 return liveness_map_.GetInLiveness(offset); 437 return liveness_map_.GetInLiveness(offset);
320 } 438 }
321 439
322 const BytecodeLivenessState* BytecodeAnalysis::GetOutLivenessFor( 440 const BytecodeLivenessState* BytecodeAnalysis::GetOutLivenessFor(
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after
477 } 595 }
478 } 596 }
479 597
480 return invalid_offset == -1; 598 return invalid_offset == -1;
481 } 599 }
482 #endif 600 #endif
483 601
484 } // namespace compiler 602 } // namespace compiler
485 } // namespace internal 603 } // namespace internal
486 } // namespace v8 604 } // namespace v8
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698