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

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

Issue 2558093005: [turbofan] Add and use bytecode loop assigment analysis (Closed)
Patch Set: Fix build 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
« no previous file with comments | « src/compiler/bytecode-analysis.h ('k') | src/compiler/bytecode-graph-builder.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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, local_count());
74 return bit_vector_->Contains(parameter_count_ + index);
75 }
76
77 bool BytecodeLoopAssignments::ContainsAccumulator() const {
78 // TODO(leszeks): This assumes the accumulator is always assigned. This is
79 // probably correct, but that assignment is also probably dead, so we should
80 // check liveness.
81 return true;
82 }
83
17 BytecodeAnalysis::BytecodeAnalysis(Handle<BytecodeArray> bytecode_array, 84 BytecodeAnalysis::BytecodeAnalysis(Handle<BytecodeArray> bytecode_array,
18 Zone* zone, bool do_liveness_analysis) 85 Zone* zone, bool do_liveness_analysis)
19 : bytecode_array_(bytecode_array), 86 : bytecode_array_(bytecode_array),
20 do_liveness_analysis_(do_liveness_analysis), 87 do_liveness_analysis_(do_liveness_analysis),
21 zone_(zone), 88 zone_(zone),
22 loop_stack_(zone), 89 loop_stack_(zone),
23 loop_end_index_queue_(zone), 90 loop_end_index_queue_(zone),
24 end_to_header_(zone), 91 end_to_header_(zone),
25 header_to_parent_(zone), 92 header_to_info_(zone),
26 liveness_map_(bytecode_array->length(), zone) {} 93 liveness_map_(bytecode_array->length(), zone) {}
27 94
28 namespace { 95 namespace {
29 96
30 void UpdateInLiveness(Bytecode bytecode, BytecodeLivenessState& in_liveness, 97 void UpdateInLiveness(Bytecode bytecode, BytecodeLivenessState& in_liveness,
31 const BytecodeArrayAccessor& accessor) { 98 const BytecodeArrayAccessor& accessor) {
32 int num_operands = Bytecodes::NumberOfOperands(bytecode); 99 int num_operands = Bytecodes::NumberOfOperands(bytecode);
33 const OperandType* operand_types = Bytecodes::GetOperandTypes(bytecode); 100 const OperandType* operand_types = Bytecodes::GetOperandTypes(bytecode);
34 AccumulatorUse accumulator_use = Bytecodes::GetAccumulatorUse(bytecode); 101 AccumulatorUse accumulator_use = Bytecodes::GetAccumulatorUse(bytecode);
35 102
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
138 int handler_offset = 205 int handler_offset =
139 table->LookupRange(current_offset, &handler_context, nullptr); 206 table->LookupRange(current_offset, &handler_context, nullptr);
140 207
141 if (handler_offset != -1) { 208 if (handler_offset != -1) {
142 out_liveness.Union(*liveness_map.GetInLiveness(handler_offset)); 209 out_liveness.Union(*liveness_map.GetInLiveness(handler_offset));
143 out_liveness.MarkRegisterLive(handler_context); 210 out_liveness.MarkRegisterLive(handler_context);
144 } 211 }
145 } 212 }
146 } 213 }
147 214
215 void UpdateAssignments(Bytecode bytecode, BytecodeLoopAssignments& assignments,
216 const BytecodeArrayAccessor& accessor) {
217 int num_operands = Bytecodes::NumberOfOperands(bytecode);
218 const OperandType* operand_types = Bytecodes::GetOperandTypes(bytecode);
219
220 for (int i = 0; i < num_operands; ++i) {
221 switch (operand_types[i]) {
222 case OperandType::kRegOut: {
223 assignments.Add(accessor.GetRegisterOperand(i));
224 break;
225 }
226 case OperandType::kRegOutPair: {
227 assignments.AddPair(accessor.GetRegisterOperand(i));
228 break;
229 }
230 case OperandType::kRegOutTriple: {
231 assignments.AddTriple(accessor.GetRegisterOperand(i));
232 break;
233 }
234 default:
235 DCHECK(!Bytecodes::IsRegisterOutputOperandType(operand_types[i]));
236 break;
237 }
238 }
239 }
240
148 } // namespace 241 } // namespace
149 242
150 void BytecodeAnalysis::Analyze() { 243 void BytecodeAnalysis::Analyze(BailoutId osr_bailout_id) {
151 loop_stack_.push(-1); 244 loop_stack_.push({-1, nullptr});
152 245
153 BytecodeLivenessState* next_bytecode_in_liveness = nullptr; 246 BytecodeLivenessState* next_bytecode_in_liveness = nullptr;
154 247
248 int osr_loop_end_offset =
249 osr_bailout_id.IsNone() ? -1 : osr_bailout_id.ToInt();
250
155 BytecodeArrayRandomIterator iterator(bytecode_array(), zone()); 251 BytecodeArrayRandomIterator iterator(bytecode_array(), zone());
156 for (iterator.GoToEnd(); iterator.IsValid(); --iterator) { 252 for (iterator.GoToEnd(); iterator.IsValid(); --iterator) {
157 Bytecode bytecode = iterator.current_bytecode(); 253 Bytecode bytecode = iterator.current_bytecode();
158 int current_offset = iterator.current_offset(); 254 int current_offset = iterator.current_offset();
159 255
160 if (bytecode == Bytecode::kJumpLoop) { 256 if (bytecode == Bytecode::kJumpLoop) {
161 // Every byte up to and including the last byte within the backwards jump 257 // 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. 258 // instruction is considered part of the loop, set loop end accordingly.
163 int loop_end = current_offset + iterator.current_bytecode_size(); 259 int loop_end = current_offset + iterator.current_bytecode_size();
164 PushLoop(iterator.GetJumpTargetOffset(), loop_end); 260 PushLoop(iterator.GetJumpTargetOffset(), loop_end);
165 261
262 // Normally prefixed bytecodes are treated as if the prefix's offset was
263 // the actual bytecode's offset. However, the OSR id is the offset of the
264 // actual JumpLoop bytecode, so we need to find the location of that
265 // bytecode ignoring the prefix.
266 int jump_loop_offset = current_offset + iterator.current_prefix_offset();
267 bool is_osr_loop = (jump_loop_offset == osr_loop_end_offset);
268
269 // Check that is_osr_loop is set iff the osr_loop_end_offset is within
270 // this bytecode.
271 DCHECK(!is_osr_loop ||
272 iterator.OffsetWithinBytecode(osr_loop_end_offset));
273
274 // OSR "assigns" everything to OSR values on entry into an OSR loop, so we
275 // need to make sure to considered everything to be assigned.
276 if (is_osr_loop) {
277 loop_stack_.top().loop_info->assignments().AddAll();
278 }
279
166 // Save the index so that we can do another pass later. 280 // Save the index so that we can do another pass later.
167 if (do_liveness_analysis_) { 281 if (do_liveness_analysis_) {
168 loop_end_index_queue_.push_back(iterator.current_index()); 282 loop_end_index_queue_.push_back(iterator.current_index());
169 } 283 }
170 } else if (current_offset == loop_stack_.top()) { 284 } else if (loop_stack_.size() > 1) {
171 loop_stack_.pop(); 285 LoopStackEntry& current_loop = loop_stack_.top();
286 LoopInfo* current_loop_info = current_loop.loop_info;
287
288 // TODO(leszeks): Ideally, we'd only set values that were assigned in
289 // the loop *and* are live when the loop exits. However, this requires
290 // tracking the out-liveness of *all* loop exits, which is not
291 // information we currently have.
292 UpdateAssignments(bytecode, current_loop_info->assignments(), iterator);
293
294 if (current_offset == current_loop.header_offset) {
295 loop_stack_.pop();
296 if (loop_stack_.size() > 1) {
297 // Propagate inner loop assignments to outer loop.
298 loop_stack_.top().loop_info->assignments().Union(
299 current_loop_info->assignments());
300 }
301 }
172 } 302 }
173 303
174 if (do_liveness_analysis_) { 304 if (do_liveness_analysis_) {
175 BytecodeLiveness& liveness = liveness_map_.InitializeLiveness( 305 BytecodeLiveness& liveness = liveness_map_.InitializeLiveness(
176 current_offset, bytecode_array()->register_count(), zone()); 306 current_offset, bytecode_array()->register_count(), zone());
177 307
178 UpdateOutLiveness(bytecode, *liveness.out, next_bytecode_in_liveness, 308 UpdateOutLiveness(bytecode, *liveness.out, next_bytecode_in_liveness,
179 iterator, liveness_map_); 309 iterator, liveness_map_);
180 liveness.in->CopyFrom(*liveness.out); 310 liveness.in->CopyFrom(*liveness.out);
181 UpdateInLiveness(bytecode, *liveness.in, iterator); 311 UpdateInLiveness(bytecode, *liveness.in, iterator);
182 312
183 next_bytecode_in_liveness = liveness.in; 313 next_bytecode_in_liveness = liveness.in;
184 } 314 }
185 } 315 }
186 316
187 DCHECK_EQ(loop_stack_.size(), 1u); 317 DCHECK_EQ(loop_stack_.size(), 1u);
188 DCHECK_EQ(loop_stack_.top(), -1); 318 DCHECK_EQ(loop_stack_.top().header_offset, -1);
189 319
190 if (!do_liveness_analysis_) return; 320 if (!do_liveness_analysis_) return;
191 321
192 // At this point, every bytecode has a valid in and out liveness, except for 322 // 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 323 // propagating liveness across back edges (i.e. JumpLoop). Subsequent liveness
194 // analysis iterations can only add additional liveness bits that are pulled 324 // analysis iterations can only add additional liveness bits that are pulled
195 // across these back edges. 325 // across these back edges.
196 // 326 //
197 // Furthermore, a loop header's in-liveness can only change based on any 327 // 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 328 // 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. 382 // can't change, we need only to update the out-liveness.
253 UpdateOutLiveness(iterator.current_bytecode(), *header_liveness.out, 383 UpdateOutLiveness(iterator.current_bytecode(), *header_liveness.out,
254 next_bytecode_in_liveness, iterator, liveness_map_); 384 next_bytecode_in_liveness, iterator, liveness_map_);
255 } 385 }
256 386
257 DCHECK(LivenessIsValid()); 387 DCHECK(LivenessIsValid());
258 } 388 }
259 389
260 void BytecodeAnalysis::PushLoop(int loop_header, int loop_end) { 390 void BytecodeAnalysis::PushLoop(int loop_header, int loop_end) {
261 DCHECK(loop_header < loop_end); 391 DCHECK(loop_header < loop_end);
262 DCHECK(loop_stack_.top() < loop_header); 392 DCHECK(loop_stack_.top().header_offset < loop_header);
263 DCHECK(end_to_header_.find(loop_end) == end_to_header_.end()); 393 DCHECK(end_to_header_.find(loop_end) == end_to_header_.end());
264 DCHECK(header_to_parent_.find(loop_header) == header_to_parent_.end()); 394 DCHECK(header_to_info_.find(loop_header) == header_to_info_.end());
265 395
266 end_to_header_.insert(ZoneMap<int, int>::value_type(loop_end, loop_header)); 396 int parent_offset = loop_stack_.top().header_offset;
267 header_to_parent_.insert( 397
268 ZoneMap<int, int>::value_type(loop_header, loop_stack_.top())); 398 end_to_header_.insert({loop_end, loop_header});
269 loop_stack_.push(loop_header); 399 auto it = header_to_info_.insert(
400 {loop_header, LoopInfo(parent_offset, bytecode_array_->parameter_count(),
401 bytecode_array_->register_count(), zone_)});
402 // Get the loop info pointer from the output of insert.
403 LoopInfo* loop_info = &it.first->second;
404
405 loop_stack_.push({loop_header, loop_info});
270 } 406 }
271 407
272 bool BytecodeAnalysis::IsLoopHeader(int offset) const { 408 bool BytecodeAnalysis::IsLoopHeader(int offset) const {
273 return header_to_parent_.find(offset) != header_to_parent_.end(); 409 return header_to_info_.find(offset) != header_to_info_.end();
274 } 410 }
275 411
276 int BytecodeAnalysis::GetLoopOffsetFor(int offset) const { 412 int BytecodeAnalysis::GetLoopOffsetFor(int offset) const {
277 auto loop_end_to_header = end_to_header_.upper_bound(offset); 413 auto loop_end_to_header = end_to_header_.upper_bound(offset);
278 // If there is no next end => offset is not in a loop. 414 // If there is no next end => offset is not in a loop.
279 if (loop_end_to_header == end_to_header_.end()) { 415 if (loop_end_to_header == end_to_header_.end()) {
280 return -1; 416 return -1;
281 } 417 }
282 // If the header preceeds the offset, this is the loop 418 // If the header preceeds the offset, this is the loop
283 // 419 //
284 // .> header <--loop_end_to_header 420 // .> header <--loop_end_to_header
285 // | 421 // |
286 // | <--offset 422 // | <--offset
287 // | 423 // |
288 // `- end 424 // `- end
289 if (loop_end_to_header->second <= offset) { 425 if (loop_end_to_header->second <= offset) {
290 return loop_end_to_header->second; 426 return loop_end_to_header->second;
291 } 427 }
292 // Otherwise there is a (potentially nested) loop after this offset. 428 // Otherwise there is a (potentially nested) loop after this offset.
293 // 429 //
294 // <--offset 430 // <--offset
295 // 431 //
296 // .> header 432 // .> header
297 // | 433 // |
298 // | .> header <--loop_end_to_header 434 // | .> header <--loop_end_to_header
299 // | | 435 // | |
300 // | `- end 436 // | `- end
301 // | 437 // |
302 // `- end 438 // `- end
303 // We just return the parent of the next loop header (might be -1). 439 // We just return the parent of the next loop (might be -1).
304 DCHECK(header_to_parent_.upper_bound(offset) != header_to_parent_.end()); 440 DCHECK(header_to_info_.upper_bound(offset) != header_to_info_.end());
305 441
306 return header_to_parent_.upper_bound(offset)->second; 442 return header_to_info_.upper_bound(offset)->second.parent_offset();
307 } 443 }
308 444
309 int BytecodeAnalysis::GetParentLoopFor(int header_offset) const { 445 const LoopInfo& BytecodeAnalysis::GetLoopInfoFor(int header_offset) const {
310 DCHECK(IsLoopHeader(header_offset)); 446 DCHECK(IsLoopHeader(header_offset));
311 447
312 return header_to_parent_.find(header_offset)->second; 448 return header_to_info_.find(header_offset)->second;
313 } 449 }
314 450
315 const BytecodeLivenessState* BytecodeAnalysis::GetInLivenessFor( 451 const BytecodeLivenessState* BytecodeAnalysis::GetInLivenessFor(
316 int offset) const { 452 int offset) const {
317 if (!do_liveness_analysis_) return nullptr; 453 if (!do_liveness_analysis_) return nullptr;
318 454
319 return liveness_map_.GetInLiveness(offset); 455 return liveness_map_.GetInLiveness(offset);
320 } 456 }
321 457
322 const BytecodeLivenessState* BytecodeAnalysis::GetOutLivenessFor( 458 const BytecodeLivenessState* BytecodeAnalysis::GetOutLivenessFor(
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after
477 } 613 }
478 } 614 }
479 615
480 return invalid_offset == -1; 616 return invalid_offset == -1;
481 } 617 }
482 #endif 618 #endif
483 619
484 } // namespace compiler 620 } // namespace compiler
485 } // namespace internal 621 } // namespace internal
486 } // namespace v8 622 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler/bytecode-analysis.h ('k') | src/compiler/bytecode-graph-builder.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698