| 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..0d1bd26cff0e6a9ba55828fb3a266d05a642aeeb 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,50 @@ 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->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 +922,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 +940,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 +964,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 +984,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 +1003,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 +1047,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 +1145,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 +1176,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.
|
|
|