Index: runtime/vm/flow_graph_optimizer.cc |
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc |
index d5bdaa68d2d9a469365b9cb0b5914b686936ad6a..94805979b711fd14c9006e56aaad9d194a38ddf2 100644 |
--- a/runtime/vm/flow_graph_optimizer.cc |
+++ b/runtime/vm/flow_graph_optimizer.cc |
@@ -20,6 +20,7 @@ DECLARE_FLAG(bool, enable_type_checks); |
DEFINE_FLAG(bool, trace_optimization, false, "Print optimization details."); |
DECLARE_FLAG(bool, trace_type_check_elimination); |
DEFINE_FLAG(bool, use_cha, true, "Use class hierarchy analysis."); |
+DEFINE_FLAG(bool, use_unboxed_doubles, true, "Try unboxing double values."); |
void FlowGraphOptimizer::ApplyICData() { |
VisitBlocks(); |
@@ -191,28 +192,15 @@ static intptr_t ReceiverClassId(Computation* comp) { |
} |
-// Insert a check computation before an instruction and set the environment |
-// of the check to the same as the instruction. |
-static void InsertCheckBefore(BindInstr* instr, |
- Computation* check, |
- Environment* env) { |
- BindInstr* check_instr = new BindInstr(BindInstr::kUnused, check); |
- check_instr->InsertBefore(instr); |
- ASSERT(env != NULL); |
- // Attach an environment to the check instruction. |
- check_instr->set_env(env); |
-} |
- |
- |
-static void AddCheckClass(BindInstr* instr, |
- InstanceCallComp* comp, |
- Value* value) { |
+void FlowGraphOptimizer::AddCheckClass(BindInstr* instr, |
+ InstanceCallComp* comp, |
+ Value* value) { |
// Type propagation has not run yet, we cannot eliminate the check. |
CheckClassComp* check = new CheckClassComp(value, comp); |
const ICData& unary_checks = |
ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecks()); |
check->set_ic_data(&unary_checks); |
- InsertCheckBefore(instr, check, instr->env()); |
+ InsertBefore(instr, check, instr->env(), BindInstr::kUnused); |
// Detach environment from the original instruction because it can't |
// deoptimize. |
instr->set_env(NULL); |
@@ -258,6 +246,34 @@ 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) bind->set_env(env->Copy()); |
+ if (use_kind == BindInstr::kUsed) { |
+ bind->set_ssa_temp_index(flow_graph_->alloc_ssa_temp_index()); |
+ } |
+ bind->InsertBefore(instr); |
+ return bind; |
+} |
+ |
+ |
+BindInstr* FlowGraphOptimizer::InsertAfter(Instruction* instr, |
+ Computation* comp, |
+ Environment* env, |
+ BindInstr::UseKind use_kind) { |
+ BindInstr* bind = new BindInstr(use_kind, comp); |
+ if (env != NULL) bind->set_env(env->Copy()); |
+ if (use_kind == BindInstr::kUsed) { |
+ bind->set_ssa_temp_index(flow_graph_->alloc_ssa_temp_index()); |
+ } |
+ bind->InsertAfter(instr); |
+ return bind; |
+} |
+ |
+ |
bool FlowGraphOptimizer::TryReplaceWithBinaryOp(BindInstr* instr, |
InstanceCallComp* comp, |
Token::Kind op_kind) { |
@@ -309,9 +325,52 @@ bool FlowGraphOptimizer::TryReplaceWithBinaryOp(BindInstr* instr, |
ASSERT(comp->ArgumentCount() == 2); |
if (operands_type == kDoubleCid) { |
- BinaryDoubleOpComp* double_bin_op = new BinaryDoubleOpComp(op_kind, comp); |
- double_bin_op->set_ic_data(comp->ic_data()); |
- instr->set_computation(double_bin_op); |
+ if (FLAG_use_unboxed_doubles) { |
+ Value* left = comp->ArgumentAt(0)->value(); |
+ Value* right = comp->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, right, comp), |
+ instr->env(), |
+ BindInstr::kUnused); |
+ |
+ // Unbox operands. |
+ BindInstr* unbox_left = InsertBefore( |
+ instr, |
+ new UnboxDoubleComp(left->CopyValue(), comp), |
+ instr->env(), |
+ BindInstr::kUsed); |
+ BindInstr* unbox_right = InsertBefore( |
+ instr, |
+ new UnboxDoubleComp(right->CopyValue(), comp), |
+ instr->env(), |
+ BindInstr::kUsed); |
+ |
+ UnboxedDoubleBinaryOpComp* double_bin_op = |
+ new UnboxedDoubleBinaryOpComp(op_kind, |
+ new UseVal(unbox_left), |
+ new UseVal(unbox_right)); |
+ double_bin_op->set_ic_data(comp->ic_data()); |
+ instr->set_computation(double_bin_op); |
+ |
+ if (instr->is_used()) { |
+ // Box result. |
+ UseVal* use_val = new UseVal(instr); |
+ BindInstr* bind = InsertAfter(instr, |
+ new BoxDoubleComp(use_val, comp), |
+ NULL, |
+ BindInstr::kUsed); |
+ instr->ReplaceUsesWith(bind); |
+ } |
+ |
+ RemovePushArguments(comp); |
+ } else { |
+ BinaryDoubleOpComp* double_bin_op = new BinaryDoubleOpComp(op_kind, comp); |
+ double_bin_op->set_ic_data(comp->ic_data()); |
+ instr->set_computation(double_bin_op); |
+ } |
} else if (operands_type == kMintCid) { |
Value* left = comp->ArgumentAt(0)->value(); |
Value* right = comp->ArgumentAt(1)->value(); |
@@ -328,12 +387,14 @@ bool FlowGraphOptimizer::TryReplaceWithBinaryOp(BindInstr* instr, |
Value* right = comp->ArgumentAt(1)->value(); |
// Insert two smi checks and attach a copy of the original |
// environment because the smi operation can still deoptimize. |
- InsertCheckBefore(instr, |
- new CheckSmiComp(left->CopyValue(), comp), |
- instr->env()->Copy()); |
- InsertCheckBefore(instr, |
- new CheckSmiComp(right->CopyValue(), comp), |
- instr->env()->Copy()); |
+ InsertBefore(instr, |
+ new CheckSmiComp(left->CopyValue(), comp), |
+ instr->env(), |
+ BindInstr::kUnused); |
+ InsertBefore(instr, |
+ new CheckSmiComp(right->CopyValue(), comp), |
+ instr->env(), |
+ BindInstr::kUnused); |
BinarySmiOpComp* bin_op = new BinarySmiOpComp(op_kind, |
comp, |
left, |
@@ -548,7 +609,7 @@ void FlowGraphOptimizer::VisitInstanceCall(InstanceCallComp* comp, |
// Type propagation has not run yet, we cannot eliminate the check. |
CheckClassComp* check = new CheckClassComp(value, comp); |
check->set_ic_data(&unary_checks); |
- InsertCheckBefore(instr, check, instr->env()->Copy()); |
+ InsertBefore(instr, check, instr->env(), BindInstr::kUnused); |
// Call can still deoptimize, do not detach environment from instr. |
call_with_checks = false; |
} else { |