OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "src/compiler/pipeline.h" | |
6 #include "src/compiler/scheduler.h" | |
7 #include "src/compiler/structured-machine-assembler.h" | |
8 | |
9 namespace v8 { | |
10 namespace internal { | |
11 namespace compiler { | |
12 | |
13 Node* Variable::Get() const { return smasm_->GetVariable(offset_); } | |
14 | |
15 | |
16 void Variable::Set(Node* value) const { smasm_->SetVariable(offset_, value); } | |
17 | |
18 | |
19 StructuredMachineAssembler::StructuredMachineAssembler( | |
20 Graph* graph, MachineSignature* machine_sig, MachineType word) | |
21 : GraphBuilder(graph), | |
22 schedule_(new (zone()) Schedule(zone())), | |
23 machine_(zone(), word), | |
24 common_(zone()), | |
25 machine_sig_(machine_sig), | |
26 call_descriptor_( | |
27 Linkage::GetSimplifiedCDescriptor(graph->zone(), machine_sig)), | |
28 parameters_(NULL), | |
29 current_environment_(new (zone()) | |
30 Environment(zone(), schedule()->start(), false)), | |
31 number_of_variables_(0) { | |
32 int param_count = static_cast<int>(parameter_count()); | |
33 Node* s = graph->NewNode(common_.Start(param_count)); | |
34 graph->SetStart(s); | |
35 if (parameter_count() == 0) return; | |
36 parameters_ = zone()->NewArray<Node*>(param_count); | |
37 for (size_t i = 0; i < parameter_count(); ++i) { | |
38 parameters_[i] = | |
39 NewNode(common()->Parameter(static_cast<int>(i)), graph->start()); | |
40 } | |
41 } | |
42 | |
43 | |
44 Schedule* StructuredMachineAssembler::Export() { | |
45 // Compute the correct codegen order. | |
46 DCHECK(schedule_->rpo_order()->empty()); | |
47 Scheduler::ComputeSpecialRPO(schedule_); | |
48 // Invalidate MachineAssembler. | |
49 Schedule* schedule = schedule_; | |
50 schedule_ = NULL; | |
51 return schedule; | |
52 } | |
53 | |
54 | |
55 Node* StructuredMachineAssembler::Parameter(size_t index) { | |
56 DCHECK(index < parameter_count()); | |
57 return parameters_[index]; | |
58 } | |
59 | |
60 | |
61 Node* StructuredMachineAssembler::MakeNode(Operator* op, int input_count, | |
62 Node** inputs) { | |
63 DCHECK(ScheduleValid()); | |
64 DCHECK(current_environment_ != NULL); | |
65 Node* node = graph()->NewNode(op, input_count, inputs); | |
66 BasicBlock* block = NULL; | |
67 switch (op->opcode()) { | |
68 case IrOpcode::kParameter: | |
69 case IrOpcode::kInt32Constant: | |
70 case IrOpcode::kInt64Constant: | |
71 case IrOpcode::kFloat64Constant: | |
72 case IrOpcode::kExternalConstant: | |
73 case IrOpcode::kNumberConstant: | |
74 case IrOpcode::kHeapConstant: | |
75 // Parameters and constants must be in start. | |
76 block = schedule()->start(); | |
77 break; | |
78 default: | |
79 // Verify all leaf nodes handled above. | |
80 DCHECK((op->OutputCount() == 0) == (op->opcode() == IrOpcode::kStore)); | |
81 block = current_environment_->block_; | |
82 break; | |
83 } | |
84 if (block != NULL) { | |
85 schedule()->AddNode(block, node); | |
86 } | |
87 return node; | |
88 } | |
89 | |
90 | |
91 Variable StructuredMachineAssembler::NewVariable(Node* initial_value) { | |
92 CHECK(initial_value != NULL); | |
93 int offset = number_of_variables_++; | |
94 // Extend current environment to correct number of values. | |
95 NodeVector* variables = CurrentVars(); | |
96 size_t to_add = number_of_variables_ - variables->size(); | |
97 if (to_add != 0) { | |
98 variables->reserve(number_of_variables_); | |
99 variables->insert(variables->end(), to_add, NULL); | |
100 } | |
101 variables->at(offset) = initial_value; | |
102 return Variable(this, offset); | |
103 } | |
104 | |
105 | |
106 Node* StructuredMachineAssembler::GetVariable(int offset) { | |
107 DCHECK(ScheduleValid()); | |
108 return VariableAt(current_environment_, offset); | |
109 } | |
110 | |
111 | |
112 void StructuredMachineAssembler::SetVariable(int offset, Node* value) { | |
113 DCHECK(ScheduleValid()); | |
114 Node*& ref = VariableAt(current_environment_, offset); | |
115 ref = value; | |
116 } | |
117 | |
118 | |
119 Node*& StructuredMachineAssembler::VariableAt(Environment* environment, | |
120 int32_t offset) { | |
121 // Variable used out of scope. | |
122 CHECK(static_cast<size_t>(offset) < environment->variables_.size()); | |
123 Node*& value = environment->variables_.at(offset); | |
124 CHECK(value != NULL); // Variable used out of scope. | |
125 return value; | |
126 } | |
127 | |
128 | |
129 void StructuredMachineAssembler::Return(Node* value) { | |
130 BasicBlock* block = current_environment_->block_; | |
131 if (block != NULL) { | |
132 schedule()->AddReturn(block, value); | |
133 } | |
134 CopyCurrentAsDead(); | |
135 } | |
136 | |
137 | |
138 void StructuredMachineAssembler::CopyCurrentAsDead() { | |
139 DCHECK(current_environment_ != NULL); | |
140 bool is_dead = current_environment_->is_dead_; | |
141 current_environment_->is_dead_ = true; | |
142 Environment* next = Copy(current_environment_); | |
143 current_environment_->is_dead_ = is_dead; | |
144 current_environment_ = next; | |
145 } | |
146 | |
147 | |
148 StructuredMachineAssembler::Environment* StructuredMachineAssembler::Copy( | |
149 Environment* env, int truncate_at) { | |
150 Environment* new_env = new (zone()) Environment(zone(), NULL, env->is_dead_); | |
151 if (!new_env->is_dead_) { | |
152 new_env->block_ = schedule()->NewBasicBlock(); | |
153 } | |
154 new_env->variables_.reserve(truncate_at); | |
155 NodeVectorIter end = env->variables_.end(); | |
156 DCHECK(truncate_at <= static_cast<int>(env->variables_.size())); | |
157 end -= static_cast<int>(env->variables_.size()) - truncate_at; | |
158 new_env->variables_.insert(new_env->variables_.begin(), | |
159 env->variables_.begin(), end); | |
160 return new_env; | |
161 } | |
162 | |
163 | |
164 StructuredMachineAssembler::Environment* | |
165 StructuredMachineAssembler::CopyForLoopHeader(Environment* env) { | |
166 Environment* new_env = new (zone()) Environment(zone(), NULL, env->is_dead_); | |
167 if (!new_env->is_dead_) { | |
168 new_env->block_ = schedule()->NewBasicBlock(); | |
169 } | |
170 new_env->variables_.reserve(env->variables_.size()); | |
171 for (NodeVectorIter i = env->variables_.begin(); i != env->variables_.end(); | |
172 ++i) { | |
173 Node* phi = NULL; | |
174 if (*i != NULL) { | |
175 phi = graph()->NewNode(common()->Phi(1), *i); | |
176 if (new_env->block_ != NULL) { | |
177 schedule()->AddNode(new_env->block_, phi); | |
178 } | |
179 } | |
180 new_env->variables_.push_back(phi); | |
181 } | |
182 return new_env; | |
183 } | |
184 | |
185 | |
186 void StructuredMachineAssembler::MergeBackEdgesToLoopHeader( | |
187 Environment* header, EnvironmentVector* environments) { | |
188 // Only merge as many variables are were declared before this loop. | |
189 int n = static_cast<int>(header->variables_.size()); | |
190 // TODO(dcarney): invert loop order and extend phis once. | |
191 for (EnvironmentVector::iterator i = environments->begin(); | |
192 i != environments->end(); ++i) { | |
193 Environment* from = *i; | |
194 if (from->is_dead_) continue; | |
195 AddGoto(from, header); | |
196 for (int i = 0; i < n; ++i) { | |
197 Node* phi = header->variables_[i]; | |
198 if (phi == NULL) continue; | |
199 phi->set_op(common()->Phi(phi->InputCount() + 1)); | |
200 phi->AppendInput(zone(), VariableAt(from, i)); | |
201 } | |
202 } | |
203 } | |
204 | |
205 | |
206 void StructuredMachineAssembler::Merge(EnvironmentVector* environments, | |
207 int truncate_at) { | |
208 DCHECK(current_environment_ == NULL || current_environment_->is_dead_); | |
209 Environment* next = new (zone()) Environment(zone(), NULL, false); | |
210 current_environment_ = next; | |
211 size_t n_vars = number_of_variables_; | |
212 NodeVector& vars = next->variables_; | |
213 vars.reserve(n_vars); | |
214 Node** scratch = NULL; | |
215 size_t n_envs = environments->size(); | |
216 Environment** live_environments = | |
217 zone()->NewArray<Environment*>(static_cast<int>(n_envs)); | |
218 size_t n_live = 0; | |
219 for (size_t i = 0; i < n_envs; i++) { | |
220 if (environments->at(i)->is_dead_) continue; | |
221 live_environments[n_live++] = environments->at(i); | |
222 } | |
223 n_envs = n_live; | |
224 if (n_live == 0) next->is_dead_ = true; | |
225 if (!next->is_dead_) { | |
226 next->block_ = schedule()->NewBasicBlock(); | |
227 } | |
228 for (size_t j = 0; j < n_vars; ++j) { | |
229 Node* resolved = NULL; | |
230 // Find first non equal variable. | |
231 size_t i = 0; | |
232 for (; i < n_envs; i++) { | |
233 DCHECK(live_environments[i]->variables_.size() <= n_vars); | |
234 Node* val = NULL; | |
235 if (j < static_cast<size_t>(truncate_at)) { | |
236 val = live_environments[i]->variables_.at(j); | |
237 // TODO(dcarney): record start position at time of split. | |
238 // all variables after this should not be NULL. | |
239 if (val != NULL) { | |
240 val = VariableAt(live_environments[i], static_cast<int>(j)); | |
241 } | |
242 } | |
243 if (val == resolved) continue; | |
244 if (i != 0) break; | |
245 resolved = val; | |
246 } | |
247 // Have to generate a phi. | |
248 if (i < n_envs) { | |
249 // All values thus far uninitialized, variable used out of scope. | |
250 CHECK(resolved != NULL); | |
251 // Init scratch buffer. | |
252 if (scratch == NULL) { | |
253 scratch = zone()->NewArray<Node*>(static_cast<int>(n_envs)); | |
254 } | |
255 for (size_t k = 0; k < i; k++) { | |
256 scratch[k] = resolved; | |
257 } | |
258 for (; i < n_envs; i++) { | |
259 scratch[i] = live_environments[i]->variables_[j]; | |
260 } | |
261 resolved = graph()->NewNode(common()->Phi(static_cast<int>(n_envs)), | |
262 static_cast<int>(n_envs), scratch); | |
263 if (next->block_ != NULL) { | |
264 schedule()->AddNode(next->block_, resolved); | |
265 } | |
266 } | |
267 vars.push_back(resolved); | |
268 } | |
269 } | |
270 | |
271 | |
272 void StructuredMachineAssembler::AddGoto(Environment* from, Environment* to) { | |
273 if (to->is_dead_) { | |
274 DCHECK(from->is_dead_); | |
275 return; | |
276 } | |
277 DCHECK(!from->is_dead_); | |
278 schedule()->AddGoto(from->block_, to->block_); | |
279 } | |
280 | |
281 | |
282 // TODO(dcarney): add pass before rpo to schedule to compute these. | |
283 BasicBlock* StructuredMachineAssembler::TrampolineFor(BasicBlock* block) { | |
284 BasicBlock* trampoline = schedule()->NewBasicBlock(); | |
285 schedule()->AddGoto(trampoline, block); | |
286 return trampoline; | |
287 } | |
288 | |
289 | |
290 void StructuredMachineAssembler::AddBranch(Environment* environment, | |
291 Node* condition, | |
292 Environment* true_val, | |
293 Environment* false_val) { | |
294 DCHECK(environment->is_dead_ == true_val->is_dead_); | |
295 DCHECK(environment->is_dead_ == false_val->is_dead_); | |
296 if (true_val->block_ == false_val->block_) { | |
297 if (environment->is_dead_) return; | |
298 AddGoto(environment, true_val); | |
299 return; | |
300 } | |
301 Node* branch = graph()->NewNode(common()->Branch(), condition); | |
302 if (environment->is_dead_) return; | |
303 BasicBlock* true_block = TrampolineFor(true_val->block_); | |
304 BasicBlock* false_block = TrampolineFor(false_val->block_); | |
305 schedule()->AddBranch(environment->block_, branch, true_block, false_block); | |
306 } | |
307 | |
308 | |
309 StructuredMachineAssembler::Environment::Environment(Zone* zone, | |
310 BasicBlock* block, | |
311 bool is_dead) | |
312 : block_(block), variables_(zone), is_dead_(is_dead) {} | |
313 | |
314 | |
315 StructuredMachineAssembler::IfBuilder::IfBuilder( | |
316 StructuredMachineAssembler* smasm) | |
317 : smasm_(smasm), | |
318 if_clauses_(smasm_->zone()), | |
319 pending_exit_merges_(smasm_->zone()) { | |
320 DCHECK(smasm_->current_environment_ != NULL); | |
321 PushNewIfClause(); | |
322 DCHECK(!IsDone()); | |
323 } | |
324 | |
325 | |
326 StructuredMachineAssembler::IfBuilder& | |
327 StructuredMachineAssembler::IfBuilder::If() { | |
328 DCHECK(smasm_->current_environment_ != NULL); | |
329 IfClause* clause = CurrentClause(); | |
330 if (clause->then_environment_ != NULL || clause->else_environment_ != NULL) { | |
331 PushNewIfClause(); | |
332 } | |
333 return *this; | |
334 } | |
335 | |
336 | |
337 StructuredMachineAssembler::IfBuilder& | |
338 StructuredMachineAssembler::IfBuilder::If(Node* condition) { | |
339 If(); | |
340 IfClause* clause = CurrentClause(); | |
341 // Store branch for future resolution. | |
342 UnresolvedBranch* next = new (smasm_->zone()) | |
343 UnresolvedBranch(smasm_->current_environment_, condition, NULL); | |
344 if (clause->unresolved_list_tail_ != NULL) { | |
345 clause->unresolved_list_tail_->next_ = next; | |
346 } | |
347 clause->unresolved_list_tail_ = next; | |
348 // Push onto merge queues. | |
349 clause->pending_else_merges_.push_back(next); | |
350 clause->pending_then_merges_.push_back(next); | |
351 smasm_->current_environment_ = NULL; | |
352 return *this; | |
353 } | |
354 | |
355 | |
356 void StructuredMachineAssembler::IfBuilder::And() { | |
357 CurrentClause()->ResolvePendingMerges(smasm_, kCombineThen, kExpressionTerm); | |
358 } | |
359 | |
360 | |
361 void StructuredMachineAssembler::IfBuilder::Or() { | |
362 CurrentClause()->ResolvePendingMerges(smasm_, kCombineElse, kExpressionTerm); | |
363 } | |
364 | |
365 | |
366 void StructuredMachineAssembler::IfBuilder::Then() { | |
367 CurrentClause()->ResolvePendingMerges(smasm_, kCombineThen, kExpressionDone); | |
368 } | |
369 | |
370 | |
371 void StructuredMachineAssembler::IfBuilder::Else() { | |
372 AddCurrentToPending(); | |
373 CurrentClause()->ResolvePendingMerges(smasm_, kCombineElse, kExpressionDone); | |
374 } | |
375 | |
376 | |
377 void StructuredMachineAssembler::IfBuilder::AddCurrentToPending() { | |
378 if (smasm_->current_environment_ != NULL && | |
379 !smasm_->current_environment_->is_dead_) { | |
380 pending_exit_merges_.push_back(smasm_->current_environment_); | |
381 } | |
382 smasm_->current_environment_ = NULL; | |
383 } | |
384 | |
385 | |
386 void StructuredMachineAssembler::IfBuilder::PushNewIfClause() { | |
387 int curr_size = | |
388 static_cast<int>(smasm_->current_environment_->variables_.size()); | |
389 IfClause* clause = new (smasm_->zone()) IfClause(smasm_->zone(), curr_size); | |
390 if_clauses_.push_back(clause); | |
391 } | |
392 | |
393 | |
394 StructuredMachineAssembler::IfBuilder::IfClause::IfClause( | |
395 Zone* zone, int initial_environment_size) | |
396 : unresolved_list_tail_(NULL), | |
397 initial_environment_size_(initial_environment_size), | |
398 expression_states_(zone), | |
399 pending_then_merges_(zone), | |
400 pending_else_merges_(zone), | |
401 then_environment_(NULL), | |
402 else_environment_(NULL) { | |
403 PushNewExpressionState(); | |
404 } | |
405 | |
406 | |
407 StructuredMachineAssembler::IfBuilder::PendingMergeStackRange | |
408 StructuredMachineAssembler::IfBuilder::IfClause::ComputeRelevantMerges( | |
409 CombineType combine_type) { | |
410 DCHECK(!expression_states_.empty()); | |
411 PendingMergeStack* stack; | |
412 int start; | |
413 if (combine_type == kCombineThen) { | |
414 stack = &pending_then_merges_; | |
415 start = expression_states_.back().pending_then_size_; | |
416 } else { | |
417 DCHECK(combine_type == kCombineElse); | |
418 stack = &pending_else_merges_; | |
419 start = expression_states_.back().pending_else_size_; | |
420 } | |
421 PendingMergeStackRange data; | |
422 data.merge_stack_ = stack; | |
423 data.start_ = start; | |
424 data.size_ = static_cast<int>(stack->size()) - start; | |
425 return data; | |
426 } | |
427 | |
428 | |
429 void StructuredMachineAssembler::IfBuilder::IfClause::ResolvePendingMerges( | |
430 StructuredMachineAssembler* smasm, CombineType combine_type, | |
431 ResolutionType resolution_type) { | |
432 DCHECK(smasm->current_environment_ == NULL); | |
433 PendingMergeStackRange data = ComputeRelevantMerges(combine_type); | |
434 DCHECK_EQ(data.merge_stack_->back(), unresolved_list_tail_); | |
435 DCHECK(data.size_ > 0); | |
436 // TODO(dcarney): assert no new variables created during expression building. | |
437 int truncate_at = initial_environment_size_; | |
438 if (data.size_ == 1) { | |
439 // Just copy environment in common case. | |
440 smasm->current_environment_ = | |
441 smasm->Copy(unresolved_list_tail_->environment_, truncate_at); | |
442 } else { | |
443 EnvironmentVector environments(smasm->zone()); | |
444 environments.reserve(data.size_); | |
445 CopyEnvironments(data, &environments); | |
446 DCHECK(static_cast<int>(environments.size()) == data.size_); | |
447 smasm->Merge(&environments, truncate_at); | |
448 } | |
449 Environment* then_environment = then_environment_; | |
450 Environment* else_environment = NULL; | |
451 if (resolution_type == kExpressionDone) { | |
452 DCHECK(expression_states_.size() == 1); | |
453 // Set the current then_ or else_environment_ to the new merged environment. | |
454 if (combine_type == kCombineThen) { | |
455 DCHECK(then_environment_ == NULL && else_environment_ == NULL); | |
456 this->then_environment_ = smasm->current_environment_; | |
457 } else { | |
458 DCHECK(else_environment_ == NULL); | |
459 this->else_environment_ = smasm->current_environment_; | |
460 } | |
461 } else { | |
462 DCHECK(resolution_type == kExpressionTerm); | |
463 DCHECK(then_environment_ == NULL && else_environment_ == NULL); | |
464 } | |
465 if (combine_type == kCombineThen) { | |
466 then_environment = smasm->current_environment_; | |
467 } else { | |
468 DCHECK(combine_type == kCombineElse); | |
469 else_environment = smasm->current_environment_; | |
470 } | |
471 // Finalize branches and clear the pending stack. | |
472 FinalizeBranches(smasm, data, combine_type, then_environment, | |
473 else_environment); | |
474 } | |
475 | |
476 | |
477 void StructuredMachineAssembler::IfBuilder::IfClause::CopyEnvironments( | |
478 const PendingMergeStackRange& data, EnvironmentVector* environments) { | |
479 PendingMergeStack::iterator i = data.merge_stack_->begin(); | |
480 PendingMergeStack::iterator end = data.merge_stack_->end(); | |
481 for (i += data.start_; i != end; ++i) { | |
482 environments->push_back((*i)->environment_); | |
483 } | |
484 } | |
485 | |
486 | |
487 void StructuredMachineAssembler::IfBuilder::IfClause::PushNewExpressionState() { | |
488 ExpressionState next; | |
489 next.pending_then_size_ = static_cast<int>(pending_then_merges_.size()); | |
490 next.pending_else_size_ = static_cast<int>(pending_else_merges_.size()); | |
491 expression_states_.push_back(next); | |
492 } | |
493 | |
494 | |
495 void StructuredMachineAssembler::IfBuilder::IfClause::PopExpressionState() { | |
496 expression_states_.pop_back(); | |
497 DCHECK(!expression_states_.empty()); | |
498 } | |
499 | |
500 | |
501 void StructuredMachineAssembler::IfBuilder::IfClause::FinalizeBranches( | |
502 StructuredMachineAssembler* smasm, const PendingMergeStackRange& data, | |
503 CombineType combine_type, Environment* const then_environment, | |
504 Environment* const else_environment) { | |
505 DCHECK(unresolved_list_tail_ != NULL); | |
506 DCHECK(smasm->current_environment_ != NULL); | |
507 if (data.size_ == 0) return; | |
508 PendingMergeStack::iterator curr = data.merge_stack_->begin(); | |
509 PendingMergeStack::iterator end = data.merge_stack_->end(); | |
510 // Finalize everything but the head first, | |
511 // in the order the branches enter the merge block. | |
512 end -= 1; | |
513 Environment* true_val = then_environment; | |
514 Environment* false_val = else_environment; | |
515 Environment** next; | |
516 if (combine_type == kCombineThen) { | |
517 next = &false_val; | |
518 } else { | |
519 DCHECK(combine_type == kCombineElse); | |
520 next = &true_val; | |
521 } | |
522 for (curr += data.start_; curr != end; ++curr) { | |
523 UnresolvedBranch* branch = *curr; | |
524 *next = branch->next_->environment_; | |
525 smasm->AddBranch(branch->environment_, branch->condition_, true_val, | |
526 false_val); | |
527 } | |
528 DCHECK(curr + 1 == data.merge_stack_->end()); | |
529 // Now finalize the tail if possible. | |
530 if (then_environment != NULL && else_environment != NULL) { | |
531 UnresolvedBranch* branch = *curr; | |
532 smasm->AddBranch(branch->environment_, branch->condition_, then_environment, | |
533 else_environment); | |
534 } | |
535 // Clear the merge stack. | |
536 PendingMergeStack::iterator begin = data.merge_stack_->begin(); | |
537 begin += data.start_; | |
538 data.merge_stack_->erase(begin, data.merge_stack_->end()); | |
539 DCHECK_EQ(static_cast<int>(data.merge_stack_->size()), data.start_); | |
540 } | |
541 | |
542 | |
543 void StructuredMachineAssembler::IfBuilder::End() { | |
544 DCHECK(!IsDone()); | |
545 AddCurrentToPending(); | |
546 size_t current_pending = pending_exit_merges_.size(); | |
547 // All unresolved branch edges are now set to pending. | |
548 for (IfClauses::iterator i = if_clauses_.begin(); i != if_clauses_.end(); | |
549 ++i) { | |
550 IfClause* clause = *i; | |
551 DCHECK(clause->expression_states_.size() == 1); | |
552 PendingMergeStackRange data; | |
553 // Copy then environments. | |
554 data = clause->ComputeRelevantMerges(kCombineThen); | |
555 clause->CopyEnvironments(data, &pending_exit_merges_); | |
556 Environment* head = NULL; | |
557 // Will resolve the head node in the else_merge | |
558 if (data.size_ > 0 && clause->then_environment_ == NULL && | |
559 clause->else_environment_ == NULL) { | |
560 head = pending_exit_merges_.back(); | |
561 pending_exit_merges_.pop_back(); | |
562 } | |
563 // Copy else environments. | |
564 data = clause->ComputeRelevantMerges(kCombineElse); | |
565 clause->CopyEnvironments(data, &pending_exit_merges_); | |
566 if (head != NULL) { | |
567 // Must have data to merge, or else head will never get a branch. | |
568 DCHECK(data.size_ != 0); | |
569 pending_exit_merges_.push_back(head); | |
570 } | |
571 } | |
572 smasm_->Merge(&pending_exit_merges_, | |
573 if_clauses_[0]->initial_environment_size_); | |
574 // Anything initally pending jumps into the new environment. | |
575 for (size_t i = 0; i < current_pending; ++i) { | |
576 smasm_->AddGoto(pending_exit_merges_[i], smasm_->current_environment_); | |
577 } | |
578 // Resolve all branches. | |
579 for (IfClauses::iterator i = if_clauses_.begin(); i != if_clauses_.end(); | |
580 ++i) { | |
581 IfClause* clause = *i; | |
582 // Must finalize all environments, so ensure they are set correctly. | |
583 Environment* then_environment = clause->then_environment_; | |
584 if (then_environment == NULL) { | |
585 then_environment = smasm_->current_environment_; | |
586 } | |
587 Environment* else_environment = clause->else_environment_; | |
588 PendingMergeStackRange data; | |
589 // Finalize then environments. | |
590 data = clause->ComputeRelevantMerges(kCombineThen); | |
591 clause->FinalizeBranches(smasm_, data, kCombineThen, then_environment, | |
592 else_environment); | |
593 // Finalize else environments. | |
594 // Now set the else environment so head is finalized for edge case above. | |
595 if (else_environment == NULL) { | |
596 else_environment = smasm_->current_environment_; | |
597 } | |
598 data = clause->ComputeRelevantMerges(kCombineElse); | |
599 clause->FinalizeBranches(smasm_, data, kCombineElse, then_environment, | |
600 else_environment); | |
601 } | |
602 // Future accesses to this builder should crash immediately. | |
603 pending_exit_merges_.clear(); | |
604 if_clauses_.clear(); | |
605 DCHECK(IsDone()); | |
606 } | |
607 | |
608 | |
609 StructuredMachineAssembler::LoopBuilder::LoopBuilder( | |
610 StructuredMachineAssembler* smasm) | |
611 : smasm_(smasm), | |
612 header_environment_(NULL), | |
613 pending_header_merges_(smasm_->zone()), | |
614 pending_exit_merges_(smasm_->zone()) { | |
615 DCHECK(smasm_->current_environment_ != NULL); | |
616 // Create header environment. | |
617 header_environment_ = smasm_->CopyForLoopHeader(smasm_->current_environment_); | |
618 smasm_->AddGoto(smasm_->current_environment_, header_environment_); | |
619 // Create body environment. | |
620 Environment* body = smasm_->Copy(header_environment_); | |
621 smasm_->AddGoto(header_environment_, body); | |
622 smasm_->current_environment_ = body; | |
623 DCHECK(!IsDone()); | |
624 } | |
625 | |
626 | |
627 void StructuredMachineAssembler::LoopBuilder::Continue() { | |
628 DCHECK(!IsDone()); | |
629 pending_header_merges_.push_back(smasm_->current_environment_); | |
630 smasm_->CopyCurrentAsDead(); | |
631 } | |
632 | |
633 | |
634 void StructuredMachineAssembler::LoopBuilder::Break() { | |
635 DCHECK(!IsDone()); | |
636 pending_exit_merges_.push_back(smasm_->current_environment_); | |
637 smasm_->CopyCurrentAsDead(); | |
638 } | |
639 | |
640 | |
641 void StructuredMachineAssembler::LoopBuilder::End() { | |
642 DCHECK(!IsDone()); | |
643 if (smasm_->current_environment_ != NULL) { | |
644 Continue(); | |
645 } | |
646 // Do loop header merges. | |
647 smasm_->MergeBackEdgesToLoopHeader(header_environment_, | |
648 &pending_header_merges_); | |
649 int initial_size = static_cast<int>(header_environment_->variables_.size()); | |
650 // Do loop exit merges, truncating loop variables away. | |
651 smasm_->Merge(&pending_exit_merges_, initial_size); | |
652 for (EnvironmentVector::iterator i = pending_exit_merges_.begin(); | |
653 i != pending_exit_merges_.end(); ++i) { | |
654 smasm_->AddGoto(*i, smasm_->current_environment_); | |
655 } | |
656 pending_header_merges_.clear(); | |
657 pending_exit_merges_.clear(); | |
658 header_environment_ = NULL; | |
659 DCHECK(IsDone()); | |
660 } | |
661 | |
662 } // namespace compiler | |
663 } // namespace internal | |
664 } // namespace v8 | |
OLD | NEW |