| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/flow_graph_optimizer.h" | 5 #include "vm/flow_graph_optimizer.h" |
| 6 | 6 |
| 7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
| 8 #include "vm/cha.h" | 8 #include "vm/cha.h" |
| 9 #include "vm/flow_graph_builder.h" | 9 #include "vm/flow_graph_builder.h" |
| 10 #include "vm/flow_graph_compiler.h" | 10 #include "vm/flow_graph_compiler.h" |
| (...skipping 15 matching lines...) Expand all Loading... |
| 26 DEFINE_FLAG(bool, use_cha, true, "Use class hierarchy analysis."); | 26 DEFINE_FLAG(bool, use_cha, true, "Use class hierarchy analysis."); |
| 27 DEFINE_FLAG(bool, load_cse, true, "Use redundant load elimination."); | 27 DEFINE_FLAG(bool, load_cse, true, "Use redundant load elimination."); |
| 28 DEFINE_FLAG(bool, trace_range_analysis, false, "Trace range analysis progress"); | 28 DEFINE_FLAG(bool, trace_range_analysis, false, "Trace range analysis progress"); |
| 29 DEFINE_FLAG(bool, trace_constant_propagation, false, | 29 DEFINE_FLAG(bool, trace_constant_propagation, false, |
| 30 "Print constant propagation and useless code elimination."); | 30 "Print constant propagation and useless code elimination."); |
| 31 DEFINE_FLAG(bool, array_bounds_check_elimination, true, | 31 DEFINE_FLAG(bool, array_bounds_check_elimination, true, |
| 32 "Eliminate redundant bounds checks."); | 32 "Eliminate redundant bounds checks."); |
| 33 DEFINE_FLAG(int, max_polymorphic_checks, 4, | 33 DEFINE_FLAG(int, max_polymorphic_checks, 4, |
| 34 "Maximum number of polymorphic check, otherwise it is megamorphic."); | 34 "Maximum number of polymorphic check, otherwise it is megamorphic."); |
| 35 DEFINE_FLAG(bool, remove_redundant_phis, true, "Remove redundant phis."); | 35 DEFINE_FLAG(bool, remove_redundant_phis, true, "Remove redundant phis."); |
| 36 DEFINE_FLAG(bool, truncating_left_shift, true, |
| 37 "Optimize left shift to truncate if possible"); |
| 36 | 38 |
| 37 | 39 |
| 38 void FlowGraphOptimizer::ApplyICData() { | 40 void FlowGraphOptimizer::ApplyICData() { |
| 39 VisitBlocks(); | 41 VisitBlocks(); |
| 40 } | 42 } |
| 41 | 43 |
| 42 | 44 |
| 43 // Attempts to convert an instance call (IC call) using propagated class-ids, | 45 // Attempts to convert an instance call (IC call) using propagated class-ids, |
| 44 // e.g., receiver class id. | 46 // e.g., receiver class id. |
| 45 void FlowGraphOptimizer::ApplyClassIds() { | 47 void FlowGraphOptimizer::ApplyClassIds() { |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 160 | 162 |
| 161 const bool with_checks = false; | 163 const bool with_checks = false; |
| 162 PolymorphicInstanceCallInstr* specialized = | 164 PolymorphicInstanceCallInstr* specialized = |
| 163 new PolymorphicInstanceCallInstr(call->instance_call(), | 165 new PolymorphicInstanceCallInstr(call->instance_call(), |
| 164 ic_data, | 166 ic_data, |
| 165 with_checks); | 167 with_checks); |
| 166 call->ReplaceWith(specialized, current_iterator()); | 168 call->ReplaceWith(specialized, current_iterator()); |
| 167 } | 169 } |
| 168 | 170 |
| 169 | 171 |
| 172 static BinarySmiOpInstr* AsSmiShiftLeftInstruction(Definition* d) { |
| 173 BinarySmiOpInstr* instr = d->AsBinarySmiOp(); |
| 174 if ((instr != NULL) && (instr->op_kind() == Token::kSHL)) { |
| 175 return instr; |
| 176 } |
| 177 return NULL; |
| 178 } |
| 179 |
| 180 |
| 181 static bool IsPositiveOrZeroSmiConst(Definition* d) { |
| 182 ConstantInstr* const_instr = d->AsConstant(); |
| 183 if ((const_instr != NULL) && (const_instr->value().IsSmi())) { |
| 184 return Smi::Cast(const_instr->value()).Value() >= 0; |
| 185 } |
| 186 return false; |
| 187 } |
| 188 |
| 189 |
| 190 void FlowGraphOptimizer::OptimizeLeftShiftBitAndSmiOp( |
| 191 Definition* bit_and_instr, |
| 192 Definition* left_instr, |
| 193 Definition* right_instr) { |
| 194 ASSERT(bit_and_instr != NULL); |
| 195 ASSERT((left_instr != NULL) && (right_instr != NULL)); |
| 196 |
| 197 // Check for pattern, smi_shift_left must be single-use. |
| 198 bool is_positive_or_zero = IsPositiveOrZeroSmiConst(left_instr); |
| 199 if (!is_positive_or_zero) { |
| 200 is_positive_or_zero = IsPositiveOrZeroSmiConst(right_instr); |
| 201 } |
| 202 if (!is_positive_or_zero) return; |
| 203 |
| 204 BinarySmiOpInstr* smi_shift_left = NULL; |
| 205 if (bit_and_instr->InputAt(0)->IsSingleUse()) { |
| 206 smi_shift_left = AsSmiShiftLeftInstruction(left_instr); |
| 207 } |
| 208 if ((smi_shift_left == NULL) && (bit_and_instr->InputAt(1)->IsSingleUse())) { |
| 209 smi_shift_left = AsSmiShiftLeftInstruction(right_instr); |
| 210 } |
| 211 if (smi_shift_left == NULL) return; |
| 212 |
| 213 // Pattern recognized. |
| 214 smi_shift_left->set_is_truncating(true); |
| 215 ASSERT(bit_and_instr->IsBinarySmiOp() || bit_and_instr->IsBinaryMintOp()); |
| 216 if (bit_and_instr->IsBinaryMintOp()) { |
| 217 // Replace Mint op with Smi op. |
| 218 BinarySmiOpInstr* smi_op = new BinarySmiOpInstr( |
| 219 Token::kBIT_AND, |
| 220 bit_and_instr->AsBinaryMintOp()->instance_call(), |
| 221 new Value(left_instr), |
| 222 new Value(right_instr)); |
| 223 bit_and_instr->ReplaceWith(smi_op, current_iterator()); |
| 224 } |
| 225 } |
| 226 |
| 227 |
| 228 // Optimize (a << b) & c pattern: if c is a positive Smi or zero, then the |
| 229 // shift can be a truncating Smi shift-left and result is always Smi. |
| 230 void FlowGraphOptimizer::TryOptimizeLeftShiftWithBitAndPattern() { |
| 231 if (!FLAG_truncating_left_shift) return; |
| 232 ASSERT(current_iterator_ == NULL); |
| 233 for (intptr_t i = 0; i < block_order_.length(); ++i) { |
| 234 BlockEntryInstr* entry = block_order_[i]; |
| 235 ForwardInstructionIterator it(entry); |
| 236 current_iterator_ = ⁢ |
| 237 for (; !it.Done(); it.Advance()) { |
| 238 if (it.Current()->IsBinarySmiOp()) { |
| 239 BinarySmiOpInstr* binop = it.Current()->AsBinarySmiOp(); |
| 240 if (binop->op_kind() == Token::kBIT_AND) { |
| 241 OptimizeLeftShiftBitAndSmiOp(binop, |
| 242 binop->left()->definition(), |
| 243 binop->right()->definition()); |
| 244 } |
| 245 } else if (it.Current()->IsBinaryMintOp()) { |
| 246 BinaryMintOpInstr* mintop = it.Current()->AsBinaryMintOp(); |
| 247 if (mintop->op_kind() == Token::kBIT_AND) { |
| 248 OptimizeLeftShiftBitAndSmiOp(mintop, |
| 249 mintop->left()->definition(), |
| 250 mintop->right()->definition()); |
| 251 } |
| 252 } |
| 253 } |
| 254 current_iterator_ = NULL; |
| 255 } |
| 256 } |
| 257 |
| 258 |
| 170 static void EnsureSSATempIndex(FlowGraph* graph, | 259 static void EnsureSSATempIndex(FlowGraph* graph, |
| 171 Definition* defn, | 260 Definition* defn, |
| 172 Definition* replacement) { | 261 Definition* replacement) { |
| 173 if ((replacement->ssa_temp_index() == -1) && | 262 if ((replacement->ssa_temp_index() == -1) && |
| 174 (defn->ssa_temp_index() != -1)) { | 263 (defn->ssa_temp_index() != -1)) { |
| 175 replacement->set_ssa_temp_index(graph->alloc_ssa_temp_index()); | 264 replacement->set_ssa_temp_index(graph->alloc_ssa_temp_index()); |
| 176 } | 265 } |
| 177 } | 266 } |
| 178 | 267 |
| 179 | 268 |
| (...skipping 313 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 493 if (ic_data.NumberOfChecks() != 1) return kIllegalCid; | 582 if (ic_data.NumberOfChecks() != 1) return kIllegalCid; |
| 494 ASSERT(ic_data.HasOneTarget()); | 583 ASSERT(ic_data.HasOneTarget()); |
| 495 | 584 |
| 496 Function& target = Function::Handle(); | 585 Function& target = Function::Handle(); |
| 497 intptr_t class_id; | 586 intptr_t class_id; |
| 498 ic_data.GetOneClassCheckAt(0, &class_id, &target); | 587 ic_data.GetOneClassCheckAt(0, &class_id, &target); |
| 499 return class_id; | 588 return class_id; |
| 500 } | 589 } |
| 501 | 590 |
| 502 | 591 |
| 592 void FlowGraphOptimizer::AddCheckSmi(Definition* to_check, |
| 593 intptr_t deopt_id, |
| 594 Environment* deopt_environment, |
| 595 Instruction* insert_before) { |
| 596 if (to_check->Type()->ToCid() != kSmiCid) { |
| 597 InsertBefore(insert_before, |
| 598 new CheckSmiInstr(new Value(to_check), deopt_id), |
| 599 deopt_environment, |
| 600 Definition::kEffect); |
| 601 } |
| 602 } |
| 603 |
| 604 |
| 503 void FlowGraphOptimizer::AddCheckClass(Definition* to_check, | 605 void FlowGraphOptimizer::AddCheckClass(Definition* to_check, |
| 504 const ICData& unary_checks, | 606 const ICData& unary_checks, |
| 505 intptr_t deopt_id, | 607 intptr_t deopt_id, |
| 506 Environment* deopt_environment, | 608 Environment* deopt_environment, |
| 507 Instruction* insert_before) { | 609 Instruction* insert_before) { |
| 508 // Type propagation has not run yet, we cannot eliminate the check. | 610 // Type propagation has not run yet, we cannot eliminate the check. |
| 509 Instruction* check = NULL; | 611 Instruction* check = NULL; |
| 510 if ((unary_checks.NumberOfChecks() == 1) && | 612 if ((unary_checks.NumberOfChecks() == 1) && |
| 511 (unary_checks.GetReceiverClassIdAt(0) == kSmiCid)) { | 613 (unary_checks.GetReceiverClassIdAt(0) == kSmiCid)) { |
| 512 check = new CheckSmiInstr(new Value(to_check), deopt_id); | 614 check = new CheckSmiInstr(new Value(to_check), deopt_id); |
| (...skipping 491 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1004 InsertBefore(call, constant, NULL, Definition::kValue); | 1106 InsertBefore(call, constant, NULL, Definition::kValue); |
| 1005 BinarySmiOpInstr* bin_op = | 1107 BinarySmiOpInstr* bin_op = |
| 1006 new BinarySmiOpInstr(Token::kBIT_AND, call, | 1108 new BinarySmiOpInstr(Token::kBIT_AND, call, |
| 1007 new Value(left), | 1109 new Value(left), |
| 1008 new Value(constant)); | 1110 new Value(constant)); |
| 1009 ReplaceCall(call, bin_op); | 1111 ReplaceCall(call, bin_op); |
| 1010 } else { | 1112 } else { |
| 1011 ASSERT(operands_type == kSmiCid); | 1113 ASSERT(operands_type == kSmiCid); |
| 1012 // Insert two smi checks and attach a copy of the original | 1114 // Insert two smi checks and attach a copy of the original |
| 1013 // environment because the smi operation can still deoptimize. | 1115 // environment because the smi operation can still deoptimize. |
| 1014 InsertBefore(call, | 1116 AddCheckSmi(left, call->deopt_id(), call->env(), call); |
| 1015 new CheckSmiInstr(new Value(left), call->deopt_id()), | 1117 AddCheckSmi(right, call->deopt_id(), call->env(), call); |
| 1016 call->env(), | |
| 1017 Definition::kEffect); | |
| 1018 InsertBefore(call, | |
| 1019 new CheckSmiInstr(new Value(right), call->deopt_id()), | |
| 1020 call->env(), | |
| 1021 Definition::kEffect); | |
| 1022 if (left->IsConstant() && | 1118 if (left->IsConstant() && |
| 1023 ((op_kind == Token::kADD) || (op_kind == Token::kMUL))) { | 1119 ((op_kind == Token::kADD) || (op_kind == Token::kMUL))) { |
| 1024 // Constant should be on the right side. | 1120 // Constant should be on the right side. |
| 1025 Definition* temp = left; | 1121 Definition* temp = left; |
| 1026 left = right; | 1122 left = right; |
| 1027 right = temp; | 1123 right = temp; |
| 1028 } | 1124 } |
| 1029 BinarySmiOpInstr* bin_op = | 1125 BinarySmiOpInstr* bin_op = |
| 1030 new BinarySmiOpInstr(op_kind, call, new Value(left), new Value(right)); | 1126 new BinarySmiOpInstr(op_kind, call, new Value(left), new Value(right)); |
| 1031 ReplaceCall(call, bin_op); | 1127 ReplaceCall(call, bin_op); |
| (...skipping 3240 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4272 | 4368 |
| 4273 if (FLAG_trace_constant_propagation) { | 4369 if (FLAG_trace_constant_propagation) { |
| 4274 OS::Print("\n==== After constant propagation ====\n"); | 4370 OS::Print("\n==== After constant propagation ====\n"); |
| 4275 FlowGraphPrinter printer(*graph_); | 4371 FlowGraphPrinter printer(*graph_); |
| 4276 printer.PrintBlocks(); | 4372 printer.PrintBlocks(); |
| 4277 } | 4373 } |
| 4278 } | 4374 } |
| 4279 | 4375 |
| 4280 | 4376 |
| 4281 } // namespace dart | 4377 } // namespace dart |
| OLD | NEW |