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 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
77 bool FlowGraphOptimizer::TryCreateICData(InstanceCallInstr* call) { | 77 bool FlowGraphOptimizer::TryCreateICData(InstanceCallInstr* call) { |
78 ASSERT(call->HasICData()); | 78 ASSERT(call->HasICData()); |
79 if (call->ic_data()->NumberOfChecks() > 0) { | 79 if (call->ic_data()->NumberOfChecks() > 0) { |
80 // This occurs when an instance call has too many checks. | 80 // This occurs when an instance call has too many checks. |
81 // TODO(srdjan): Replace IC call with megamorphic call. | 81 // TODO(srdjan): Replace IC call with megamorphic call. |
82 return false; | 82 return false; |
83 } | 83 } |
84 GrowableArray<intptr_t> class_ids(call->ic_data()->num_args_tested()); | 84 GrowableArray<intptr_t> class_ids(call->ic_data()->num_args_tested()); |
85 ASSERT(call->ic_data()->num_args_tested() <= call->ArgumentCount()); | 85 ASSERT(call->ic_data()->num_args_tested() <= call->ArgumentCount()); |
86 for (intptr_t i = 0; i < call->ic_data()->num_args_tested(); i++) { | 86 for (intptr_t i = 0; i < call->ic_data()->num_args_tested(); i++) { |
87 intptr_t cid = call->ArgumentAt(i)->value()->ResultCid(); | 87 intptr_t cid = call->ArgumentAt(i)->value()->Type()->ToCid(); |
88 class_ids.Add(cid); | 88 class_ids.Add(cid); |
89 } | 89 } |
90 // TODO(srdjan): Test for other class_ids > 1. | 90 // TODO(srdjan): Test for other class_ids > 1. |
91 if (class_ids.length() != 1) return false; | 91 if (class_ids.length() != 1) return false; |
92 if (class_ids[0] != kDynamicCid) { | 92 if (class_ids[0] != kDynamicCid) { |
93 const intptr_t num_named_arguments = call->argument_names().IsNull() ? | 93 const intptr_t num_named_arguments = call->argument_names().IsNull() ? |
94 0 : call->argument_names().Length(); | 94 0 : call->argument_names().Length(); |
95 const Class& receiver_class = Class::Handle( | 95 const Class& receiver_class = Class::Handle( |
96 Isolate::Current()->class_table()->At(class_ids[0])); | 96 Isolate::Current()->class_table()->At(class_ids[0])); |
97 Function& function = Function::Handle(); | 97 Function& function = Function::Handle(); |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
143 return new_ic_data; | 143 return new_ic_data; |
144 } | 144 } |
145 | 145 |
146 | 146 |
147 void FlowGraphOptimizer::SpecializePolymorphicInstanceCall( | 147 void FlowGraphOptimizer::SpecializePolymorphicInstanceCall( |
148 PolymorphicInstanceCallInstr* call) { | 148 PolymorphicInstanceCallInstr* call) { |
149 if (!call->with_checks()) { | 149 if (!call->with_checks()) { |
150 return; // Already specialized. | 150 return; // Already specialized. |
151 } | 151 } |
152 | 152 |
153 const intptr_t receiver_cid = call->ArgumentAt(0)->value()->ResultCid(); | 153 const intptr_t receiver_cid = call->ArgumentAt(0)->value()->Type()->ToCid(); |
154 if (receiver_cid == kDynamicCid) { | 154 if (receiver_cid == kDynamicCid) { |
155 return; // No information about receiver was infered. | 155 return; // No information about receiver was infered. |
156 } | 156 } |
157 | 157 |
158 const ICData& ic_data = SpecializeICData(call->ic_data(), receiver_cid); | 158 const ICData& ic_data = SpecializeICData(call->ic_data(), receiver_cid); |
159 | 159 |
160 const bool with_checks = false; | 160 const bool with_checks = false; |
161 PolymorphicInstanceCallInstr* specialized = | 161 PolymorphicInstanceCallInstr* specialized = |
162 new PolymorphicInstanceCallInstr(call->instance_call(), | 162 new PolymorphicInstanceCallInstr(call->instance_call(), |
163 ic_data, | 163 ic_data, |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
224 | 224 |
225 | 225 |
226 void FlowGraphOptimizer::InsertConversion(Representation from, | 226 void FlowGraphOptimizer::InsertConversion(Representation from, |
227 Representation to, | 227 Representation to, |
228 Value* use, | 228 Value* use, |
229 Instruction* insert_before, | 229 Instruction* insert_before, |
230 Instruction* deopt_target) { | 230 Instruction* deopt_target) { |
231 Definition* converted = NULL; | 231 Definition* converted = NULL; |
232 if ((from == kTagged) && (to == kUnboxedMint)) { | 232 if ((from == kTagged) && (to == kUnboxedMint)) { |
233 ASSERT((deopt_target != NULL) || | 233 ASSERT((deopt_target != NULL) || |
234 (use->definition()->GetPropagatedCid() == kDoubleCid)); | 234 (use->Type()->ToCid() == kDoubleCid)); |
235 const intptr_t deopt_id = (deopt_target != NULL) ? | 235 const intptr_t deopt_id = (deopt_target != NULL) ? |
236 deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId; | 236 deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId; |
237 converted = new UnboxIntegerInstr(new Value(use->definition()), deopt_id); | 237 converted = new UnboxIntegerInstr(new Value(use->definition()), deopt_id); |
238 } else if ((from == kUnboxedMint) && (to == kTagged)) { | 238 } else if ((from == kUnboxedMint) && (to == kTagged)) { |
239 converted = new BoxIntegerInstr(new Value(use->definition())); | 239 converted = new BoxIntegerInstr(new Value(use->definition())); |
240 } else if (from == kUnboxedMint && to == kUnboxedDouble) { | 240 } else if (from == kUnboxedMint && to == kUnboxedDouble) { |
241 // Convert by boxing/unboxing. | 241 // Convert by boxing/unboxing. |
242 // TODO(fschneider): Implement direct unboxed mint-to-double conversion. | 242 // TODO(fschneider): Implement direct unboxed mint-to-double conversion. |
243 BoxIntegerInstr* boxed = new BoxIntegerInstr(new Value(use->definition())); | 243 BoxIntegerInstr* boxed = new BoxIntegerInstr(new Value(use->definition())); |
244 InsertBefore(insert_before, boxed, NULL, Definition::kValue); | 244 InsertBefore(insert_before, boxed, NULL, Definition::kValue); |
245 const intptr_t deopt_id = (deopt_target != NULL) ? | 245 const intptr_t deopt_id = (deopt_target != NULL) ? |
246 deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId; | 246 deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId; |
247 converted = new UnboxDoubleInstr(new Value(boxed), deopt_id); | 247 converted = new UnboxDoubleInstr(new Value(boxed), deopt_id); |
248 } else if ((from == kUnboxedDouble) && (to == kTagged)) { | 248 } else if ((from == kUnboxedDouble) && (to == kTagged)) { |
249 converted = new BoxDoubleInstr(new Value(use->definition()), NULL); | 249 converted = new BoxDoubleInstr(new Value(use->definition()), NULL); |
250 } else if ((from == kTagged) && (to == kUnboxedDouble)) { | 250 } else if ((from == kTagged) && (to == kUnboxedDouble)) { |
251 const intptr_t deopt_id = (deopt_target != NULL) ? | 251 const intptr_t deopt_id = (deopt_target != NULL) ? |
252 deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId; | 252 deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId; |
253 ASSERT((deopt_target != NULL) || | 253 ASSERT((deopt_target != NULL) || |
254 (use->definition()->GetPropagatedCid() == kDoubleCid)); | 254 (use->Type()->ToCid() == kDoubleCid)); |
255 ConstantInstr* constant = use->definition()->AsConstant(); | 255 ConstantInstr* constant = use->definition()->AsConstant(); |
256 if ((constant != NULL) && constant->value().IsSmi()) { | 256 if ((constant != NULL) && constant->value().IsSmi()) { |
257 const double dbl_val = Smi::Cast(constant->value()).AsDoubleValue(); | 257 const double dbl_val = Smi::Cast(constant->value()).AsDoubleValue(); |
258 const Double& dbl_obj = | 258 const Double& dbl_obj = |
259 Double::ZoneHandle(Double::New(dbl_val, Heap::kOld)); | 259 Double::ZoneHandle(Double::New(dbl_val, Heap::kOld)); |
260 ConstantInstr* double_const = new ConstantInstr(dbl_obj); | 260 ConstantInstr* double_const = new ConstantInstr(dbl_obj); |
261 InsertBefore(insert_before, double_const, NULL, Definition::kValue); | 261 InsertBefore(insert_before, double_const, NULL, Definition::kValue); |
262 converted = new UnboxDoubleInstr(new Value(double_const), deopt_id); | 262 converted = new UnboxDoubleInstr(new Value(double_const), deopt_id); |
263 } else { | 263 } else { |
264 converted = new UnboxDoubleInstr(new Value(use->definition()), deopt_id); | 264 converted = new UnboxDoubleInstr(new Value(use->definition()), deopt_id); |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
306 void FlowGraphOptimizer::SelectRepresentations() { | 306 void FlowGraphOptimizer::SelectRepresentations() { |
307 // Convervatively unbox all phis that were proven to be of type Double. | 307 // Convervatively unbox all phis that were proven to be of type Double. |
308 for (intptr_t i = 0; i < block_order_.length(); ++i) { | 308 for (intptr_t i = 0; i < block_order_.length(); ++i) { |
309 JoinEntryInstr* join_entry = block_order_[i]->AsJoinEntry(); | 309 JoinEntryInstr* join_entry = block_order_[i]->AsJoinEntry(); |
310 if (join_entry == NULL) continue; | 310 if (join_entry == NULL) continue; |
311 | 311 |
312 if (join_entry->phis() != NULL) { | 312 if (join_entry->phis() != NULL) { |
313 for (intptr_t i = 0; i < join_entry->phis()->length(); ++i) { | 313 for (intptr_t i = 0; i < join_entry->phis()->length(); ++i) { |
314 PhiInstr* phi = (*join_entry->phis())[i]; | 314 PhiInstr* phi = (*join_entry->phis())[i]; |
315 if (phi == NULL) continue; | 315 if (phi == NULL) continue; |
316 if (phi->GetPropagatedCid() == kDoubleCid) { | 316 if (phi->Type()->ToCid() == kDoubleCid) { |
317 phi->set_representation(kUnboxedDouble); | 317 phi->set_representation(kUnboxedDouble); |
318 } | 318 } |
319 } | 319 } |
320 } | 320 } |
321 } | 321 } |
322 | 322 |
323 // Process all instructions and insert conversions where needed. | 323 // Process all instructions and insert conversions where needed. |
324 GraphEntryInstr* graph_entry = block_order_[0]->AsGraphEntry(); | 324 GraphEntryInstr* graph_entry = block_order_[0]->AsGraphEntry(); |
325 | 325 |
326 // Visit incoming parameters and constants. | 326 // Visit incoming parameters and constants. |
(...skipping 1631 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1958 (cid == kDoubleCid); | 1958 (cid == kDoubleCid); |
1959 } | 1959 } |
1960 | 1960 |
1961 | 1961 |
1962 // Check if number check is not needed. | 1962 // Check if number check is not needed. |
1963 void FlowGraphOptimizer::VisitStrictCompare(StrictCompareInstr* instr) { | 1963 void FlowGraphOptimizer::VisitStrictCompare(StrictCompareInstr* instr) { |
1964 if (!instr->needs_number_check()) return; | 1964 if (!instr->needs_number_check()) return; |
1965 | 1965 |
1966 // If one of the input is not a boxable number (Mint, Double, Bigint), no | 1966 // If one of the input is not a boxable number (Mint, Double, Bigint), no |
1967 // need for number checks. | 1967 // need for number checks. |
1968 if (!MayBeBoxableNumber(instr->left()->ResultCid()) || | 1968 if (!MayBeBoxableNumber(instr->left()->Type()->ToCid()) || |
1969 !MayBeBoxableNumber(instr->right()->ResultCid())) { | 1969 !MayBeBoxableNumber(instr->right()->Type()->ToCid())) { |
1970 instr->set_needs_number_check(false); | 1970 instr->set_needs_number_check(false); |
1971 } | 1971 } |
1972 } | 1972 } |
1973 | 1973 |
1974 | 1974 |
1975 // SminessPropagator ensures that CheckSmis are eliminated across phis. | |
1976 class SminessPropagator : public ValueObject { | |
1977 public: | |
1978 explicit SminessPropagator(FlowGraph* flow_graph) | |
1979 : flow_graph_(flow_graph), | |
1980 known_smis_(new BitVector(flow_graph_->current_ssa_temp_index())), | |
1981 rollback_checks_(10), | |
1982 in_worklist_(NULL), | |
1983 worklist_(0) { } | |
1984 | |
1985 void Propagate(); | |
1986 | |
1987 private: | |
1988 void PropagateSminessRecursive(BlockEntryInstr* block); | |
1989 void AddToWorklist(PhiInstr* phi); | |
1990 PhiInstr* RemoveLastFromWorklist(); | |
1991 void ProcessPhis(); | |
1992 | |
1993 FlowGraph* flow_graph_; | |
1994 | |
1995 BitVector* known_smis_; | |
1996 GrowableArray<intptr_t> rollback_checks_; | |
1997 | |
1998 BitVector* in_worklist_; | |
1999 GrowableArray<PhiInstr*> worklist_; | |
2000 | |
2001 DISALLOW_COPY_AND_ASSIGN(SminessPropagator); | |
2002 }; | |
2003 | |
2004 | |
2005 void SminessPropagator::AddToWorklist(PhiInstr* phi) { | |
2006 if (in_worklist_ == NULL) { | |
2007 in_worklist_ = new BitVector(flow_graph_->current_ssa_temp_index()); | |
2008 } | |
2009 if (!in_worklist_->Contains(phi->ssa_temp_index())) { | |
2010 in_worklist_->Add(phi->ssa_temp_index()); | |
2011 worklist_.Add(phi); | |
2012 } | |
2013 } | |
2014 | |
2015 | |
2016 PhiInstr* SminessPropagator::RemoveLastFromWorklist() { | |
2017 PhiInstr* phi = worklist_.RemoveLast(); | |
2018 ASSERT(in_worklist_->Contains(phi->ssa_temp_index())); | |
2019 in_worklist_->Remove(phi->ssa_temp_index()); | |
2020 return phi; | |
2021 } | |
2022 | |
2023 | |
2024 static bool IsDefinitelySmiPhi(PhiInstr* phi) { | |
2025 for (intptr_t i = 0; i < phi->InputCount(); i++) { | |
2026 const intptr_t cid = phi->InputAt(i)->ResultCid(); | |
2027 if (cid != kSmiCid) { | |
2028 return false; | |
2029 } | |
2030 } | |
2031 return true; | |
2032 } | |
2033 | |
2034 | |
2035 static bool IsPossiblySmiPhi(PhiInstr* phi) { | |
2036 for (intptr_t i = 0; i < phi->InputCount(); i++) { | |
2037 const intptr_t cid = phi->InputAt(i)->ResultCid(); | |
2038 if ((cid != kSmiCid) && (cid != kDynamicCid)) { | |
2039 return false; | |
2040 } | |
2041 } | |
2042 return true; | |
2043 } | |
2044 | |
2045 | |
2046 void SminessPropagator::ProcessPhis() { | |
2047 // First optimistically mark all possible smi-phis: phi is possibly a smi if | |
2048 // its operands are either smis or phis in the worklist. | |
2049 for (intptr_t i = 0; i < worklist_.length(); i++) { | |
2050 PhiInstr* phi = worklist_[i]; | |
2051 ASSERT(phi->GetPropagatedCid() == kDynamicCid); | |
2052 phi->SetPropagatedCid(kSmiCid); | |
2053 | |
2054 // Append all phis that use this phi and can potentially be smi to the | |
2055 // end of worklist. | |
2056 for (Value* use = phi->input_use_list(); | |
2057 use != NULL; | |
2058 use = use->next_use()) { | |
2059 PhiInstr* phi_use = use->instruction()->AsPhi(); | |
2060 if ((phi_use != NULL) && | |
2061 (phi_use->GetPropagatedCid() == kDynamicCid) && | |
2062 IsPossiblySmiPhi(phi_use)) { | |
2063 AddToWorklist(phi_use); | |
2064 } | |
2065 } | |
2066 } | |
2067 | |
2068 // Now unmark phis that are not definitely smi: that is have only | |
2069 // smi operands. | |
2070 while (!worklist_.is_empty()) { | |
2071 PhiInstr* phi = RemoveLastFromWorklist(); | |
2072 if (!IsDefinitelySmiPhi(phi)) { | |
2073 // Phi result is not a smi. Propagate this fact to phis that depend on it. | |
2074 phi->SetPropagatedCid(kDynamicCid); | |
2075 for (Value* use = phi->input_use_list(); | |
2076 use != NULL; | |
2077 use = use->next_use()) { | |
2078 PhiInstr* phi_use = use->instruction()->AsPhi(); | |
2079 if ((phi_use != NULL) && (phi_use->GetPropagatedCid() == kSmiCid)) { | |
2080 AddToWorklist(phi_use); | |
2081 } | |
2082 } | |
2083 } | |
2084 } | |
2085 } | |
2086 | |
2087 | |
2088 void SminessPropagator::PropagateSminessRecursive(BlockEntryInstr* block) { | |
2089 const intptr_t rollback_point = rollback_checks_.length(); | |
2090 | |
2091 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { | |
2092 Instruction* instr = it.Current(); | |
2093 if (instr->IsCheckSmi()) { | |
2094 const intptr_t value_ssa_index = | |
2095 instr->InputAt(0)->definition()->ssa_temp_index(); | |
2096 if (!known_smis_->Contains(value_ssa_index)) { | |
2097 known_smis_->Add(value_ssa_index); | |
2098 rollback_checks_.Add(value_ssa_index); | |
2099 } | |
2100 } else if (instr->IsBranch()) { | |
2101 for (intptr_t i = 0; i < instr->InputCount(); i++) { | |
2102 Value* use = instr->InputAt(i); | |
2103 if (known_smis_->Contains(use->definition()->ssa_temp_index())) { | |
2104 use->set_reaching_cid(kSmiCid); | |
2105 } | |
2106 } | |
2107 } | |
2108 } | |
2109 | |
2110 for (intptr_t i = 0; i < block->dominated_blocks().length(); ++i) { | |
2111 PropagateSminessRecursive(block->dominated_blocks()[i]); | |
2112 } | |
2113 | |
2114 if (block->last_instruction()->SuccessorCount() == 1 && | |
2115 block->last_instruction()->SuccessorAt(0)->IsJoinEntry()) { | |
2116 JoinEntryInstr* join = | |
2117 block->last_instruction()->SuccessorAt(0)->AsJoinEntry(); | |
2118 intptr_t pred_index = join->IndexOfPredecessor(block); | |
2119 ASSERT(pred_index >= 0); | |
2120 if (join->phis() != NULL) { | |
2121 for (intptr_t i = 0; i < join->phis()->length(); ++i) { | |
2122 PhiInstr* phi = (*join->phis())[i]; | |
2123 if (phi == NULL) continue; | |
2124 Value* use = phi->InputAt(pred_index); | |
2125 const intptr_t value_ssa_index = use->definition()->ssa_temp_index(); | |
2126 if (known_smis_->Contains(value_ssa_index) && | |
2127 (phi->GetPropagatedCid() != kSmiCid)) { | |
2128 use->set_reaching_cid(kSmiCid); | |
2129 AddToWorklist(phi); | |
2130 } | |
2131 } | |
2132 } | |
2133 } | |
2134 | |
2135 for (intptr_t i = rollback_point; i < rollback_checks_.length(); i++) { | |
2136 known_smis_->Remove(rollback_checks_[i]); | |
2137 } | |
2138 rollback_checks_.TruncateTo(rollback_point); | |
2139 } | |
2140 | |
2141 | |
2142 void SminessPropagator::Propagate() { | |
2143 PropagateSminessRecursive(flow_graph_->graph_entry()); | |
2144 ProcessPhis(); | |
2145 } | |
2146 | |
2147 | |
2148 void FlowGraphOptimizer::PropagateSminess() { | |
2149 SminessPropagator propagator(flow_graph_); | |
2150 propagator.Propagate(); | |
2151 } | |
2152 | |
2153 | |
2154 // Range analysis for smi values. | 1975 // Range analysis for smi values. |
2155 class RangeAnalysis : public ValueObject { | 1976 class RangeAnalysis : public ValueObject { |
2156 public: | 1977 public: |
2157 explicit RangeAnalysis(FlowGraph* flow_graph) | 1978 explicit RangeAnalysis(FlowGraph* flow_graph) |
2158 : flow_graph_(flow_graph), | 1979 : flow_graph_(flow_graph), |
2159 marked_defns_(NULL) { } | 1980 marked_defns_(NULL) { } |
2160 | 1981 |
2161 // Infer ranges for all values and remove overflow checks from binary smi | 1982 // Infer ranges for all values and remove overflow checks from binary smi |
2162 // operations when proven redundant. | 1983 // operations when proven redundant. |
2163 void Analyze(); | 1984 void Analyze(); |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2261 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); | 2082 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); |
2262 !block_it.Done(); | 2083 !block_it.Done(); |
2263 block_it.Advance()) { | 2084 block_it.Advance()) { |
2264 BlockEntryInstr* block = block_it.Current(); | 2085 BlockEntryInstr* block = block_it.Current(); |
2265 for (ForwardInstructionIterator instr_it(block); | 2086 for (ForwardInstructionIterator instr_it(block); |
2266 !instr_it.Done(); | 2087 !instr_it.Done(); |
2267 instr_it.Advance()) { | 2088 instr_it.Advance()) { |
2268 Instruction* current = instr_it.Current(); | 2089 Instruction* current = instr_it.Current(); |
2269 Definition* defn = current->AsDefinition(); | 2090 Definition* defn = current->AsDefinition(); |
2270 if (defn != NULL) { | 2091 if (defn != NULL) { |
2271 if ((defn->GetPropagatedCid() == kSmiCid) && | 2092 if ((defn->Type()->ToCid() == kSmiCid) && |
2272 (defn->ssa_temp_index() != -1)) { | 2093 (defn->ssa_temp_index() != -1)) { |
2273 smi_values_.Add(defn); | 2094 smi_values_.Add(defn); |
2274 } | 2095 } |
2275 } else if (current->IsCheckSmi()) { | 2096 } else if (current->IsCheckSmi()) { |
2276 smi_checks_.Add(current->AsCheckSmi()); | 2097 smi_checks_.Add(current->AsCheckSmi()); |
2277 } | 2098 } |
2278 } | 2099 } |
2279 | 2100 |
2280 JoinEntryInstr* join = block->AsJoinEntry(); | 2101 JoinEntryInstr* join = block->AsJoinEntry(); |
2281 if (join != NULL) { | 2102 if (join != NULL) { |
2282 for (PhiIterator phi_it(join); !phi_it.Done(); phi_it.Advance()) { | 2103 for (PhiIterator phi_it(join); !phi_it.Done(); phi_it.Advance()) { |
2283 PhiInstr* current = phi_it.Current(); | 2104 PhiInstr* current = phi_it.Current(); |
2284 if (current->GetPropagatedCid() == kSmiCid) { | 2105 if ((current->Type()->ToCid() == kSmiCid)) { |
2285 smi_values_.Add(current); | 2106 smi_values_.Add(current); |
2286 } | 2107 } |
2287 } | 2108 } |
2288 } | 2109 } |
2289 } | 2110 } |
2290 } | 2111 } |
2291 | 2112 |
2292 | 2113 |
2293 // Returns true if use is dominated by the given instruction. | 2114 // Returns true if use is dominated by the given instruction. |
2294 // Note: uses that occur at instruction itself are not dominated by it. | 2115 // Note: uses that occur at instruction itself are not dominated by it. |
(...skipping 434 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2729 } | 2550 } |
2730 } | 2551 } |
2731 | 2552 |
2732 | 2553 |
2733 void FlowGraphOptimizer::InferSmiRanges() { | 2554 void FlowGraphOptimizer::InferSmiRanges() { |
2734 RangeAnalysis range_analysis(flow_graph_); | 2555 RangeAnalysis range_analysis(flow_graph_); |
2735 range_analysis.Analyze(); | 2556 range_analysis.Analyze(); |
2736 } | 2557 } |
2737 | 2558 |
2738 | 2559 |
2739 void FlowGraphTypePropagator::VisitBlocks() { | |
2740 ASSERT(current_iterator_ == NULL); | |
2741 for (intptr_t i = 0; i < block_order_.length(); ++i) { | |
2742 BlockEntryInstr* entry = block_order_[i]; | |
2743 entry->Accept(this); | |
2744 ForwardInstructionIterator it(entry); | |
2745 current_iterator_ = ⁢ | |
2746 for (; !it.Done(); it.Advance()) { | |
2747 Instruction* current = it.Current(); | |
2748 // No need to propagate the input types of the instruction, as long as | |
2749 // PhiInstr's are handled as part of JoinEntryInstr. | |
2750 | |
2751 // Visit the instruction and possibly eliminate type checks. | |
2752 current->Accept(this); | |
2753 // The instruction may have been removed from the graph. | |
2754 Definition* defn = current->AsDefinition(); | |
2755 if ((defn != NULL) && | |
2756 !defn->IsPushArgument() && | |
2757 (defn->previous() != NULL)) { | |
2758 // Cache the propagated computation type. | |
2759 AbstractType& type = AbstractType::Handle(defn->CompileType()); | |
2760 still_changing_ = defn->SetPropagatedType(type) || still_changing_; | |
2761 | |
2762 // Propagate class ids. | |
2763 const intptr_t cid = defn->ResultCid(); | |
2764 still_changing_ = defn->SetPropagatedCid(cid) || still_changing_; | |
2765 } | |
2766 } | |
2767 current_iterator_ = NULL; | |
2768 } | |
2769 } | |
2770 | |
2771 | |
2772 void FlowGraphTypePropagator::VisitAssertAssignable( | |
2773 AssertAssignableInstr* instr) { | |
2774 bool is_null, is_instance; | |
2775 if (FLAG_eliminate_type_checks && | |
2776 !instr->is_eliminated() && | |
2777 ((instr->value()->CanComputeIsNull(&is_null) && is_null) || | |
2778 (instr->value()->CanComputeIsInstanceOf(instr->dst_type(), &is_instance) | |
2779 && is_instance))) { | |
2780 // TODO(regis): Remove is_eliminated_ field and support. | |
2781 instr->eliminate(); | |
2782 | |
2783 Value* use = instr->value(); | |
2784 ASSERT(use != NULL); | |
2785 Definition* result = use->definition(); | |
2786 ASSERT(result != NULL); | |
2787 // Replace uses and remove the current instruction via the iterator. | |
2788 instr->ReplaceUsesWith(result); | |
2789 ASSERT(current_iterator()->Current() == instr); | |
2790 current_iterator()->RemoveCurrentFromGraph(); | |
2791 if (FLAG_trace_optimization) { | |
2792 OS::Print("Replacing v%"Pd" with v%"Pd"\n", | |
2793 instr->ssa_temp_index(), | |
2794 result->ssa_temp_index()); | |
2795 } | |
2796 | |
2797 if (FLAG_trace_type_check_elimination) { | |
2798 FlowGraphPrinter::PrintTypeCheck(parsed_function(), | |
2799 instr->token_pos(), | |
2800 instr->value(), | |
2801 instr->dst_type(), | |
2802 instr->dst_name(), | |
2803 instr->is_eliminated()); | |
2804 } | |
2805 } | |
2806 } | |
2807 | |
2808 | |
2809 void FlowGraphTypePropagator::VisitAssertBoolean(AssertBooleanInstr* instr) { | |
2810 bool is_null, is_bool; | |
2811 if (FLAG_eliminate_type_checks && | |
2812 !instr->is_eliminated() && | |
2813 instr->value()->CanComputeIsNull(&is_null) && | |
2814 !is_null && | |
2815 instr->value()->CanComputeIsInstanceOf(Type::Handle(Type::BoolType()), | |
2816 &is_bool) && | |
2817 is_bool) { | |
2818 // TODO(regis): Remove is_eliminated_ field and support. | |
2819 instr->eliminate(); | |
2820 Value* use = instr->value(); | |
2821 Definition* result = use->definition(); | |
2822 ASSERT(result != NULL); | |
2823 // Replace uses and remove the current instruction via the iterator. | |
2824 instr->ReplaceUsesWith(result); | |
2825 ASSERT(current_iterator()->Current() == instr); | |
2826 current_iterator()->RemoveCurrentFromGraph(); | |
2827 if (FLAG_trace_optimization) { | |
2828 OS::Print("Replacing v%"Pd" with v%"Pd"\n", | |
2829 instr->ssa_temp_index(), | |
2830 result->ssa_temp_index()); | |
2831 } | |
2832 | |
2833 if (FLAG_trace_type_check_elimination) { | |
2834 FlowGraphPrinter::PrintTypeCheck(parsed_function(), | |
2835 instr->token_pos(), | |
2836 instr->value(), | |
2837 Type::Handle(Type::BoolType()), | |
2838 Symbols::BooleanExpression(), | |
2839 instr->is_eliminated()); | |
2840 } | |
2841 } | |
2842 } | |
2843 | |
2844 | |
2845 void FlowGraphTypePropagator::VisitInstanceOf(InstanceOfInstr* instr) { | |
2846 bool is_null; | |
2847 bool is_instance = false; | |
2848 if (FLAG_eliminate_type_checks && | |
2849 instr->value()->CanComputeIsNull(&is_null) && | |
2850 (is_null || | |
2851 instr->value()->CanComputeIsInstanceOf(instr->type(), &is_instance))) { | |
2852 bool val = instr->negate_result() ? !is_instance : is_instance; | |
2853 Definition* result = new ConstantInstr(val ? Bool::True() : Bool::False()); | |
2854 result->set_ssa_temp_index(flow_graph_->alloc_ssa_temp_index()); | |
2855 result->InsertBefore(instr); | |
2856 // Replace uses and remove the current instruction via the iterator. | |
2857 instr->ReplaceUsesWith(result); | |
2858 ASSERT(current_iterator()->Current() == instr); | |
2859 current_iterator()->RemoveCurrentFromGraph(); | |
2860 if (FLAG_trace_optimization) { | |
2861 OS::Print("Replacing v%"Pd" with v%"Pd"\n", | |
2862 instr->ssa_temp_index(), | |
2863 result->ssa_temp_index()); | |
2864 } | |
2865 | |
2866 if (FLAG_trace_type_check_elimination) { | |
2867 FlowGraphPrinter::PrintTypeCheck(parsed_function(), | |
2868 instr->token_pos(), | |
2869 instr->value(), | |
2870 instr->type(), | |
2871 Symbols::InstanceOf(), | |
2872 /* eliminated = */ true); | |
2873 } | |
2874 } | |
2875 } | |
2876 | |
2877 | |
2878 void FlowGraphTypePropagator::VisitGraphEntry(GraphEntryInstr* graph_entry) { | |
2879 // Visit incoming parameters. | |
2880 for (intptr_t i = 0; i < graph_entry->initial_definitions()->length(); i++) { | |
2881 ParameterInstr* param = | |
2882 (*graph_entry->initial_definitions())[i]->AsParameter(); | |
2883 if (param != NULL) VisitParameter(param); | |
2884 } | |
2885 } | |
2886 | |
2887 | |
2888 void FlowGraphTypePropagator::VisitJoinEntry(JoinEntryInstr* join_entry) { | |
2889 if (join_entry->phis() != NULL) { | |
2890 for (intptr_t i = 0; i < join_entry->phis()->length(); ++i) { | |
2891 PhiInstr* phi = (*join_entry->phis())[i]; | |
2892 if (phi != NULL) { | |
2893 VisitPhi(phi); | |
2894 } | |
2895 } | |
2896 } | |
2897 } | |
2898 | |
2899 | |
2900 // TODO(srdjan): Investigate if the propagated cid should be more specific. | |
2901 void FlowGraphTypePropagator::VisitPushArgument(PushArgumentInstr* push) { | |
2902 if (!push->has_propagated_cid()) push->SetPropagatedCid(kDynamicCid); | |
2903 } | |
2904 | |
2905 | |
2906 void FlowGraphTypePropagator::VisitPhi(PhiInstr* phi) { | |
2907 // We could set the propagated type of the phi to the least upper bound of its | |
2908 // input propagated types. However, keeping all propagated types allows us to | |
2909 // optimize method dispatch. | |
2910 // TODO(regis): Support a set of propagated types. For now, we compute the | |
2911 // least specific of the input propagated types. | |
2912 AbstractType& type = AbstractType::Handle(phi->LeastSpecificInputType()); | |
2913 bool changed = phi->SetPropagatedType(type); | |
2914 if (changed) { | |
2915 still_changing_ = true; | |
2916 } | |
2917 | |
2918 // Merge class ids: if any two inputs have different class ids then result | |
2919 // is kDynamicCid. | |
2920 intptr_t merged_cid = kIllegalCid; | |
2921 for (intptr_t i = 0; i < phi->InputCount(); i++) { | |
2922 // Result cid of UseVal can be kIllegalCid if the referred definition | |
2923 // has not been visited yet. | |
2924 intptr_t cid = phi->InputAt(i)->ResultCid(); | |
2925 if (cid == kIllegalCid) { | |
2926 still_changing_ = true; | |
2927 continue; | |
2928 } | |
2929 if (merged_cid == kIllegalCid) { | |
2930 // First time set. | |
2931 merged_cid = cid; | |
2932 } else if (merged_cid != cid) { | |
2933 merged_cid = kDynamicCid; | |
2934 } | |
2935 } | |
2936 if (merged_cid == kIllegalCid) { | |
2937 merged_cid = kDynamicCid; | |
2938 } | |
2939 changed = phi->SetPropagatedCid(merged_cid); | |
2940 if (changed) { | |
2941 still_changing_ = true; | |
2942 } | |
2943 } | |
2944 | |
2945 | |
2946 void FlowGraphTypePropagator::VisitParameter(ParameterInstr* param) { | |
2947 // TODO(regis): Once we inline functions, the propagated type of the formal | |
2948 // parameter will reflect the compile type of the passed-in argument. | |
2949 // For now, we do not know anything about the argument type and therefore set | |
2950 // it to the DynamicType, unless the argument is a compiler generated value, | |
2951 // i.e. the receiver argument or the constructor phase argument. | |
2952 AbstractType& param_type = AbstractType::Handle(Type::DynamicType()); | |
2953 param->SetPropagatedCid(kDynamicCid); | |
2954 bool param_type_is_known = false; | |
2955 if (param->index() == 0) { | |
2956 const Function& function = parsed_function().function(); | |
2957 if ((function.IsDynamicFunction() || function.IsConstructor())) { | |
2958 // Parameter is the receiver . | |
2959 param_type_is_known = true; | |
2960 } | |
2961 } else if ((param->index() == 1) && | |
2962 parsed_function().function().IsConstructor()) { | |
2963 // Parameter is the constructor phase. | |
2964 param_type_is_known = true; | |
2965 } | |
2966 if (param_type_is_known) { | |
2967 LocalScope* scope = parsed_function().node_sequence()->scope(); | |
2968 param_type = scope->VariableAt(param->index())->type().raw(); | |
2969 if (FLAG_use_cha) { | |
2970 const intptr_t cid = Class::Handle(param_type.type_class()).id(); | |
2971 if (!CHA::HasSubclasses(cid)) { | |
2972 // Receiver's class has no subclasses. | |
2973 param->SetPropagatedCid(cid); | |
2974 } | |
2975 } | |
2976 } | |
2977 bool changed = param->SetPropagatedType(param_type); | |
2978 if (changed) { | |
2979 still_changing_ = true; | |
2980 } | |
2981 } | |
2982 | |
2983 | |
2984 void FlowGraphTypePropagator::PropagateTypes() { | |
2985 // TODO(regis): Is there a way to make this more efficient, e.g. by visiting | |
2986 // only blocks depending on blocks that have changed and not the whole graph. | |
2987 do { | |
2988 still_changing_ = false; | |
2989 VisitBlocks(); | |
2990 } while (still_changing_); | |
2991 } | |
2992 | |
2993 | |
2994 static BlockEntryInstr* FindPreHeader(BlockEntryInstr* header) { | 2560 static BlockEntryInstr* FindPreHeader(BlockEntryInstr* header) { |
2995 for (intptr_t j = 0; j < header->PredecessorCount(); ++j) { | 2561 for (intptr_t j = 0; j < header->PredecessorCount(); ++j) { |
2996 BlockEntryInstr* candidate = header->PredecessorAt(j); | 2562 BlockEntryInstr* candidate = header->PredecessorAt(j); |
2997 if (header->dominator() == candidate) { | 2563 if (header->dominator() == candidate) { |
2998 return candidate; | 2564 return candidate; |
2999 } | 2565 } |
3000 } | 2566 } |
3001 return NULL; | 2567 return NULL; |
3002 } | 2568 } |
3003 | 2569 |
(...skipping 24 matching lines...) Expand all Loading... |
3028 | 2594 |
3029 void LICM::TryHoistCheckSmiThroughPhi(ForwardInstructionIterator* it, | 2595 void LICM::TryHoistCheckSmiThroughPhi(ForwardInstructionIterator* it, |
3030 BlockEntryInstr* header, | 2596 BlockEntryInstr* header, |
3031 BlockEntryInstr* pre_header, | 2597 BlockEntryInstr* pre_header, |
3032 CheckSmiInstr* current) { | 2598 CheckSmiInstr* current) { |
3033 PhiInstr* phi = current->value()->definition()->AsPhi(); | 2599 PhiInstr* phi = current->value()->definition()->AsPhi(); |
3034 if (!header->loop_info()->Contains(phi->block()->preorder_number())) { | 2600 if (!header->loop_info()->Contains(phi->block()->preorder_number())) { |
3035 return; | 2601 return; |
3036 } | 2602 } |
3037 | 2603 |
3038 if (phi->GetPropagatedCid() == kSmiCid) { | 2604 if (phi->Type()->ToCid() == kSmiCid) { |
3039 current->UnuseAllInputs(); | 2605 current->UnuseAllInputs(); |
3040 it->RemoveCurrentFromGraph(); | 2606 it->RemoveCurrentFromGraph(); |
3041 return; | 2607 return; |
3042 } | 2608 } |
3043 | 2609 |
3044 // Check if there is only a single kDynamicCid input to the phi that | 2610 // Check if there is only a single kDynamicCid input to the phi that |
3045 // comes from the pre-header. | 2611 // comes from the pre-header. |
3046 const intptr_t kNotFound = -1; | 2612 const intptr_t kNotFound = -1; |
3047 intptr_t non_smi_input = kNotFound; | 2613 intptr_t non_smi_input = kNotFound; |
3048 for (intptr_t i = 0; i < phi->InputCount(); ++i) { | 2614 for (intptr_t i = 0; i < phi->InputCount(); ++i) { |
3049 Value* input = phi->InputAt(i); | 2615 Value* input = phi->InputAt(i); |
3050 if (input->ResultCid() != kSmiCid) { | 2616 if (input->Type()->ToCid() != kSmiCid) { |
3051 if ((non_smi_input != kNotFound) || (input->ResultCid() != kDynamicCid)) { | 2617 if ((non_smi_input != kNotFound) || |
| 2618 (input->Type()->ToCid() != kDynamicCid)) { |
3052 // There are multiple kDynamicCid inputs or there is an input that is | 2619 // There are multiple kDynamicCid inputs or there is an input that is |
3053 // known to be non-smi. | 2620 // known to be non-smi. |
3054 return; | 2621 return; |
3055 } else { | 2622 } else { |
3056 non_smi_input = i; | 2623 non_smi_input = i; |
3057 } | 2624 } |
3058 } | 2625 } |
3059 } | 2626 } |
3060 | 2627 |
3061 if ((non_smi_input == kNotFound) || | 2628 if ((non_smi_input == kNotFound) || |
3062 (phi->block()->PredecessorAt(non_smi_input) != pre_header)) { | 2629 (phi->block()->PredecessorAt(non_smi_input) != pre_header)) { |
3063 return; | 2630 return; |
3064 } | 2631 } |
3065 | 2632 |
3066 // Host CheckSmi instruction and make this phi smi one. | 2633 // Host CheckSmi instruction and make this phi smi one. |
3067 Hoist(it, pre_header, current); | 2634 Hoist(it, pre_header, current); |
3068 | 2635 |
3069 // Replace value we are checking with phi's input. Maintain use lists. | 2636 // Replace value we are checking with phi's input. Maintain use lists. |
3070 Definition* non_smi_input_defn = phi->InputAt(non_smi_input)->definition(); | 2637 Definition* non_smi_input_defn = phi->InputAt(non_smi_input)->definition(); |
3071 current->value()->RemoveFromUseList(); | 2638 current->value()->RemoveFromUseList(); |
3072 current->value()->set_definition(non_smi_input_defn); | 2639 current->value()->set_definition(non_smi_input_defn); |
3073 non_smi_input_defn->AddInputUse(current->value()); | 2640 non_smi_input_defn->AddInputUse(current->value()); |
3074 | 2641 |
3075 phi->SetPropagatedCid(kSmiCid); | 2642 phi->Type()->ReplaceWith(CompileType::FromCid(kSmiCid)); |
3076 } | 2643 } |
3077 | 2644 |
3078 | 2645 |
3079 void LICM::Optimize(FlowGraph* flow_graph) { | 2646 void LICM::Optimize(FlowGraph* flow_graph) { |
3080 GrowableArray<BlockEntryInstr*> loop_headers; | 2647 GrowableArray<BlockEntryInstr*> loop_headers; |
3081 flow_graph->ComputeLoops(&loop_headers); | 2648 flow_graph->ComputeLoops(&loop_headers); |
3082 | 2649 |
3083 for (intptr_t i = 0; i < loop_headers.length(); ++i) { | 2650 for (intptr_t i = 0; i < loop_headers.length(); ++i) { |
3084 BlockEntryInstr* header = loop_headers[i]; | 2651 BlockEntryInstr* header = loop_headers[i]; |
3085 // Skip loop that don't have a pre-header block. | 2652 // Skip loop that don't have a pre-header block. |
(...skipping 1025 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4111 UNREACHABLE(); | 3678 UNREACHABLE(); |
4112 } | 3679 } |
4113 | 3680 |
4114 | 3681 |
4115 void ConstantPropagator::VisitStrictCompare(StrictCompareInstr* instr) { | 3682 void ConstantPropagator::VisitStrictCompare(StrictCompareInstr* instr) { |
4116 const Object& left = instr->left()->definition()->constant_value(); | 3683 const Object& left = instr->left()->definition()->constant_value(); |
4117 const Object& right = instr->right()->definition()->constant_value(); | 3684 const Object& right = instr->right()->definition()->constant_value(); |
4118 | 3685 |
4119 if (IsNonConstant(left) || IsNonConstant(right)) { | 3686 if (IsNonConstant(left) || IsNonConstant(right)) { |
4120 // TODO(vegorov): incorporate nullability information into the lattice. | 3687 // TODO(vegorov): incorporate nullability information into the lattice. |
4121 if ((left.IsNull() && (instr->right()->ResultCid() != kDynamicCid)) || | 3688 if ((left.IsNull() && instr->right()->Type()->HasDecidableNullability()) || |
4122 (right.IsNull() && (instr->left()->ResultCid() != kDynamicCid))) { | 3689 (right.IsNull() && instr->left()->Type()->HasDecidableNullability())) { |
4123 bool result = left.IsNull() ? (instr->right()->ResultCid() == kNullCid) | 3690 bool result = left.IsNull() ? instr->right()->Type()->IsNull() |
4124 : (instr->left()->ResultCid() == kNullCid); | 3691 : instr->left()->Type()->IsNull(); |
4125 if (instr->kind() == Token::kNE_STRICT) result = !result; | 3692 if (instr->kind() == Token::kNE_STRICT) result = !result; |
4126 SetValue(instr, result ? Bool::True() : Bool::False()); | 3693 SetValue(instr, result ? Bool::True() : Bool::False()); |
4127 } else { | 3694 } else { |
4128 SetValue(instr, non_constant_); | 3695 SetValue(instr, non_constant_); |
4129 } | 3696 } |
4130 } else if (IsConstant(left) && IsConstant(right)) { | 3697 } else if (IsConstant(left) && IsConstant(right)) { |
4131 bool result = (left.raw() == right.raw()); | 3698 bool result = (left.raw() == right.raw()); |
4132 if (instr->kind() == Token::kNE_STRICT) result = !result; | 3699 if (instr->kind() == Token::kNE_STRICT) result = !result; |
4133 SetValue(instr, result ? Bool::True() : Bool::False()); | 3700 SetValue(instr, result ? Bool::True() : Bool::False()); |
4134 } | 3701 } |
(...skipping 551 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4686 | 4253 |
4687 if (FLAG_trace_constant_propagation) { | 4254 if (FLAG_trace_constant_propagation) { |
4688 OS::Print("\n==== After constant propagation ====\n"); | 4255 OS::Print("\n==== After constant propagation ====\n"); |
4689 FlowGraphPrinter printer(*graph_); | 4256 FlowGraphPrinter printer(*graph_); |
4690 printer.PrintBlocks(); | 4257 printer.PrintBlocks(); |
4691 } | 4258 } |
4692 } | 4259 } |
4693 | 4260 |
4694 | 4261 |
4695 } // namespace dart | 4262 } // namespace dart |
OLD | NEW |