From d62337e127d7f6ce69cb9602a2b4203e56077314 Mon Sep 17 00:00:00 2001 From: "danno@chromium.org" Date: Fri, 15 Nov 2013 10:36:02 +0000 Subject: [PATCH] Add ability to do "else-if" clauses in IfBuilder - In an Else block it's possible to add more If<>'s in the same builder that are treated as an else if. - Simplified and cleaned-up some of the IfBuilder's internals. R=mstarzinger@chromium.org Review URL: https://codereview.chromium.org/66983002 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@17780 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/hydrogen.cc | 199 ++++++++++++++++++++++++++++++++---------------- src/hydrogen.h | 37 +++++++-- 2 files changed, 165 insertions(+), 71 deletions(-) diff --git a/src/hydrogen.cc b/src/hydrogen.cc index 67bea00109..a63c6884ef 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -605,7 +605,8 @@ void HGraph::Verify(bool do_full_verify) const { block->predecessors()->first()->last_environment()->ast_id(); for (int k = 0; k < block->predecessors()->length(); k++) { HBasicBlock* predecessor = block->predecessors()->at(k); - ASSERT(predecessor->end()->IsGoto()); + ASSERT(predecessor->end()->IsGoto() || + predecessor->end()->IsDeoptimize()); ASSERT(predecessor->last_environment()->ast_id() == id); } } @@ -745,19 +746,20 @@ bool HGraph::IsStandardConstant(HConstant* constant) { HGraphBuilder::IfBuilder::IfBuilder(HGraphBuilder* builder) : builder_(builder), finished_(false), - deopt_then_(false), - deopt_else_(false), did_then_(false), did_else_(false), + did_else_if_(false), did_and_(false), did_or_(false), captured_(false), needs_compare_(true), + pending_merge_block_(false), split_edge_merge_block_(NULL), - merge_block_(NULL) { + merge_at_join_blocks_(NULL), + normal_merge_at_join_block_count_(0), + deopt_merge_at_join_block_count_(0) { HEnvironment* env = builder->environment(); first_true_block_ = builder->CreateBasicBlock(env->Copy()); - last_true_block_ = NULL; first_false_block_ = builder->CreateBasicBlock(env->Copy()); } @@ -767,19 +769,20 @@ HGraphBuilder::IfBuilder::IfBuilder( HIfContinuation* continuation) : builder_(builder), finished_(false), - deopt_then_(false), - deopt_else_(false), did_then_(false), did_else_(false), + did_else_if_(false), did_and_(false), did_or_(false), captured_(false), needs_compare_(false), + pending_merge_block_(false), first_true_block_(NULL), - last_true_block_(NULL), first_false_block_(NULL), split_edge_merge_block_(NULL), - merge_block_(NULL) { + merge_at_join_blocks_(NULL), + normal_merge_at_join_block_count_(0), + deopt_merge_at_join_block_count_(0) { continuation->Continue(&first_true_block_, &first_false_block_); } @@ -787,6 +790,20 @@ HGraphBuilder::IfBuilder::IfBuilder( HControlInstruction* HGraphBuilder::IfBuilder::AddCompare( HControlInstruction* compare) { + ASSERT(did_then_ == did_else_); + if (did_else_) { + // Handle if-then-elseif + did_else_if_ = true; + did_else_ = false; + did_then_ = false; + did_and_ = false; + did_or_ = false; + pending_merge_block_ = false; + split_edge_merge_block_ = NULL; + HEnvironment* env = builder_->environment(); + first_true_block_ = builder_->CreateBasicBlock(env->Copy()); + first_false_block_ = builder_->CreateBasicBlock(env->Copy()); + } if (split_edge_merge_block_ != NULL) { HEnvironment* env = first_false_block_->last_environment(); HBasicBlock* split_edge = @@ -842,29 +859,30 @@ void HGraphBuilder::IfBuilder::And() { void HGraphBuilder::IfBuilder::CaptureContinuation( HIfContinuation* continuation) { + ASSERT(!did_else_if_); ASSERT(!finished_); ASSERT(!captured_); - HBasicBlock* true_block = last_true_block_ == NULL - ? first_true_block_ - : last_true_block_; - HBasicBlock* false_block = did_else_ && (first_false_block_ != NULL) - ? builder_->current_block() - : first_false_block_; + + HBasicBlock* true_block = NULL; + HBasicBlock* false_block = NULL; + Finish(&true_block, &false_block); + ASSERT(true_block != NULL); + ASSERT(false_block != NULL); continuation->Capture(true_block, false_block); captured_ = true; + builder_->set_current_block(NULL); End(); } void HGraphBuilder::IfBuilder::JoinContinuation(HIfContinuation* continuation) { + ASSERT(!did_else_if_); ASSERT(!finished_); ASSERT(!captured_); - ASSERT(did_then_); - if (!did_else_) Else(); - HBasicBlock* true_block = last_true_block_ == NULL - ? first_true_block_ - : last_true_block_; - HBasicBlock* false_block = builder_->current_block(); + HBasicBlock* true_block = NULL; + HBasicBlock* false_block = NULL; + Finish(&true_block, &false_block); + merge_at_join_blocks_ = NULL; if (true_block != NULL && !true_block->IsFinished()) { ASSERT(continuation->IsTrueReachable()); builder_->GotoNoSimulate(true_block, continuation->true_branch()); @@ -895,6 +913,7 @@ void HGraphBuilder::IfBuilder::Then() { builder_->FinishCurrentBlock(branch); } builder_->set_current_block(first_true_block_); + pending_merge_block_ = true; } @@ -902,20 +921,17 @@ void HGraphBuilder::IfBuilder::Else() { ASSERT(did_then_); ASSERT(!captured_); ASSERT(!finished_); - last_true_block_ = builder_->current_block(); + AddMergeAtJoinBlock(false); builder_->set_current_block(first_false_block_); + pending_merge_block_ = true; did_else_ = true; } void HGraphBuilder::IfBuilder::Deopt(const char* reason) { ASSERT(did_then_); - if (did_else_) { - deopt_else_ = true; - } else { - deopt_then_ = true; - } builder_->Add(reason, Deoptimizer::EAGER); + AddMergeAtJoinBlock(true); } @@ -923,51 +939,99 @@ void HGraphBuilder::IfBuilder::Return(HValue* value) { HValue* parameter_count = builder_->graph()->GetConstantMinus1(); builder_->FinishExitCurrentBlock( builder_->New(value, parameter_count)); - if (did_else_) { - first_false_block_ = NULL; - } else { - first_true_block_ = NULL; + AddMergeAtJoinBlock(false); +} + + +void HGraphBuilder::IfBuilder::AddMergeAtJoinBlock(bool deopt) { + if (!pending_merge_block_) return; + HBasicBlock* block = builder_->current_block(); + ASSERT(block == NULL || !block->IsFinished()); + MergeAtJoinBlock* record = + new(builder_->zone()) MergeAtJoinBlock(block, deopt, + merge_at_join_blocks_); + merge_at_join_blocks_ = record; + if (block != NULL) { + ASSERT(block->end() == NULL); + if (deopt) { + normal_merge_at_join_block_count_++; + } else { + deopt_merge_at_join_block_count_++; + } } + builder_->set_current_block(NULL); + pending_merge_block_ = false; +} + + +void HGraphBuilder::IfBuilder::Finish() { + ASSERT(!finished_); + if (!did_then_) { + Then(); + } + AddMergeAtJoinBlock(false); + if (!did_else_) { + Else(); + AddMergeAtJoinBlock(false); + } + finished_ = true; +} + + +void HGraphBuilder::IfBuilder::Finish(HBasicBlock** then_continuation, + HBasicBlock** else_continuation) { + Finish(); + + MergeAtJoinBlock* else_record = merge_at_join_blocks_; + if (else_continuation != NULL) { + *else_continuation = else_record->block_; + } + MergeAtJoinBlock* then_record = else_record->next_; + if (then_continuation != NULL) { + *then_continuation = then_record->block_; + } + ASSERT(then_record->next_ == NULL); } void HGraphBuilder::IfBuilder::End() { - if (!captured_) { - ASSERT(did_then_); - if (!did_else_) { - last_true_block_ = builder_->current_block(); - } - if (last_true_block_ == NULL || last_true_block_->IsFinished()) { - ASSERT(did_else_); - // Return on true. Nothing to do, just continue the false block. - } else if (first_false_block_ == NULL || - (did_else_ && builder_->current_block()->IsFinished())) { - // Deopt on false. Nothing to do except switching to the true block. - builder_->set_current_block(last_true_block_); - } else { - merge_block_ = builder_->graph()->CreateBasicBlock(); - ASSERT(!finished_); - if (!did_else_) Else(); - ASSERT(!last_true_block_->IsFinished()); - HBasicBlock* last_false_block = builder_->current_block(); - ASSERT(!last_false_block->IsFinished()); - if (deopt_then_) { - builder_->GotoNoSimulate(last_false_block, merge_block_); - builder_->PadEnvironmentForContinuation(last_true_block_, - merge_block_); - builder_->GotoNoSimulate(last_true_block_, merge_block_); - } else { - builder_->GotoNoSimulate(last_true_block_, merge_block_); - if (deopt_else_) { - builder_->PadEnvironmentForContinuation(last_false_block, - merge_block_); - } - builder_->GotoNoSimulate(last_false_block, merge_block_); + if (captured_) return; + Finish(); + + int total_merged_blocks = normal_merge_at_join_block_count_ + + deopt_merge_at_join_block_count_; + ASSERT(total_merged_blocks >= 1); + HBasicBlock* merge_block = total_merged_blocks == 1 + ? NULL : builder_->graph()->CreateBasicBlock(); + + // Merge non-deopt blocks first to ensure environment has right size for + // padding. + MergeAtJoinBlock* current = merge_at_join_blocks_; + while (current != NULL) { + if (!current->deopt_ && current->block_ != NULL) { + // If there is only one block that makes it through to the end of the + // if, then just set it as the current block and continue rather then + // creating an unnecessary merge block. + if (total_merged_blocks == 1) { + builder_->set_current_block(current->block_); + return; } - builder_->set_current_block(merge_block_); + builder_->GotoNoSimulate(current->block_, merge_block); } + current = current->next_; } - finished_ = true; + + // Merge deopt blocks, padding when necessary. + current = merge_at_join_blocks_; + while (current != NULL) { + if (current->deopt_ && current->block_ != NULL) { + builder_->PadEnvironmentForContinuation(current->block_, + merge_block); + builder_->GotoNoSimulate(current->block_, merge_block); + } + current = current->next_; + } + builder_->set_current_block(merge_block); } @@ -1051,6 +1115,7 @@ void HGraphBuilder::LoopBuilder::Break() { } builder_->GotoNoSimulate(exit_trampoline_block_); + builder_->set_current_block(NULL); } @@ -1859,6 +1924,7 @@ HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( HInstruction* result = AddElementAccess( external_elements, key, val, bounds_check, elements_kind, is_store); negative_checker.ElseDeopt("Negative key encountered"); + negative_checker.End(); length_checker.End(); return result; } else { @@ -1940,9 +2006,10 @@ HValue* HGraphBuilder::BuildAllocateArrayFromLength( IsFastPackedElementsKind(array_builder->kind())) { // We'll come back later with better (holey) feedback. if_builder.Deopt("Holey array despite packed elements_kind feedback"); + } else { + Push(checked_length); // capacity + Push(checked_length); // length } - Push(checked_length); // capacity - Push(checked_length); // length if_builder.End(); // Figure out total size diff --git a/src/hydrogen.h b/src/hydrogen.h index 7987a97a51..ea09ab039f 100644 --- a/src/hydrogen.h +++ b/src/hydrogen.h @@ -953,7 +953,10 @@ class FunctionState V8_FINAL { class HIfContinuation V8_FINAL { public: - HIfContinuation() : continuation_captured_(false) {} + HIfContinuation() + : continuation_captured_(false), + true_branch_(NULL), + false_branch_(NULL) {} HIfContinuation(HBasicBlock* true_branch, HBasicBlock* false_branch) : continuation_captured_(true), true_branch_(true_branch), @@ -1493,6 +1496,10 @@ class HGraphBuilder { void End(); void Deopt(const char* reason); + void ThenDeopt(const char* reason) { + Then(); + Deopt(reason); + } void ElseDeopt(const char* reason) { Else(); Deopt(reason); @@ -1505,21 +1512,41 @@ class HGraphBuilder { HGraphBuilder* builder() const { return builder_; } + void AddMergeAtJoinBlock(bool deopt); + + void Finish(); + void Finish(HBasicBlock** then_continuation, + HBasicBlock** else_continuation); + + class MergeAtJoinBlock : public ZoneObject { + public: + MergeAtJoinBlock(HBasicBlock* block, + bool deopt, + MergeAtJoinBlock* next) + : block_(block), + deopt_(deopt), + next_(next) {} + HBasicBlock* block_; + bool deopt_; + MergeAtJoinBlock* next_; + }; + HGraphBuilder* builder_; bool finished_ : 1; - bool deopt_then_ : 1; - bool deopt_else_ : 1; bool did_then_ : 1; bool did_else_ : 1; + bool did_else_if_ : 1; bool did_and_ : 1; bool did_or_ : 1; bool captured_ : 1; bool needs_compare_ : 1; + bool pending_merge_block_ : 1; HBasicBlock* first_true_block_; - HBasicBlock* last_true_block_; HBasicBlock* first_false_block_; HBasicBlock* split_edge_merge_block_; - HBasicBlock* merge_block_; + MergeAtJoinBlock* merge_at_join_blocks_; + int normal_merge_at_join_block_count_; + int deopt_merge_at_join_block_count_; }; class LoopBuilder V8_FINAL {