| 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 |