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