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