Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(168)

Side by Side Diff: runtime/vm/flow_graph_optimizer.cc

Issue 12260008: Reapply r18377 it was reverted due to the unrelated bug it surfaced. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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
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
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_ = &it;
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698