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