| 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 288 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 299 } | 299 } |
| 300 } | 300 } |
| 301 iterator->RemoveCurrentFromGraph(); | 301 iterator->RemoveCurrentFromGraph(); |
| 302 } | 302 } |
| 303 | 303 |
| 304 | 304 |
| 305 bool FlowGraphOptimizer::Canonicalize() { | 305 bool FlowGraphOptimizer::Canonicalize() { |
| 306 bool changed = false; | 306 bool changed = false; |
| 307 for (intptr_t i = 0; i < block_order_.length(); ++i) { | 307 for (intptr_t i = 0; i < block_order_.length(); ++i) { |
| 308 BlockEntryInstr* entry = block_order_[i]; | 308 BlockEntryInstr* entry = block_order_[i]; |
| 309 entry->Accept(this); | |
| 310 for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) { | 309 for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) { |
| 311 Instruction* current = it.Current(); | 310 Instruction* current = it.Current(); |
| 312 Instruction* replacement = current->Canonicalize(this); | 311 Instruction* replacement = current->Canonicalize(flow_graph()); |
| 313 if (replacement != current) { | 312 if (replacement != current) { |
| 314 // For non-definitions Canonicalize should return either NULL or | 313 // For non-definitions Canonicalize should return either NULL or |
| 315 // this. | 314 // this. |
| 316 ASSERT((replacement == NULL) || current->IsDefinition()); | 315 ASSERT((replacement == NULL) || current->IsDefinition()); |
| 317 ReplaceCurrentInstruction(&it, current, replacement, flow_graph_); | 316 ReplaceCurrentInstruction(&it, current, replacement, flow_graph_); |
| 318 changed = true; | 317 changed = true; |
| 319 } | 318 } |
| 320 } | 319 } |
| 321 } | 320 } |
| 322 return changed; | 321 return changed; |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 356 } else if ((from == kTagged) && (to == kUnboxedDouble)) { | 355 } else if ((from == kTagged) && (to == kUnboxedDouble)) { |
| 357 ASSERT((deopt_target != NULL) || | 356 ASSERT((deopt_target != NULL) || |
| 358 (use->Type()->ToCid() == kDoubleCid)); | 357 (use->Type()->ToCid() == kDoubleCid)); |
| 359 const intptr_t deopt_id = (deopt_target != NULL) ? | 358 const intptr_t deopt_id = (deopt_target != NULL) ? |
| 360 deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId; | 359 deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId; |
| 361 ConstantInstr* constant = use->definition()->AsConstant(); | 360 ConstantInstr* constant = use->definition()->AsConstant(); |
| 362 if ((constant != NULL) && constant->value().IsSmi()) { | 361 if ((constant != NULL) && constant->value().IsSmi()) { |
| 363 const double dbl_val = Smi::Cast(constant->value()).AsDoubleValue(); | 362 const double dbl_val = Smi::Cast(constant->value()).AsDoubleValue(); |
| 364 const Double& dbl_obj = | 363 const Double& dbl_obj = |
| 365 Double::ZoneHandle(Double::New(dbl_val, Heap::kOld)); | 364 Double::ZoneHandle(Double::New(dbl_val, Heap::kOld)); |
| 366 ConstantInstr* double_const = new ConstantInstr(dbl_obj); | 365 ConstantInstr* double_const = flow_graph()->GetConstant(dbl_obj); |
| 367 InsertBefore(insert_before, double_const, NULL, Definition::kValue); | |
| 368 converted = new UnboxDoubleInstr(new Value(double_const), deopt_id); | 366 converted = new UnboxDoubleInstr(new Value(double_const), deopt_id); |
| 369 } else { | 367 } else { |
| 370 converted = new UnboxDoubleInstr(use->CopyWithType(), deopt_id); | 368 converted = new UnboxDoubleInstr(use->CopyWithType(), deopt_id); |
| 371 } | 369 } |
| 372 } else if ((from == kTagged) && (to == kUnboxedFloat32x4)) { | 370 } else if ((from == kTagged) && (to == kUnboxedFloat32x4)) { |
| 373 ASSERT((deopt_target != NULL) || | 371 ASSERT((deopt_target != NULL) || |
| 374 (use->Type()->ToCid() == kFloat32x4Cid)); | 372 (use->Type()->ToCid() == kFloat32x4Cid)); |
| 375 const intptr_t deopt_id = (deopt_target != NULL) ? | 373 const intptr_t deopt_id = (deopt_target != NULL) ? |
| 376 deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId; | 374 deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId; |
| 377 converted = new UnboxFloat32x4Instr(use->CopyWithType(), deopt_id); | 375 converted = new UnboxFloat32x4Instr(use->CopyWithType(), deopt_id); |
| (...skipping 746 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1124 const intptr_t value = Smi::Cast(obj).Value(); | 1122 const intptr_t value = Smi::Cast(obj).Value(); |
| 1125 if ((value <= 0) || !Utils::IsPowerOfTwo(value)) return false; | 1123 if ((value <= 0) || !Utils::IsPowerOfTwo(value)) return false; |
| 1126 | 1124 |
| 1127 // Insert smi check and attach a copy of the original environment | 1125 // Insert smi check and attach a copy of the original environment |
| 1128 // because the smi operation can still deoptimize. | 1126 // because the smi operation can still deoptimize. |
| 1129 InsertBefore(call, | 1127 InsertBefore(call, |
| 1130 new CheckSmiInstr(new Value(left), call->deopt_id()), | 1128 new CheckSmiInstr(new Value(left), call->deopt_id()), |
| 1131 call->env(), | 1129 call->env(), |
| 1132 Definition::kEffect); | 1130 Definition::kEffect); |
| 1133 ConstantInstr* constant = | 1131 ConstantInstr* constant = |
| 1134 new ConstantInstr(Smi::Handle(Smi::New(value - 1))); | 1132 flow_graph()->GetConstant(Smi::Handle(Smi::New(value - 1))); |
| 1135 InsertBefore(call, constant, NULL, Definition::kValue); | |
| 1136 BinarySmiOpInstr* bin_op = | 1133 BinarySmiOpInstr* bin_op = |
| 1137 new BinarySmiOpInstr(Token::kBIT_AND, call, | 1134 new BinarySmiOpInstr(Token::kBIT_AND, call, |
| 1138 new Value(left), | 1135 new Value(left), |
| 1139 new Value(constant)); | 1136 new Value(constant)); |
| 1140 ReplaceCall(call, bin_op); | 1137 ReplaceCall(call, bin_op); |
| 1141 } else { | 1138 } else { |
| 1142 ASSERT(operands_type == kSmiCid); | 1139 ASSERT(operands_type == kSmiCid); |
| 1143 // Insert two smi checks and attach a copy of the original | 1140 // Insert two smi checks and attach a copy of the original |
| 1144 // environment because the smi operation can still deoptimize. | 1141 // environment because the smi operation can still deoptimize. |
| 1145 AddCheckSmi(left, call->deopt_id(), call->env(), call); | 1142 AddCheckSmi(left, call->deopt_id(), call->env(), call); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 1171 Definition::kEffect); | 1168 Definition::kEffect); |
| 1172 unary_op = new UnarySmiOpInstr(op_kind, call, new Value(input)); | 1169 unary_op = new UnarySmiOpInstr(op_kind, call, new Value(input)); |
| 1173 } else if ((op_kind == Token::kBIT_NOT) && | 1170 } else if ((op_kind == Token::kBIT_NOT) && |
| 1174 HasOnlySmiOrMint(*call->ic_data()) && | 1171 HasOnlySmiOrMint(*call->ic_data()) && |
| 1175 FlowGraphCompiler::SupportsUnboxedMints()) { | 1172 FlowGraphCompiler::SupportsUnboxedMints()) { |
| 1176 unary_op = new UnaryMintOpInstr(op_kind, new Value(input), call); | 1173 unary_op = new UnaryMintOpInstr(op_kind, new Value(input), call); |
| 1177 } else if (HasOnlyOneDouble(*call->ic_data()) && | 1174 } else if (HasOnlyOneDouble(*call->ic_data()) && |
| 1178 (op_kind == Token::kNEGATE)) { | 1175 (op_kind == Token::kNEGATE)) { |
| 1179 AddReceiverCheck(call); | 1176 AddReceiverCheck(call); |
| 1180 ConstantInstr* minus_one = | 1177 ConstantInstr* minus_one = |
| 1181 new ConstantInstr(Double::ZoneHandle(Double::NewCanonical(-1))); | 1178 flow_graph()->GetConstant(Double::ZoneHandle(Double::NewCanonical(-1))); |
| 1182 InsertBefore(call, minus_one, NULL, Definition::kValue); | |
| 1183 unary_op = new BinaryDoubleOpInstr(Token::kMUL, | 1179 unary_op = new BinaryDoubleOpInstr(Token::kMUL, |
| 1184 new Value(input), | 1180 new Value(input), |
| 1185 new Value(minus_one), | 1181 new Value(minus_one), |
| 1186 call); | 1182 call); |
| 1187 } | 1183 } |
| 1188 if (unary_op == NULL) return false; | 1184 if (unary_op == NULL) return false; |
| 1189 | 1185 |
| 1190 ReplaceCall(call, unary_op); | 1186 ReplaceCall(call, unary_op); |
| 1191 return true; | 1187 return true; |
| 1192 } | 1188 } |
| (...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1365 ReplaceCall(call, load); | 1361 ReplaceCall(call, load); |
| 1366 } | 1362 } |
| 1367 | 1363 |
| 1368 | 1364 |
| 1369 void FlowGraphOptimizer::InlineStringIsEmptyGetter(InstanceCallInstr* call) { | 1365 void FlowGraphOptimizer::InlineStringIsEmptyGetter(InstanceCallInstr* call) { |
| 1370 AddReceiverCheck(call); | 1366 AddReceiverCheck(call); |
| 1371 | 1367 |
| 1372 LoadFieldInstr* load = BuildLoadStringLength(call->ArgumentAt(0)); | 1368 LoadFieldInstr* load = BuildLoadStringLength(call->ArgumentAt(0)); |
| 1373 InsertBefore(call, load, NULL, Definition::kValue); | 1369 InsertBefore(call, load, NULL, Definition::kValue); |
| 1374 | 1370 |
| 1375 ConstantInstr* zero = new ConstantInstr(Smi::Handle(Smi::New(0))); | 1371 ConstantInstr* zero = flow_graph()->GetConstant(Smi::Handle(Smi::New(0))); |
| 1376 InsertBefore(call, zero, NULL, Definition::kValue); | |
| 1377 | |
| 1378 StrictCompareInstr* compare = | 1372 StrictCompareInstr* compare = |
| 1379 new StrictCompareInstr(Token::kEQ_STRICT, | 1373 new StrictCompareInstr(Token::kEQ_STRICT, |
| 1380 new Value(load), | 1374 new Value(load), |
| 1381 new Value(zero)); | 1375 new Value(zero)); |
| 1382 ReplaceCall(call, compare); | 1376 ReplaceCall(call, compare); |
| 1383 } | 1377 } |
| 1384 | 1378 |
| 1385 | 1379 |
| 1386 static intptr_t OffsetForLengthGetter(MethodRecognizer::Kind kind) { | 1380 static intptr_t OffsetForLengthGetter(MethodRecognizer::Kind kind) { |
| 1387 switch (kind) { | 1381 switch (kind) { |
| (...skipping 630 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2018 Type::ZoneHandle(Type::SmiType()), | 2012 Type::ZoneHandle(Type::SmiType()), |
| 2019 is_immutable); | 2013 is_immutable); |
| 2020 length->set_result_cid(kSmiCid); | 2014 length->set_result_cid(kSmiCid); |
| 2021 length->set_recognized_kind( | 2015 length->set_recognized_kind( |
| 2022 LoadFieldInstr::RecognizedKindFromArrayCid(receiver_cid)); | 2016 LoadFieldInstr::RecognizedKindFromArrayCid(receiver_cid)); |
| 2023 InsertBefore(call, length, NULL, Definition::kValue); | 2017 InsertBefore(call, length, NULL, Definition::kValue); |
| 2024 | 2018 |
| 2025 // len_in_bytes = length * kBytesPerElement(receiver) | 2019 // len_in_bytes = length * kBytesPerElement(receiver) |
| 2026 intptr_t element_size = FlowGraphCompiler::ElementSizeFor(receiver_cid); | 2020 intptr_t element_size = FlowGraphCompiler::ElementSizeFor(receiver_cid); |
| 2027 ConstantInstr* bytes_per_element = | 2021 ConstantInstr* bytes_per_element = |
| 2028 new ConstantInstr(Smi::Handle(Smi::New(element_size))); | 2022 flow_graph()->GetConstant(Smi::Handle(Smi::New(element_size))); |
| 2029 InsertBefore(call, bytes_per_element, NULL, Definition::kValue); | |
| 2030 BinarySmiOpInstr* len_in_bytes = | 2023 BinarySmiOpInstr* len_in_bytes = |
| 2031 new BinarySmiOpInstr(Token::kMUL, | 2024 new BinarySmiOpInstr(Token::kMUL, |
| 2032 call, | 2025 call, |
| 2033 new Value(length), | 2026 new Value(length), |
| 2034 new Value(bytes_per_element)); | 2027 new Value(bytes_per_element)); |
| 2035 InsertBefore(call, len_in_bytes, call->env(), Definition::kValue); | 2028 InsertBefore(call, len_in_bytes, call->env(), Definition::kValue); |
| 2036 | 2029 |
| 2037 // Check byte_index < len_in_bytes. | 2030 // Check byte_index < len_in_bytes. |
| 2038 InsertBefore(call, | 2031 InsertBefore(call, |
| 2039 new CheckArrayBoundInstr(new Value(len_in_bytes), | 2032 new CheckArrayBoundInstr(new Value(len_in_bytes), |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2106 Bool::Cast(call->ArgumentAt(4)->AsConstant()->value()).value(); | 2099 Bool::Cast(call->ArgumentAt(4)->AsConstant()->value()).value(); |
| 2107 const ICData& unary_checks = | 2100 const ICData& unary_checks = |
| 2108 ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecks()); | 2101 ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecks()); |
| 2109 if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) { | 2102 if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) { |
| 2110 Bool& as_bool = Bool::ZoneHandle(InstanceOfAsBool(unary_checks, type)); | 2103 Bool& as_bool = Bool::ZoneHandle(InstanceOfAsBool(unary_checks, type)); |
| 2111 if (!as_bool.IsNull()) { | 2104 if (!as_bool.IsNull()) { |
| 2112 AddReceiverCheck(call); | 2105 AddReceiverCheck(call); |
| 2113 if (negate) { | 2106 if (negate) { |
| 2114 as_bool = Bool::Get(!as_bool.value()); | 2107 as_bool = Bool::Get(!as_bool.value()); |
| 2115 } | 2108 } |
| 2116 ConstantInstr* bool_const = new ConstantInstr(as_bool); | 2109 ConstantInstr* bool_const = flow_graph()->GetConstant(as_bool); |
| 2117 ReplaceCall(call, bool_const); | 2110 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { |
| 2111 PushArgumentInstr* push = call->PushArgumentAt(i); |
| 2112 push->ReplaceUsesWith(push->value()->definition()); |
| 2113 push->RemoveFromGraph(); |
| 2114 } |
| 2115 call->ReplaceUsesWith(bool_const); |
| 2116 ASSERT(current_iterator()->Current() == call); |
| 2117 current_iterator()->RemoveCurrentFromGraph(); |
| 2118 return; | 2118 return; |
| 2119 } | 2119 } |
| 2120 } | 2120 } |
| 2121 InstanceOfInstr* instance_of = | 2121 InstanceOfInstr* instance_of = |
| 2122 new InstanceOfInstr(call->token_pos(), | 2122 new InstanceOfInstr(call->token_pos(), |
| 2123 new Value(left), | 2123 new Value(left), |
| 2124 new Value(instantiator), | 2124 new Value(instantiator), |
| 2125 new Value(type_args), | 2125 new Value(type_args), |
| 2126 type, | 2126 type, |
| 2127 negate, | 2127 negate, |
| (...skipping 544 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2672 | 2672 |
| 2673 void RangeAnalysis::Analyze() { | 2673 void RangeAnalysis::Analyze() { |
| 2674 CollectSmiValues(); | 2674 CollectSmiValues(); |
| 2675 InsertConstraints(); | 2675 InsertConstraints(); |
| 2676 InferRanges(); | 2676 InferRanges(); |
| 2677 RemoveConstraints(); | 2677 RemoveConstraints(); |
| 2678 } | 2678 } |
| 2679 | 2679 |
| 2680 | 2680 |
| 2681 void RangeAnalysis::CollectSmiValues() { | 2681 void RangeAnalysis::CollectSmiValues() { |
| 2682 const GrowableArray<Definition*>& initial = |
| 2683 *flow_graph_->graph_entry()->initial_definitions(); |
| 2684 for (intptr_t i = 0; i < initial.length(); ++i) { |
| 2685 Definition* current = initial[i]; |
| 2686 if (current->Type()->ToCid() == kSmiCid) { |
| 2687 smi_values_.Add(current); |
| 2688 } |
| 2689 } |
| 2690 |
| 2682 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); | 2691 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); |
| 2683 !block_it.Done(); | 2692 !block_it.Done(); |
| 2684 block_it.Advance()) { | 2693 block_it.Advance()) { |
| 2685 BlockEntryInstr* block = block_it.Current(); | 2694 BlockEntryInstr* block = block_it.Current(); |
| 2686 for (ForwardInstructionIterator instr_it(block); | 2695 for (ForwardInstructionIterator instr_it(block); |
| 2687 !instr_it.Done(); | 2696 !instr_it.Done(); |
| 2688 instr_it.Advance()) { | 2697 instr_it.Advance()) { |
| 2689 Instruction* current = instr_it.Current(); | 2698 Instruction* current = instr_it.Current(); |
| 2690 Definition* defn = current->AsDefinition(); | 2699 Definition* defn = current->AsDefinition(); |
| 2691 if (defn != NULL) { | 2700 if (defn != NULL) { |
| 2692 if ((defn->Type()->ToCid() == kSmiCid) && | 2701 if ((defn->Type()->ToCid() == kSmiCid) && |
| 2693 (defn->ssa_temp_index() != -1)) { | 2702 (defn->ssa_temp_index() != -1)) { |
| 2694 smi_values_.Add(defn); | 2703 smi_values_.Add(defn); |
| 2695 } | 2704 } |
| 2696 } else if (current->IsCheckSmi()) { | 2705 } else if (current->IsCheckSmi()) { |
| 2697 smi_checks_.Add(current->AsCheckSmi()); | 2706 smi_checks_.Add(current->AsCheckSmi()); |
| 2698 } | 2707 } |
| 2699 } | 2708 } |
| 2700 | 2709 |
| 2701 JoinEntryInstr* join = block->AsJoinEntry(); | 2710 JoinEntryInstr* join = block->AsJoinEntry(); |
| 2702 if (join != NULL) { | 2711 if (join != NULL) { |
| 2703 for (PhiIterator phi_it(join); !phi_it.Done(); phi_it.Advance()) { | 2712 for (PhiIterator phi_it(join); !phi_it.Done(); phi_it.Advance()) { |
| 2704 PhiInstr* current = phi_it.Current(); | 2713 PhiInstr* current = phi_it.Current(); |
| 2705 if ((current->Type()->ToCid() == kSmiCid)) { | 2714 if (current->Type()->ToCid() == kSmiCid) { |
| 2706 smi_values_.Add(current); | 2715 smi_values_.Add(current); |
| 2707 } | 2716 } |
| 2708 } | 2717 } |
| 2709 } | 2718 } |
| 2710 } | 2719 } |
| 2711 } | 2720 } |
| 2712 | 2721 |
| 2713 | 2722 |
| 2714 // Returns true if use is dominated by the given instruction. | 2723 // Returns true if use is dominated by the given instruction. |
| 2715 // Note: uses that occur at instruction itself are not dominated by it. | 2724 // Note: uses that occur at instruction itself are not dominated by it. |
| (...skipping 383 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3099 // Initialize bitvector for quick filtering of smi values. | 3108 // Initialize bitvector for quick filtering of smi values. |
| 3100 smi_definitions_ = new BitVector(flow_graph_->current_ssa_temp_index()); | 3109 smi_definitions_ = new BitVector(flow_graph_->current_ssa_temp_index()); |
| 3101 for (intptr_t i = 0; i < smi_values_.length(); i++) { | 3110 for (intptr_t i = 0; i < smi_values_.length(); i++) { |
| 3102 smi_definitions_->Add(smi_values_[i]->ssa_temp_index()); | 3111 smi_definitions_->Add(smi_values_[i]->ssa_temp_index()); |
| 3103 } | 3112 } |
| 3104 for (intptr_t i = 0; i < constraints_.length(); i++) { | 3113 for (intptr_t i = 0; i < constraints_.length(); i++) { |
| 3105 smi_definitions_->Add(constraints_[i]->ssa_temp_index()); | 3114 smi_definitions_->Add(constraints_[i]->ssa_temp_index()); |
| 3106 } | 3115 } |
| 3107 | 3116 |
| 3108 // Infer initial values of ranges. | 3117 // Infer initial values of ranges. |
| 3118 const GrowableArray<Definition*>& initial = |
| 3119 *flow_graph_->graph_entry()->initial_definitions(); |
| 3120 for (intptr_t i = 0; i < initial.length(); ++i) { |
| 3121 Definition* definition = initial[i]; |
| 3122 if (smi_definitions_->Contains(definition->ssa_temp_index())) { |
| 3123 definition->InferRange(); |
| 3124 } |
| 3125 } |
| 3109 InferRangesRecursive(flow_graph_->graph_entry()); | 3126 InferRangesRecursive(flow_graph_->graph_entry()); |
| 3110 | 3127 |
| 3111 if (FLAG_trace_range_analysis) { | 3128 if (FLAG_trace_range_analysis) { |
| 3112 OS::Print("---- after range analysis -------\n"); | 3129 OS::Print("---- after range analysis -------\n"); |
| 3113 FlowGraphPrinter printer(*flow_graph_); | 3130 FlowGraphPrinter printer(*flow_graph_); |
| 3114 printer.PrintBlocks(); | 3131 printer.PrintBlocks(); |
| 3115 } | 3132 } |
| 3116 } | 3133 } |
| 3117 | 3134 |
| 3118 | 3135 |
| (...skipping 2233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5352 !defn->IsPushArgument() && | 5369 !defn->IsPushArgument() && |
| 5353 !defn->IsStoreIndexed() && | 5370 !defn->IsStoreIndexed() && |
| 5354 !defn->IsStoreInstanceField() && | 5371 !defn->IsStoreInstanceField() && |
| 5355 !defn->IsStoreStaticField() && | 5372 !defn->IsStoreStaticField() && |
| 5356 !defn->IsStoreVMField()) { | 5373 !defn->IsStoreVMField()) { |
| 5357 if (FLAG_trace_constant_propagation) { | 5374 if (FLAG_trace_constant_propagation) { |
| 5358 OS::Print("Constant v%"Pd" = %s\n", | 5375 OS::Print("Constant v%"Pd" = %s\n", |
| 5359 defn->ssa_temp_index(), | 5376 defn->ssa_temp_index(), |
| 5360 defn->constant_value().ToCString()); | 5377 defn->constant_value().ToCString()); |
| 5361 } | 5378 } |
| 5362 defn->ReplaceWith(new ConstantInstr(defn->constant_value()), &i); | 5379 ConstantInstr* constant = graph_->GetConstant(defn->constant_value()); |
| 5380 defn->ReplaceUsesWith(constant); |
| 5381 i.RemoveCurrentFromGraph(); |
| 5363 } | 5382 } |
| 5364 } | 5383 } |
| 5365 | 5384 |
| 5366 // Replace branches where one target is unreachable with jumps. | 5385 // Replace branches where one target is unreachable with jumps. |
| 5367 BranchInstr* branch = block->last_instruction()->AsBranch(); | 5386 BranchInstr* branch = block->last_instruction()->AsBranch(); |
| 5368 if (branch != NULL) { | 5387 if (branch != NULL) { |
| 5369 TargetEntryInstr* if_true = branch->true_successor(); | 5388 TargetEntryInstr* if_true = branch->true_successor(); |
| 5370 TargetEntryInstr* if_false = branch->false_successor(); | 5389 TargetEntryInstr* if_false = branch->false_successor(); |
| 5371 JoinEntryInstr* join = NULL; | 5390 JoinEntryInstr* join = NULL; |
| 5372 Instruction* next = NULL; | 5391 Instruction* next = NULL; |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5442 } | 5461 } |
| 5443 | 5462 |
| 5444 | 5463 |
| 5445 bool BranchSimplifier::Match(JoinEntryInstr* block) { | 5464 bool BranchSimplifier::Match(JoinEntryInstr* block) { |
| 5446 // Match the pattern of a branch on a comparison whose left operand is a | 5465 // Match the pattern of a branch on a comparison whose left operand is a |
| 5447 // phi from the same block, and whose right operand is a constant. | 5466 // phi from the same block, and whose right operand is a constant. |
| 5448 // | 5467 // |
| 5449 // Branch(Comparison(kind, Phi, Constant)) | 5468 // Branch(Comparison(kind, Phi, Constant)) |
| 5450 // | 5469 // |
| 5451 // These are the branches produced by inlining in a test context. Also, | 5470 // These are the branches produced by inlining in a test context. Also, |
| 5452 // the phi and the constant have no other uses so they can simply be | 5471 // the phi has no other uses so they can simply be eliminated. The block |
| 5453 // eliminated. The block has no other phis and no instructions | 5472 // has no other phis and no instructions intervening between the phi and |
| 5454 // intervening between the phi, constant, and branch so the block can | 5473 // branch so the block can simply be eliminated. |
| 5455 // simply be eliminated. | |
| 5456 BranchInstr* branch = block->last_instruction()->AsBranch(); | 5474 BranchInstr* branch = block->last_instruction()->AsBranch(); |
| 5457 ASSERT(branch != NULL); | 5475 ASSERT(branch != NULL); |
| 5458 ComparisonInstr* comparison = branch->comparison(); | 5476 ComparisonInstr* comparison = branch->comparison(); |
| 5459 Value* left = comparison->left(); | 5477 Value* left = comparison->left(); |
| 5460 PhiInstr* phi = left->definition()->AsPhi(); | 5478 PhiInstr* phi = left->definition()->AsPhi(); |
| 5461 Value* right = comparison->right(); | 5479 Value* right = comparison->right(); |
| 5462 ConstantInstr* constant = right->definition()->AsConstant(); | 5480 ConstantInstr* constant = right->definition()->AsConstant(); |
| 5463 return (phi != NULL) && | 5481 return (phi != NULL) && |
| 5464 (constant != NULL) && | 5482 (constant != NULL) && |
| 5465 (phi->GetBlock() == block) && | 5483 (phi->GetBlock() == block) && |
| 5466 PhiHasSingleUse(phi, left) && | 5484 PhiHasSingleUse(phi, left) && |
| 5467 constant->HasOnlyUse(right) && | 5485 (block->next() == branch) && |
| 5468 (block->next() == constant) && | |
| 5469 (constant->next() == branch) && | |
| 5470 (block->phis()->length() == 1); | 5486 (block->phis()->length() == 1); |
| 5471 } | 5487 } |
| 5472 | 5488 |
| 5473 | 5489 |
| 5474 JoinEntryInstr* BranchSimplifier::ToJoinEntry(TargetEntryInstr* target) { | 5490 JoinEntryInstr* BranchSimplifier::ToJoinEntry(TargetEntryInstr* target) { |
| 5475 // Convert a target block into a join block. Branches will be duplicated | 5491 // Convert a target block into a join block. Branches will be duplicated |
| 5476 // so the former true and false targets become joins of the control flows | 5492 // so the former true and false targets become joins of the control flows |
| 5477 // from all the duplicated branches. | 5493 // from all the duplicated branches. |
| 5478 JoinEntryInstr* join = | 5494 JoinEntryInstr* join = |
| 5479 new JoinEntryInstr(target->block_id(), target->try_index()); | 5495 new JoinEntryInstr(target->block_id(), target->try_index()); |
| 5480 join->InheritDeoptTarget(target); | 5496 join->InheritDeoptTarget(target); |
| 5481 join->LinkTo(target->next()); | 5497 join->LinkTo(target->next()); |
| 5482 join->set_last_instruction(target->last_instruction()); | 5498 join->set_last_instruction(target->last_instruction()); |
| 5483 target->UnuseAllInputs(); | 5499 target->UnuseAllInputs(); |
| 5484 return join; | 5500 return join; |
| 5485 } | 5501 } |
| 5486 | 5502 |
| 5487 | 5503 |
| 5488 ConstantInstr* BranchSimplifier::CloneConstant(FlowGraph* flow_graph, | |
| 5489 ConstantInstr* constant) { | |
| 5490 ConstantInstr* new_constant = new ConstantInstr(constant->value()); | |
| 5491 new_constant->set_ssa_temp_index(flow_graph->alloc_ssa_temp_index()); | |
| 5492 return new_constant; | |
| 5493 } | |
| 5494 | |
| 5495 | |
| 5496 BranchInstr* BranchSimplifier::CloneBranch(BranchInstr* branch, | 5504 BranchInstr* BranchSimplifier::CloneBranch(BranchInstr* branch, |
| 5497 Value* left, | 5505 Value* left, |
| 5498 Value* right) { | 5506 Value* right) { |
| 5499 ComparisonInstr* comparison = branch->comparison(); | 5507 ComparisonInstr* comparison = branch->comparison(); |
| 5500 ComparisonInstr* new_comparison = NULL; | 5508 ComparisonInstr* new_comparison = NULL; |
| 5501 if (comparison->IsStrictCompare()) { | 5509 if (comparison->IsStrictCompare()) { |
| 5502 new_comparison = new StrictCompareInstr(comparison->kind(), left, right); | 5510 new_comparison = new StrictCompareInstr(comparison->kind(), left, right); |
| 5503 } else if (comparison->IsEqualityCompare()) { | 5511 } else if (comparison->IsEqualityCompare()) { |
| 5504 EqualityCompareInstr* equality_compare = comparison->AsEqualityCompare(); | 5512 EqualityCompareInstr* equality_compare = comparison->AsEqualityCompare(); |
| 5505 EqualityCompareInstr* new_equality_compare = | 5513 EqualityCompareInstr* new_equality_compare = |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5571 ComparisonInstr* comparison = branch->comparison(); | 5579 ComparisonInstr* comparison = branch->comparison(); |
| 5572 PhiInstr* phi = comparison->left()->definition()->AsPhi(); | 5580 PhiInstr* phi = comparison->left()->definition()->AsPhi(); |
| 5573 ConstantInstr* constant = comparison->right()->definition()->AsConstant(); | 5581 ConstantInstr* constant = comparison->right()->definition()->AsConstant(); |
| 5574 ASSERT(constant != NULL); | 5582 ASSERT(constant != NULL); |
| 5575 // Copy the constant and branch and push it to all the predecessors. | 5583 // Copy the constant and branch and push it to all the predecessors. |
| 5576 for (intptr_t i = 0, count = block->PredecessorCount(); i < count; ++i) { | 5584 for (intptr_t i = 0, count = block->PredecessorCount(); i < count; ++i) { |
| 5577 GotoInstr* old_goto = | 5585 GotoInstr* old_goto = |
| 5578 block->PredecessorAt(i)->last_instruction()->AsGoto(); | 5586 block->PredecessorAt(i)->last_instruction()->AsGoto(); |
| 5579 ASSERT(old_goto != NULL); | 5587 ASSERT(old_goto != NULL); |
| 5580 | 5588 |
| 5581 // Insert a copy of the constant in all the predecessors. | |
| 5582 ConstantInstr* new_constant = CloneConstant(flow_graph, constant); | |
| 5583 new_constant->InsertBefore(old_goto); | |
| 5584 | |
| 5585 // Replace the goto in each predecessor with a rewritten branch, | 5589 // Replace the goto in each predecessor with a rewritten branch, |
| 5586 // rewritten to use the corresponding phi input instead of the phi. | 5590 // rewritten to use the corresponding phi input instead of the phi. |
| 5587 Value* new_left = phi->InputAt(i)->Copy(); | 5591 Value* new_left = phi->InputAt(i)->Copy(); |
| 5588 Value* new_right = new Value(new_constant); | 5592 Value* new_right = new Value(constant); |
| 5589 BranchInstr* new_branch = CloneBranch(branch, new_left, new_right); | 5593 BranchInstr* new_branch = CloneBranch(branch, new_left, new_right); |
| 5590 if (branch->env() == NULL) { | 5594 if (branch->env() == NULL) { |
| 5591 new_branch->InheritDeoptTarget(old_goto); | 5595 new_branch->InheritDeoptTarget(old_goto); |
| 5592 } else { | 5596 } else { |
| 5593 // Take the environment from the branch if it has one. | 5597 // Take the environment from the branch if it has one. |
| 5594 new_branch->InheritDeoptTarget(branch); | 5598 new_branch->InheritDeoptTarget(branch); |
| 5595 // InheritDeoptTarget gave the new branch's comparison the same | 5599 // InheritDeoptTarget gave the new branch's comparison the same |
| 5596 // deopt id that it gave the new branch. The id should be the | 5600 // deopt id that it gave the new branch. The id should be the |
| 5597 // deopt id of the original comparison. | 5601 // deopt id of the original comparison. |
| 5598 new_branch->comparison()->SetDeoptId(comparison->GetDeoptId()); | 5602 new_branch->comparison()->SetDeoptId(comparison->GetDeoptId()); |
| 5599 // The phi and constant can be used in the branch's environment. | 5603 // The phi can be used in the branch's environment. Rename such |
| 5600 // Rename such uses. | 5604 // uses. |
| 5601 for (Environment::DeepIterator it(new_branch->env()); | 5605 for (Environment::DeepIterator it(new_branch->env()); |
| 5602 !it.Done(); | 5606 !it.Done(); |
| 5603 it.Advance()) { | 5607 it.Advance()) { |
| 5604 Value* use = it.CurrentValue(); | 5608 Value* use = it.CurrentValue(); |
| 5605 Definition* replacement = NULL; | |
| 5606 if (use->definition() == phi) { | 5609 if (use->definition() == phi) { |
| 5607 replacement = phi->InputAt(i)->definition(); | 5610 Definition* replacement = phi->InputAt(i)->definition(); |
| 5608 } else if (use->definition() == constant) { | |
| 5609 replacement = new_constant; | |
| 5610 } | |
| 5611 if (replacement != NULL) { | |
| 5612 use->RemoveFromUseList(); | 5611 use->RemoveFromUseList(); |
| 5613 use->set_definition(replacement); | 5612 use->set_definition(replacement); |
| 5614 replacement->AddEnvUse(use); | 5613 replacement->AddEnvUse(use); |
| 5615 } | 5614 } |
| 5616 } | 5615 } |
| 5617 } | 5616 } |
| 5618 | 5617 |
| 5619 new_branch->InsertBefore(old_goto); | 5618 new_branch->InsertBefore(old_goto); |
| 5620 new_branch->set_next(NULL); // Detaching the goto from the graph. | 5619 new_branch->set_next(NULL); // Detaching the goto from the graph. |
| 5621 old_goto->UnuseAllInputs(); | 5620 old_goto->UnuseAllInputs(); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 5647 goto_false->InheritDeoptTarget(join_false); | 5646 goto_false->InheritDeoptTarget(join_false); |
| 5648 false_target->LinkTo(goto_false); | 5647 false_target->LinkTo(goto_false); |
| 5649 false_target->set_last_instruction(goto_false); | 5648 false_target->set_last_instruction(goto_false); |
| 5650 } | 5649 } |
| 5651 // When all predecessors have been rewritten, the original block is | 5650 // When all predecessors have been rewritten, the original block is |
| 5652 // unreachable from the graph. | 5651 // unreachable from the graph. |
| 5653 phi->UnuseAllInputs(); | 5652 phi->UnuseAllInputs(); |
| 5654 branch->UnuseAllInputs(); | 5653 branch->UnuseAllInputs(); |
| 5655 block->UnuseAllInputs(); | 5654 block->UnuseAllInputs(); |
| 5656 ASSERT(!phi->HasUses()); | 5655 ASSERT(!phi->HasUses()); |
| 5657 ASSERT(!constant->HasUses()); | |
| 5658 } | 5656 } |
| 5659 } | 5657 } |
| 5660 | 5658 |
| 5661 if (changed) { | 5659 if (changed) { |
| 5662 // We may have changed the block order and the dominator tree. | 5660 // We may have changed the block order and the dominator tree. |
| 5663 flow_graph->DiscoverBlocks(); | 5661 flow_graph->DiscoverBlocks(); |
| 5664 GrowableArray<BitVector*> dominance_frontier; | 5662 GrowableArray<BitVector*> dominance_frontier; |
| 5665 flow_graph->ComputeDominators(&dominance_frontier); | 5663 flow_graph->ComputeDominators(&dominance_frontier); |
| 5666 } | 5664 } |
| 5667 } | 5665 } |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5790 if (changed) { | 5788 if (changed) { |
| 5791 // We may have changed the block order and the dominator tree. | 5789 // We may have changed the block order and the dominator tree. |
| 5792 flow_graph->DiscoverBlocks(); | 5790 flow_graph->DiscoverBlocks(); |
| 5793 GrowableArray<BitVector*> dominance_frontier; | 5791 GrowableArray<BitVector*> dominance_frontier; |
| 5794 flow_graph->ComputeDominators(&dominance_frontier); | 5792 flow_graph->ComputeDominators(&dominance_frontier); |
| 5795 } | 5793 } |
| 5796 } | 5794 } |
| 5797 | 5795 |
| 5798 | 5796 |
| 5799 } // namespace dart | 5797 } // namespace dart |
| OLD | NEW |