| 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 |