Index: runtime/vm/flow_graph_optimizer.cc |
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc |
index 45a2670e554bbd70d2ba864751c7bc3f2ffae6ff..9f67fa2ca1f0785be8960a591f57a520f01f2df3 100644 |
--- a/runtime/vm/flow_graph_optimizer.cc |
+++ b/runtime/vm/flow_graph_optimizer.cc |
@@ -54,6 +54,107 @@ void FlowGraphOptimizer::OptimizeComputations() { |
} |
+static Computation* CreateConversion(Representation from, |
+ Representation to, |
+ Definition* def, |
+ Instruction* deopt_target) { |
+ if ((from == kUnboxedDouble) && (to == kTagged)) { |
+ return new BoxDoubleComp(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); |
+ } else { |
+ UNREACHABLE(); |
+ return NULL; |
+ } |
+} |
+ |
+ |
+void FlowGraphOptimizer::InsertConversionsFor(Definition* def) { |
+ const Representation from_rep = def->representation(); |
+ |
+ for (Value* use = def->input_use_list(); |
+ use != NULL; |
+ use = use->next_use()) { |
+ const Representation to_rep = |
+ use->instruction()->RequiredInputRepresentation(use->use_index()); |
+ if (from_rep == to_rep) { |
+ continue; |
+ } |
+ |
+ Instruction* deopt_target = NULL; |
+ Instruction* instr = use->instruction(); |
+ if (instr->IsPhi()) { |
+ if (!instr->AsPhi()->is_alive()) continue; |
+ |
+ // For phis conversions have to be inserted in the predecessor. |
+ const BlockEntryInstr* pred = |
+ instr->AsPhi()->block()->PredecessorAt(use->use_index()); |
+ instr = pred->last_instruction(); |
+ } else { |
+ deopt_target = instr; |
+ } |
+ |
+ BindInstr* converted = InsertBefore( |
+ instr, |
+ CreateConversion(from_rep, to_rep, def, deopt_target), |
+ use->instruction()->env(), |
+ BindInstr::kUsed); |
+ |
+ 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) { |
+ JoinEntryInstr* join_entry = block_order_[i]->AsJoinEntry(); |
+ if (join_entry == NULL) continue; |
+ |
+ if (join_entry->phis() != NULL) { |
+ for (intptr_t i = 0; i < join_entry->phis()->length(); ++i) { |
+ PhiInstr* phi = (*join_entry->phis())[i]; |
+ if ((phi != NULL) && (phi->GetPropagatedCid() == kDoubleCid)) { |
+ phi->set_representation(kUnboxedDouble); |
+ } |
+ } |
+ } |
+ } |
+ |
+ // Process all instructions and insert conversions where needed. |
+ GraphEntryInstr* graph_entry = block_order_[0]->AsGraphEntry(); |
+ |
+ // Visit incoming parameters. |
+ for (intptr_t i = 0; i < graph_entry->start_env()->values().length(); i++) { |
+ Value* val = graph_entry->start_env()->values()[i]; |
+ InsertConversionsFor(val->definition()); |
+ } |
+ |
+ for (intptr_t i = 0; i < block_order_.length(); ++i) { |
+ BlockEntryInstr* entry = block_order_[i]; |
+ |
+ JoinEntryInstr* join_entry = entry->AsJoinEntry(); |
+ if ((join_entry != NULL) && (join_entry->phis() != NULL)) { |
+ for (intptr_t i = 0; i < join_entry->phis()->length(); ++i) { |
+ PhiInstr* phi = (*join_entry->phis())[i]; |
+ if ((phi != NULL) && (phi->is_alive())) { |
+ InsertConversionsFor(phi); |
+ } |
+ } |
+ } |
+ |
+ for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) { |
+ Definition* def = it.Current()->AsDefinition(); |
+ if (def != NULL) { |
+ InsertConversionsFor(def); |
+ } |
+ } |
+ } |
+} |
+ |
+ |
static bool ICDataHasReceiverClassId(const ICData& ic_data, intptr_t class_id) { |
ASSERT(ic_data.num_args_tested() > 0); |
for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { |
@@ -341,39 +442,20 @@ bool FlowGraphOptimizer::TryReplaceWithBinaryOp(BindInstr* instr, |
// 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, right, comp), |
+ new CheckEitherNonSmiComp(left->Copy(), |
+ right->Copy(), |
+ comp), |
instr->env(), |
BindInstr::kUnused); |
- // Unbox operands. |
- BindInstr* unbox_left = InsertBefore( |
- instr, |
- new UnboxDoubleComp(left->Copy(), comp), |
- instr->env(), |
- BindInstr::kUsed); |
- BindInstr* unbox_right = InsertBefore( |
- instr, |
- new UnboxDoubleComp(right->Copy(), comp), |
- instr->env(), |
- BindInstr::kUsed); |
- |
UnboxedDoubleBinaryOpComp* double_bin_op = |
new UnboxedDoubleBinaryOpComp(op_kind, |
- new Value(unbox_left), |
- new Value(unbox_right)); |
+ left->Copy(), |
+ right->Copy(), |
+ comp); |
double_bin_op->set_ic_data(comp->ic_data()); |
instr->set_computation(double_bin_op); |
- if (instr->is_used()) { |
- // Box result. |
- Value* value = new Value(instr); |
- BindInstr* bind = InsertAfter(instr, |
- new BoxDoubleComp(value, comp), |
- NULL, |
- BindInstr::kUsed); |
- instr->ReplaceUsesWith(bind); |
- } |
- |
RemovePushArguments(comp); |
} else { |
BinaryDoubleOpComp* double_bin_op = new BinaryDoubleOpComp(op_kind, comp); |