| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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_range_analysis.h" | 5 #include "vm/flow_graph_range_analysis.h" |
| 6 | 6 |
| 7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
| 8 #include "vm/il_printer.h" | 8 #include "vm/il_printer.h" |
| 9 | 9 |
| 10 namespace dart { | 10 namespace dart { |
| 11 | 11 |
| 12 DEFINE_FLAG(bool, array_bounds_check_elimination, true, | 12 DEFINE_FLAG(bool, array_bounds_check_elimination, true, |
| 13 "Eliminate redundant bounds checks."); | 13 "Eliminate redundant bounds checks."); |
| 14 DEFINE_FLAG(bool, trace_range_analysis, false, "Trace range analysis progress"); | 14 DEFINE_FLAG(bool, trace_range_analysis, false, "Trace range analysis progress"); |
| 15 DEFINE_FLAG(bool, trace_integer_ir_selection, false, | 15 DEFINE_FLAG(bool, trace_integer_ir_selection, false, |
| 16 "Print integer IR selection optimization pass."); | 16 "Print integer IR selection optimization pass."); |
| 17 DECLARE_FLAG(bool, trace_constant_propagation); | 17 DECLARE_FLAG(bool, trace_constant_propagation); |
| 18 | 18 |
| 19 // Quick access to the locally defined isolate() method. | 19 // Quick access to the locally defined isolate() method. |
| 20 #define I (isolate()) | 20 #define I (isolate()) |
| 21 | 21 |
| 22 void RangeAnalysis::Analyze() { | 22 void RangeAnalysis::Analyze() { |
| 23 CollectValues(); | 23 CollectValues(); |
| 24 InsertConstraints(); | 24 InsertConstraints(); |
| 25 InferRanges(); | 25 InferRanges(); |
| 26 EliminateRedundantBoundsChecks(); | |
| 27 MarkUnreachableBlocks(); | |
| 28 | |
| 29 IntegerInstructionSelector iis(flow_graph_); | 26 IntegerInstructionSelector iis(flow_graph_); |
| 30 iis.Select(); | 27 iis.Select(); |
| 31 | |
| 32 RemoveConstraints(); | 28 RemoveConstraints(); |
| 33 } | 29 } |
| 34 | 30 |
| 35 | 31 |
| 36 void RangeAnalysis::CollectValues() { | 32 void RangeAnalysis::CollectValues() { |
| 37 const GrowableArray<Definition*>& initial = | 33 const GrowableArray<Definition*>& initial = |
| 38 *flow_graph_->graph_entry()->initial_definitions(); | 34 *flow_graph_->graph_entry()->initial_definitions(); |
| 39 for (intptr_t i = 0; i < initial.length(); ++i) { | 35 for (intptr_t i = 0; i < initial.length(); ++i) { |
| 40 Definition* current = initial[i]; | 36 Definition* current = initial[i]; |
| 41 if (current->Type()->ToCid() == kSmiCid) { | 37 if (current->Type()->ToCid() == kSmiCid) { |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 82 Definition* defn = current->AsDefinition(); | 78 Definition* defn = current->AsDefinition(); |
| 83 if (defn != NULL) { | 79 if (defn != NULL) { |
| 84 if ((defn->Type()->ToCid() == kSmiCid) && | 80 if ((defn->Type()->ToCid() == kSmiCid) && |
| 85 (defn->ssa_temp_index() != -1)) { | 81 (defn->ssa_temp_index() != -1)) { |
| 86 values_.Add(defn); | 82 values_.Add(defn); |
| 87 } else if ((defn->IsMintDefinition()) && | 83 } else if ((defn->IsMintDefinition()) && |
| 88 (defn->ssa_temp_index() != -1)) { | 84 (defn->ssa_temp_index() != -1)) { |
| 89 values_.Add(defn); | 85 values_.Add(defn); |
| 90 } | 86 } |
| 91 } else if (current->IsCheckSmi()) { | 87 } else if (current->IsCheckSmi()) { |
| 92 if (current->Canonicalize(flow_graph_) == NULL) { | |
| 93 instr_it.RemoveCurrentFromGraph(); | |
| 94 continue; | |
| 95 } | |
| 96 smi_checks_.Add(current->AsCheckSmi()); | 88 smi_checks_.Add(current->AsCheckSmi()); |
| 97 } else if (current->IsCheckArrayBound()) { | |
| 98 bounds_checks_.Add(current->AsCheckArrayBound()); | |
| 99 } | 89 } |
| 100 } | 90 } |
| 101 } | 91 } |
| 102 } | 92 } |
| 103 | 93 |
| 104 | 94 |
| 105 // Returns true if use is dominated by the given instruction. | 95 // Returns true if use is dominated by the given instruction. |
| 106 // Note: uses that occur at instruction itself are not dominated by it. | 96 // Note: uses that occur at instruction itself are not dominated by it. |
| 107 static bool IsDominatedUse(Instruction* dom, Value* use) { | 97 static bool IsDominatedUse(Instruction* dom, Value* use) { |
| 108 BlockEntryInstr* dom_block = dom->GetBlock(); | 98 BlockEntryInstr* dom_block = dom->GetBlock(); |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 163 return Token::kILLEGAL; | 153 return Token::kILLEGAL; |
| 164 } | 154 } |
| 165 } | 155 } |
| 166 | 156 |
| 167 | 157 |
| 168 // Given a boundary (right operand) and a comparison operation return | 158 // Given a boundary (right operand) and a comparison operation return |
| 169 // a symbolic range constraint for the left operand of the comparison assuming | 159 // a symbolic range constraint for the left operand of the comparison assuming |
| 170 // that it evaluated to true. | 160 // that it evaluated to true. |
| 171 // For example for the comparison a < b symbol a is constrained with range | 161 // For example for the comparison a < b symbol a is constrained with range |
| 172 // [Smi::kMinValue, b - 1]. | 162 // [Smi::kMinValue, b - 1]. |
| 173 Range* RangeAnalysis::ConstraintSmiRange(Token::Kind op, Definition* boundary) { | 163 Range* RangeAnalysis::ConstraintRange(Token::Kind op, Definition* boundary) { |
| 174 switch (op) { | 164 switch (op) { |
| 175 case Token::kEQ: | 165 case Token::kEQ: |
| 176 return new(I) Range(RangeBoundary::FromDefinition(boundary), | 166 return new(I) Range(RangeBoundary::FromDefinition(boundary), |
| 177 RangeBoundary::FromDefinition(boundary)); | 167 RangeBoundary::FromDefinition(boundary)); |
| 178 case Token::kNE: | 168 case Token::kNE: |
| 179 return new(I) Range(Range::Full(RangeBoundary::kRangeBoundarySmi)); | 169 return Range::Unknown(); |
| 180 case Token::kLT: | 170 case Token::kLT: |
| 181 return new(I) Range(RangeBoundary::MinSmi(), | 171 return new(I) Range(RangeBoundary::MinSmi(), |
| 182 RangeBoundary::FromDefinition(boundary, -1)); | 172 RangeBoundary::FromDefinition(boundary, -1)); |
| 183 case Token::kGT: | 173 case Token::kGT: |
| 184 return new(I) Range(RangeBoundary::FromDefinition(boundary, 1), | 174 return new(I) Range(RangeBoundary::FromDefinition(boundary, 1), |
| 185 RangeBoundary::MaxSmi()); | 175 RangeBoundary::MaxSmi()); |
| 186 case Token::kLTE: | 176 case Token::kLTE: |
| 187 return new(I) Range(RangeBoundary::MinSmi(), | 177 return new(I) Range(RangeBoundary::MinSmi(), |
| 188 RangeBoundary::FromDefinition(boundary)); | 178 RangeBoundary::FromDefinition(boundary)); |
| 189 case Token::kGTE: | 179 case Token::kGTE: |
| 190 return new(I) Range(RangeBoundary::FromDefinition(boundary), | 180 return new(I) Range(RangeBoundary::FromDefinition(boundary), |
| 191 RangeBoundary::MaxSmi()); | 181 RangeBoundary::MaxSmi()); |
| 192 default: | 182 default: |
| 193 UNREACHABLE(); | 183 UNREACHABLE(); |
| 194 return NULL; | 184 return Range::Unknown(); |
| 195 } | 185 } |
| 196 } | 186 } |
| 197 | 187 |
| 198 | 188 |
| 199 ConstraintInstr* RangeAnalysis::InsertConstraintFor(Definition* defn, | 189 ConstraintInstr* RangeAnalysis::InsertConstraintFor(Definition* defn, |
| 200 Range* constraint_range, | 190 Range* constraint_range, |
| 201 Instruction* after) { | 191 Instruction* after) { |
| 202 // No need to constrain constants. | 192 // No need to constrain constants. |
| 203 if (defn->IsConstant()) return NULL; | 193 if (defn->IsConstant()) return NULL; |
| 204 | 194 |
| 205 // Check if the value is already constrained to avoid inserting duplicated | 195 ConstraintInstr* constraint = new(I) ConstraintInstr( |
| 206 // constraints. | |
| 207 ConstraintInstr* constraint = after->next()->AsConstraint(); | |
| 208 while (constraint != NULL) { | |
| 209 if ((constraint->value()->definition() == defn) && | |
| 210 constraint->constraint()->Equals(constraint_range)) { | |
| 211 return NULL; | |
| 212 } | |
| 213 constraint = constraint->next()->AsConstraint(); | |
| 214 } | |
| 215 | |
| 216 constraint = new(I) ConstraintInstr( | |
| 217 new(I) Value(defn), constraint_range); | 196 new(I) Value(defn), constraint_range); |
| 218 flow_graph_->InsertAfter(after, constraint, NULL, FlowGraph::kValue); | 197 flow_graph_->InsertAfter(after, constraint, NULL, FlowGraph::kValue); |
| 219 RenameDominatedUses(defn, constraint, constraint); | 198 RenameDominatedUses(defn, constraint, constraint); |
| 220 constraints_.Add(constraint); | 199 constraints_.Add(constraint); |
| 221 return constraint; | 200 return constraint; |
| 222 } | 201 } |
| 223 | 202 |
| 224 | 203 |
| 225 void RangeAnalysis::ConstrainValueAfterBranch(Definition* defn, Value* use) { | 204 void RangeAnalysis::ConstrainValueAfterBranch(Definition* defn, Value* use) { |
| 226 BranchInstr* branch = use->instruction()->AsBranch(); | 205 BranchInstr* branch = use->instruction()->AsBranch(); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 237 ASSERT(use->use_index() == 1); // Right operand. | 216 ASSERT(use->use_index() == 1); // Right operand. |
| 238 boundary = rel_op->InputAt(0)->definition(); | 217 boundary = rel_op->InputAt(0)->definition(); |
| 239 // InsertConstraintFor assumes that defn is left operand of a | 218 // InsertConstraintFor assumes that defn is left operand of a |
| 240 // comparison if it is right operand flip the comparison. | 219 // comparison if it is right operand flip the comparison. |
| 241 op_kind = FlipComparison(rel_op->kind()); | 220 op_kind = FlipComparison(rel_op->kind()); |
| 242 } | 221 } |
| 243 | 222 |
| 244 // Constrain definition at the true successor. | 223 // Constrain definition at the true successor. |
| 245 ConstraintInstr* true_constraint = | 224 ConstraintInstr* true_constraint = |
| 246 InsertConstraintFor(defn, | 225 InsertConstraintFor(defn, |
| 247 ConstraintSmiRange(op_kind, boundary), | 226 ConstraintRange(op_kind, boundary), |
| 248 branch->true_successor()); | 227 branch->true_successor()); |
| 249 // Mark true_constraint an artificial use of boundary. This ensures | 228 // Mark true_constraint an artificial use of boundary. This ensures |
| 250 // that constraint's range is recalculated if boundary's range changes. | 229 // that constraint's range is recalculated if boundary's range changes. |
| 251 if (true_constraint != NULL) { | 230 if (true_constraint != NULL) { |
| 252 true_constraint->AddDependency(boundary); | 231 true_constraint->AddDependency(boundary); |
| 253 true_constraint->set_target(branch->true_successor()); | 232 true_constraint->set_target(branch->true_successor()); |
| 254 } | 233 } |
| 255 | 234 |
| 256 // Constrain definition with a negated condition at the false successor. | 235 // Constrain definition with a negated condition at the false successor. |
| 257 ConstraintInstr* false_constraint = | 236 ConstraintInstr* false_constraint = |
| 258 InsertConstraintFor( | 237 InsertConstraintFor( |
| 259 defn, | 238 defn, |
| 260 ConstraintSmiRange(Token::NegateComparison(op_kind), boundary), | 239 ConstraintRange(Token::NegateComparison(op_kind), boundary), |
| 261 branch->false_successor()); | 240 branch->false_successor()); |
| 262 // Mark false_constraint an artificial use of boundary. This ensures | 241 // Mark false_constraint an artificial use of boundary. This ensures |
| 263 // that constraint's range is recalculated if boundary's range changes. | 242 // that constraint's range is recalculated if boundary's range changes. |
| 264 if (false_constraint != NULL) { | 243 if (false_constraint != NULL) { |
| 265 false_constraint->AddDependency(boundary); | 244 false_constraint->AddDependency(boundary); |
| 266 false_constraint->set_target(branch->false_successor()); | 245 false_constraint->set_target(branch->false_successor()); |
| 267 } | 246 } |
| 268 } | 247 } |
| 269 } | 248 } |
| 270 | 249 |
| (...skipping 27 matching lines...) Expand all Loading... |
| 298 Definition* index = check->index()->definition(); | 277 Definition* index = check->index()->definition(); |
| 299 constraint_range = new(I) Range( | 278 constraint_range = new(I) Range( |
| 300 RangeBoundary::FromDefinition(index, 1), | 279 RangeBoundary::FromDefinition(index, 1), |
| 301 RangeBoundary::MaxSmi()); | 280 RangeBoundary::MaxSmi()); |
| 302 } | 281 } |
| 303 InsertConstraintFor(defn, constraint_range, check); | 282 InsertConstraintFor(defn, constraint_range, check); |
| 304 } | 283 } |
| 305 | 284 |
| 306 | 285 |
| 307 void RangeAnalysis::InsertConstraints() { | 286 void RangeAnalysis::InsertConstraints() { |
| 308 Range* smi_range = new(I) Range( | |
| 309 Range::Full(RangeBoundary::kRangeBoundarySmi)); | |
| 310 | |
| 311 for (intptr_t i = 0; i < smi_checks_.length(); i++) { | 287 for (intptr_t i = 0; i < smi_checks_.length(); i++) { |
| 312 CheckSmiInstr* check = smi_checks_[i]; | 288 CheckSmiInstr* check = smi_checks_[i]; |
| 313 ConstraintInstr* constraint = | 289 ConstraintInstr* constraint = |
| 314 InsertConstraintFor(check->value()->definition(), | 290 InsertConstraintFor(check->value()->definition(), |
| 315 smi_range, | 291 Range::UnknownSmi(), |
| 316 check); | 292 check); |
| 317 if (constraint == NULL) { | 293 if (constraint == NULL) { |
| 318 // No constraint was needed. | 294 // No constraint was needed. |
| 319 continue; | 295 continue; |
| 320 } | 296 } |
| 321 if (!check->value()->definition()->IsBoxInteger()) { | |
| 322 constraint->set_range(Range::Full(RangeBoundary::kRangeBoundarySmi)); | |
| 323 } | |
| 324 | |
| 325 // Mark the constraint's value's reaching type as smi. | 297 // Mark the constraint's value's reaching type as smi. |
| 326 CompileType* smi_compile_type = | 298 CompileType* smi_compile_type = |
| 327 ZoneCompileType::Wrap(CompileType::FromCid(kSmiCid)); | 299 ZoneCompileType::Wrap(CompileType::FromCid(kSmiCid)); |
| 328 constraint->value()->SetReachingType(smi_compile_type); | 300 constraint->value()->SetReachingType(smi_compile_type); |
| 329 } | 301 } |
| 330 | 302 |
| 331 for (intptr_t i = 0; i < values_.length(); i++) { | 303 for (intptr_t i = 0; i < values_.length(); i++) { |
| 332 InsertConstraintsFor(values_[i]); | 304 InsertConstraintsFor(values_[i]); |
| 333 } | 305 } |
| 334 | 306 |
| 335 for (intptr_t i = 0; i < constraints_.length(); i++) { | 307 for (intptr_t i = 0; i < constraints_.length(); i++) { |
| 336 InsertConstraintsFor(constraints_[i]); | 308 InsertConstraintsFor(constraints_[i]); |
| 337 } | 309 } |
| 338 } | 310 } |
| 339 | 311 |
| 340 | 312 |
| 341 static Definition* UnwrapConstraint(Definition* defn) { | 313 void RangeAnalysis::ResetWorklist() { |
| 314 if (marked_defns_ == NULL) { |
| 315 marked_defns_ = new(I) BitVector(flow_graph_->current_ssa_temp_index()); |
| 316 } else { |
| 317 marked_defns_->Clear(); |
| 318 } |
| 319 worklist_.Clear(); |
| 320 } |
| 321 |
| 322 |
| 323 void RangeAnalysis::MarkDefinition(Definition* defn) { |
| 324 // Unwrap constrained value. |
| 342 while (defn->IsConstraint()) { | 325 while (defn->IsConstraint()) { |
| 343 defn = defn->AsConstraint()->value()->definition(); | 326 defn = defn->AsConstraint()->value()->definition(); |
| 344 } | 327 } |
| 345 return defn; | 328 |
| 346 } | 329 if (!marked_defns_->Contains(defn->ssa_temp_index())) { |
| 347 | 330 worklist_.Add(defn); |
| 348 | 331 marked_defns_->Add(defn->ssa_temp_index()); |
| 349 static bool AreEqualDefinitions(Definition* a, Definition* b) { | 332 } |
| 350 a = UnwrapConstraint(a); | 333 } |
| 351 b = UnwrapConstraint(b); | 334 |
| 352 return (a == b) || | 335 |
| 353 (a->AllowsCSE() && | 336 RangeAnalysis::Direction RangeAnalysis::ToDirection(Value* val) { |
| 354 a->Dependencies().IsNone() && | 337 if (val->BindsToConstant()) { |
| 355 b->AllowsCSE() && | 338 return (Smi::Cast(val->BoundConstant()).Value() >= 0) ? kPositive |
| 356 b->Dependencies().IsNone() && | 339 : kNegative; |
| 357 a->Equals(b)); | 340 } else if (val->definition()->range() != NULL) { |
| 358 } | 341 Range* range = val->definition()->range(); |
| 359 | 342 if (Range::ConstantMin(range).ConstantValue() >= 0) { |
| 360 | 343 return kPositive; |
| 361 static bool DependOnSameSymbol(const RangeBoundary& a, const RangeBoundary& b) { | 344 } else if (Range::ConstantMax(range).ConstantValue() <= 0) { |
| 362 return a.IsSymbol() && b.IsSymbol() && | 345 return kNegative; |
| 363 AreEqualDefinitions(a.symbol(), b.symbol()); | 346 } |
| 364 } | 347 } |
| 365 | 348 return kUnknown; |
| 366 | 349 } |
| 367 // Given the current range of a phi and a newly computed range check | 350 |
| 368 // if it is growing towards negative infinity, if it does widen it to | 351 |
| 369 // MinSmi. | 352 Range* RangeAnalysis::InferInductionVariableRange(JoinEntryInstr* loop_header, |
| 370 static RangeBoundary WidenMin(const Range* range, const Range* new_range) { | 353 PhiInstr* var) { |
| 371 RangeBoundary min = range->min(); | 354 BitVector* loop_info = loop_header->loop_info(); |
| 372 RangeBoundary new_min = new_range->min(); | 355 |
| 373 | 356 Definition* initial_value = NULL; |
| 374 if (min.IsSymbol()) { | 357 Direction direction = kUnknown; |
| 375 if (min.LowerBound().OverflowedSmi()) { | 358 |
| 376 return RangeBoundary::MinSmi(); | 359 ResetWorklist(); |
| 377 } else if (DependOnSameSymbol(min, new_min)) { | 360 MarkDefinition(var); |
| 378 return min.offset() <= new_min.offset() ? min : RangeBoundary::MinSmi(); | 361 while (!worklist_.is_empty()) { |
| 379 } else if (min.SmiUpperBound() <= new_min.SmiLowerBound()) { | 362 Definition* defn = worklist_.RemoveLast(); |
| 380 return min; | 363 |
| 381 } | 364 if (defn->IsPhi()) { |
| 382 } | 365 PhiInstr* phi = defn->AsPhi(); |
| 383 | 366 for (intptr_t i = 0; i < phi->InputCount(); i++) { |
| 384 min = Range::ConstantMinSmi(range); | 367 Definition* defn = phi->InputAt(i)->definition(); |
| 385 new_min = Range::ConstantMinSmi(new_range); | 368 |
| 386 | 369 if (!loop_info->Contains(defn->GetBlock()->preorder_number())) { |
| 387 return (min.ConstantValue() <= new_min.ConstantValue()) ? | 370 // The value is coming from outside of the loop. |
| 388 min : RangeBoundary::MinSmi(); | 371 if (initial_value == NULL) { |
| 389 } | 372 initial_value = defn; |
| 390 | 373 continue; |
| 391 // Given the current range of a phi and a newly computed range check | 374 } else if (initial_value == defn) { |
| 392 // if it is growing towards positive infinity, if it does widen it to | 375 continue; |
| 393 // MaxSmi. | 376 } else { |
| 394 static RangeBoundary WidenMax(const Range* range, const Range* new_range) { | 377 return NULL; |
| 395 RangeBoundary max = range->max(); | 378 } |
| 396 RangeBoundary new_max = new_range->max(); | 379 } |
| 397 | 380 |
| 398 if (max.IsSymbol()) { | 381 MarkDefinition(defn); |
| 399 if (max.UpperBound().OverflowedSmi()) { | 382 } |
| 400 return RangeBoundary::MaxSmi(); | 383 } else if (defn->IsBinarySmiOp()) { |
| 401 } else if (DependOnSameSymbol(max, new_max)) { | 384 BinarySmiOpInstr* binary_op = defn->AsBinarySmiOp(); |
| 402 return max.offset() >= new_max.offset() ? max : RangeBoundary::MaxSmi(); | 385 |
| 403 } else if (max.SmiLowerBound() >= new_max.SmiUpperBound()) { | 386 switch (binary_op->op_kind()) { |
| 404 return max; | 387 case Token::kADD: { |
| 405 } | 388 const Direction growth_right = |
| 406 } | 389 ToDirection(binary_op->right()); |
| 407 | 390 if (growth_right != kUnknown) { |
| 408 max = Range::ConstantMaxSmi(range); | 391 UpdateDirection(&direction, growth_right); |
| 409 new_max = Range::ConstantMaxSmi(new_range); | 392 MarkDefinition(binary_op->left()->definition()); |
| 410 | 393 break; |
| 411 return (max.ConstantValue() >= new_max.ConstantValue()) ? | 394 } |
| 412 max : RangeBoundary::MaxSmi(); | 395 |
| 413 } | 396 const Direction growth_left = |
| 414 | 397 ToDirection(binary_op->left()); |
| 415 | 398 if (growth_left != kUnknown) { |
| 416 // Given the current range of a phi and a newly computed range check | 399 UpdateDirection(&direction, growth_left); |
| 417 // if we can perform narrowing: use newly computed minimum to improve precision | 400 MarkDefinition(binary_op->right()->definition()); |
| 418 // of the computed range. We do it only if current minimum was widened and is | 401 break; |
| 419 // equal to MinSmi. | 402 } |
| 420 // Newly computed minimum is expected to be greater of equal then old one as | 403 |
| 421 // we are running after widening phase. | 404 return NULL; |
| 422 static RangeBoundary NarrowMin(const Range* range, const Range* new_range) { | 405 } |
| 423 #ifdef DEBUG | 406 |
| 424 const RangeBoundary min = Range::ConstantMinSmi(range); | 407 case Token::kSUB: { |
| 425 const RangeBoundary new_min = Range::ConstantMinSmi(new_range); | 408 const Direction growth_right = |
| 426 ASSERT(min.ConstantValue() <= new_min.ConstantValue()); | 409 ToDirection(binary_op->right()); |
| 427 #endif | 410 if (growth_right != kUnknown) { |
| 428 // TODO(vegorov): consider using negative infinity to indicate widened bound. | 411 UpdateDirection(&direction, Invert(growth_right)); |
| 429 return range->min().IsSmiMinimumOrBelow() ? new_range->min() : range->min(); | 412 MarkDefinition(binary_op->left()->definition()); |
| 430 } | 413 break; |
| 431 | 414 } |
| 432 | 415 return NULL; |
| 433 // Given the current range of a phi and a newly computed range check | 416 } |
| 434 // if we can perform narrowing: use newly computed maximum to improve precision | 417 |
| 435 // of the computed range. We do it only if current maximum was widened and is | 418 default: |
| 436 // equal to MaxSmi. | 419 return NULL; |
| 437 // Newly computed minimum is expected to be greater of equal then old one as | 420 } |
| 438 // we are running after widening phase. | 421 } else { |
| 439 static RangeBoundary NarrowMax(const Range* range, const Range* new_range) { | 422 return NULL; |
| 440 #ifdef DEBUG | 423 } |
| 441 const RangeBoundary max = Range::ConstantMaxSmi(range); | 424 } |
| 442 const RangeBoundary new_max = Range::ConstantMaxSmi(new_range); | 425 |
| 443 ASSERT(max.ConstantValue() >= new_max.ConstantValue()); | 426 |
| 444 #endif | 427 // We transitively discovered all dependencies of the given phi |
| 445 // TODO(vegorov): consider using positive infinity to indicate widened bound. | 428 // and confirmed that it depends on a single value coming from outside of |
| 446 return range->max().IsSmiMaximumOrAbove() ? new_range->max() : range->max(); | 429 // the loop and some linear combinations of itself. |
| 447 } | 430 // Compute the range based on initial value and the direction of the growth. |
| 448 | 431 switch (direction) { |
| 449 | 432 case kPositive: |
| 450 char RangeAnalysis::OpPrefix(JoinOperator op) { | 433 return new(I) Range(RangeBoundary::FromDefinition(initial_value), |
| 451 switch (op) { | 434 RangeBoundary::MaxSmi()); |
| 452 case WIDEN: return 'W'; | 435 |
| 453 case NARROW: return 'N'; | 436 case kNegative: |
| 454 case NONE: return 'I'; | 437 return new(I) Range(RangeBoundary::MinSmi(), |
| 455 } | 438 RangeBoundary::FromDefinition(initial_value)); |
| 439 |
| 440 case kUnknown: |
| 441 case kBoth: |
| 442 return Range::UnknownSmi(); |
| 443 } |
| 444 |
| 456 UNREACHABLE(); | 445 UNREACHABLE(); |
| 457 return ' '; | 446 return NULL; |
| 458 } | 447 } |
| 459 | 448 |
| 460 | 449 |
| 461 bool RangeAnalysis::InferRange(JoinOperator op, | 450 void RangeAnalysis::InferRangesRecursive(BlockEntryInstr* block) { |
| 462 Definition* defn, | 451 JoinEntryInstr* join = block->AsJoinEntry(); |
| 463 intptr_t iteration) { | 452 if (join != NULL) { |
| 464 Range range; | 453 const bool is_loop_header = (join->loop_info() != NULL); |
| 465 defn->InferRange(&range); | 454 for (PhiIterator it(join); !it.Done(); it.Advance()) { |
| 466 | 455 PhiInstr* phi = it.Current(); |
| 467 if (!Range::IsUnknown(&range)) { | 456 if (definitions_->Contains(phi->ssa_temp_index())) { |
| 468 if (!Range::IsUnknown(defn->range()) && defn->IsPhi()) { | 457 if (is_loop_header) { |
| 469 // TODO(vegorov): we are currently supporting only smi phis. | 458 // Try recognizing simple induction variables. |
| 470 ASSERT(defn->Type()->ToCid() == kSmiCid); | 459 Range* range = InferInductionVariableRange(join, phi); |
| 471 if (op == WIDEN) { | 460 if (range != NULL) { |
| 472 range = Range(WidenMin(defn->range(), &range), | 461 phi->range_ = range; |
| 473 WidenMax(defn->range(), &range)); | 462 continue; |
| 474 } else if (op == NARROW) { | 463 } |
| 475 range = Range(NarrowMin(defn->range(), &range), | 464 } |
| 476 NarrowMax(defn->range(), &range)); | 465 |
| 477 } | 466 phi->InferRange(); |
| 478 } | 467 } |
| 479 | 468 } |
| 480 if (!range.Equals(defn->range())) { | 469 } |
| 481 if (FLAG_trace_range_analysis) { | 470 |
| 482 OS::Print("%c [%" Pd "] %s: %s => %s\n", | 471 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { |
| 483 OpPrefix(op), | 472 Instruction* current = it.Current(); |
| 484 iteration, | 473 |
| 485 defn->ToCString(), | 474 Definition* defn = current->AsDefinition(); |
| 486 Range::ToCString(defn->range()), | 475 if ((defn != NULL) && |
| 487 Range::ToCString(&range)); | 476 (defn->ssa_temp_index() != -1) && |
| 488 } | 477 definitions_->Contains(defn->ssa_temp_index())) { |
| 489 defn->set_range(range); | 478 defn->InferRange(); |
| 490 return true; | 479 } else if (FLAG_array_bounds_check_elimination && |
| 491 } | 480 current->IsCheckArrayBound()) { |
| 492 } | 481 CheckArrayBoundInstr* check = current->AsCheckArrayBound(); |
| 493 | 482 RangeBoundary array_length = |
| 494 return false; | 483 RangeBoundary::FromDefinition(check->length()->definition()); |
| 495 } | 484 if (check->IsRedundant(array_length)) { |
| 496 | 485 it.RemoveCurrentFromGraph(); |
| 497 | 486 } |
| 498 void RangeAnalysis::CollectDefinitions(BlockEntryInstr* block, BitVector* set) { | 487 } |
| 499 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); | 488 } |
| 500 !block_it.Done(); | 489 |
| 501 block_it.Advance()) { | 490 for (intptr_t i = 0; i < block->dominated_blocks().length(); ++i) { |
| 502 BlockEntryInstr* block = block_it.Current(); | 491 InferRangesRecursive(block->dominated_blocks()[i]); |
| 503 | 492 } |
| 504 JoinEntryInstr* join = block->AsJoinEntry(); | |
| 505 if (join != NULL) { | |
| 506 for (PhiIterator it(join); !it.Done(); it.Advance()) { | |
| 507 PhiInstr* phi = it.Current(); | |
| 508 if (set->Contains(phi->ssa_temp_index())) { | |
| 509 definitions_.Add(phi); | |
| 510 } | |
| 511 } | |
| 512 } | |
| 513 | |
| 514 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { | |
| 515 Definition* defn = it.Current()->AsDefinition(); | |
| 516 if ((defn != NULL) && | |
| 517 (defn->ssa_temp_index() != -1) && | |
| 518 set->Contains(defn->ssa_temp_index())) { | |
| 519 definitions_.Add(defn); | |
| 520 } | |
| 521 } | |
| 522 } | |
| 523 } | |
| 524 | |
| 525 | |
| 526 void RangeAnalysis::Iterate(JoinOperator op, intptr_t max_iterations) { | |
| 527 // TODO(vegorov): switch to worklist if this becomes performance bottleneck. | |
| 528 intptr_t iteration = 0; | |
| 529 bool changed; | |
| 530 do { | |
| 531 changed = false; | |
| 532 for (intptr_t i = 0; i < definitions_.length(); i++) { | |
| 533 Definition* defn = definitions_[i]; | |
| 534 if (InferRange(op, defn, iteration)) { | |
| 535 changed = true; | |
| 536 } | |
| 537 } | |
| 538 | |
| 539 iteration++; | |
| 540 } while (changed && (iteration < max_iterations)); | |
| 541 } | 493 } |
| 542 | 494 |
| 543 | 495 |
| 544 void RangeAnalysis::InferRanges() { | 496 void RangeAnalysis::InferRanges() { |
| 545 if (FLAG_trace_range_analysis) { | 497 if (FLAG_trace_range_analysis) { |
| 546 FlowGraphPrinter::PrintGraph("Range Analysis (BEFORE)", flow_graph_); | 498 OS::Print("---- before range analysis -------\n"); |
| 547 } | 499 FlowGraphPrinter printer(*flow_graph_); |
| 548 | 500 printer.PrintBlocks(); |
| 501 } |
| 549 // Initialize bitvector for quick filtering of int values. | 502 // Initialize bitvector for quick filtering of int values. |
| 550 BitVector* set = new(I) BitVector(flow_graph_->current_ssa_temp_index()); | 503 definitions_ = |
| 504 new(I) BitVector(flow_graph_->current_ssa_temp_index()); |
| 551 for (intptr_t i = 0; i < values_.length(); i++) { | 505 for (intptr_t i = 0; i < values_.length(); i++) { |
| 552 set->Add(values_[i]->ssa_temp_index()); | 506 definitions_->Add(values_[i]->ssa_temp_index()); |
| 553 } | 507 } |
| 554 for (intptr_t i = 0; i < constraints_.length(); i++) { | 508 for (intptr_t i = 0; i < constraints_.length(); i++) { |
| 555 set->Add(constraints_[i]->ssa_temp_index()); | 509 definitions_->Add(constraints_[i]->ssa_temp_index()); |
| 556 } | 510 } |
| 557 | 511 |
| 558 // Collect integer definitions (including constraints) in the reverse | 512 // Infer initial values of ranges. |
| 559 // postorder. This improves convergence speed compared to iterating | |
| 560 // values_ and constraints_ array separately. | |
| 561 const GrowableArray<Definition*>& initial = | 513 const GrowableArray<Definition*>& initial = |
| 562 *flow_graph_->graph_entry()->initial_definitions(); | 514 *flow_graph_->graph_entry()->initial_definitions(); |
| 563 for (intptr_t i = 0; i < initial.length(); ++i) { | 515 for (intptr_t i = 0; i < initial.length(); ++i) { |
| 564 Definition* definition = initial[i]; | 516 Definition* definition = initial[i]; |
| 565 if (set->Contains(definition->ssa_temp_index())) { | 517 if (definitions_->Contains(definition->ssa_temp_index())) { |
| 566 definitions_.Add(definition); | 518 definition->InferRange(); |
| 567 } | 519 } |
| 568 } | 520 } |
| 569 CollectDefinitions(flow_graph_->graph_entry(), set); | 521 InferRangesRecursive(flow_graph_->graph_entry()); |
| 570 | |
| 571 // Perform an iteration of range inference just propagating ranges | |
| 572 // through the graph as-is without applying widening or narrowing. | |
| 573 // This helps to improve precision of initial bounds. | |
| 574 Iterate(NONE, 1); | |
| 575 | |
| 576 // Perform fix-point iteration of range inference applying widening | |
| 577 // operator to phis to ensure fast convergence. | |
| 578 // Widening simply maps growing bounds to the respective range bound. | |
| 579 Iterate(WIDEN, kMaxInt32); | |
| 580 | 522 |
| 581 if (FLAG_trace_range_analysis) { | 523 if (FLAG_trace_range_analysis) { |
| 582 FlowGraphPrinter::PrintGraph("Range Analysis (WIDEN)", flow_graph_); | 524 OS::Print("---- after range analysis -------\n"); |
| 583 } | 525 FlowGraphPrinter printer(*flow_graph_); |
| 584 | 526 printer.PrintBlocks(); |
| 585 // Perform fix-point iteration of range inference applying narrowing | 527 } |
| 586 // to phis to compute more accurate range. | 528 } |
| 587 // Narrowing only improves those boundaries that were widened up to | 529 |
| 588 // range boundary and leaves other boundaries intact. | |
| 589 Iterate(NARROW, kMaxInt32); | |
| 590 | |
| 591 if (FLAG_trace_range_analysis) { | |
| 592 FlowGraphPrinter::PrintGraph("Range Analysis (AFTER)", flow_graph_); | |
| 593 } | |
| 594 } | |
| 595 | |
| 596 | |
| 597 void RangeAnalysis::EliminateRedundantBoundsChecks() { | |
| 598 if (FLAG_array_bounds_check_elimination) { | |
| 599 for (intptr_t i = 0; i < bounds_checks_.length(); i++) { | |
| 600 CheckArrayBoundInstr* check = bounds_checks_[i]; | |
| 601 RangeBoundary array_length = | |
| 602 RangeBoundary::FromDefinition(check->length()->definition()); | |
| 603 if (check->IsRedundant(array_length)) { | |
| 604 check->RemoveFromGraph(); | |
| 605 } | |
| 606 } | |
| 607 } | |
| 608 } | |
| 609 | |
| 610 | |
| 611 void RangeAnalysis::MarkUnreachableBlocks() { | |
| 612 for (intptr_t i = 0; i < constraints_.length(); i++) { | |
| 613 if (Range::IsUnknown(constraints_[i]->range())) { | |
| 614 TargetEntryInstr* target = constraints_[i]->target(); | |
| 615 if (target == NULL) { | |
| 616 // TODO(vegorov): replace Constraint with an uncoditional | |
| 617 // deoptimization and kill all dominated dead code. | |
| 618 continue; | |
| 619 } | |
| 620 | |
| 621 BranchInstr* branch = | |
| 622 target->PredecessorAt(0)->last_instruction()->AsBranch(); | |
| 623 if (target == branch->true_successor()) { | |
| 624 // True unreachable. | |
| 625 if (FLAG_trace_constant_propagation) { | |
| 626 OS::Print("Range analysis: True unreachable (B%" Pd ")\n", | |
| 627 branch->true_successor()->block_id()); | |
| 628 } | |
| 629 branch->set_constant_target(branch->false_successor()); | |
| 630 } else { | |
| 631 ASSERT(target == branch->false_successor()); | |
| 632 // False unreachable. | |
| 633 if (FLAG_trace_constant_propagation) { | |
| 634 OS::Print("Range analysis: False unreachable (B%" Pd ")\n", | |
| 635 branch->false_successor()->block_id()); | |
| 636 } | |
| 637 branch->set_constant_target(branch->true_successor()); | |
| 638 } | |
| 639 } | |
| 640 } | |
| 641 } | |
| 642 | |
| 643 | 530 |
| 644 void RangeAnalysis::RemoveConstraints() { | 531 void RangeAnalysis::RemoveConstraints() { |
| 645 for (intptr_t i = 0; i < constraints_.length(); i++) { | 532 for (intptr_t i = 0; i < constraints_.length(); i++) { |
| 646 Definition* def = constraints_[i]->value()->definition(); | 533 Definition* def = constraints_[i]->value()->definition(); |
| 647 // Some constraints might be constraining constraints. Unwind the chain of | 534 // Some constraints might be constraining constraints. Unwind the chain of |
| 648 // constraints until we reach the actual definition. | 535 // constraints until we reach the actual definition. |
| 649 while (def->IsConstraint()) { | 536 while (def->IsConstraint()) { |
| 650 def = def->AsConstraint()->value()->definition(); | 537 def = def->AsConstraint()->value()->definition(); |
| 651 } | 538 } |
| 652 constraints_[i]->ReplaceUsesWith(def); | 539 constraints_[i]->ReplaceUsesWith(def); |
| (...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 913 } | 800 } |
| 914 return RangeBoundary(kSymbol, reinterpret_cast<intptr_t>(defn), offs); | 801 return RangeBoundary(kSymbol, reinterpret_cast<intptr_t>(defn), offs); |
| 915 } | 802 } |
| 916 | 803 |
| 917 | 804 |
| 918 RangeBoundary RangeBoundary::LowerBound() const { | 805 RangeBoundary RangeBoundary::LowerBound() const { |
| 919 if (IsInfinity()) { | 806 if (IsInfinity()) { |
| 920 return NegativeInfinity(); | 807 return NegativeInfinity(); |
| 921 } | 808 } |
| 922 if (IsConstant()) return *this; | 809 if (IsConstant()) return *this; |
| 923 return Add(Range::ConstantMinSmi(symbol()->range()), | 810 return Add(Range::ConstantMin(symbol()->range()), |
| 924 RangeBoundary::FromConstant(offset_), | 811 RangeBoundary::FromConstant(offset_), |
| 925 NegativeInfinity()); | 812 NegativeInfinity()); |
| 926 } | 813 } |
| 927 | 814 |
| 928 | 815 |
| 929 RangeBoundary RangeBoundary::UpperBound() const { | 816 RangeBoundary RangeBoundary::UpperBound() const { |
| 930 if (IsInfinity()) { | 817 if (IsInfinity()) { |
| 931 return PositiveInfinity(); | 818 return PositiveInfinity(); |
| 932 } | 819 } |
| 933 if (IsConstant()) return *this; | 820 if (IsConstant()) return *this; |
| 934 | 821 return Add(Range::ConstantMax(symbol()->range()), |
| 935 return Add(Range::ConstantMaxSmi(symbol()->range()), | |
| 936 RangeBoundary::FromConstant(offset_), | 822 RangeBoundary::FromConstant(offset_), |
| 937 PositiveInfinity()); | 823 PositiveInfinity()); |
| 938 } | 824 } |
| 939 | 825 |
| 940 | 826 |
| 941 RangeBoundary RangeBoundary::Add(const RangeBoundary& a, | 827 RangeBoundary RangeBoundary::Add(const RangeBoundary& a, |
| 942 const RangeBoundary& b, | 828 const RangeBoundary& b, |
| 943 const RangeBoundary& overflow) { | 829 const RangeBoundary& overflow) { |
| 944 if (a.IsInfinity() || b.IsInfinity()) return overflow; | 830 if (a.IsInfinity() || b.IsInfinity()) return overflow; |
| 945 | 831 |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 998 | 884 |
| 999 const int64_t offset = a.offset() - b.ConstantValue(); | 885 const int64_t offset = a.offset() - b.ConstantValue(); |
| 1000 | 886 |
| 1001 *result = RangeBoundary::FromDefinition(a.symbol(), offset); | 887 *result = RangeBoundary::FromDefinition(a.symbol(), offset); |
| 1002 return true; | 888 return true; |
| 1003 } | 889 } |
| 1004 return false; | 890 return false; |
| 1005 } | 891 } |
| 1006 | 892 |
| 1007 | 893 |
| 894 static Definition* UnwrapConstraint(Definition* defn) { |
| 895 while (defn->IsConstraint()) { |
| 896 defn = defn->AsConstraint()->value()->definition(); |
| 897 } |
| 898 return defn; |
| 899 } |
| 900 |
| 901 |
| 902 static bool AreEqualDefinitions(Definition* a, Definition* b) { |
| 903 a = UnwrapConstraint(a); |
| 904 b = UnwrapConstraint(b); |
| 905 return (a == b) || |
| 906 (a->AllowsCSE() && |
| 907 a->Dependencies().IsNone() && |
| 908 b->AllowsCSE() && |
| 909 b->Dependencies().IsNone() && |
| 910 a->Equals(b)); |
| 911 } |
| 912 |
| 913 |
| 914 // Returns true if two range boundaries refer to the same symbol. |
| 915 static bool DependOnSameSymbol(const RangeBoundary& a, const RangeBoundary& b) { |
| 916 return a.IsSymbol() && b.IsSymbol() && |
| 917 AreEqualDefinitions(a.symbol(), b.symbol()); |
| 918 } |
| 919 |
| 920 |
| 1008 bool RangeBoundary::Equals(const RangeBoundary& other) const { | 921 bool RangeBoundary::Equals(const RangeBoundary& other) const { |
| 1009 if (IsConstant() && other.IsConstant()) { | 922 if (IsConstant() && other.IsConstant()) { |
| 1010 return ConstantValue() == other.ConstantValue(); | 923 return ConstantValue() == other.ConstantValue(); |
| 1011 } else if (IsInfinity() && other.IsInfinity()) { | 924 } else if (IsInfinity() && other.IsInfinity()) { |
| 1012 return kind() == other.kind(); | 925 return kind() == other.kind(); |
| 1013 } else if (IsSymbol() && other.IsSymbol()) { | 926 } else if (IsSymbol() && other.IsSymbol()) { |
| 1014 return (offset() == other.offset()) && DependOnSameSymbol(*this, other); | 927 return (offset() == other.offset()) && DependOnSameSymbol(*this, other); |
| 1015 } else if (IsUnknown() && other.IsUnknown()) { | 928 } else if (IsUnknown() && other.IsUnknown()) { |
| 1016 return true; | 929 return true; |
| 1017 } | 930 } |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1137 | 1050 |
| 1138 const int64_t offset = range->min().offset() + a->offset(); | 1051 const int64_t offset = range->min().offset() + a->offset(); |
| 1139 | 1052 |
| 1140 *a = CanonicalizeBoundary( | 1053 *a = CanonicalizeBoundary( |
| 1141 RangeBoundary::FromDefinition(range->min().symbol(), offset), | 1054 RangeBoundary::FromDefinition(range->min().symbol(), offset), |
| 1142 RangeBoundary::NegativeInfinity()); | 1055 RangeBoundary::NegativeInfinity()); |
| 1143 | 1056 |
| 1144 return true; | 1057 return true; |
| 1145 } | 1058 } |
| 1146 | 1059 |
| 1147 typedef bool (*BoundaryOp)(RangeBoundary*); | |
| 1148 | 1060 |
| 1149 static bool CanonicalizeForComparison(RangeBoundary* a, | 1061 RangeBoundary RangeBoundary::Min(RangeBoundary a, RangeBoundary b, |
| 1150 RangeBoundary* b, | 1062 RangeSize size) { |
| 1151 BoundaryOp op, | 1063 ASSERT(!(a.IsNegativeInfinity() || b.IsNegativeInfinity())); |
| 1152 const RangeBoundary& overflow) { | 1064 ASSERT(!a.IsUnknown() || !b.IsUnknown()); |
| 1153 if (!a->IsSymbol() || !b->IsSymbol()) { | 1065 if (a.IsUnknown() && !b.IsUnknown()) { |
| 1154 return false; | 1066 return b; |
| 1067 } |
| 1068 if (!a.IsUnknown() && b.IsUnknown()) { |
| 1069 return a; |
| 1070 } |
| 1071 if (size == kRangeBoundarySmi) { |
| 1072 if (a.IsSmiMaximumOrAbove() && !b.IsSmiMaximumOrAbove()) { |
| 1073 return b; |
| 1074 } |
| 1075 if (!a.IsSmiMaximumOrAbove() && b.IsSmiMaximumOrAbove()) { |
| 1076 return a; |
| 1077 } |
| 1078 } else { |
| 1079 ASSERT(size == kRangeBoundaryInt64); |
| 1080 if (a.IsMaximumOrAbove() && !b.IsMaximumOrAbove()) { |
| 1081 return b; |
| 1082 } |
| 1083 if (!a.IsMaximumOrAbove() && b.IsMaximumOrAbove()) { |
| 1084 return a; |
| 1085 } |
| 1155 } | 1086 } |
| 1156 | 1087 |
| 1157 if (DependOnSameSymbol(*a, *b)) { | |
| 1158 return true; | |
| 1159 } | |
| 1160 | |
| 1161 | |
| 1162 RangeBoundary canonical_a = CanonicalizeBoundary(*a, overflow); | |
| 1163 RangeBoundary canonical_b = CanonicalizeBoundary(*b, overflow); | |
| 1164 | |
| 1165 do { | |
| 1166 if (DependOnSameSymbol(canonical_a, canonical_b)) { | |
| 1167 *a = canonical_a; | |
| 1168 *b = canonical_b; | |
| 1169 return true; | |
| 1170 } | |
| 1171 } while (op(&canonical_a) || op(&canonical_b)); | |
| 1172 | |
| 1173 return false; | |
| 1174 } | |
| 1175 | |
| 1176 | |
| 1177 RangeBoundary RangeBoundary::JoinMin(RangeBoundary a, RangeBoundary b) { | |
| 1178 if (a.Equals(b)) { | 1088 if (a.Equals(b)) { |
| 1179 return b; | 1089 return b; |
| 1180 } | 1090 } |
| 1181 | 1091 |
| 1182 if (CanonicalizeForComparison(&a, | 1092 { |
| 1183 &b, | 1093 RangeBoundary canonical_a = |
| 1184 &CanonicalizeMinBoundary, | 1094 CanonicalizeBoundary(a, RangeBoundary::PositiveInfinity()); |
| 1185 RangeBoundary::NegativeInfinity())) { | 1095 RangeBoundary canonical_b = |
| 1096 CanonicalizeBoundary(b, RangeBoundary::PositiveInfinity()); |
| 1097 do { |
| 1098 if (DependOnSameSymbol(canonical_a, canonical_b)) { |
| 1099 a = canonical_a; |
| 1100 b = canonical_b; |
| 1101 break; |
| 1102 } |
| 1103 } while (CanonicalizeMaxBoundary(&canonical_a) || |
| 1104 CanonicalizeMaxBoundary(&canonical_b)); |
| 1105 } |
| 1106 |
| 1107 if (DependOnSameSymbol(a, b)) { |
| 1186 return (a.offset() <= b.offset()) ? a : b; | 1108 return (a.offset() <= b.offset()) ? a : b; |
| 1187 } | 1109 } |
| 1188 | 1110 |
| 1189 const int64_t inf_a = a.SmiLowerBound(); | 1111 const int64_t min_a = a.UpperBound().Clamp(size).ConstantValue(); |
| 1190 const int64_t inf_b = b.SmiLowerBound(); | 1112 const int64_t min_b = b.UpperBound().Clamp(size).ConstantValue(); |
| 1191 const int64_t sup_a = a.SmiUpperBound(); | |
| 1192 const int64_t sup_b = b.SmiUpperBound(); | |
| 1193 | 1113 |
| 1194 if ((sup_a <= inf_b) && !a.LowerBound().OverflowedSmi()) { | 1114 return RangeBoundary::FromConstant(Utils::Minimum(min_a, min_b)); |
| 1195 return a; | |
| 1196 } else if ((sup_b <= inf_a) && !b.LowerBound().OverflowedSmi()) { | |
| 1197 return b; | |
| 1198 } else { | |
| 1199 return RangeBoundary::FromConstant(Utils::Minimum(inf_a, inf_b)); | |
| 1200 } | |
| 1201 } | 1115 } |
| 1202 | 1116 |
| 1203 | 1117 |
| 1204 RangeBoundary RangeBoundary::JoinMax(RangeBoundary a, RangeBoundary b) { | 1118 RangeBoundary RangeBoundary::Max(RangeBoundary a, RangeBoundary b, |
| 1119 RangeSize size) { |
| 1120 ASSERT(!(a.IsPositiveInfinity() || b.IsPositiveInfinity())); |
| 1121 ASSERT(!a.IsUnknown() || !b.IsUnknown()); |
| 1122 if (a.IsUnknown() && !b.IsUnknown()) { |
| 1123 return b; |
| 1124 } |
| 1125 if (!a.IsUnknown() && b.IsUnknown()) { |
| 1126 return a; |
| 1127 } |
| 1128 if (size == kRangeBoundarySmi) { |
| 1129 if (a.IsSmiMinimumOrBelow() && !b.IsSmiMinimumOrBelow()) { |
| 1130 return b; |
| 1131 } |
| 1132 if (!a.IsSmiMinimumOrBelow() && b.IsSmiMinimumOrBelow()) { |
| 1133 return a; |
| 1134 } |
| 1135 } else { |
| 1136 ASSERT(size == kRangeBoundaryInt64); |
| 1137 if (a.IsMinimumOrBelow() && !b.IsMinimumOrBelow()) { |
| 1138 return b; |
| 1139 } |
| 1140 if (!a.IsMinimumOrBelow() && b.IsMinimumOrBelow()) { |
| 1141 return a; |
| 1142 } |
| 1143 } |
| 1205 if (a.Equals(b)) { | 1144 if (a.Equals(b)) { |
| 1206 return b; | 1145 return b; |
| 1207 } | 1146 } |
| 1208 | 1147 |
| 1209 if (CanonicalizeForComparison(&a, | 1148 { |
| 1210 &b, | 1149 RangeBoundary canonical_a = |
| 1211 &CanonicalizeMaxBoundary, | 1150 CanonicalizeBoundary(a, RangeBoundary::NegativeInfinity()); |
| 1212 RangeBoundary::PositiveInfinity())) { | 1151 RangeBoundary canonical_b = |
| 1213 return (a.offset() >= b.offset()) ? a : b; | 1152 CanonicalizeBoundary(b, RangeBoundary::NegativeInfinity()); |
| 1153 |
| 1154 do { |
| 1155 if (DependOnSameSymbol(canonical_a, canonical_b)) { |
| 1156 a = canonical_a; |
| 1157 b = canonical_b; |
| 1158 break; |
| 1159 } |
| 1160 } while (CanonicalizeMinBoundary(&canonical_a) || |
| 1161 CanonicalizeMinBoundary(&canonical_b)); |
| 1214 } | 1162 } |
| 1215 | 1163 |
| 1216 const int64_t inf_a = a.SmiLowerBound(); | 1164 if (DependOnSameSymbol(a, b)) { |
| 1217 const int64_t inf_b = b.SmiLowerBound(); | 1165 return (a.offset() <= b.offset()) ? b : a; |
| 1218 const int64_t sup_a = a.SmiUpperBound(); | 1166 } |
| 1219 const int64_t sup_b = b.SmiUpperBound(); | |
| 1220 | 1167 |
| 1221 if ((sup_a <= inf_b) && !b.UpperBound().OverflowedSmi()) { | 1168 const int64_t max_a = a.LowerBound().Clamp(size).ConstantValue(); |
| 1222 return b; | 1169 const int64_t max_b = b.LowerBound().Clamp(size).ConstantValue(); |
| 1223 } else if ((sup_b <= inf_a) && !a.UpperBound().OverflowedSmi()) { | 1170 |
| 1224 return a; | 1171 return RangeBoundary::FromConstant(Utils::Maximum(max_a, max_b)); |
| 1225 } else { | |
| 1226 return RangeBoundary::FromConstant(Utils::Maximum(sup_a, sup_b)); | |
| 1227 } | |
| 1228 } | 1172 } |
| 1229 | 1173 |
| 1230 | 1174 |
| 1231 RangeBoundary RangeBoundary::IntersectionMin(RangeBoundary a, RangeBoundary b) { | |
| 1232 ASSERT(!a.IsPositiveInfinity() && !b.IsPositiveInfinity()); | |
| 1233 ASSERT(!a.IsUnknown() && !b.IsUnknown()); | |
| 1234 | |
| 1235 if (a.Equals(b)) { | |
| 1236 return a; | |
| 1237 } | |
| 1238 | |
| 1239 if (a.IsSmiMinimumOrBelow()) { | |
| 1240 return b; | |
| 1241 } else if (b.IsSmiMinimumOrBelow()) { | |
| 1242 return a; | |
| 1243 } | |
| 1244 | |
| 1245 if (CanonicalizeForComparison(&a, | |
| 1246 &b, | |
| 1247 &CanonicalizeMinBoundary, | |
| 1248 RangeBoundary::NegativeInfinity())) { | |
| 1249 return (a.offset() >= b.offset()) ? a : b; | |
| 1250 } | |
| 1251 | |
| 1252 const int64_t inf_a = a.SmiLowerBound(); | |
| 1253 const int64_t inf_b = b.SmiLowerBound(); | |
| 1254 | |
| 1255 return (inf_a >= inf_b) ? a : b; | |
| 1256 } | |
| 1257 | |
| 1258 | |
| 1259 RangeBoundary RangeBoundary::IntersectionMax(RangeBoundary a, RangeBoundary b) { | |
| 1260 ASSERT(!a.IsNegativeInfinity() && !b.IsNegativeInfinity()); | |
| 1261 ASSERT(!a.IsUnknown() && !b.IsUnknown()); | |
| 1262 | |
| 1263 if (a.Equals(b)) { | |
| 1264 return a; | |
| 1265 } | |
| 1266 | |
| 1267 if (a.IsSmiMaximumOrAbove()) { | |
| 1268 return b; | |
| 1269 } else if (b.IsSmiMaximumOrAbove()) { | |
| 1270 return a; | |
| 1271 } | |
| 1272 | |
| 1273 if (CanonicalizeForComparison(&a, | |
| 1274 &b, | |
| 1275 &CanonicalizeMaxBoundary, | |
| 1276 RangeBoundary::PositiveInfinity())) { | |
| 1277 return (a.offset() <= b.offset()) ? a : b; | |
| 1278 } | |
| 1279 | |
| 1280 const int64_t sup_a = a.SmiUpperBound(); | |
| 1281 const int64_t sup_b = b.SmiUpperBound(); | |
| 1282 | |
| 1283 return (sup_a <= sup_b) ? a : b; | |
| 1284 } | |
| 1285 | |
| 1286 | |
| 1287 int64_t RangeBoundary::ConstantValue() const { | 1175 int64_t RangeBoundary::ConstantValue() const { |
| 1288 ASSERT(IsConstant()); | 1176 ASSERT(IsConstant()); |
| 1289 return value_; | 1177 return value_; |
| 1290 } | 1178 } |
| 1291 | 1179 |
| 1292 | 1180 |
| 1293 bool Range::IsPositive() const { | 1181 bool Range::IsPositive() const { |
| 1294 if (min().IsNegativeInfinity()) { | 1182 if (min().IsNegativeInfinity()) { |
| 1295 return false; | 1183 return false; |
| 1296 } | 1184 } |
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1458 } | 1346 } |
| 1459 | 1347 |
| 1460 return false; | 1348 return false; |
| 1461 } | 1349 } |
| 1462 | 1350 |
| 1463 | 1351 |
| 1464 static bool IsArrayLength(Definition* defn) { | 1352 static bool IsArrayLength(Definition* defn) { |
| 1465 if (defn == NULL) { | 1353 if (defn == NULL) { |
| 1466 return false; | 1354 return false; |
| 1467 } | 1355 } |
| 1468 LoadFieldInstr* load = UnwrapConstraint(defn)->AsLoadField(); | 1356 LoadFieldInstr* load = defn->AsLoadField(); |
| 1469 return (load != NULL) && load->IsImmutableLengthLoad(); | 1357 return (load != NULL) && load->IsImmutableLengthLoad(); |
| 1470 } | 1358 } |
| 1471 | 1359 |
| 1472 | 1360 |
| 1473 void Range::Add(const Range* left_range, | 1361 void Range::Add(const Range* left_range, |
| 1474 const Range* right_range, | 1362 const Range* right_range, |
| 1475 RangeBoundary* result_min, | 1363 RangeBoundary* result_min, |
| 1476 RangeBoundary* result_max, | 1364 RangeBoundary* result_max, |
| 1477 Definition* left_defn) { | 1365 Definition* left_defn) { |
| 1478 ASSERT(left_range != NULL); | 1366 ASSERT(left_range != NULL); |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1550 if (Smi::IsValid(mul_max) && Smi::IsValid(-mul_max)) { | 1438 if (Smi::IsValid(mul_max) && Smi::IsValid(-mul_max)) { |
| 1551 const int64_t r_min = | 1439 const int64_t r_min = |
| 1552 OnlyPositiveOrZero(*left_range, *right_range) ? 0 : -mul_max; | 1440 OnlyPositiveOrZero(*left_range, *right_range) ? 0 : -mul_max; |
| 1553 *result_min = RangeBoundary::FromConstant(r_min); | 1441 *result_min = RangeBoundary::FromConstant(r_min); |
| 1554 const int64_t r_max = | 1442 const int64_t r_max = |
| 1555 OnlyNegativeOrZero(*left_range, *right_range) ? 0 : mul_max; | 1443 OnlyNegativeOrZero(*left_range, *right_range) ? 0 : mul_max; |
| 1556 *result_max = RangeBoundary::FromConstant(r_max); | 1444 *result_max = RangeBoundary::FromConstant(r_max); |
| 1557 return true; | 1445 return true; |
| 1558 } | 1446 } |
| 1559 } | 1447 } |
| 1560 | |
| 1561 // TODO(vegorov): handle mixed sign case that leads to (-Infinity, 0] range. | |
| 1562 if (OnlyPositiveOrZero(*left_range, *right_range) || | |
| 1563 OnlyNegativeOrZero(*left_range, *right_range)) { | |
| 1564 *result_min = RangeBoundary::FromConstant(0); | |
| 1565 *result_max = RangeBoundary::PositiveInfinity(); | |
| 1566 return true; | |
| 1567 } | |
| 1568 | |
| 1569 return false; | 1448 return false; |
| 1570 } | 1449 } |
| 1571 | 1450 |
| 1572 | 1451 |
| 1573 // Both the a and b ranges are >= 0. | 1452 // Both the a and b ranges are >= 0. |
| 1574 bool Range::OnlyPositiveOrZero(const Range& a, const Range& b) { | 1453 bool Range::OnlyPositiveOrZero(const Range& a, const Range& b) { |
| 1575 return a.OnlyGreaterThanOrEqualTo(0) && b.OnlyGreaterThanOrEqualTo(0); | 1454 return a.OnlyGreaterThanOrEqualTo(0) && b.OnlyGreaterThanOrEqualTo(0); |
| 1576 } | 1455 } |
| 1577 | 1456 |
| 1578 | 1457 |
| 1579 // Both the a and b ranges are <= 0. | 1458 // Both the a and b ranges are <= 0. |
| 1580 bool Range::OnlyNegativeOrZero(const Range& a, const Range& b) { | 1459 bool Range::OnlyNegativeOrZero(const Range& a, const Range& b) { |
| 1581 return a.OnlyLessThanOrEqualTo(0) && b.OnlyLessThanOrEqualTo(0); | 1460 return a.OnlyLessThanOrEqualTo(0) && b.OnlyLessThanOrEqualTo(0); |
| 1582 } | 1461 } |
| 1583 | 1462 |
| 1584 | 1463 |
| 1585 // Return the maximum absolute value included in range. | 1464 // Return the maximum absolute value included in range. |
| 1586 int64_t Range::ConstantAbsMax(const Range* range) { | 1465 int64_t Range::ConstantAbsMax(const Range* range) { |
| 1587 if (range == NULL) { | 1466 if (range == NULL) { |
| 1588 return RangeBoundary::kMax; | 1467 return RangeBoundary::kMax; |
| 1589 } | 1468 } |
| 1590 const int64_t abs_min = Utils::Abs(Range::ConstantMin(range).ConstantValue()); | 1469 const int64_t abs_min = Utils::Abs(Range::ConstantMin(range).ConstantValue()); |
| 1591 const int64_t abs_max = Utils::Abs(Range::ConstantMax(range).ConstantValue()); | 1470 const int64_t abs_max = Utils::Abs(Range::ConstantMax(range).ConstantValue()); |
| 1592 return Utils::Maximum(abs_min, abs_max); | 1471 return Utils::Maximum(abs_min, abs_max); |
| 1593 } | 1472 } |
| 1594 | 1473 |
| 1595 | 1474 |
| 1596 void Range::BinaryOp(const Token::Kind op, | 1475 Range* Range::BinaryOp(const Token::Kind op, |
| 1597 const Range* left_range, | 1476 const Range* left_range, |
| 1598 const Range* right_range, | 1477 const Range* right_range, |
| 1599 Definition* left_defn, | 1478 Definition* left_defn) { |
| 1600 Range* result) { | |
| 1601 ASSERT(left_range != NULL); | 1479 ASSERT(left_range != NULL); |
| 1602 ASSERT(right_range != NULL); | 1480 ASSERT(right_range != NULL); |
| 1603 | 1481 |
| 1604 // Both left and right ranges are finite. | 1482 // Both left and right ranges are finite. |
| 1605 ASSERT(left_range->IsFinite()); | 1483 ASSERT(left_range->IsFinite()); |
| 1606 ASSERT(right_range->IsFinite()); | 1484 ASSERT(right_range->IsFinite()); |
| 1607 | 1485 |
| 1608 RangeBoundary min; | 1486 RangeBoundary min; |
| 1609 RangeBoundary max; | 1487 RangeBoundary max; |
| 1610 ASSERT(min.IsUnknown() && max.IsUnknown()); | 1488 ASSERT(min.IsUnknown() && max.IsUnknown()); |
| 1611 | 1489 |
| 1612 switch (op) { | 1490 switch (op) { |
| 1613 case Token::kADD: | 1491 case Token::kADD: |
| 1614 Range::Add(left_range, right_range, &min, &max, left_defn); | 1492 Range::Add(left_range, right_range, &min, &max, left_defn); |
| 1615 break; | 1493 break; |
| 1616 case Token::kSUB: | 1494 case Token::kSUB: |
| 1617 Range::Sub(left_range, right_range, &min, &max, left_defn); | 1495 Range::Sub(left_range, right_range, &min, &max, left_defn); |
| 1618 break; | 1496 break; |
| 1619 case Token::kMUL: { | 1497 case Token::kMUL: { |
| 1620 if (!Range::Mul(left_range, right_range, &min, &max)) { | 1498 if (!Range::Mul(left_range, right_range, &min, &max)) { |
| 1621 *result = Range::Full(RangeBoundary::kRangeBoundaryInt64); | 1499 return NULL; |
| 1622 return; | |
| 1623 } | 1500 } |
| 1624 break; | 1501 break; |
| 1625 } | 1502 } |
| 1626 case Token::kSHL: { | 1503 case Token::kSHL: { |
| 1627 Range::Shl(left_range, right_range, &min, &max); | 1504 Range::Shl(left_range, right_range, &min, &max); |
| 1628 break; | 1505 break; |
| 1629 } | 1506 } |
| 1630 case Token::kSHR: { | 1507 case Token::kSHR: { |
| 1631 Range::Shr(left_range, right_range, &min, &max); | 1508 Range::Shr(left_range, right_range, &min, &max); |
| 1632 break; | 1509 break; |
| 1633 } | 1510 } |
| 1634 case Token::kBIT_AND: | 1511 case Token::kBIT_AND: |
| 1635 if (!Range::And(left_range, right_range, &min, &max)) { | 1512 if (!Range::And(left_range, right_range, &min, &max)) { |
| 1636 *result = Range::Full(RangeBoundary::kRangeBoundaryInt64); | 1513 return NULL; |
| 1637 return; | |
| 1638 } | 1514 } |
| 1639 break; | 1515 break; |
| 1640 default: | 1516 default: |
| 1641 *result = Range::Full(RangeBoundary::kRangeBoundaryInt64); | 1517 return NULL; |
| 1642 return; | 1518 break; |
| 1643 } | 1519 } |
| 1644 | 1520 |
| 1645 ASSERT(!min.IsUnknown() && !max.IsUnknown()); | 1521 ASSERT(!min.IsUnknown() && !max.IsUnknown()); |
| 1646 | 1522 |
| 1647 *result = Range(min, max); | 1523 return new Range(min, max); |
| 1648 } | 1524 } |
| 1649 | 1525 |
| 1650 | 1526 |
| 1651 void Definition::set_range(const Range& range) { | 1527 void Definition::InferRange() { |
| 1652 if (range_ == NULL) { | |
| 1653 range_ = new Range(); | |
| 1654 } | |
| 1655 *range_ = range; | |
| 1656 } | |
| 1657 | |
| 1658 | |
| 1659 void Definition::InferRange(Range* range) { | |
| 1660 if (Type()->ToCid() == kSmiCid) { | 1528 if (Type()->ToCid() == kSmiCid) { |
| 1661 *range = Range::Full(RangeBoundary::kRangeBoundarySmi); | 1529 if (range_ == NULL) { |
| 1530 range_ = Range::UnknownSmi(); |
| 1531 } |
| 1662 } else if (IsMintDefinition()) { | 1532 } else if (IsMintDefinition()) { |
| 1663 *range = Range::Full(RangeBoundary::kRangeBoundaryInt64); | 1533 if (range_ == NULL) { |
| 1534 range_ = Range::Unknown(); |
| 1535 } |
| 1664 } else { | 1536 } else { |
| 1665 // Only Smi and Mint supported. | 1537 // Only Smi and Mint supported. |
| 1666 UNREACHABLE(); | 1538 UNREACHABLE(); |
| 1667 } | 1539 } |
| 1668 } | 1540 } |
| 1669 | 1541 |
| 1670 | 1542 |
| 1671 static bool DependsOnSymbol(const RangeBoundary& a, Definition* symbol) { | 1543 void PhiInstr::InferRange() { |
| 1672 return a.IsSymbol() && (UnwrapConstraint(a.symbol()) == symbol); | 1544 RangeBoundary new_min; |
| 1545 RangeBoundary new_max; |
| 1546 |
| 1547 ASSERT(Type()->ToCid() == kSmiCid); |
| 1548 |
| 1549 for (intptr_t i = 0; i < InputCount(); i++) { |
| 1550 Range* input_range = InputAt(i)->definition()->range(); |
| 1551 if (input_range == NULL) { |
| 1552 range_ = Range::UnknownSmi(); |
| 1553 return; |
| 1554 } |
| 1555 |
| 1556 if (new_min.IsUnknown()) { |
| 1557 new_min = Range::ConstantMin(input_range); |
| 1558 } else { |
| 1559 new_min = RangeBoundary::Min(new_min, |
| 1560 Range::ConstantMinSmi(input_range), |
| 1561 RangeBoundary::kRangeBoundarySmi); |
| 1562 } |
| 1563 |
| 1564 if (new_max.IsUnknown()) { |
| 1565 new_max = Range::ConstantMax(input_range); |
| 1566 } else { |
| 1567 new_max = RangeBoundary::Max(new_max, |
| 1568 Range::ConstantMaxSmi(input_range), |
| 1569 RangeBoundary::kRangeBoundarySmi); |
| 1570 } |
| 1571 } |
| 1572 |
| 1573 ASSERT(new_min.IsUnknown() == new_max.IsUnknown()); |
| 1574 if (new_min.IsUnknown()) { |
| 1575 range_ = Range::UnknownSmi(); |
| 1576 return; |
| 1577 } |
| 1578 |
| 1579 range_ = new Range(new_min, new_max); |
| 1673 } | 1580 } |
| 1674 | 1581 |
| 1675 | 1582 |
| 1676 // Given the range and definition update the range so that | 1583 void ConstantInstr::InferRange() { |
| 1677 // it covers both original range and defintions range. | |
| 1678 // | |
| 1679 // The following should also hold: | |
| 1680 // | |
| 1681 // [_|_, _|_] U a = a U [_|_, _|_] = a | |
| 1682 // | |
| 1683 static void Join(Range* range, Definition* defn) { | |
| 1684 if (Range::IsUnknown(defn->range())) { | |
| 1685 return; | |
| 1686 } | |
| 1687 | |
| 1688 if (Range::IsUnknown(range)) { | |
| 1689 *range = *defn->range(); | |
| 1690 return; | |
| 1691 } | |
| 1692 | |
| 1693 Range other = *defn->range(); | |
| 1694 | |
| 1695 // Handle patterns where range already depends on defn as a symbol: | |
| 1696 // | |
| 1697 // (..., S+o] U range(S) and [S+o, ...) U range(S) | |
| 1698 // | |
| 1699 // To improve precision of the computed join use [S, S] instead of | |
| 1700 // using range(S). It will be canonicalized away by JoinMin/JoinMax | |
| 1701 // functions. | |
| 1702 Definition* unwrapped = UnwrapConstraint(defn); | |
| 1703 if (DependsOnSymbol(range->min(), unwrapped) || | |
| 1704 DependsOnSymbol(range->max(), unwrapped)) { | |
| 1705 other = Range(RangeBoundary::FromDefinition(defn, 0), | |
| 1706 RangeBoundary::FromDefinition(defn, 0)); | |
| 1707 } | |
| 1708 | |
| 1709 // First try to compare ranges based on their upper and lower bounds. | |
| 1710 const int64_t inf_range = range->min().SmiLowerBound(); | |
| 1711 const int64_t inf_other = other.min().SmiLowerBound(); | |
| 1712 const int64_t sup_range = range->max().SmiUpperBound(); | |
| 1713 const int64_t sup_other = other.max().SmiUpperBound(); | |
| 1714 | |
| 1715 if (sup_range <= inf_other) { | |
| 1716 // The range is fully below defn's range. Keep the minimum and | |
| 1717 // expand the maximum. | |
| 1718 range->set_max(other.max()); | |
| 1719 } else if (sup_other <= inf_range) { | |
| 1720 // The range is fully above defn's range. Keep the maximum and | |
| 1721 // expand the minimum. | |
| 1722 range->set_min(other.min()); | |
| 1723 } else { | |
| 1724 // Can't compare ranges as whole. Join minimum and maximum separately. | |
| 1725 *range = Range(RangeBoundary::JoinMin(range->min(), other.min()), | |
| 1726 RangeBoundary::JoinMax(range->max(), other.max())); | |
| 1727 } | |
| 1728 } | |
| 1729 | |
| 1730 | |
| 1731 // When assigning range to a phi we must take care to avoid self-reference | |
| 1732 // cycles when phi's range depends on the phi itself. | |
| 1733 // To prevent such cases we impose additional restriction on symbols that | |
| 1734 // can be used as boundaries for phi's range: they must dominate | |
| 1735 // phi's definition. | |
| 1736 static RangeBoundary EnsureAcyclicSymbol(BlockEntryInstr* phi_block, | |
| 1737 const RangeBoundary& a, | |
| 1738 const RangeBoundary& limit) { | |
| 1739 if (!a.IsSymbol() || a.symbol()->GetBlock()->Dominates(phi_block)) { | |
| 1740 return a; | |
| 1741 } | |
| 1742 | |
| 1743 // Symbol does not dominate phi. Try unwrapping constraint and check again. | |
| 1744 Definition* unwrapped = UnwrapConstraint(a.symbol()); | |
| 1745 if ((unwrapped != a.symbol()) && | |
| 1746 unwrapped->GetBlock()->Dominates(phi_block)) { | |
| 1747 return RangeBoundary::FromDefinition(unwrapped, a.offset()); | |
| 1748 } | |
| 1749 | |
| 1750 return limit; | |
| 1751 } | |
| 1752 | |
| 1753 | |
| 1754 void PhiInstr::InferRange(Range* range) { | |
| 1755 ASSERT(Type()->ToCid() == kSmiCid); | |
| 1756 for (intptr_t i = 0; i < InputCount(); i++) { | |
| 1757 Join(range, InputAt(i)->definition()); | |
| 1758 } | |
| 1759 | |
| 1760 BlockEntryInstr* phi_block = GetBlock(); | |
| 1761 range->set_min(EnsureAcyclicSymbol( | |
| 1762 phi_block, range->min(), RangeBoundary::MinSmi())); | |
| 1763 range->set_max(EnsureAcyclicSymbol( | |
| 1764 phi_block, range->max(), RangeBoundary::MaxSmi())); | |
| 1765 } | |
| 1766 | |
| 1767 | |
| 1768 void ConstantInstr::InferRange(Range* range) { | |
| 1769 if (value_.IsSmi()) { | 1584 if (value_.IsSmi()) { |
| 1770 int64_t value = Smi::Cast(value_).Value(); | 1585 if (range_ == NULL) { |
| 1771 *range = Range(RangeBoundary::FromConstant(value), | 1586 int64_t value = Smi::Cast(value_).Value(); |
| 1772 RangeBoundary::FromConstant(value)); | 1587 range_ = new Range(RangeBoundary::FromConstant(value), |
| 1588 RangeBoundary::FromConstant(value)); |
| 1589 } |
| 1773 } else if (value_.IsMint()) { | 1590 } else if (value_.IsMint()) { |
| 1774 int64_t value = Mint::Cast(value_).value(); | 1591 if (range_ == NULL) { |
| 1775 *range = Range(RangeBoundary::FromConstant(value), | 1592 int64_t value = Mint::Cast(value_).value(); |
| 1776 RangeBoundary::FromConstant(value)); | 1593 range_ = new Range(RangeBoundary::FromConstant(value), |
| 1594 RangeBoundary::FromConstant(value)); |
| 1595 } |
| 1777 } else { | 1596 } else { |
| 1778 // Only Smi and Mint supported. | 1597 // Only Smi and Mint supported. |
| 1779 UNREACHABLE(); | 1598 UNREACHABLE(); |
| 1780 } | 1599 } |
| 1781 } | 1600 } |
| 1782 | 1601 |
| 1783 | 1602 |
| 1784 void ConstraintInstr::InferRange(Range* range) { | 1603 void UnboxIntegerInstr::InferRange() { |
| 1785 // Only constraining smi values. | 1604 if (range_ == NULL) { |
| 1786 ASSERT(value()->IsSmiValue()); | 1605 Definition* unboxed = value()->definition(); |
| 1787 | 1606 ASSERT(unboxed != NULL); |
| 1788 Range* value_range = value()->definition()->range(); | 1607 Range* range = unboxed->range(); |
| 1789 if (Range::IsUnknown(value_range)) { | 1608 if (range == NULL) { |
| 1790 return; | 1609 range_ = Range::Unknown(); |
| 1791 } | 1610 return; |
| 1792 | 1611 } |
| 1793 // TODO(vegorov) check if precision of the analysis can be improved by | 1612 range_ = new Range(range->min(), range->max()); |
| 1794 // recognizing intersections of the form: | |
| 1795 // | |
| 1796 // (..., S+x] ^ [S+x, ...) = [S+x, S+x] | |
| 1797 // | |
| 1798 Range result = value_range->Intersect(constraint()); | |
| 1799 if (result.IsUnsatisfiable()) { | |
| 1800 return; | |
| 1801 } | |
| 1802 | |
| 1803 *range = result; | |
| 1804 } | |
| 1805 | |
| 1806 | |
| 1807 void LoadFieldInstr::InferRange(Range* range) { | |
| 1808 switch (recognized_kind()) { | |
| 1809 case MethodRecognizer::kObjectArrayLength: | |
| 1810 case MethodRecognizer::kImmutableArrayLength: | |
| 1811 *range = Range(RangeBoundary::FromConstant(0), | |
| 1812 RangeBoundary::FromConstant(Array::kMaxElements)); | |
| 1813 break; | |
| 1814 | |
| 1815 case MethodRecognizer::kTypedDataLength: | |
| 1816 *range = Range(RangeBoundary::FromConstant(0), RangeBoundary::MaxSmi()); | |
| 1817 break; | |
| 1818 | |
| 1819 case MethodRecognizer::kStringBaseLength: | |
| 1820 *range = Range(RangeBoundary::FromConstant(0), | |
| 1821 RangeBoundary::FromConstant(String::kMaxElements)); | |
| 1822 break; | |
| 1823 | |
| 1824 default: | |
| 1825 Definition::InferRange(range); | |
| 1826 } | 1613 } |
| 1827 } | 1614 } |
| 1828 | 1615 |
| 1829 | 1616 |
| 1617 void ConstraintInstr::InferRange() { |
| 1618 Range* value_range = value()->definition()->range(); |
| 1830 | 1619 |
| 1831 void LoadIndexedInstr::InferRange(Range* range) { | 1620 // Only constraining smi values. |
| 1621 ASSERT(value()->IsSmiValue()); |
| 1622 |
| 1623 RangeBoundary min; |
| 1624 RangeBoundary max; |
| 1625 |
| 1626 { |
| 1627 RangeBoundary value_min = (value_range == NULL) ? |
| 1628 RangeBoundary() : value_range->min(); |
| 1629 RangeBoundary constraint_min = constraint()->min(); |
| 1630 min = RangeBoundary::Max(value_min, constraint_min, |
| 1631 RangeBoundary::kRangeBoundarySmi); |
| 1632 } |
| 1633 |
| 1634 ASSERT(!min.IsUnknown()); |
| 1635 |
| 1636 { |
| 1637 RangeBoundary value_max = (value_range == NULL) ? |
| 1638 RangeBoundary() : value_range->max(); |
| 1639 RangeBoundary constraint_max = constraint()->max(); |
| 1640 max = RangeBoundary::Min(value_max, constraint_max, |
| 1641 RangeBoundary::kRangeBoundarySmi); |
| 1642 } |
| 1643 |
| 1644 ASSERT(!max.IsUnknown()); |
| 1645 |
| 1646 range_ = new Range(min, max); |
| 1647 |
| 1648 // Mark branches that generate unsatisfiable constraints as constant. |
| 1649 if (target() != NULL && range_->IsUnsatisfiable()) { |
| 1650 BranchInstr* branch = |
| 1651 target()->PredecessorAt(0)->last_instruction()->AsBranch(); |
| 1652 if (target() == branch->true_successor()) { |
| 1653 // True unreachable. |
| 1654 if (FLAG_trace_constant_propagation) { |
| 1655 OS::Print("Range analysis: True unreachable (B%" Pd ")\n", |
| 1656 branch->true_successor()->block_id()); |
| 1657 } |
| 1658 branch->set_constant_target(branch->false_successor()); |
| 1659 } else { |
| 1660 ASSERT(target() == branch->false_successor()); |
| 1661 // False unreachable. |
| 1662 if (FLAG_trace_constant_propagation) { |
| 1663 OS::Print("Range analysis: False unreachable (B%" Pd ")\n", |
| 1664 branch->false_successor()->block_id()); |
| 1665 } |
| 1666 branch->set_constant_target(branch->true_successor()); |
| 1667 } |
| 1668 } |
| 1669 } |
| 1670 |
| 1671 |
| 1672 void LoadFieldInstr::InferRange() { |
| 1673 if ((range_ == NULL) && |
| 1674 ((recognized_kind() == MethodRecognizer::kObjectArrayLength) || |
| 1675 (recognized_kind() == MethodRecognizer::kImmutableArrayLength))) { |
| 1676 range_ = new Range(RangeBoundary::FromConstant(0), |
| 1677 RangeBoundary::FromConstant(Array::kMaxElements)); |
| 1678 return; |
| 1679 } |
| 1680 if ((range_ == NULL) && |
| 1681 (recognized_kind() == MethodRecognizer::kTypedDataLength)) { |
| 1682 range_ = new Range(RangeBoundary::FromConstant(0), RangeBoundary::MaxSmi()); |
| 1683 return; |
| 1684 } |
| 1685 if ((range_ == NULL) && |
| 1686 (recognized_kind() == MethodRecognizer::kStringBaseLength)) { |
| 1687 range_ = new Range(RangeBoundary::FromConstant(0), |
| 1688 RangeBoundary::FromConstant(String::kMaxElements)); |
| 1689 return; |
| 1690 } |
| 1691 Definition::InferRange(); |
| 1692 } |
| 1693 |
| 1694 |
| 1695 |
| 1696 void LoadIndexedInstr::InferRange() { |
| 1832 switch (class_id()) { | 1697 switch (class_id()) { |
| 1833 case kTypedDataInt8ArrayCid: | 1698 case kTypedDataInt8ArrayCid: |
| 1834 *range = Range(RangeBoundary::FromConstant(-128), | 1699 range_ = new Range(RangeBoundary::FromConstant(-128), |
| 1835 RangeBoundary::FromConstant(127)); | 1700 RangeBoundary::FromConstant(127)); |
| 1836 break; | 1701 break; |
| 1837 case kTypedDataUint8ArrayCid: | 1702 case kTypedDataUint8ArrayCid: |
| 1838 case kTypedDataUint8ClampedArrayCid: | 1703 case kTypedDataUint8ClampedArrayCid: |
| 1839 case kExternalTypedDataUint8ArrayCid: | 1704 case kExternalTypedDataUint8ArrayCid: |
| 1840 case kExternalTypedDataUint8ClampedArrayCid: | 1705 case kExternalTypedDataUint8ClampedArrayCid: |
| 1841 *range = Range(RangeBoundary::FromConstant(0), | 1706 range_ = new Range(RangeBoundary::FromConstant(0), |
| 1842 RangeBoundary::FromConstant(255)); | 1707 RangeBoundary::FromConstant(255)); |
| 1843 break; | 1708 break; |
| 1844 case kTypedDataInt16ArrayCid: | 1709 case kTypedDataInt16ArrayCid: |
| 1845 *range = Range(RangeBoundary::FromConstant(-32768), | 1710 range_ = new Range(RangeBoundary::FromConstant(-32768), |
| 1846 RangeBoundary::FromConstant(32767)); | 1711 RangeBoundary::FromConstant(32767)); |
| 1847 break; | 1712 break; |
| 1848 case kTypedDataUint16ArrayCid: | 1713 case kTypedDataUint16ArrayCid: |
| 1849 *range = Range(RangeBoundary::FromConstant(0), | 1714 range_ = new Range(RangeBoundary::FromConstant(0), |
| 1850 RangeBoundary::FromConstant(65535)); | 1715 RangeBoundary::FromConstant(65535)); |
| 1851 break; | 1716 break; |
| 1852 case kTypedDataInt32ArrayCid: | 1717 case kTypedDataInt32ArrayCid: |
| 1853 if (Typed32BitIsSmi()) { | 1718 if (Typed32BitIsSmi()) { |
| 1854 *range = Range::Full(RangeBoundary::kRangeBoundarySmi); | 1719 range_ = Range::UnknownSmi(); |
| 1855 } else { | 1720 } else { |
| 1856 *range = Range(RangeBoundary::FromConstant(kMinInt32), | 1721 range_ = new Range(RangeBoundary::FromConstant(kMinInt32), |
| 1857 RangeBoundary::FromConstant(kMaxInt32)); | 1722 RangeBoundary::FromConstant(kMaxInt32)); |
| 1858 } | 1723 } |
| 1859 break; | 1724 break; |
| 1860 case kTypedDataUint32ArrayCid: | 1725 case kTypedDataUint32ArrayCid: |
| 1861 if (Typed32BitIsSmi()) { | 1726 if (Typed32BitIsSmi()) { |
| 1862 *range = Range::Full(RangeBoundary::kRangeBoundarySmi); | 1727 range_ = Range::UnknownSmi(); |
| 1863 } else { | 1728 } else { |
| 1864 *range = Range(RangeBoundary::FromConstant(0), | 1729 range_ = new Range(RangeBoundary::FromConstant(0), |
| 1865 RangeBoundary::FromConstant(kMaxUint32)); | 1730 RangeBoundary::FromConstant(kMaxUint32)); |
| 1866 } | 1731 } |
| 1867 break; | 1732 break; |
| 1868 case kOneByteStringCid: | 1733 case kOneByteStringCid: |
| 1869 *range = Range(RangeBoundary::FromConstant(0), | 1734 range_ = new Range(RangeBoundary::FromConstant(0), |
| 1870 RangeBoundary::FromConstant(0xFF)); | 1735 RangeBoundary::FromConstant(0xFF)); |
| 1871 break; | 1736 break; |
| 1872 case kTwoByteStringCid: | 1737 case kTwoByteStringCid: |
| 1873 *range = Range(RangeBoundary::FromConstant(0), | 1738 range_ = new Range(RangeBoundary::FromConstant(0), |
| 1874 RangeBoundary::FromConstant(0xFFFF)); | 1739 RangeBoundary::FromConstant(0xFFFF)); |
| 1875 break; | 1740 break; |
| 1876 default: | 1741 default: |
| 1877 Definition::InferRange(range); | 1742 Definition::InferRange(); |
| 1878 break; | 1743 break; |
| 1879 } | 1744 } |
| 1880 } | 1745 } |
| 1881 | 1746 |
| 1882 | 1747 |
| 1883 void IfThenElseInstr::InferRange(Range* range) { | 1748 void IfThenElseInstr::InferRange() { |
| 1884 const intptr_t min = Utils::Minimum(if_true_, if_false_); | 1749 const intptr_t min = Utils::Minimum(if_true_, if_false_); |
| 1885 const intptr_t max = Utils::Maximum(if_true_, if_false_); | 1750 const intptr_t max = Utils::Maximum(if_true_, if_false_); |
| 1886 *range = Range(RangeBoundary::FromConstant(min), | 1751 range_ = new Range(RangeBoundary::FromConstant(min), |
| 1887 RangeBoundary::FromConstant(max)); | 1752 RangeBoundary::FromConstant(max)); |
| 1888 } | 1753 } |
| 1889 | 1754 |
| 1890 | 1755 |
| 1891 void BinarySmiOpInstr::InferRange(Range* range) { | 1756 void BinarySmiOpInstr::InferRange() { |
| 1892 // TODO(vegorov): canonicalize BinarySmiOp to always have constant on the | 1757 // TODO(vegorov): canonicalize BinarySmiOp to always have constant on the |
| 1893 // right and a non-constant on the left. | 1758 // right and a non-constant on the left. |
| 1894 Definition* left_defn = left()->definition(); | 1759 Definition* left_defn = left()->definition(); |
| 1895 | 1760 |
| 1896 Range* left_range = left_defn->range(); | 1761 Range* left_range = left_defn->range(); |
| 1897 Range* right_range = right()->definition()->range(); | 1762 Range* right_range = right()->definition()->range(); |
| 1898 | 1763 |
| 1899 if (Range::IsUnknown(left_range) || Range::IsUnknown(right_range)) { | 1764 if ((left_range == NULL) || (right_range == NULL)) { |
| 1765 range_ = Range::UnknownSmi(); |
| 1900 return; | 1766 return; |
| 1901 } | 1767 } |
| 1902 | 1768 |
| 1903 Range::BinaryOp(op_kind(), | 1769 Range* possible_range = Range::BinaryOp(op_kind(), |
| 1904 left_range, | 1770 left_range, |
| 1905 right_range, | 1771 right_range, |
| 1906 left_defn, | 1772 left_defn); |
| 1907 range); | |
| 1908 ASSERT(!Range::IsUnknown(range)); | |
| 1909 | 1773 |
| 1774 if ((range_ == NULL) && (possible_range == NULL)) { |
| 1775 // Initialize. |
| 1776 range_ = Range::UnknownSmi(); |
| 1777 return; |
| 1778 } |
| 1779 |
| 1780 if (possible_range == NULL) { |
| 1781 // Nothing new. |
| 1782 return; |
| 1783 } |
| 1784 |
| 1785 range_ = possible_range; |
| 1786 |
| 1787 ASSERT(!range_->min().IsUnknown() && !range_->max().IsUnknown()); |
| 1910 // Calculate overflowed status before clamping. | 1788 // Calculate overflowed status before clamping. |
| 1911 const bool overflowed = range->min().LowerBound().OverflowedSmi() || | 1789 const bool overflowed = range_->min().LowerBound().OverflowedSmi() || |
| 1912 range->max().UpperBound().OverflowedSmi(); | 1790 range_->max().UpperBound().OverflowedSmi(); |
| 1913 set_overflow(overflowed); | 1791 set_overflow(overflowed); |
| 1914 | 1792 |
| 1915 // Clamp value to be within smi range. | 1793 // Clamp value to be within smi range. |
| 1916 range->Clamp(RangeBoundary::kRangeBoundarySmi); | 1794 range_->Clamp(RangeBoundary::kRangeBoundarySmi); |
| 1917 } | 1795 } |
| 1918 | 1796 |
| 1919 | 1797 |
| 1920 void BinaryMintOpInstr::InferRange(Range* range) { | 1798 void BinaryMintOpInstr::InferRange() { |
| 1921 // TODO(vegorov): canonicalize BinaryMintOpInstr to always have constant on | 1799 // TODO(vegorov): canonicalize BinaryMintOpInstr to always have constant on |
| 1922 // the right and a non-constant on the left. | 1800 // the right and a non-constant on the left. |
| 1923 Definition* left_defn = left()->definition(); | 1801 Definition* left_defn = left()->definition(); |
| 1924 | 1802 |
| 1925 Range* left_range = left_defn->range(); | 1803 Range* left_range = left_defn->range(); |
| 1926 Range* right_range = right()->definition()->range(); | 1804 Range* right_range = right()->definition()->range(); |
| 1927 | 1805 |
| 1928 if (Range::IsUnknown(left_range) || Range::IsUnknown(right_range)) { | 1806 if ((left_range == NULL) || (right_range == NULL)) { |
| 1807 range_ = Range::Unknown(); |
| 1929 return; | 1808 return; |
| 1930 } | 1809 } |
| 1931 | 1810 |
| 1932 Range::BinaryOp(op_kind(), | 1811 Range* possible_range = Range::BinaryOp(op_kind(), |
| 1933 left_range, | 1812 left_range, |
| 1934 right_range, | 1813 right_range, |
| 1935 left_defn, | 1814 left_defn); |
| 1936 range); | 1815 |
| 1937 ASSERT(!Range::IsUnknown(range)); | 1816 if ((range_ == NULL) && (possible_range == NULL)) { |
| 1817 // Initialize. |
| 1818 range_ = Range::Unknown(); |
| 1819 return; |
| 1820 } |
| 1821 |
| 1822 if (possible_range == NULL) { |
| 1823 // Nothing new. |
| 1824 return; |
| 1825 } |
| 1826 |
| 1827 range_ = possible_range; |
| 1828 |
| 1829 ASSERT(!range_->min().IsUnknown() && !range_->max().IsUnknown()); |
| 1938 | 1830 |
| 1939 // Calculate overflowed status before clamping. | 1831 // Calculate overflowed status before clamping. |
| 1940 const bool overflowed = range->min().LowerBound().OverflowedMint() || | 1832 const bool overflowed = range_->min().LowerBound().OverflowedMint() || |
| 1941 range->max().UpperBound().OverflowedMint(); | 1833 range_->max().UpperBound().OverflowedMint(); |
| 1942 set_can_overflow(overflowed); | 1834 set_can_overflow(overflowed); |
| 1943 | 1835 |
| 1944 // Clamp value to be within mint range. | 1836 // Clamp value to be within mint range. |
| 1945 range->Clamp(RangeBoundary::kRangeBoundaryInt64); | 1837 range_->Clamp(RangeBoundary::kRangeBoundaryInt64); |
| 1946 } | 1838 } |
| 1947 | 1839 |
| 1948 | 1840 |
| 1949 void ShiftMintOpInstr::InferRange(Range* range) { | 1841 void ShiftMintOpInstr::InferRange() { |
| 1950 Definition* left_defn = left()->definition(); | 1842 Definition* left_defn = left()->definition(); |
| 1951 | 1843 |
| 1952 Range* left_range = left_defn->range(); | 1844 Range* left_range = left_defn->range(); |
| 1953 Range* right_range = right()->definition()->range(); | 1845 Range* right_range = right()->definition()->range(); |
| 1954 | 1846 |
| 1955 if (Range::IsUnknown(left_range) || Range::IsUnknown(right_range)) { | 1847 if ((left_range == NULL) || (right_range == NULL)) { |
| 1848 range_ = Range::Unknown(); |
| 1956 return; | 1849 return; |
| 1957 } | 1850 } |
| 1958 | 1851 |
| 1959 Range::BinaryOp(op_kind(), | 1852 Range* possible_range = Range::BinaryOp(op_kind(), |
| 1960 left_range, | 1853 left_range, |
| 1961 right_range, | 1854 right_range, |
| 1962 left_defn, | 1855 left_defn); |
| 1963 range); | 1856 |
| 1964 ASSERT(!Range::IsUnknown(range)); | 1857 if ((range_ == NULL) && (possible_range == NULL)) { |
| 1858 // Initialize. |
| 1859 range_ = Range::Unknown(); |
| 1860 return; |
| 1861 } |
| 1862 |
| 1863 if (possible_range == NULL) { |
| 1864 // Nothing new. |
| 1865 return; |
| 1866 } |
| 1867 |
| 1868 range_ = possible_range; |
| 1869 |
| 1870 ASSERT(!range_->min().IsUnknown() && !range_->max().IsUnknown()); |
| 1965 | 1871 |
| 1966 // Calculate overflowed status before clamping. | 1872 // Calculate overflowed status before clamping. |
| 1967 const bool overflowed = range->min().LowerBound().OverflowedMint() || | 1873 const bool overflowed = range_->min().LowerBound().OverflowedMint() || |
| 1968 range->max().UpperBound().OverflowedMint(); | 1874 range_->max().UpperBound().OverflowedMint(); |
| 1969 set_can_overflow(overflowed); | 1875 set_can_overflow(overflowed); |
| 1970 | 1876 |
| 1971 // Clamp value to be within mint range. | 1877 // Clamp value to be within mint range. |
| 1972 range->Clamp(RangeBoundary::kRangeBoundaryInt64); | 1878 range_->Clamp(RangeBoundary::kRangeBoundaryInt64); |
| 1973 } | 1879 } |
| 1974 | 1880 |
| 1975 | 1881 |
| 1976 void BoxIntegerInstr::InferRange(Range* range) { | 1882 void BoxIntegerInstr::InferRange() { |
| 1977 Range* input_range = value()->definition()->range(); | 1883 Range* input_range = value()->definition()->range(); |
| 1978 if (input_range != NULL) { | 1884 if (input_range != NULL) { |
| 1979 bool is_smi = !input_range->min().LowerBound().OverflowedSmi() && | 1885 bool is_smi = !input_range->min().LowerBound().OverflowedSmi() && |
| 1980 !input_range->max().UpperBound().OverflowedSmi(); | 1886 !input_range->max().UpperBound().OverflowedSmi(); |
| 1981 set_is_smi(is_smi); | 1887 set_is_smi(is_smi); |
| 1982 // The output range is the same as the input range. | 1888 // The output range is the same as the input range. |
| 1983 *range = *input_range; | 1889 range_ = input_range; |
| 1984 } | 1890 } |
| 1985 } | 1891 } |
| 1986 | 1892 |
| 1987 | |
| 1988 void UnboxIntegerInstr::InferRange(Range* range) { | |
| 1989 Range* value_range = value()->definition()->range(); | |
| 1990 if (value_range != NULL) { | |
| 1991 *range = *value_range; | |
| 1992 } else if (!value()->definition()->IsMintDefinition() && | |
| 1993 (value()->Type()->ToCid() != kSmiCid)) { | |
| 1994 *range = Range::Full(RangeBoundary::kRangeBoundaryInt64); | |
| 1995 } | |
| 1996 } | |
| 1997 | |
| 1998 | 1893 |
| 1999 bool CheckArrayBoundInstr::IsRedundant(const RangeBoundary& length) { | 1894 bool CheckArrayBoundInstr::IsRedundant(const RangeBoundary& length) { |
| 2000 Range* index_range = index()->definition()->range(); | 1895 Range* index_range = index()->definition()->range(); |
| 2001 | 1896 |
| 2002 // Range of the index is unknown can't decide if the check is redundant. | 1897 // Range of the index is unknown can't decide if the check is redundant. |
| 2003 if (index_range == NULL) { | 1898 if (index_range == NULL) { |
| 2004 return false; | 1899 return false; |
| 2005 } | 1900 } |
| 2006 | 1901 |
| 2007 // Range of the index is not positive. Check can't be redundant. | 1902 // Range of the index is not positive. Check can't be redundant. |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2042 } | 1937 } |
| 2043 } while (CanonicalizeMaxBoundary(&max) || | 1938 } while (CanonicalizeMaxBoundary(&max) || |
| 2044 CanonicalizeMinBoundary(&canonical_length)); | 1939 CanonicalizeMinBoundary(&canonical_length)); |
| 2045 | 1940 |
| 2046 // Failed to prove that maximum is bounded with array length. | 1941 // Failed to prove that maximum is bounded with array length. |
| 2047 return false; | 1942 return false; |
| 2048 } | 1943 } |
| 2049 | 1944 |
| 2050 | 1945 |
| 2051 } // namespace dart | 1946 } // namespace dart |
| OLD | NEW |