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