Chromium Code Reviews| Index: runtime/vm/flow_graph_optimizer.cc |
| diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc |
| index 6b1c0f526a44bfc554800aaba9d92b1b2fe2aa8b..140e314730b348232b2e400dec9da41cd2f3f305 100644 |
| --- a/runtime/vm/flow_graph_optimizer.cc |
| +++ b/runtime/vm/flow_graph_optimizer.cc |
| @@ -31,19 +31,19 @@ void FlowGraphOptimizer::OptimizeComputations() { |
| BlockEntryInstr* entry = block_order_[i]; |
| entry->Accept(this); |
| for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) { |
| - BindInstr* instr = it.Current()->AsBind(); |
| - if (instr != NULL) { |
| - Definition* result = instr->computation()->TryReplace(instr); |
| - if (result != instr) { |
| + Definition* defn = it.Current()->AsDefinition(); |
| + if (defn != NULL) { |
| + Definition* result = defn->Canonicalize(); |
| + if (result != defn) { |
| if (result != NULL) { |
| - instr->ReplaceUsesWith(result); |
| + defn->ReplaceUsesWith(result); |
| if (FLAG_trace_optimization) { |
| OS::Print("Replacing v%d with v%d\n", |
| - instr->ssa_temp_index(), |
| + defn->ssa_temp_index(), |
| result->ssa_temp_index()); |
| } |
| } else if (FLAG_trace_optimization) { |
| - OS::Print("Removing v%d.\n", instr->ssa_temp_index()); |
| + OS::Print("Removing v%d.\n", defn->ssa_temp_index()); |
| } |
| it.RemoveCurrentFromGraph(); |
| } |
| @@ -53,17 +53,17 @@ void FlowGraphOptimizer::OptimizeComputations() { |
| } |
| -static Computation* CreateConversion(Representation from, |
| - Representation to, |
| - Definition* def, |
| - Instruction* deopt_target) { |
| +static Definition* CreateConversion(Representation from, |
| + Representation to, |
| + Definition* def, |
| + Instruction* deopt_target) { |
| if ((from == kUnboxedDouble) && (to == kTagged)) { |
| - return new BoxDoubleComp(new Value(def), NULL); |
| + return new BoxDoubleInstr(new Value(def), NULL); |
| } else if ((from == kTagged) && (to == kUnboxedDouble)) { |
| const intptr_t deopt_id = (deopt_target != NULL) ? |
| deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId; |
| ASSERT((deopt_target != NULL) || (def->GetPropagatedCid() == kDoubleCid)); |
| - return new UnboxDoubleComp(new Value(def), deopt_id); |
| + return new UnboxDoubleInstr(new Value(def), deopt_id); |
| } else { |
| UNREACHABLE(); |
| return NULL; |
| @@ -96,16 +96,15 @@ void FlowGraphOptimizer::InsertConversionsFor(Definition* def) { |
| deopt_target = instr; |
| } |
| - BindInstr* converted = InsertBefore( |
| - instr, |
| - CreateConversion(from_rep, to_rep, def, deopt_target), |
| - use->instruction()->env(), |
| - Definition::kValue); |
| - |
| + Definition* converted = |
| + CreateConversion(from_rep, to_rep, def, deopt_target); |
| + InsertBefore(instr, converted, use->instruction()->env(), |
| + Definition::kValue); |
| use->set_definition(converted); |
| } |
| } |
| + |
| void FlowGraphOptimizer::SelectRepresentations() { |
| // Convervatively unbox all phis that were proven to be of type Double. |
| for (intptr_t i = 0; i < block_order_.length(); ++i) { |
| @@ -264,10 +263,10 @@ static bool ShouldSpecializeForDouble(const ICData& ic_data) { |
| } |
| -static void RemovePushArguments(InstanceCallComp* comp) { |
| +static void RemovePushArguments(InstanceCallInstr* call) { |
| // Remove original push arguments. |
| - for (intptr_t i = 0; i < comp->ArgumentCount(); ++i) { |
| - PushArgumentInstr* push = comp->ArgumentAt(i); |
| + for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { |
| + PushArgumentInstr* push = call->ArgumentAt(i); |
| push->ReplaceUsesWith(push->value()->definition()); |
| push->RemoveFromGraph(); |
| } |
| @@ -290,10 +289,10 @@ static bool HasOneTarget(const ICData& ic_data) { |
| } |
| -static intptr_t ReceiverClassId(InstanceCallComp* comp) { |
| - if (!comp->HasICData()) return kIllegalCid; |
| +static intptr_t ReceiverClassId(InstanceCallInstr* call) { |
| + if (!call->HasICData()) return kIllegalCid; |
| - const ICData& ic_data = *comp->ic_data(); |
| + const ICData& ic_data = *call->ic_data(); |
| if (ic_data.NumberOfChecks() == 0) return kIllegalCid; |
| // TODO(vegorov): Add multiple receiver type support. |
| @@ -307,24 +306,22 @@ static intptr_t ReceiverClassId(InstanceCallComp* comp) { |
| } |
| -void FlowGraphOptimizer::AddCheckClass(BindInstr* instr, |
| - InstanceCallComp* comp, |
| +void FlowGraphOptimizer::AddCheckClass(InstanceCallInstr* call, |
| Value* value) { |
| // Type propagation has not run yet, we cannot eliminate the check. |
| const ICData& unary_checks = |
| - ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecks()); |
| - CheckClassComp* check = new CheckClassComp(value, comp, unary_checks); |
| - InsertBefore(instr, check, instr->env(), Definition::kEffect); |
| + ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecks()); |
| + CheckClassInstr* check = new CheckClassInstr(value, call, unary_checks); |
| + InsertBefore(call, check, call->env(), Definition::kEffect); |
| } |
| -bool FlowGraphOptimizer::TryReplaceWithArrayOp(BindInstr* instr, |
| - InstanceCallComp* comp, |
| +bool FlowGraphOptimizer::TryReplaceWithArrayOp(InstanceCallInstr* call, |
| Token::Kind op_kind) { |
| // TODO(fschneider): Optimize []= operator in checked mode as well. |
| if (op_kind == Token::kASSIGN_INDEX && FLAG_enable_type_checks) return false; |
| - const intptr_t class_id = ReceiverClassId(comp); |
| + const intptr_t class_id = ReceiverClassId(call); |
| switch (class_id) { |
| case kImmutableArrayCid: |
| // Stores are only specialized for Array and GrowableObjectArray, |
| @@ -333,32 +330,32 @@ bool FlowGraphOptimizer::TryReplaceWithArrayOp(BindInstr* instr, |
| // Fall through. |
| case kArrayCid: |
| case kGrowableObjectArrayCid: { |
| - Value* array = comp->ArgumentAt(0)->value(); |
| - Value* index = comp->ArgumentAt(1)->value(); |
| + Value* array = call->ArgumentAt(0)->value(); |
| + Value* index = call->ArgumentAt(1)->value(); |
| // Insert class check and index smi checks and attach a copy of the |
| // original environment because the operation can still deoptimize. |
| - AddCheckClass(instr, comp, array->Copy()); |
| - InsertBefore(instr, |
| - new CheckSmiComp(index->Copy(), comp->deopt_id()), |
| - instr->env(), |
| + AddCheckClass(call, array->Copy()); |
| + InsertBefore(call, |
| + new CheckSmiInstr(index->Copy(), call->deopt_id()), |
| + call->env(), |
| Definition::kEffect); |
| // Insert array bounds check. |
| - InsertBefore(instr, |
| - new CheckArrayBoundComp(array->Copy(), |
| - index->Copy(), |
| - class_id, |
| - comp), |
| - instr->env(), |
| + InsertBefore(call, |
| + new CheckArrayBoundInstr(array->Copy(), |
| + index->Copy(), |
| + class_id, |
| + call), |
| + call->env(), |
| Definition::kEffect); |
| - Computation* array_op = NULL; |
| + Definition* array_op = NULL; |
| if (op_kind == Token::kINDEX) { |
| - array_op = new LoadIndexedComp(array, index, class_id); |
| + array_op = new LoadIndexedInstr(array, index, class_id); |
| } else { |
| - Value* value = comp->ArgumentAt(2)->value(); |
| - array_op = new StoreIndexedComp(array, index, value, class_id); |
| + Value* value = call->ArgumentAt(2)->value(); |
| + array_op = new StoreIndexedInstr(array, index, value, class_id); |
| } |
| - instr->set_computation(array_op); |
| - RemovePushArguments(comp); |
| + call->ReplaceWith(array_op, current_iterator()); |
| + RemovePushArguments(call); |
| return true; |
| } |
| default: |
| @@ -367,40 +364,35 @@ bool FlowGraphOptimizer::TryReplaceWithArrayOp(BindInstr* instr, |
| } |
| -BindInstr* FlowGraphOptimizer::InsertBefore(Instruction* instr, |
| - Computation* comp, |
| - Environment* env, |
| - BindInstr::UseKind use_kind) { |
| - BindInstr* bind = new BindInstr(use_kind, comp); |
| - if (env != NULL) env->CopyTo(bind); |
| +void FlowGraphOptimizer::InsertBefore(Instruction* instr, |
| + Definition* defn, |
| + Environment* env, |
| + Definition::UseKind use_kind) { |
| + if (env != NULL) env->CopyTo(defn); |
| if (use_kind == Definition::kValue) { |
| - bind->set_ssa_temp_index(flow_graph_->alloc_ssa_temp_index()); |
| + defn->set_ssa_temp_index(flow_graph_->alloc_ssa_temp_index()); |
| } |
| - bind->InsertBefore(instr); |
| - return bind; |
| + defn->InsertBefore(instr); |
| } |
| -BindInstr* FlowGraphOptimizer::InsertAfter(Instruction* instr, |
| - Computation* comp, |
| - Environment* env, |
| - BindInstr::UseKind use_kind) { |
| - BindInstr* bind = new BindInstr(use_kind, comp); |
| - if (env != NULL) env->CopyTo(bind); |
| +void FlowGraphOptimizer::InsertAfter(Instruction* instr, |
| + Definition* defn, |
| + Environment* env, |
| + Definition::UseKind use_kind) { |
| + if (env != NULL) env->CopyTo(defn); |
| if (use_kind == Definition::kValue) { |
| - bind->set_ssa_temp_index(flow_graph_->alloc_ssa_temp_index()); |
| + defn->set_ssa_temp_index(flow_graph_->alloc_ssa_temp_index()); |
| } |
| - bind->InsertAfter(instr); |
| - return bind; |
| + defn->InsertAfter(instr); |
| } |
| -bool FlowGraphOptimizer::TryReplaceWithBinaryOp(BindInstr* instr, |
| - InstanceCallComp* comp, |
| +bool FlowGraphOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call, |
| Token::Kind op_kind) { |
| intptr_t operands_type = kIllegalCid; |
| - ASSERT(comp->HasICData()); |
| - const ICData& ic_data = *comp->ic_data(); |
| + ASSERT(call->HasICData()); |
| + const ICData& ic_data = *call->ic_data(); |
| switch (op_kind) { |
| case Token::kADD: |
| case Token::kSUB: |
| @@ -447,87 +439,82 @@ bool FlowGraphOptimizer::TryReplaceWithBinaryOp(BindInstr* instr, |
| UNREACHABLE(); |
| }; |
| - ASSERT(comp->ArgumentCount() == 2); |
| + ASSERT(call->ArgumentCount() == 2); |
| if (operands_type == kDoubleCid) { |
| - Value* left = comp->ArgumentAt(0)->value(); |
| - Value* right = comp->ArgumentAt(1)->value(); |
| + Value* left = call->ArgumentAt(0)->value(); |
| + Value* right = call->ArgumentAt(1)->value(); |
| // Check that either left or right are not a smi. Result or a |
| // binary operation with two smis is a smi not a double. |
| - InsertBefore(instr, |
| - new CheckEitherNonSmiComp(left->Copy(), |
| - right->Copy(), |
| - comp), |
| - instr->env(), |
| + InsertBefore(call, |
| + new CheckEitherNonSmiInstr(left->Copy(), |
| + right->Copy(), |
| + call), |
| + call->env(), |
| Definition::kEffect); |
| - UnboxedDoubleBinaryOpComp* double_bin_op = |
| - new UnboxedDoubleBinaryOpComp(op_kind, |
| - left->Copy(), |
| - right->Copy(), |
| - comp); |
| - instr->set_computation(double_bin_op); |
| - |
| - RemovePushArguments(comp); |
| + UnboxedDoubleBinaryOpInstr* double_bin_op = |
| + new UnboxedDoubleBinaryOpInstr(op_kind, |
| + left->Copy(), |
| + right->Copy(), |
| + call); |
| + call->ReplaceWith(double_bin_op, current_iterator()); |
| + RemovePushArguments(call); |
| } else if (operands_type == kMintCid) { |
| - Value* left = comp->ArgumentAt(0)->value(); |
| - Value* right = comp->ArgumentAt(1)->value(); |
| - BinaryMintOpComp* bin_op = new BinaryMintOpComp(op_kind, |
| - comp, |
| - left, |
| - right); |
| - instr->set_computation(bin_op); |
| - RemovePushArguments(comp); |
| + Value* left = call->ArgumentAt(0)->value(); |
| + Value* right = call->ArgumentAt(1)->value(); |
| + BinaryMintOpInstr* bin_op = new BinaryMintOpInstr(op_kind, |
| + call, |
| + left, |
| + right); |
| + call->ReplaceWith(bin_op, current_iterator()); |
| + RemovePushArguments(call); |
| } else { |
| ASSERT(operands_type == kSmiCid); |
| - Value* left = comp->ArgumentAt(0)->value(); |
| - Value* right = comp->ArgumentAt(1)->value(); |
| + Value* left = call->ArgumentAt(0)->value(); |
| + Value* right = call->ArgumentAt(1)->value(); |
| // Insert two smi checks and attach a copy of the original |
| // environment because the smi operation can still deoptimize. |
| - InsertBefore(instr, |
| - new CheckSmiComp(left->Copy(), comp->deopt_id()), |
| - instr->env(), |
| + InsertBefore(call, |
| + new CheckSmiInstr(left->Copy(), call->deopt_id()), |
| + call->env(), |
| Definition::kEffect); |
| - InsertBefore(instr, |
| - new CheckSmiComp(right->Copy(), comp->deopt_id()), |
| - instr->env(), |
| + InsertBefore(call, |
| + new CheckSmiInstr(right->Copy(), call->deopt_id()), |
| + call->env(), |
| Definition::kEffect); |
| - BinarySmiOpComp* bin_op = new BinarySmiOpComp(op_kind, |
| - comp, |
| - left, |
| - right); |
| - instr->set_computation(bin_op); |
| - RemovePushArguments(comp); |
| + BinarySmiOpInstr* bin_op = new BinarySmiOpInstr(op_kind, call, left, right); |
| + call->ReplaceWith(bin_op, current_iterator()); |
| + RemovePushArguments(call); |
| } |
| return true; |
| } |
| -bool FlowGraphOptimizer::TryReplaceWithUnaryOp(BindInstr* instr, |
| - InstanceCallComp* comp, |
| +bool FlowGraphOptimizer::TryReplaceWithUnaryOp(InstanceCallInstr* call, |
| Token::Kind op_kind) { |
| - if (comp->ic_data()->NumberOfChecks() != 1) { |
| + if (call->ic_data()->NumberOfChecks() != 1) { |
| // TODO(srdjan): Not yet supported. |
| return false; |
| } |
| - ASSERT(comp->ArgumentCount() == 1); |
| - Computation* unary_op = NULL; |
| - if (HasOneSmi(*comp->ic_data())) { |
| - Value* value = comp->ArgumentAt(0)->value(); |
| - InsertBefore(instr, |
| - new CheckSmiComp(value->Copy(), comp->deopt_id()), |
| - instr->env(), |
| + ASSERT(call->ArgumentCount() == 1); |
| + Definition* unary_op = NULL; |
| + if (HasOneSmi(*call->ic_data())) { |
| + Value* value = call->ArgumentAt(0)->value(); |
| + InsertBefore(call, |
| + new CheckSmiInstr(value->Copy(), call->deopt_id()), |
| + call->env(), |
| Definition::kEffect); |
| - unary_op = new UnarySmiOpComp(op_kind, |
| - (op_kind == Token::kNEGATE) ? comp : NULL, |
| - value); |
| - } else if (HasOneDouble(*comp->ic_data()) && (op_kind == Token::kNEGATE)) { |
| - unary_op = new NumberNegateComp(comp, comp->ArgumentAt(0)->value()); |
| + unary_op = new UnarySmiOpInstr(op_kind, |
| + (op_kind == Token::kNEGATE) ? call : NULL, |
| + value); |
| + } else if (HasOneDouble(*call->ic_data()) && (op_kind == Token::kNEGATE)) { |
| + unary_op = new NumberNegateInstr(call, call->ArgumentAt(0)->value()); |
| } |
| if (unary_op == NULL) return false; |
| - instr->set_computation(unary_op); |
| - RemovePushArguments(comp); |
| + call->ReplaceWith(unary_op, current_iterator()); |
| + RemovePushArguments(call); |
| return true; |
| } |
| @@ -548,10 +535,9 @@ static RawField* GetField(intptr_t class_id, const String& field_name) { |
| // Only unique implicit instance getters can be currently handled. |
| -bool FlowGraphOptimizer::TryInlineInstanceGetter(BindInstr* instr, |
| - InstanceCallComp* comp) { |
| - ASSERT(comp->HasICData()); |
| - const ICData& ic_data = *comp->ic_data(); |
| +bool FlowGraphOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call) { |
| + ASSERT(call->HasICData()); |
| + const ICData& ic_data = *call->ic_data(); |
| if (ic_data.NumberOfChecks() == 0) { |
| // No type feedback collected. |
| return false; |
| @@ -568,18 +554,18 @@ bool FlowGraphOptimizer::TryInlineInstanceGetter(BindInstr* instr, |
| } |
| // Inline implicit instance getter. |
| const String& field_name = |
| - String::Handle(Field::NameFromGetter(comp->function_name())); |
| + String::Handle(Field::NameFromGetter(call->function_name())); |
| const Field& field = Field::Handle(GetField(class_ids[0], field_name)); |
| ASSERT(!field.IsNull()); |
| - AddCheckClass(instr, comp, comp->ArgumentAt(0)->value()->Copy()); |
| + AddCheckClass(call, call->ArgumentAt(0)->value()->Copy()); |
| // Detach environment from the original instruction because it can't |
| // deoptimize. |
| - instr->set_env(NULL); |
| - LoadInstanceFieldComp* load = |
| - new LoadInstanceFieldComp(field, comp->ArgumentAt(0)->value()); |
| - instr->set_computation(load); |
| - RemovePushArguments(comp); |
| + call->set_env(NULL); |
| + LoadInstanceFieldInstr* load = |
| + new LoadInstanceFieldInstr(field, call->ArgumentAt(0)->value()); |
| + call->ReplaceWith(load, current_iterator()); |
| + RemovePushArguments(call); |
| return true; |
| } |
| @@ -608,15 +594,15 @@ bool FlowGraphOptimizer::TryInlineInstanceGetter(BindInstr* instr, |
| UNREACHABLE(); |
| } |
| // Check receiver class. |
| - AddCheckClass(instr, comp, comp->ArgumentAt(0)->value()->Copy()); |
| + AddCheckClass(call, call->ArgumentAt(0)->value()->Copy()); |
| - LoadVMFieldComp* load = new LoadVMFieldComp( |
| - comp->ArgumentAt(0)->value(), |
| + LoadVMFieldInstr* load = new LoadVMFieldInstr( |
| + call->ArgumentAt(0)->value(), |
| length_offset, |
| Type::ZoneHandle(Type::SmiType())); |
| load->set_result_cid(kSmiCid); |
| - instr->set_computation(load); |
| - RemovePushArguments(comp); |
| + call->ReplaceWith(load, current_iterator()); |
| + RemovePushArguments(call); |
| return true; |
| } |
| @@ -626,15 +612,15 @@ bool FlowGraphOptimizer::TryInlineInstanceGetter(BindInstr* instr, |
| return false; |
| } |
| // Check receiver class. |
| - AddCheckClass(instr, comp, comp->ArgumentAt(0)->value()->Copy()); |
| + AddCheckClass(call, call->ArgumentAt(0)->value()->Copy()); |
| - LoadVMFieldComp* load = new LoadVMFieldComp( |
| - comp->ArgumentAt(0)->value(), |
| + LoadVMFieldInstr* load = new LoadVMFieldInstr( |
| + call->ArgumentAt(0)->value(), |
| String::length_offset(), |
| Type::ZoneHandle(Type::SmiType())); |
| load->set_result_cid(kSmiCid); |
| - instr->set_computation(load); |
| - RemovePushArguments(comp); |
| + call->ReplaceWith(load, current_iterator()); |
| + RemovePushArguments(call); |
| return true; |
| } |
| return false; |
| @@ -642,10 +628,9 @@ bool FlowGraphOptimizer::TryInlineInstanceGetter(BindInstr* instr, |
| // Inline only simple, frequently called core library methods. |
| -bool FlowGraphOptimizer::TryInlineInstanceMethod(BindInstr* instr, |
| - InstanceCallComp* comp) { |
| - ASSERT(comp->HasICData()); |
| - const ICData& ic_data = *comp->ic_data(); |
| +bool FlowGraphOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) { |
| + ASSERT(call->HasICData()); |
| + const ICData& ic_data = *call->ic_data(); |
| if ((ic_data.NumberOfChecks() == 0) || !HasOneTarget(ic_data)) { |
| // No type feedback collected. |
| return false; |
| @@ -658,16 +643,16 @@ bool FlowGraphOptimizer::TryInlineInstanceMethod(BindInstr* instr, |
| if ((recognized_kind == MethodRecognizer::kDoubleToDouble) && |
| (class_ids[0] == kDoubleCid)) { |
| - DoubleToDoubleComp* d2d_comp = |
| - new DoubleToDoubleComp(comp->ArgumentAt(0)->value(), comp); |
| - instr->set_computation(d2d_comp); |
| - RemovePushArguments(comp); |
| + DoubleToDoubleInstr* d2d_instr = |
| + new DoubleToDoubleInstr(call->ArgumentAt(0)->value(), call); |
| + call->ReplaceWith(d2d_instr, current_iterator()); |
| + RemovePushArguments(call); |
| return true; |
| } |
| if ((recognized_kind == MethodRecognizer::kIntegerToDouble) && |
| (class_ids[0] == kSmiCid)) { |
| - SmiToDoubleComp* s2d_comp = new SmiToDoubleComp(comp); |
| - instr->set_computation(s2d_comp); |
| + SmiToDoubleInstr* s2d_instr = new SmiToDoubleInstr(call); |
| + call->ReplaceWith(s2d_instr, current_iterator()); |
| // Pushed arguments are not removed because SmiToDouble is implemented |
| // as a call. |
| return true; |
| @@ -676,51 +661,49 @@ bool FlowGraphOptimizer::TryInlineInstanceMethod(BindInstr* instr, |
| } |
| -void FlowGraphOptimizer::VisitInstanceCall(InstanceCallComp* comp, |
| - BindInstr* instr) { |
| - if (comp->HasICData() && (comp->ic_data()->NumberOfChecks() > 0)) { |
| - const Token::Kind op_kind = comp->token_kind(); |
| +void FlowGraphOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { |
| + if (instr->HasICData() && (instr->ic_data()->NumberOfChecks() > 0)) { |
| + const Token::Kind op_kind = instr->token_kind(); |
| if (Token::IsIndexOperator(op_kind) && |
| - TryReplaceWithArrayOp(instr, comp, op_kind)) { |
| + TryReplaceWithArrayOp(instr, op_kind)) { |
| return; |
| } |
| if (Token::IsBinaryToken(op_kind) && |
| - TryReplaceWithBinaryOp(instr, comp, op_kind)) { |
| + TryReplaceWithBinaryOp(instr, op_kind)) { |
| return; |
| } |
| if (Token::IsUnaryToken(op_kind) && |
| - TryReplaceWithUnaryOp(instr, comp, op_kind)) { |
| + TryReplaceWithUnaryOp(instr, op_kind)) { |
| return; |
| } |
| - if ((op_kind == Token::kGET) && TryInlineInstanceGetter(instr, comp)) { |
| + if ((op_kind == Token::kGET) && TryInlineInstanceGetter(instr)) { |
| return; |
| } |
| - if ((op_kind == Token::kSET) && TryInlineInstanceSetter(instr, comp)) { |
| + if ((op_kind == Token::kSET) && TryInlineInstanceSetter(instr)) { |
| return; |
| } |
| - if (TryInlineInstanceMethod(instr, comp)) { |
| + if (TryInlineInstanceMethod(instr)) { |
| return; |
| } |
| const intptr_t kMaxChecks = 4; |
| - if (comp->ic_data()->NumberOfChecks() <= kMaxChecks) { |
| + if (instr->ic_data()->NumberOfChecks() <= kMaxChecks) { |
| const ICData& unary_checks = |
| - ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecks()); |
| + ICData::ZoneHandle(instr->ic_data()->AsUnaryClassChecks()); |
| bool call_with_checks; |
| - // TODO(srdjan): Add check class comp for mixed smi/non-smi. |
| + // TODO(srdjan): Add check class instr for mixed smi/non-smi. |
| if (HasOneTarget(unary_checks) && |
| (unary_checks.GetReceiverClassIdAt(0) != kSmiCid)) { |
| // Type propagation has not run yet, we cannot eliminate the check. |
| - AddCheckClass(instr, comp, comp->ArgumentAt(0)->value()->Copy()); |
| + AddCheckClass(instr, instr->ArgumentAt(0)->value()->Copy()); |
| // Call can still deoptimize, do not detach environment from instr. |
| call_with_checks = false; |
| } else { |
| call_with_checks = true; |
| } |
| - PolymorphicInstanceCallComp* call = |
| - new PolymorphicInstanceCallComp(comp, |
| - unary_checks, |
| - call_with_checks); |
| - instr->set_computation(call); |
| + PolymorphicInstanceCallInstr* call = |
| + new PolymorphicInstanceCallInstr(instr, unary_checks, |
| + call_with_checks); |
| + instr->ReplaceWith(call, current_iterator()); |
| } |
| } |
| // An instance call without ICData should continue calling via IC calls |
| @@ -728,25 +711,23 @@ void FlowGraphOptimizer::VisitInstanceCall(InstanceCallComp* comp, |
| } |
| -void FlowGraphOptimizer::VisitStaticCall(StaticCallComp* comp, |
| - BindInstr* instr) { |
| +void FlowGraphOptimizer::VisitStaticCall(StaticCallInstr* instr) { |
| MethodRecognizer::Kind recognized_kind = |
| - MethodRecognizer::RecognizeKind(comp->function()); |
| + MethodRecognizer::RecognizeKind(instr->function()); |
| if (recognized_kind == MethodRecognizer::kMathSqrt) { |
| - comp->set_recognized(MethodRecognizer::kMathSqrt); |
| + instr->set_recognized(MethodRecognizer::kMathSqrt); |
| } |
| } |
| -bool FlowGraphOptimizer::TryInlineInstanceSetter(BindInstr* instr, |
| - InstanceCallComp* comp) { |
| +bool FlowGraphOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr) { |
| if (FLAG_enable_type_checks) { |
| // TODO(srdjan): Add assignable check node if --enable_type_checks. |
| return false; |
| } |
| - ASSERT(comp->HasICData()); |
| - const ICData& ic_data = *comp->ic_data(); |
| + ASSERT(instr->HasICData()); |
| + const ICData& ic_data = *instr->ic_data(); |
| if (ic_data.NumberOfChecks() == 0) { |
| // No type feedback collected. |
| return false; |
| @@ -765,20 +746,20 @@ bool FlowGraphOptimizer::TryInlineInstanceSetter(BindInstr* instr, |
| } |
| // Inline implicit instance setter. |
| const String& field_name = |
| - String::Handle(Field::NameFromSetter(comp->function_name())); |
| + String::Handle(Field::NameFromSetter(instr->function_name())); |
| const Field& field = Field::Handle(GetField(class_id, field_name)); |
| ASSERT(!field.IsNull()); |
| - AddCheckClass(instr, comp, comp->ArgumentAt(0)->value()->Copy()); |
| + AddCheckClass(instr, instr->ArgumentAt(0)->value()->Copy()); |
| // Detach environment from the original instruction because it can't |
| // deoptimize. |
| instr->set_env(NULL); |
| - StoreInstanceFieldComp* store = new StoreInstanceFieldComp( |
| + StoreInstanceFieldInstr* store = new StoreInstanceFieldInstr( |
| field, |
| - comp->ArgumentAt(0)->value(), |
| - comp->ArgumentAt(1)->value()); |
| - instr->set_computation(store); |
| - RemovePushArguments(comp); |
| + instr->ArgumentAt(0)->value(), |
| + instr->ArgumentAt(1)->value()); |
| + instr->ReplaceWith(store, current_iterator()); |
| + RemovePushArguments(instr); |
| return true; |
| } |
| @@ -786,7 +767,7 @@ bool FlowGraphOptimizer::TryInlineInstanceSetter(BindInstr* instr, |
| // TODO(fschneider): Once we get rid of the distinction between Instruction |
| // and computation, this helper can go away. |
| static void HandleRelationalOp(FlowGraphOptimizer* optimizer, |
| - RelationalOpComp* comp, |
| + RelationalOpInstr* comp, |
| Instruction* instr) { |
| if (!comp->HasICData()) return; |
| @@ -799,12 +780,12 @@ static void HandleRelationalOp(FlowGraphOptimizer* optimizer, |
| if (HasOnlyTwoSmi(ic_data)) { |
| optimizer->InsertBefore( |
| instr, |
| - new CheckSmiComp(comp->left()->Copy(), comp->deopt_id()), |
| + new CheckSmiInstr(comp->left()->Copy(), comp->deopt_id()), |
| instr->env(), |
| Definition::kEffect); |
| optimizer->InsertBefore( |
| instr, |
| - new CheckSmiComp(comp->right()->Copy(), comp->deopt_id()), |
| + new CheckSmiInstr(comp->right()->Copy(), comp->deopt_id()), |
| instr->env(), |
| Definition::kEffect); |
| comp->set_operands_class_id(kSmiCid); |
| @@ -815,9 +796,8 @@ static void HandleRelationalOp(FlowGraphOptimizer* optimizer, |
| } |
| } |
| -void FlowGraphOptimizer::VisitRelationalOp(RelationalOpComp* comp, |
| - BindInstr* instr) { |
| - HandleRelationalOp(this, comp, instr); |
| +void FlowGraphOptimizer::VisitRelationalOp(RelationalOpInstr* instr) { |
| + HandleRelationalOp(this, instr, instr); |
| } |
| @@ -825,16 +805,17 @@ void FlowGraphOptimizer::VisitRelationalOp(RelationalOpComp* comp, |
| // and computation, this helper can go away. |
| template <typename T> |
| static void HandleEqualityCompare(FlowGraphOptimizer* optimizer, |
| - EqualityCompareComp* comp, |
| - T instr) { |
| + EqualityCompareInstr* comp, |
| + T instr, |
| + ForwardInstructionIterator* iterator) { |
| // If one of the inputs is null, no ICdata will be collected. |
| if (comp->left()->BindsToConstantNull() || |
| comp->right()->BindsToConstantNull()) { |
| Token::Kind strict_kind = (comp->kind() == Token::kEQ) ? |
| Token::kEQ_STRICT : Token::kNE_STRICT; |
| - StrictCompareComp* strict_comp = |
| - new StrictCompareComp(strict_kind, comp->left(), comp->right()); |
| - instr->set_computation(strict_comp); |
| + StrictCompareInstr* strict_comp = |
| + new StrictCompareInstr(strict_kind, comp->left(), comp->right()); |
| + instr->ReplaceWith(strict_comp, iterator); |
| return; |
| } |
| if (!comp->HasICData() || (comp->ic_data()->NumberOfChecks() == 0)) return; |
| @@ -847,12 +828,12 @@ static void HandleEqualityCompare(FlowGraphOptimizer* optimizer, |
| if ((class_ids[0] == kSmiCid) && (class_ids[1] == kSmiCid)) { |
| optimizer->InsertBefore( |
| instr, |
| - new CheckSmiComp(comp->left()->Copy(), comp->deopt_id()), |
| + new CheckSmiInstr(comp->left()->Copy(), comp->deopt_id()), |
| instr->env(), |
| Definition::kEffect); |
| optimizer->InsertBefore( |
| instr, |
| - new CheckSmiComp(comp->right()->Copy(), comp->deopt_id()), |
| + new CheckSmiInstr(comp->right()->Copy(), comp->deopt_id()), |
| instr->env(), |
| Definition::kEffect); |
| comp->set_receiver_class_id(kSmiCid); |
| @@ -867,23 +848,18 @@ static void HandleEqualityCompare(FlowGraphOptimizer* optimizer, |
| } |
| -void FlowGraphOptimizer::VisitEqualityCompare(EqualityCompareComp* comp, |
| - BindInstr* instr) { |
| - HandleEqualityCompare(this, comp, instr); |
| -} |
| - |
| - |
| -void FlowGraphOptimizer::VisitBind(BindInstr* instr) { |
| - instr->computation()->Accept(this, instr); |
| +void FlowGraphOptimizer::VisitEqualityCompare(EqualityCompareInstr* instr) { |
| + HandleEqualityCompare(this, instr, instr, current_iterator()); |
| } |
| void FlowGraphOptimizer::VisitBranch(BranchInstr* instr) { |
| - ComparisonComp* comparison = instr->computation(); |
| + ComparisonInstr* comparison = instr->comparison(); |
| if (comparison->IsRelationalOp()) { |
| HandleRelationalOp(this, comparison->AsRelationalOp(), instr); |
| } else if (comparison->IsEqualityCompare()) { |
| - HandleEqualityCompare(this, comparison->AsEqualityCompare(), instr); |
| + HandleEqualityCompare(this, comparison->AsEqualityCompare(), instr, |
| + current_iterator()); |
| } else { |
| ASSERT(comparison->IsStrictCompare()); |
| // Nothing to do. |
| @@ -891,19 +867,52 @@ void FlowGraphOptimizer::VisitBranch(BranchInstr* instr) { |
| } |
| -void FlowGraphTypePropagator::VisitAssertAssignable(AssertAssignableComp* comp, |
| - BindInstr* instr) { |
| +void FlowGraphTypePropagator::VisitBlocks() { |
| + ASSERT(current_iterator_ == NULL); |
| + for (intptr_t i = 0; i < block_order_.length(); ++i) { |
| + BlockEntryInstr* entry = block_order_[i]; |
| + entry->Accept(this); |
| + ForwardInstructionIterator it(entry); |
| + current_iterator_ = ⁢ |
| + for (; !it.Done(); it.Advance()) { |
| + Instruction* current = it.Current(); |
| + // No need to propagate the input types of the instruction, as long as |
| + // PhiInstr's are handled as part of JoinEntryInstr. |
| + |
| + // Visit the instruction and possibly eliminate type checks. |
| + current->Accept(this); |
| + // The instruction may have been removed from the graph. |
| + Definition* defn = current->AsDefinition(); |
| + if ((defn != NULL) && |
| + !defn->IsPushArgument() && |
|
Kevin Millikin (Google)
2012/09/05 12:50:09
This line is added.
|
| + (defn->previous() != NULL)) { |
| + // Cache the propagated computation type. |
| + AbstractType& type = AbstractType::Handle(defn->CompileType()); |
| + still_changing_ = defn->SetPropagatedType(type) || still_changing_; |
| + |
| + // Propagate class ids. |
| + const intptr_t cid = defn->ResultCid(); |
| + still_changing_ = defn->SetPropagatedCid(cid) || still_changing_; |
| + } |
| + } |
| + current_iterator_ = NULL; |
| + } |
| +} |
| + |
| + |
| +void FlowGraphTypePropagator::VisitAssertAssignable( |
| + AssertAssignableInstr* instr) { |
| if (FLAG_eliminate_type_checks && |
| - !comp->is_eliminated() && |
| - comp->value()->CompileTypeIsMoreSpecificThan(comp->dst_type())) { |
| + !instr->is_eliminated() && |
| + instr->value()->CompileTypeIsMoreSpecificThan(instr->dst_type())) { |
| // TODO(regis): Remove is_eliminated_ field and support. |
| - comp->eliminate(); |
| + instr->eliminate(); |
| - Value* use = comp->value(); |
| + Value* use = instr->value(); |
| ASSERT(use != NULL); |
| Definition* result = use->definition(); |
| ASSERT(result != NULL); |
| - // Replace uses and remove the current instructions via the iterator. |
| + // Replace uses and remove the current instruction via the iterator. |
| instr->ReplaceUsesWith(result); |
| ASSERT(current_iterator()->Current() == instr); |
| current_iterator()->RemoveCurrentFromGraph(); |
| @@ -915,18 +924,17 @@ void FlowGraphTypePropagator::VisitAssertAssignable(AssertAssignableComp* comp, |
| if (FLAG_trace_type_check_elimination) { |
| FlowGraphPrinter::PrintTypeCheck(parsed_function(), |
| - comp->token_pos(), |
| - comp->value(), |
| - comp->dst_type(), |
| - comp->dst_name(), |
| - comp->is_eliminated()); |
| + instr->token_pos(), |
| + instr->value(), |
| + instr->dst_type(), |
| + instr->dst_name(), |
| + instr->is_eliminated()); |
| } |
| } |
| } |
| -void FlowGraphTypePropagator::VisitAssertBoolean(AssertBooleanComp* comp, |
| - BindInstr* instr) { |
| +void FlowGraphTypePropagator::VisitAssertBoolean(AssertBooleanInstr* instr) { |
| // TODO(regis): Propagate NullType as well and revise the comment and code |
| // below to also eliminate the test for non-null and non-constant value. |
| @@ -934,18 +942,18 @@ void FlowGraphTypePropagator::VisitAssertBoolean(AssertBooleanComp* comp, |
| // a constant time constant. Indeed, a variable of the proper compile time |
| // type (bool) may still hold null at run time and therefore fail the test. |
| if (FLAG_eliminate_type_checks && |
| - !comp->is_eliminated() && |
| - comp->value()->BindsToConstant() && |
| - !comp->value()->BindsToConstantNull() && |
| - comp->value()->CompileTypeIsMoreSpecificThan( |
| + !instr->is_eliminated() && |
| + instr->value()->BindsToConstant() && |
| + !instr->value()->BindsToConstantNull() && |
| + instr->value()->CompileTypeIsMoreSpecificThan( |
| Type::Handle(Type::BoolType()))) { |
| // TODO(regis): Remove is_eliminated_ field and support. |
| - comp->eliminate(); |
| + instr->eliminate(); |
| - Value* use = comp->value(); |
| + Value* use = instr->value(); |
| Definition* result = use->definition(); |
| ASSERT(result != NULL); |
| - // Replace uses and remove the current instructions via the iterator. |
| + // Replace uses and remove the current instruction via the iterator. |
| instr->ReplaceUsesWith(result); |
| ASSERT(current_iterator()->Current() == instr); |
| current_iterator()->RemoveCurrentFromGraph(); |
| @@ -958,18 +966,17 @@ void FlowGraphTypePropagator::VisitAssertBoolean(AssertBooleanComp* comp, |
| if (FLAG_trace_type_check_elimination) { |
| const String& name = String::Handle(Symbols::New("boolean expression")); |
| FlowGraphPrinter::PrintTypeCheck(parsed_function(), |
| - comp->token_pos(), |
| - comp->value(), |
| + instr->token_pos(), |
| + instr->value(), |
| Type::Handle(Type::BoolType()), |
| name, |
| - comp->is_eliminated()); |
| + instr->is_eliminated()); |
| } |
| } |
| } |
| -void FlowGraphTypePropagator::VisitInstanceOf(InstanceOfComp* comp, |
| - BindInstr* instr) { |
| +void FlowGraphTypePropagator::VisitInstanceOf(InstanceOfInstr* instr) { |
| // TODO(regis): Propagate NullType as well and revise the comment and code |
| // below to also eliminate the test for non-null and non-constant value. |
| @@ -979,13 +986,13 @@ void FlowGraphTypePropagator::VisitInstanceOf(InstanceOfComp* comp, |
| // We do not bother checking for Object destination type, since the graph |
| // builder did already. |
| if (FLAG_eliminate_type_checks && |
| - comp->value()->BindsToConstant() && |
| - !comp->value()->BindsToConstantNull() && |
| - comp->value()->CompileTypeIsMoreSpecificThan(comp->type())) { |
| - Value* use = comp->value(); |
| + instr->value()->BindsToConstant() && |
| + !instr->value()->BindsToConstantNull() && |
| + instr->value()->CompileTypeIsMoreSpecificThan(instr->type())) { |
| + Value* use = instr->value(); |
| Definition* result = use->definition(); |
| ASSERT(result != NULL); |
| - // Replace uses and remove the current instructions via the iterator. |
| + // Replace uses and remove the current instruction via the iterator. |
| instr->ReplaceUsesWith(result); |
| ASSERT(current_iterator()->Current() == instr); |
| current_iterator()->RemoveCurrentFromGraph(); |
| @@ -998,9 +1005,9 @@ void FlowGraphTypePropagator::VisitInstanceOf(InstanceOfComp* comp, |
| if (FLAG_trace_type_check_elimination) { |
| const String& name = String::Handle(Symbols::New("InstanceOf")); |
| FlowGraphPrinter::PrintTypeCheck(parsed_function(), |
| - comp->token_pos(), |
| - comp->value(), |
| - comp->type(), |
| + instr->token_pos(), |
| + instr->value(), |
| + instr->type(), |
| name, |
| /* eliminated = */ true); |
| } |
| @@ -1042,31 +1049,6 @@ void FlowGraphTypePropagator::VisitPushArgument(PushArgumentInstr* push) { |
| } |
| -void FlowGraphTypePropagator::VisitBind(BindInstr* bind) { |
| - // No need to propagate the input types of the bound computation, as long as |
| - // PhiInstr's are handled as part of JoinEntryInstr. |
| - // Visit computation and possibly eliminate type check. |
| - bind->computation()->Accept(this, bind); |
| - // The current bind may have been removed from the graph. |
| - if (current_iterator()->Current() == bind) { |
| - // Current bind was not removed. |
| - // Cache propagated computation type. |
| - AbstractType& computation_type = |
| - AbstractType::Handle(bind->computation()->CompileType()); |
| - bool changed = bind->SetPropagatedType(computation_type); |
| - if (changed) { |
| - still_changing_ = true; |
| - } |
| - // Propagate class ids. |
| - const intptr_t cid = bind->computation()->ResultCid(); |
| - changed = bind->SetPropagatedCid(cid); |
| - if (changed) { |
| - still_changing_ = true; |
| - } |
| - } |
| -} |
| - |
| - |
| void FlowGraphTypePropagator::VisitPhi(PhiInstr* phi) { |
| // We could set the propagated type of the phi to the least upper bound of its |
| // input propagated types. However, keeping all propagated types allows us to |
| @@ -1165,28 +1147,28 @@ void FlowGraphAnalyzer::Analyze() { |
| void DominatorBasedCSE::Optimize(BlockEntryInstr* graph_entry) { |
| ASSERT(graph_entry->IsGraphEntry()); |
| - DirectChainedHashMap<BindInstr*> map; |
| + DirectChainedHashMap<Definition*> map; |
| OptimizeRecursive(graph_entry, &map); |
| } |
| void DominatorBasedCSE::OptimizeRecursive( |
| BlockEntryInstr* block, |
| - DirectChainedHashMap<BindInstr*>* map) { |
| + DirectChainedHashMap<Definition*>* map) { |
| for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { |
| - BindInstr* instr = it.Current()->AsBind(); |
| - if (instr == NULL || instr->computation()->HasSideEffect()) continue; |
| - BindInstr* result = map->Lookup(instr); |
| + Definition* defn = it.Current()->AsDefinition(); |
| + if ((defn == NULL) || defn->HasSideEffect()) continue; |
| + Definition* result = map->Lookup(defn); |
| if (result == NULL) { |
| - map->Insert(instr); |
| + map->Insert(defn); |
| continue; |
| } |
| // Replace current with lookup result. |
| - instr->ReplaceUsesWith(result); |
| + defn->ReplaceUsesWith(result); |
| it.RemoveCurrentFromGraph(); |
| if (FLAG_trace_optimization) { |
| OS::Print("Replacing v%d with v%d\n", |
| - instr->ssa_temp_index(), |
| + defn->ssa_temp_index(), |
| result->ssa_temp_index()); |
| } |
| } |
| @@ -1196,7 +1178,7 @@ void DominatorBasedCSE::OptimizeRecursive( |
| for (intptr_t i = 0; i < num_children; ++i) { |
| BlockEntryInstr* child = block->dominated_blocks()[i]; |
| if (i < num_children - 1) { |
| - DirectChainedHashMap<BindInstr*> child_map(*map); // Copy map. |
| + DirectChainedHashMap<Definition*> child_map(*map); // Copy map. |
| OptimizeRecursive(child, &child_map); |
| } else { |
| OptimizeRecursive(child, map); // Reuse map for the last child. |