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 { |
(...skipping 13 matching lines...) Expand all Loading... |
24 | 24 |
25 if (FLAG_trace_range_analysis) { | 25 if (FLAG_trace_range_analysis) { |
26 FlowGraphPrinter::PrintGraph("Range Analysis (BBB)", flow_graph_); | 26 FlowGraphPrinter::PrintGraph("Range Analysis (BBB)", flow_graph_); |
27 } | 27 } |
28 | 28 |
29 InsertConstraints(); | 29 InsertConstraints(); |
30 InferRanges(); | 30 InferRanges(); |
31 EliminateRedundantBoundsChecks(); | 31 EliminateRedundantBoundsChecks(); |
32 MarkUnreachableBlocks(); | 32 MarkUnreachableBlocks(); |
33 | 33 |
| 34 NarrowMintToInt32(); |
| 35 |
34 IntegerInstructionSelector iis(flow_graph_); | 36 IntegerInstructionSelector iis(flow_graph_); |
35 iis.Select(); | 37 iis.Select(); |
36 | 38 |
37 RemoveConstraints(); | 39 RemoveConstraints(); |
38 } | 40 } |
39 | 41 |
40 | 42 |
41 void RangeAnalysis::CollectValues() { | 43 void RangeAnalysis::CollectValues() { |
42 const GrowableArray<Definition*>& initial = | 44 const GrowableArray<Definition*>& initial = |
43 *flow_graph_->graph_entry()->initial_definitions(); | 45 *flow_graph_->graph_entry()->initial_definitions(); |
44 for (intptr_t i = 0; i < initial.length(); ++i) { | 46 for (intptr_t i = 0; i < initial.length(); ++i) { |
45 Definition* current = initial[i]; | 47 Definition* current = initial[i]; |
46 if (current->Type()->ToCid() == kSmiCid) { | 48 if (current->Type()->ToCid() == kSmiCid) { |
47 values_.Add(current); | 49 values_.Add(current); |
48 } else if (current->IsMintDefinition()) { | 50 } else if (current->IsMintDefinition()) { |
49 values_.Add(current); | 51 values_.Add(current); |
| 52 } else if (current->IsInt32Definition()) { |
| 53 values_.Add(current); |
50 } | 54 } |
51 } | 55 } |
52 | 56 |
53 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); | 57 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); |
54 !block_it.Done(); | 58 !block_it.Done(); |
55 block_it.Advance()) { | 59 block_it.Advance()) { |
56 BlockEntryInstr* block = block_it.Current(); | 60 BlockEntryInstr* block = block_it.Current(); |
57 | 61 |
58 | 62 |
59 if (block->IsGraphEntry() || block->IsCatchBlockEntry()) { | 63 if (block->IsGraphEntry() || block->IsCatchBlockEntry()) { |
60 const GrowableArray<Definition*>& initial = block->IsGraphEntry() | 64 const GrowableArray<Definition*>& initial = block->IsGraphEntry() |
61 ? *block->AsGraphEntry()->initial_definitions() | 65 ? *block->AsGraphEntry()->initial_definitions() |
62 : *block->AsCatchBlockEntry()->initial_definitions(); | 66 : *block->AsCatchBlockEntry()->initial_definitions(); |
63 for (intptr_t i = 0; i < initial.length(); ++i) { | 67 for (intptr_t i = 0; i < initial.length(); ++i) { |
64 Definition* current = initial[i]; | 68 Definition* current = initial[i]; |
65 if (current->Type()->ToCid() == kSmiCid) { | 69 if (current->Type()->ToCid() == kSmiCid) { |
66 values_.Add(current); | 70 values_.Add(current); |
67 } else if (current->IsMintDefinition()) { | 71 } else if (current->IsMintDefinition()) { |
68 values_.Add(current); | 72 values_.Add(current); |
| 73 } else if (current->IsInt32Definition()) { |
| 74 values_.Add(current); |
69 } | 75 } |
70 } | 76 } |
71 } | 77 } |
72 | 78 |
73 JoinEntryInstr* join = block->AsJoinEntry(); | 79 JoinEntryInstr* join = block->AsJoinEntry(); |
74 if (join != NULL) { | 80 if (join != NULL) { |
75 for (PhiIterator phi_it(join); !phi_it.Done(); phi_it.Advance()) { | 81 for (PhiIterator phi_it(join); !phi_it.Done(); phi_it.Advance()) { |
76 PhiInstr* current = phi_it.Current(); | 82 PhiInstr* current = phi_it.Current(); |
77 if (current->Type()->ToCid() == kSmiCid) { | 83 if (current->Type()->ToCid() == kSmiCid) { |
78 values_.Add(current); | 84 values_.Add(current); |
| 85 } else if (current->representation() == kUnboxedInt32) { |
| 86 values_.Add(current); |
79 } | 87 } |
80 } | 88 } |
81 } | 89 } |
82 | 90 |
83 for (ForwardInstructionIterator instr_it(block); | 91 for (ForwardInstructionIterator instr_it(block); |
84 !instr_it.Done(); | 92 !instr_it.Done(); |
85 instr_it.Advance()) { | 93 instr_it.Advance()) { |
86 Instruction* current = instr_it.Current(); | 94 Instruction* current = instr_it.Current(); |
87 Definition* defn = current->AsDefinition(); | 95 Definition* defn = current->AsDefinition(); |
88 if (defn != NULL) { | 96 if (defn != NULL) { |
89 if ((defn->Type()->ToCid() == kSmiCid) && | 97 if ((defn->Type()->ToCid() == kSmiCid) && |
90 (defn->ssa_temp_index() != -1)) { | 98 (defn->ssa_temp_index() != -1)) { |
91 values_.Add(defn); | 99 values_.Add(defn); |
92 } else if ((defn->IsMintDefinition()) && | 100 } else if ((defn->IsMintDefinition()) && |
93 (defn->ssa_temp_index() != -1)) { | 101 (defn->ssa_temp_index() != -1)) { |
94 values_.Add(defn); | 102 values_.Add(defn); |
| 103 if (defn->IsBinaryMintOp()) { |
| 104 binary_mint_ops_.Add(defn->AsBinaryMintOp()); |
| 105 } else if (defn->IsShiftMintOp()) { |
| 106 shift_mint_ops_.Add(defn->AsShiftMintOp()); |
| 107 } |
| 108 } else if (defn->IsInt32Definition()) { |
| 109 values_.Add(defn); |
95 } | 110 } |
96 } else if (current->IsCheckArrayBound()) { | 111 } else if (current->IsCheckArrayBound()) { |
97 bounds_checks_.Add(current->AsCheckArrayBound()); | 112 bounds_checks_.Add(current->AsCheckArrayBound()); |
98 } | 113 } |
99 } | 114 } |
100 } | 115 } |
101 } | 116 } |
102 | 117 |
103 | 118 |
104 // Returns true if use is dominated by the given instruction. | 119 // Returns true if use is dominated by the given instruction. |
(...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
363 | 378 |
364 static bool DependOnSameSymbol(const RangeBoundary& a, const RangeBoundary& b) { | 379 static bool DependOnSameSymbol(const RangeBoundary& a, const RangeBoundary& b) { |
365 return a.IsSymbol() && b.IsSymbol() && | 380 return a.IsSymbol() && b.IsSymbol() && |
366 AreEqualDefinitions(a.symbol(), b.symbol()); | 381 AreEqualDefinitions(a.symbol(), b.symbol()); |
367 } | 382 } |
368 | 383 |
369 | 384 |
370 // Given the current range of a phi and a newly computed range check | 385 // Given the current range of a phi and a newly computed range check |
371 // if it is growing towards negative infinity, if it does widen it to | 386 // if it is growing towards negative infinity, if it does widen it to |
372 // MinSmi. | 387 // MinSmi. |
373 static RangeBoundary WidenMin(const Range* range, const Range* new_range) { | 388 static RangeBoundary WidenMin(const Range* range, |
| 389 const Range* new_range, |
| 390 RangeBoundary::RangeSize size) { |
374 RangeBoundary min = range->min(); | 391 RangeBoundary min = range->min(); |
375 RangeBoundary new_min = new_range->min(); | 392 RangeBoundary new_min = new_range->min(); |
376 | 393 |
377 if (min.IsSymbol()) { | 394 if (min.IsSymbol()) { |
378 if (min.LowerBound().OverflowedSmi()) { | 395 if (min.LowerBound().Overflowed(size)) { |
379 return RangeBoundary::MinSmi(); | 396 return RangeBoundary::MinConstant(size); |
380 } else if (DependOnSameSymbol(min, new_min)) { | 397 } else if (DependOnSameSymbol(min, new_min)) { |
381 return min.offset() <= new_min.offset() ? min : RangeBoundary::MinSmi(); | 398 return min.offset() <= new_min.offset() ? |
382 } else if (min.SmiUpperBound() <= new_min.SmiLowerBound()) { | 399 min : RangeBoundary::MinConstant(size); |
| 400 } else if (min.UpperBound(size) <= new_min.LowerBound(size)) { |
383 return min; | 401 return min; |
384 } | 402 } |
385 } | 403 } |
386 | 404 |
387 min = Range::ConstantMinSmi(range); | 405 min = Range::ConstantMin(range, size); |
388 new_min = Range::ConstantMinSmi(new_range); | 406 new_min = Range::ConstantMin(new_range, size); |
389 | 407 |
390 return (min.ConstantValue() <= new_min.ConstantValue()) ? | 408 return (min.ConstantValue() <= new_min.ConstantValue()) ? |
391 min : RangeBoundary::MinSmi(); | 409 min : RangeBoundary::MinConstant(size); |
392 } | 410 } |
393 | 411 |
394 // Given the current range of a phi and a newly computed range check | 412 // Given the current range of a phi and a newly computed range check |
395 // if it is growing towards positive infinity, if it does widen it to | 413 // if it is growing towards positive infinity, if it does widen it to |
396 // MaxSmi. | 414 // MaxSmi. |
397 static RangeBoundary WidenMax(const Range* range, const Range* new_range) { | 415 static RangeBoundary WidenMax(const Range* range, |
| 416 const Range* new_range, |
| 417 RangeBoundary::RangeSize size) { |
398 RangeBoundary max = range->max(); | 418 RangeBoundary max = range->max(); |
399 RangeBoundary new_max = new_range->max(); | 419 RangeBoundary new_max = new_range->max(); |
400 | 420 |
401 if (max.IsSymbol()) { | 421 if (max.IsSymbol()) { |
402 if (max.UpperBound().OverflowedSmi()) { | 422 if (max.UpperBound().Overflowed(size)) { |
403 return RangeBoundary::MaxSmi(); | 423 return RangeBoundary::MaxConstant(size); |
404 } else if (DependOnSameSymbol(max, new_max)) { | 424 } else if (DependOnSameSymbol(max, new_max)) { |
405 return max.offset() >= new_max.offset() ? max : RangeBoundary::MaxSmi(); | 425 return max.offset() >= new_max.offset() ? |
406 } else if (max.SmiLowerBound() >= new_max.SmiUpperBound()) { | 426 max : RangeBoundary::MaxConstant(size); |
| 427 } else if (max.LowerBound(size) >= new_max.UpperBound(size)) { |
407 return max; | 428 return max; |
408 } | 429 } |
409 } | 430 } |
410 | 431 |
411 max = Range::ConstantMaxSmi(range); | 432 max = Range::ConstantMax(range, size); |
412 new_max = Range::ConstantMaxSmi(new_range); | 433 new_max = Range::ConstantMax(new_range, size); |
413 | 434 |
414 return (max.ConstantValue() >= new_max.ConstantValue()) ? | 435 return (max.ConstantValue() >= new_max.ConstantValue()) ? |
415 max : RangeBoundary::MaxSmi(); | 436 max : RangeBoundary::MaxConstant(size); |
416 } | 437 } |
417 | 438 |
418 | 439 |
419 // Given the current range of a phi and a newly computed range check | 440 // Given the current range of a phi and a newly computed range check |
420 // if we can perform narrowing: use newly computed minimum to improve precision | 441 // if we can perform narrowing: use newly computed minimum to improve precision |
421 // of the computed range. We do it only if current minimum was widened and is | 442 // of the computed range. We do it only if current minimum was widened and is |
422 // equal to MinSmi. | 443 // equal to MinSmi. |
423 // Newly computed minimum is expected to be greater of equal then old one as | 444 // Newly computed minimum is expected to be greater of equal then old one as |
424 // we are running after widening phase. | 445 // we are running after widening phase. |
425 static RangeBoundary NarrowMin(const Range* range, const Range* new_range) { | 446 static RangeBoundary NarrowMin(const Range* range, |
| 447 const Range* new_range, |
| 448 RangeBoundary::RangeSize size) { |
426 #ifdef DEBUG | 449 #ifdef DEBUG |
427 const RangeBoundary min = Range::ConstantMinSmi(range); | 450 const RangeBoundary min = Range::ConstantMin(range, size); |
428 const RangeBoundary new_min = Range::ConstantMinSmi(new_range); | 451 const RangeBoundary new_min = Range::ConstantMin(new_range, size); |
429 ASSERT(min.ConstantValue() <= new_min.ConstantValue()); | 452 ASSERT(min.ConstantValue() <= new_min.ConstantValue()); |
430 #endif | 453 #endif |
431 // TODO(vegorov): consider using negative infinity to indicate widened bound. | 454 // TODO(vegorov): consider using negative infinity to indicate widened bound. |
432 return range->min().IsSmiMinimumOrBelow() ? new_range->min() : range->min(); | 455 return range->min().IsMinimumOrBelow(size) ? new_range->min() : range->min(); |
433 } | 456 } |
434 | 457 |
435 | 458 |
436 // Given the current range of a phi and a newly computed range check | 459 // Given the current range of a phi and a newly computed range check |
437 // if we can perform narrowing: use newly computed maximum to improve precision | 460 // if we can perform narrowing: use newly computed maximum to improve precision |
438 // of the computed range. We do it only if current maximum was widened and is | 461 // of the computed range. We do it only if current maximum was widened and is |
439 // equal to MaxSmi. | 462 // equal to MaxSmi. |
440 // Newly computed minimum is expected to be greater of equal then old one as | 463 // Newly computed minimum is expected to be greater of equal then old one as |
441 // we are running after widening phase. | 464 // we are running after widening phase. |
442 static RangeBoundary NarrowMax(const Range* range, const Range* new_range) { | 465 static RangeBoundary NarrowMax(const Range* range, |
| 466 const Range* new_range, |
| 467 RangeBoundary::RangeSize size) { |
443 #ifdef DEBUG | 468 #ifdef DEBUG |
444 const RangeBoundary max = Range::ConstantMaxSmi(range); | 469 const RangeBoundary max = Range::ConstantMax(range, size); |
445 const RangeBoundary new_max = Range::ConstantMaxSmi(new_range); | 470 const RangeBoundary new_max = Range::ConstantMax(new_range, size); |
446 ASSERT(max.ConstantValue() >= new_max.ConstantValue()); | 471 ASSERT(max.ConstantValue() >= new_max.ConstantValue()); |
447 #endif | 472 #endif |
448 // TODO(vegorov): consider using positive infinity to indicate widened bound. | 473 // TODO(vegorov): consider using positive infinity to indicate widened bound. |
449 return range->max().IsSmiMaximumOrAbove() ? new_range->max() : range->max(); | 474 return range->max().IsMaximumOrAbove(size) ? new_range->max() : range->max(); |
450 } | 475 } |
451 | 476 |
452 | 477 |
453 char RangeAnalysis::OpPrefix(JoinOperator op) { | 478 char RangeAnalysis::OpPrefix(JoinOperator op) { |
454 switch (op) { | 479 switch (op) { |
455 case WIDEN: return 'W'; | 480 case WIDEN: return 'W'; |
456 case NARROW: return 'N'; | 481 case NARROW: return 'N'; |
457 case NONE: return 'I'; | 482 case NONE: return 'I'; |
458 } | 483 } |
459 UNREACHABLE(); | 484 UNREACHABLE(); |
460 return ' '; | 485 return ' '; |
461 } | 486 } |
462 | 487 |
463 | 488 |
464 bool RangeAnalysis::InferRange(JoinOperator op, | 489 bool RangeAnalysis::InferRange(JoinOperator op, |
465 Definition* defn, | 490 Definition* defn, |
466 intptr_t iteration) { | 491 intptr_t iteration) { |
467 Range range; | 492 Range range; |
468 defn->InferRange(this, &range); | 493 defn->InferRange(this, &range); |
469 | 494 |
470 if (!Range::IsUnknown(&range)) { | 495 if (!Range::IsUnknown(&range)) { |
471 if (!Range::IsUnknown(defn->range()) && defn->IsPhi()) { | 496 if (!Range::IsUnknown(defn->range()) && defn->IsPhi()) { |
472 // TODO(vegorov): we are currently supporting only smi phis. | 497 // TODO(vegorov): we are currently supporting only smi/int32 phis. |
473 ASSERT(defn->Type()->ToCid() == kSmiCid); | 498 ASSERT((defn->Type()->ToCid() == kSmiCid) || |
| 499 (defn->representation() == kUnboxedInt32)); |
| 500 const RangeBoundary::RangeSize size = (defn->Type()->ToCid() == kSmiCid) ? |
| 501 RangeBoundary::kRangeBoundarySmi : RangeBoundary::kRangeBoundaryInt32; |
474 if (op == WIDEN) { | 502 if (op == WIDEN) { |
475 range = Range(WidenMin(defn->range(), &range), | 503 range = Range(WidenMin(defn->range(), &range, size), |
476 WidenMax(defn->range(), &range)); | 504 WidenMax(defn->range(), &range, size)); |
477 } else if (op == NARROW) { | 505 } else if (op == NARROW) { |
478 range = Range(NarrowMin(defn->range(), &range), | 506 range = Range(NarrowMin(defn->range(), &range, size), |
479 NarrowMax(defn->range(), &range)); | 507 NarrowMax(defn->range(), &range, size)); |
480 } | 508 } |
481 } | 509 } |
482 | 510 |
483 if (!range.Equals(defn->range())) { | 511 if (!range.Equals(defn->range())) { |
484 if (FLAG_trace_range_analysis) { | 512 if (FLAG_trace_range_analysis) { |
485 OS::Print("%c [%" Pd "] %s: %s => %s\n", | 513 OS::Print("%c [%" Pd "] %s: %s => %s\n", |
486 OpPrefix(op), | 514 OpPrefix(op), |
487 iteration, | 515 iteration, |
488 defn->ToCString(), | 516 defn->ToCString(), |
489 Range::ToCString(defn->range()), | 517 Range::ToCString(defn->range()), |
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
651 // constraints until we reach the actual definition. | 679 // constraints until we reach the actual definition. |
652 while (def->IsConstraint()) { | 680 while (def->IsConstraint()) { |
653 def = def->AsConstraint()->value()->definition(); | 681 def = def->AsConstraint()->value()->definition(); |
654 } | 682 } |
655 constraints_[i]->ReplaceUsesWith(def); | 683 constraints_[i]->ReplaceUsesWith(def); |
656 constraints_[i]->RemoveFromGraph(); | 684 constraints_[i]->RemoveFromGraph(); |
657 } | 685 } |
658 } | 686 } |
659 | 687 |
660 | 688 |
| 689 static void NarrowBinaryMintOp(BinaryMintOpInstr* mint_op) { |
| 690 if (Range::Fits(mint_op->range(), RangeBoundary::kRangeBoundaryInt32) && |
| 691 Range::Fits(mint_op->left()->definition()->range(), |
| 692 RangeBoundary::kRangeBoundaryInt32) && |
| 693 Range::Fits(mint_op->right()->definition()->range(), |
| 694 RangeBoundary::kRangeBoundaryInt32) && |
| 695 BinaryInt32OpInstr::IsSupported(mint_op->op_kind(), |
| 696 mint_op->left(), |
| 697 mint_op->right())) { |
| 698 BinaryInt32OpInstr* int32_op = |
| 699 new BinaryInt32OpInstr(mint_op->op_kind(), |
| 700 mint_op->left()->CopyWithType(), |
| 701 mint_op->right()->CopyWithType(), |
| 702 mint_op->DeoptimizationTarget()); |
| 703 int32_op->set_range(*mint_op->range()); |
| 704 int32_op->set_overflow(false); |
| 705 mint_op->ReplaceWith(int32_op, NULL); |
| 706 } |
| 707 } |
| 708 |
| 709 |
| 710 static void NarrowShiftMintOp(ShiftMintOpInstr* mint_op) { |
| 711 if (Range::Fits(mint_op->range(), RangeBoundary::kRangeBoundaryInt32) && |
| 712 Range::Fits(mint_op->left()->definition()->range(), |
| 713 RangeBoundary::kRangeBoundaryInt32) && |
| 714 Range::Fits(mint_op->right()->definition()->range(), |
| 715 RangeBoundary::kRangeBoundaryInt32) && |
| 716 BinaryInt32OpInstr::IsSupported(mint_op->op_kind(), |
| 717 mint_op->left(), |
| 718 mint_op->right())) { |
| 719 BinaryInt32OpInstr* int32_op = |
| 720 new BinaryInt32OpInstr(mint_op->op_kind(), |
| 721 mint_op->left()->CopyWithType(), |
| 722 mint_op->right()->CopyWithType(), |
| 723 mint_op->DeoptimizationTarget()); |
| 724 int32_op->set_range(*mint_op->range()); |
| 725 int32_op->set_overflow(false); |
| 726 mint_op->ReplaceWith(int32_op, NULL); |
| 727 } |
| 728 } |
| 729 |
| 730 |
| 731 void RangeAnalysis::NarrowMintToInt32() { |
| 732 for (intptr_t i = 0; i < binary_mint_ops_.length(); i++) { |
| 733 NarrowBinaryMintOp(binary_mint_ops_[i]); |
| 734 } |
| 735 |
| 736 for (intptr_t i = 0; i < shift_mint_ops_.length(); i++) { |
| 737 NarrowShiftMintOp(shift_mint_ops_[i]); |
| 738 } |
| 739 } |
| 740 |
| 741 |
661 IntegerInstructionSelector::IntegerInstructionSelector(FlowGraph* flow_graph) | 742 IntegerInstructionSelector::IntegerInstructionSelector(FlowGraph* flow_graph) |
662 : flow_graph_(flow_graph), | 743 : flow_graph_(flow_graph), |
663 isolate_(NULL) { | 744 isolate_(NULL) { |
664 ASSERT(flow_graph_ != NULL); | 745 ASSERT(flow_graph_ != NULL); |
665 isolate_ = flow_graph_->isolate(); | 746 isolate_ = flow_graph_->isolate(); |
666 ASSERT(isolate_ != NULL); | 747 ASSERT(isolate_ != NULL); |
667 selected_uint32_defs_ = | 748 selected_uint32_defs_ = |
668 new(I) BitVector(flow_graph_->current_ssa_temp_index()); | 749 new(I) BitVector(flow_graph_->current_ssa_temp_index()); |
669 } | 750 } |
670 | 751 |
(...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
897 if (!selected_uint32_defs_->Contains(defn->ssa_temp_index())) { | 978 if (!selected_uint32_defs_->Contains(defn->ssa_temp_index())) { |
898 // Not a candidate. | 979 // Not a candidate. |
899 continue; | 980 continue; |
900 } | 981 } |
901 Definition* replacement = ConstructReplacementFor(defn); | 982 Definition* replacement = ConstructReplacementFor(defn); |
902 ASSERT(replacement != NULL); | 983 ASSERT(replacement != NULL); |
903 if (FLAG_trace_integer_ir_selection) { | 984 if (FLAG_trace_integer_ir_selection) { |
904 OS::Print("Replacing %s with %s\n", defn->ToCString(), | 985 OS::Print("Replacing %s with %s\n", defn->ToCString(), |
905 replacement->ToCString()); | 986 replacement->ToCString()); |
906 } | 987 } |
| 988 if (!Range::IsUnknown(defn->range())) { |
| 989 replacement->set_range(*defn->range()); |
| 990 } |
907 defn->ReplaceWith(replacement, NULL); | 991 defn->ReplaceWith(replacement, NULL); |
908 ASSERT(flow_graph_->VerifyUseLists()); | 992 ASSERT(flow_graph_->VerifyUseLists()); |
909 } | 993 } |
910 } | 994 } |
911 | 995 |
912 | 996 |
913 RangeBoundary RangeBoundary::FromDefinition(Definition* defn, int64_t offs) { | 997 RangeBoundary RangeBoundary::FromDefinition(Definition* defn, int64_t offs) { |
914 if (defn->IsConstant() && defn->AsConstant()->value().IsSmi()) { | 998 if (defn->IsConstant() && defn->AsConstant()->value().IsSmi()) { |
915 return FromConstant(Smi::Cast(defn->AsConstant()->value()).Value() + offs); | 999 return FromConstant(Smi::Cast(defn->AsConstant()->value()).Value() + offs); |
916 } | 1000 } |
(...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1170 *a = canonical_a; | 1254 *a = canonical_a; |
1171 *b = canonical_b; | 1255 *b = canonical_b; |
1172 return true; | 1256 return true; |
1173 } | 1257 } |
1174 } while (op(&canonical_a) || op(&canonical_b)); | 1258 } while (op(&canonical_a) || op(&canonical_b)); |
1175 | 1259 |
1176 return false; | 1260 return false; |
1177 } | 1261 } |
1178 | 1262 |
1179 | 1263 |
1180 RangeBoundary RangeBoundary::JoinMin(RangeBoundary a, RangeBoundary b) { | 1264 RangeBoundary RangeBoundary::JoinMin(RangeBoundary a, |
| 1265 RangeBoundary b, |
| 1266 RangeBoundary::RangeSize size) { |
1181 if (a.Equals(b)) { | 1267 if (a.Equals(b)) { |
1182 return b; | 1268 return b; |
1183 } | 1269 } |
1184 | 1270 |
1185 if (CanonicalizeForComparison(&a, | 1271 if (CanonicalizeForComparison(&a, |
1186 &b, | 1272 &b, |
1187 &CanonicalizeMinBoundary, | 1273 &CanonicalizeMinBoundary, |
1188 RangeBoundary::NegativeInfinity())) { | 1274 RangeBoundary::NegativeInfinity())) { |
1189 return (a.offset() <= b.offset()) ? a : b; | 1275 return (a.offset() <= b.offset()) ? a : b; |
1190 } | 1276 } |
1191 | 1277 |
1192 const int64_t inf_a = a.SmiLowerBound(); | 1278 const int64_t inf_a = a.LowerBound(size); |
1193 const int64_t inf_b = b.SmiLowerBound(); | 1279 const int64_t inf_b = b.LowerBound(size); |
1194 const int64_t sup_a = a.SmiUpperBound(); | 1280 const int64_t sup_a = a.UpperBound(size); |
1195 const int64_t sup_b = b.SmiUpperBound(); | 1281 const int64_t sup_b = b.UpperBound(size); |
1196 | 1282 |
1197 if ((sup_a <= inf_b) && !a.LowerBound().OverflowedSmi()) { | 1283 if ((sup_a <= inf_b) && !a.LowerBound().Overflowed(size)) { |
1198 return a; | 1284 return a; |
1199 } else if ((sup_b <= inf_a) && !b.LowerBound().OverflowedSmi()) { | 1285 } else if ((sup_b <= inf_a) && !b.LowerBound().Overflowed(size)) { |
1200 return b; | 1286 return b; |
1201 } else { | 1287 } else { |
1202 return RangeBoundary::FromConstant(Utils::Minimum(inf_a, inf_b)); | 1288 return RangeBoundary::FromConstant(Utils::Minimum(inf_a, inf_b)); |
1203 } | 1289 } |
1204 } | 1290 } |
1205 | 1291 |
1206 | 1292 |
1207 RangeBoundary RangeBoundary::JoinMax(RangeBoundary a, RangeBoundary b) { | 1293 RangeBoundary RangeBoundary::JoinMax(RangeBoundary a, |
| 1294 RangeBoundary b, |
| 1295 RangeBoundary::RangeSize size) { |
1208 if (a.Equals(b)) { | 1296 if (a.Equals(b)) { |
1209 return b; | 1297 return b; |
1210 } | 1298 } |
1211 | 1299 |
1212 if (CanonicalizeForComparison(&a, | 1300 if (CanonicalizeForComparison(&a, |
1213 &b, | 1301 &b, |
1214 &CanonicalizeMaxBoundary, | 1302 &CanonicalizeMaxBoundary, |
1215 RangeBoundary::PositiveInfinity())) { | 1303 RangeBoundary::PositiveInfinity())) { |
1216 return (a.offset() >= b.offset()) ? a : b; | 1304 return (a.offset() >= b.offset()) ? a : b; |
1217 } | 1305 } |
1218 | 1306 |
1219 const int64_t inf_a = a.SmiLowerBound(); | 1307 const int64_t inf_a = a.LowerBound(size); |
1220 const int64_t inf_b = b.SmiLowerBound(); | 1308 const int64_t inf_b = b.LowerBound(size); |
1221 const int64_t sup_a = a.SmiUpperBound(); | 1309 const int64_t sup_a = a.UpperBound(size); |
1222 const int64_t sup_b = b.SmiUpperBound(); | 1310 const int64_t sup_b = b.UpperBound(size); |
1223 | 1311 |
1224 if ((sup_a <= inf_b) && !b.UpperBound().OverflowedSmi()) { | 1312 if ((sup_a <= inf_b) && !b.UpperBound().Overflowed(size)) { |
1225 return b; | 1313 return b; |
1226 } else if ((sup_b <= inf_a) && !a.UpperBound().OverflowedSmi()) { | 1314 } else if ((sup_b <= inf_a) && !a.UpperBound().Overflowed(size)) { |
1227 return a; | 1315 return a; |
1228 } else { | 1316 } else { |
1229 return RangeBoundary::FromConstant(Utils::Maximum(sup_a, sup_b)); | 1317 return RangeBoundary::FromConstant(Utils::Maximum(sup_a, sup_b)); |
1230 } | 1318 } |
1231 } | 1319 } |
1232 | 1320 |
1233 | 1321 |
1234 RangeBoundary RangeBoundary::IntersectionMin(RangeBoundary a, RangeBoundary b) { | 1322 RangeBoundary RangeBoundary::IntersectionMin(RangeBoundary a, RangeBoundary b) { |
1235 ASSERT(!a.IsPositiveInfinity() && !b.IsPositiveInfinity()); | 1323 ASSERT(!a.IsPositiveInfinity() && !b.IsPositiveInfinity()); |
1236 ASSERT(!a.IsUnknown() && !b.IsUnknown()); | 1324 ASSERT(!a.IsUnknown() && !b.IsUnknown()); |
1237 | 1325 |
1238 if (a.Equals(b)) { | 1326 if (a.Equals(b)) { |
1239 return a; | 1327 return a; |
1240 } | 1328 } |
1241 | 1329 |
1242 if (a.IsSmiMinimumOrBelow()) { | 1330 if (a.IsMinimumOrBelow(RangeBoundary::kRangeBoundarySmi)) { |
1243 return b; | 1331 return b; |
1244 } else if (b.IsSmiMinimumOrBelow()) { | 1332 } else if (b.IsMinimumOrBelow(RangeBoundary::kRangeBoundarySmi)) { |
1245 return a; | 1333 return a; |
1246 } | 1334 } |
1247 | 1335 |
1248 if (CanonicalizeForComparison(&a, | 1336 if (CanonicalizeForComparison(&a, |
1249 &b, | 1337 &b, |
1250 &CanonicalizeMinBoundary, | 1338 &CanonicalizeMinBoundary, |
1251 RangeBoundary::NegativeInfinity())) { | 1339 RangeBoundary::NegativeInfinity())) { |
1252 return (a.offset() >= b.offset()) ? a : b; | 1340 return (a.offset() >= b.offset()) ? a : b; |
1253 } | 1341 } |
1254 | 1342 |
1255 const int64_t inf_a = a.SmiLowerBound(); | 1343 const int64_t inf_a = a.SmiLowerBound(); |
1256 const int64_t inf_b = b.SmiLowerBound(); | 1344 const int64_t inf_b = b.SmiLowerBound(); |
1257 | 1345 |
1258 return (inf_a >= inf_b) ? a : b; | 1346 return (inf_a >= inf_b) ? a : b; |
1259 } | 1347 } |
1260 | 1348 |
1261 | 1349 |
1262 RangeBoundary RangeBoundary::IntersectionMax(RangeBoundary a, RangeBoundary b) { | 1350 RangeBoundary RangeBoundary::IntersectionMax(RangeBoundary a, RangeBoundary b) { |
1263 ASSERT(!a.IsNegativeInfinity() && !b.IsNegativeInfinity()); | 1351 ASSERT(!a.IsNegativeInfinity() && !b.IsNegativeInfinity()); |
1264 ASSERT(!a.IsUnknown() && !b.IsUnknown()); | 1352 ASSERT(!a.IsUnknown() && !b.IsUnknown()); |
1265 | 1353 |
1266 if (a.Equals(b)) { | 1354 if (a.Equals(b)) { |
1267 return a; | 1355 return a; |
1268 } | 1356 } |
1269 | 1357 |
1270 if (a.IsSmiMaximumOrAbove()) { | 1358 if (a.IsMaximumOrAbove(RangeBoundary::kRangeBoundarySmi)) { |
1271 return b; | 1359 return b; |
1272 } else if (b.IsSmiMaximumOrAbove()) { | 1360 } else if (b.IsMaximumOrAbove(RangeBoundary::kRangeBoundarySmi)) { |
1273 return a; | 1361 return a; |
1274 } | 1362 } |
1275 | 1363 |
1276 if (CanonicalizeForComparison(&a, | 1364 if (CanonicalizeForComparison(&a, |
1277 &b, | 1365 &b, |
1278 &CanonicalizeMaxBoundary, | 1366 &CanonicalizeMaxBoundary, |
1279 RangeBoundary::PositiveInfinity())) { | 1367 RangeBoundary::PositiveInfinity())) { |
1280 return (a.offset() <= b.offset()) ? a : b; | 1368 return (a.offset() <= b.offset()) ? a : b; |
1281 } | 1369 } |
1282 | 1370 |
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1543 ASSERT(right_range != NULL); | 1631 ASSERT(right_range != NULL); |
1544 ASSERT(result_min != NULL); | 1632 ASSERT(result_min != NULL); |
1545 ASSERT(result_max != NULL); | 1633 ASSERT(result_max != NULL); |
1546 | 1634 |
1547 const int64_t left_max = ConstantAbsMax(left_range); | 1635 const int64_t left_max = ConstantAbsMax(left_range); |
1548 const int64_t right_max = ConstantAbsMax(right_range); | 1636 const int64_t right_max = ConstantAbsMax(right_range); |
1549 if ((left_max <= -kSmiMin) && (right_max <= -kSmiMin) && | 1637 if ((left_max <= -kSmiMin) && (right_max <= -kSmiMin) && |
1550 ((left_max == 0) || (right_max <= kMaxInt64 / left_max))) { | 1638 ((left_max == 0) || (right_max <= kMaxInt64 / left_max))) { |
1551 // Product of left and right max values stays in 64 bit range. | 1639 // Product of left and right max values stays in 64 bit range. |
1552 const int64_t mul_max = left_max * right_max; | 1640 const int64_t mul_max = left_max * right_max; |
1553 if (Smi::IsValid(mul_max) && Smi::IsValid(-mul_max)) { | 1641 const int64_t r_min = |
1554 const int64_t r_min = | 1642 OnlyPositiveOrZero(*left_range, *right_range) ? 0 : -mul_max; |
1555 OnlyPositiveOrZero(*left_range, *right_range) ? 0 : -mul_max; | 1643 *result_min = RangeBoundary::FromConstant(r_min); |
1556 *result_min = RangeBoundary::FromConstant(r_min); | 1644 const int64_t r_max = |
1557 const int64_t r_max = | 1645 OnlyNegativeOrZero(*left_range, *right_range) ? 0 : mul_max; |
1558 OnlyNegativeOrZero(*left_range, *right_range) ? 0 : mul_max; | 1646 *result_max = RangeBoundary::FromConstant(r_max); |
1559 *result_max = RangeBoundary::FromConstant(r_max); | 1647 return true; |
1560 return true; | |
1561 } | |
1562 } | 1648 } |
1563 | 1649 |
1564 // TODO(vegorov): handle mixed sign case that leads to (-Infinity, 0] range. | 1650 // TODO(vegorov): handle mixed sign case that leads to (-Infinity, 0] range. |
1565 if (OnlyPositiveOrZero(*left_range, *right_range) || | 1651 if (OnlyPositiveOrZero(*left_range, *right_range) || |
1566 OnlyNegativeOrZero(*left_range, *right_range)) { | 1652 OnlyNegativeOrZero(*left_range, *right_range)) { |
1567 *result_min = RangeBoundary::FromConstant(0); | 1653 *result_min = RangeBoundary::FromConstant(0); |
1568 *result_max = RangeBoundary::PositiveInfinity(); | 1654 *result_max = RangeBoundary::PositiveInfinity(); |
1569 return true; | 1655 return true; |
1570 } | 1656 } |
1571 | 1657 |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1657 } | 1743 } |
1658 *range_ = range; | 1744 *range_ = range; |
1659 } | 1745 } |
1660 | 1746 |
1661 | 1747 |
1662 void Definition::InferRange(RangeAnalysis* analysis, Range* range) { | 1748 void Definition::InferRange(RangeAnalysis* analysis, Range* range) { |
1663 if (Type()->ToCid() == kSmiCid) { | 1749 if (Type()->ToCid() == kSmiCid) { |
1664 *range = Range::Full(RangeBoundary::kRangeBoundarySmi); | 1750 *range = Range::Full(RangeBoundary::kRangeBoundarySmi); |
1665 } else if (IsMintDefinition()) { | 1751 } else if (IsMintDefinition()) { |
1666 *range = Range::Full(RangeBoundary::kRangeBoundaryInt64); | 1752 *range = Range::Full(RangeBoundary::kRangeBoundaryInt64); |
| 1753 } else if (IsInt32Definition()) { |
| 1754 *range = Range::Full(RangeBoundary::kRangeBoundaryInt32); |
1667 } else { | 1755 } else { |
1668 // Only Smi and Mint supported. | 1756 // Only Smi and Mint supported. |
1669 UNREACHABLE(); | 1757 UNREACHABLE(); |
1670 } | 1758 } |
1671 } | 1759 } |
1672 | 1760 |
1673 | 1761 |
1674 static bool DependsOnSymbol(const RangeBoundary& a, Definition* symbol) { | 1762 static bool DependsOnSymbol(const RangeBoundary& a, Definition* symbol) { |
1675 return a.IsSymbol() && (UnwrapConstraint(a.symbol()) == symbol); | 1763 return a.IsSymbol() && (UnwrapConstraint(a.symbol()) == symbol); |
1676 } | 1764 } |
1677 | 1765 |
1678 | 1766 |
1679 // Given the range and definition update the range so that | 1767 // Given the range and definition update the range so that |
1680 // it covers both original range and defintions range. | 1768 // it covers both original range and defintions range. |
1681 // | 1769 // |
1682 // The following should also hold: | 1770 // The following should also hold: |
1683 // | 1771 // |
1684 // [_|_, _|_] U a = a U [_|_, _|_] = a | 1772 // [_|_, _|_] U a = a U [_|_, _|_] = a |
1685 // | 1773 // |
1686 static void Join(Range* range, Definition* defn, const Range* defn_range) { | 1774 static void Join(Range* range, |
| 1775 Definition* defn, |
| 1776 const Range* defn_range, |
| 1777 RangeBoundary::RangeSize size) { |
1687 if (Range::IsUnknown(defn_range)) { | 1778 if (Range::IsUnknown(defn_range)) { |
1688 return; | 1779 return; |
1689 } | 1780 } |
1690 | 1781 |
1691 if (Range::IsUnknown(range)) { | 1782 if (Range::IsUnknown(range)) { |
1692 *range = *defn_range; | 1783 *range = *defn_range; |
1693 return; | 1784 return; |
1694 } | 1785 } |
1695 | 1786 |
1696 Range other = *defn_range; | 1787 Range other = *defn_range; |
1697 | 1788 |
1698 // Handle patterns where range already depends on defn as a symbol: | 1789 // Handle patterns where range already depends on defn as a symbol: |
1699 // | 1790 // |
1700 // (..., S+o] U range(S) and [S+o, ...) U range(S) | 1791 // (..., S+o] U range(S) and [S+o, ...) U range(S) |
1701 // | 1792 // |
1702 // To improve precision of the computed join use [S, S] instead of | 1793 // To improve precision of the computed join use [S, S] instead of |
1703 // using range(S). It will be canonicalized away by JoinMin/JoinMax | 1794 // using range(S). It will be canonicalized away by JoinMin/JoinMax |
1704 // functions. | 1795 // functions. |
1705 Definition* unwrapped = UnwrapConstraint(defn); | 1796 Definition* unwrapped = UnwrapConstraint(defn); |
1706 if (DependsOnSymbol(range->min(), unwrapped) || | 1797 if (DependsOnSymbol(range->min(), unwrapped) || |
1707 DependsOnSymbol(range->max(), unwrapped)) { | 1798 DependsOnSymbol(range->max(), unwrapped)) { |
1708 other = Range(RangeBoundary::FromDefinition(defn, 0), | 1799 other = Range(RangeBoundary::FromDefinition(defn, 0), |
1709 RangeBoundary::FromDefinition(defn, 0)); | 1800 RangeBoundary::FromDefinition(defn, 0)); |
1710 } | 1801 } |
1711 | 1802 |
1712 // First try to compare ranges based on their upper and lower bounds. | 1803 // First try to compare ranges based on their upper and lower bounds. |
1713 const int64_t inf_range = range->min().SmiLowerBound(); | 1804 const int64_t inf_range = range->min().LowerBound(size); |
1714 const int64_t inf_other = other.min().SmiLowerBound(); | 1805 const int64_t inf_other = other.min().LowerBound(size); |
1715 const int64_t sup_range = range->max().SmiUpperBound(); | 1806 const int64_t sup_range = range->max().UpperBound(size); |
1716 const int64_t sup_other = other.max().SmiUpperBound(); | 1807 const int64_t sup_other = other.max().UpperBound(size); |
1717 | 1808 |
1718 if (sup_range <= inf_other) { | 1809 if (sup_range <= inf_other) { |
1719 // The range is fully below defn's range. Keep the minimum and | 1810 // The range is fully below defn's range. Keep the minimum and |
1720 // expand the maximum. | 1811 // expand the maximum. |
1721 range->set_max(other.max()); | 1812 range->set_max(other.max()); |
1722 } else if (sup_other <= inf_range) { | 1813 } else if (sup_other <= inf_range) { |
1723 // The range is fully above defn's range. Keep the maximum and | 1814 // The range is fully above defn's range. Keep the maximum and |
1724 // expand the minimum. | 1815 // expand the minimum. |
1725 range->set_min(other.min()); | 1816 range->set_min(other.min()); |
1726 } else { | 1817 } else { |
1727 // Can't compare ranges as whole. Join minimum and maximum separately. | 1818 // Can't compare ranges as whole. Join minimum and maximum separately. |
1728 *range = Range(RangeBoundary::JoinMin(range->min(), other.min()), | 1819 *range = Range(RangeBoundary::JoinMin(range->min(), other.min(), size), |
1729 RangeBoundary::JoinMax(range->max(), other.max())); | 1820 RangeBoundary::JoinMax(range->max(), other.max(), size)); |
1730 } | 1821 } |
1731 } | 1822 } |
1732 | 1823 |
1733 | 1824 |
1734 // When assigning range to a phi we must take care to avoid self-reference | 1825 // When assigning range to a phi we must take care to avoid self-reference |
1735 // cycles when phi's range depends on the phi itself. | 1826 // cycles when phi's range depends on the phi itself. |
1736 // To prevent such cases we impose additional restriction on symbols that | 1827 // To prevent such cases we impose additional restriction on symbols that |
1737 // can be used as boundaries for phi's range: they must dominate | 1828 // can be used as boundaries for phi's range: they must dominate |
1738 // phi's definition. | 1829 // phi's definition. |
1739 static RangeBoundary EnsureAcyclicSymbol(BlockEntryInstr* phi_block, | 1830 static RangeBoundary EnsureAcyclicSymbol(BlockEntryInstr* phi_block, |
1740 const RangeBoundary& a, | 1831 const RangeBoundary& a, |
1741 const RangeBoundary& limit) { | 1832 const RangeBoundary& limit) { |
1742 if (!a.IsSymbol() || a.symbol()->GetBlock()->Dominates(phi_block)) { | 1833 if (!a.IsSymbol() || a.symbol()->GetBlock()->Dominates(phi_block)) { |
1743 return a; | 1834 return a; |
1744 } | 1835 } |
1745 | 1836 |
1746 // Symbol does not dominate phi. Try unwrapping constraint and check again. | 1837 // Symbol does not dominate phi. Try unwrapping constraint and check again. |
1747 Definition* unwrapped = UnwrapConstraint(a.symbol()); | 1838 Definition* unwrapped = UnwrapConstraint(a.symbol()); |
1748 if ((unwrapped != a.symbol()) && | 1839 if ((unwrapped != a.symbol()) && |
1749 unwrapped->GetBlock()->Dominates(phi_block)) { | 1840 unwrapped->GetBlock()->Dominates(phi_block)) { |
1750 return RangeBoundary::FromDefinition(unwrapped, a.offset()); | 1841 return RangeBoundary::FromDefinition(unwrapped, a.offset()); |
1751 } | 1842 } |
1752 | 1843 |
1753 return limit; | 1844 return limit; |
1754 } | 1845 } |
1755 | 1846 |
1756 | 1847 |
1757 void PhiInstr::InferRange(RangeAnalysis* analysis, Range* range) { | 1848 void PhiInstr::InferRange(RangeAnalysis* analysis, Range* range) { |
1758 ASSERT(Type()->ToCid() == kSmiCid); | 1849 ASSERT((Type()->ToCid() == kSmiCid) || (representation() == kUnboxedInt32)); |
| 1850 const RangeBoundary::RangeSize size = (Type()->ToCid() == kSmiCid) ? |
| 1851 RangeBoundary::kRangeBoundarySmi : RangeBoundary::kRangeBoundaryInt32; |
1759 for (intptr_t i = 0; i < InputCount(); i++) { | 1852 for (intptr_t i = 0; i < InputCount(); i++) { |
1760 Value* input = InputAt(i); | 1853 Value* input = InputAt(i); |
1761 Join(range, input->definition(), analysis->GetSmiRange(input)); | 1854 const Range* input_range = (size == RangeBoundary::kRangeBoundarySmi) ? |
| 1855 analysis->GetSmiRange(input) : input->definition()->range(); |
| 1856 Join(range, |
| 1857 input->definition(), input_range, size); |
1762 } | 1858 } |
1763 | 1859 |
1764 BlockEntryInstr* phi_block = GetBlock(); | 1860 BlockEntryInstr* phi_block = GetBlock(); |
1765 range->set_min(EnsureAcyclicSymbol( | 1861 range->set_min(EnsureAcyclicSymbol( |
1766 phi_block, range->min(), RangeBoundary::MinSmi())); | 1862 phi_block, range->min(), RangeBoundary::MinSmi())); |
1767 range->set_max(EnsureAcyclicSymbol( | 1863 range->set_max(EnsureAcyclicSymbol( |
1768 phi_block, range->max(), RangeBoundary::MaxSmi())); | 1864 phi_block, range->max(), RangeBoundary::MaxSmi())); |
1769 } | 1865 } |
1770 | 1866 |
1771 | 1867 |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1912 // Calculate overflowed status before clamping. | 2008 // Calculate overflowed status before clamping. |
1913 const bool overflowed = range->min().LowerBound().OverflowedSmi() || | 2009 const bool overflowed = range->min().LowerBound().OverflowedSmi() || |
1914 range->max().UpperBound().OverflowedSmi(); | 2010 range->max().UpperBound().OverflowedSmi(); |
1915 set_overflow(overflowed); | 2011 set_overflow(overflowed); |
1916 | 2012 |
1917 // Clamp value to be within smi range. | 2013 // Clamp value to be within smi range. |
1918 range->Clamp(RangeBoundary::kRangeBoundarySmi); | 2014 range->Clamp(RangeBoundary::kRangeBoundarySmi); |
1919 } | 2015 } |
1920 | 2016 |
1921 | 2017 |
| 2018 void BoxInt32Instr::InferRange(RangeAnalysis* analysis, Range* range) { |
| 2019 const Range* value_range = value()->definition()->range(); |
| 2020 if (!Range::IsUnknown(value_range)) { |
| 2021 *range = *value_range; |
| 2022 } |
| 2023 } |
| 2024 |
| 2025 |
| 2026 void UnboxInt32Instr::InferRange(RangeAnalysis* analysis, Range* range) { |
| 2027 if (value()->definition()->Type()->ToCid() == kSmiCid) { |
| 2028 const Range* value_range = analysis->GetSmiRange(value()); |
| 2029 if (!Range::IsUnknown(value_range)) { |
| 2030 *range = *value_range; |
| 2031 } |
| 2032 } else if (value()->definition()->IsMintDefinition() || |
| 2033 value()->definition()->IsInt32Definition()) { |
| 2034 const Range* value_range = value()->definition()->range(); |
| 2035 if (!Range::IsUnknown(value_range)) { |
| 2036 *range = *value_range; |
| 2037 } |
| 2038 } else if (value()->Type()->ToCid() == kSmiCid) { |
| 2039 *range = Range::Full(RangeBoundary::kRangeBoundarySmi); |
| 2040 } else { |
| 2041 *range = Range::Full(RangeBoundary::kRangeBoundaryInt32); |
| 2042 } |
| 2043 } |
| 2044 |
| 2045 |
| 2046 void UnboxedIntConverterInstr::InferRange(RangeAnalysis* analysis, |
| 2047 Range* range) { |
| 2048 ASSERT((from() == kUnboxedInt32) || |
| 2049 (from() == kUnboxedMint) || |
| 2050 (from() == kUnboxedUint32)); |
| 2051 ASSERT((to() == kUnboxedInt32) || |
| 2052 (to() == kUnboxedMint) || |
| 2053 (to() == kUnboxedUint32)); |
| 2054 const Range* value_range = value()->definition()->range(); |
| 2055 if (Range::IsUnknown(value_range)) { |
| 2056 return; |
| 2057 } |
| 2058 |
| 2059 if (to() == kUnboxedUint32) { |
| 2060 // TODO(vegorov): improve range information for unboxing to Uint32. |
| 2061 *range = Range( |
| 2062 RangeBoundary::FromConstant(0), |
| 2063 RangeBoundary::FromConstant(static_cast<int64_t>(kMaxUint32))); |
| 2064 } else { |
| 2065 *range = *value_range; |
| 2066 if (to() == kUnboxedInt32) { |
| 2067 range->Clamp(RangeBoundary::kRangeBoundaryInt32); |
| 2068 } |
| 2069 } |
| 2070 } |
| 2071 |
| 2072 |
| 2073 void BinaryInt32OpInstr::InferRange(RangeAnalysis* analysis, Range* range) { |
| 2074 // TODO(vegorov): canonicalize BinarySmiOp to always have constant on the |
| 2075 // right and a non-constant on the left. |
| 2076 Definition* left_defn = left()->definition(); |
| 2077 |
| 2078 const Range* left_range = analysis->GetSmiRange(left()); |
| 2079 const Range* right_range = analysis->GetSmiRange(right()); |
| 2080 |
| 2081 if (Range::IsUnknown(left_range) || Range::IsUnknown(right_range)) { |
| 2082 return; |
| 2083 } |
| 2084 |
| 2085 Range::BinaryOp(op_kind(), |
| 2086 left_range, |
| 2087 right_range, |
| 2088 left_defn, |
| 2089 range); |
| 2090 ASSERT(!Range::IsUnknown(range)); |
| 2091 |
| 2092 // Calculate overflowed status before clamping. |
| 2093 set_overflow(!range->Fits(RangeBoundary::kRangeBoundaryInt32)); |
| 2094 |
| 2095 // Clamp value to be within smi range. |
| 2096 range->Clamp(RangeBoundary::kRangeBoundaryInt32); |
| 2097 } |
| 2098 |
1922 void BinaryMintOpInstr::InferRange(RangeAnalysis* analysis, Range* range) { | 2099 void BinaryMintOpInstr::InferRange(RangeAnalysis* analysis, Range* range) { |
1923 // TODO(vegorov): canonicalize BinaryMintOpInstr to always have constant on | 2100 // TODO(vegorov): canonicalize BinaryMintOpInstr to always have constant on |
1924 // the right and a non-constant on the left. | 2101 // the right and a non-constant on the left. |
1925 Definition* left_defn = left()->definition(); | 2102 Definition* left_defn = left()->definition(); |
1926 | 2103 |
1927 const Range* left_range = left_defn->range(); | 2104 const Range* left_range = left_defn->range(); |
1928 const Range* right_range = right()->definition()->range(); | 2105 const Range* right_range = right()->definition()->range(); |
1929 | 2106 |
1930 if (Range::IsUnknown(left_range) || Range::IsUnknown(right_range)) { | 2107 if (Range::IsUnknown(left_range) || Range::IsUnknown(right_range)) { |
1931 return; | 2108 return; |
1932 } | 2109 } |
1933 | 2110 |
1934 Range::BinaryOp(op_kind(), | 2111 Range::BinaryOp(op_kind(), |
1935 left_range, | 2112 left_range, |
1936 right_range, | 2113 right_range, |
1937 left_defn, | 2114 left_defn, |
1938 range); | 2115 range); |
1939 ASSERT(!Range::IsUnknown(range)); | 2116 ASSERT(!Range::IsUnknown(range)); |
1940 | 2117 |
1941 // Calculate overflowed status before clamping. | 2118 // Calculate overflowed status before clamping. |
1942 const bool overflowed = range->min().LowerBound().OverflowedMint() || | 2119 set_can_overflow(!range->Fits(RangeBoundary::kRangeBoundaryInt64)); |
1943 range->max().UpperBound().OverflowedMint(); | |
1944 set_can_overflow(overflowed); | |
1945 | 2120 |
1946 // Clamp value to be within mint range. | 2121 // Clamp value to be within mint range. |
1947 range->Clamp(RangeBoundary::kRangeBoundaryInt64); | 2122 range->Clamp(RangeBoundary::kRangeBoundaryInt64); |
1948 } | 2123 } |
1949 | 2124 |
1950 | 2125 |
1951 void ShiftMintOpInstr::InferRange(RangeAnalysis* analysis, Range* range) { | 2126 void ShiftMintOpInstr::InferRange(RangeAnalysis* analysis, Range* range) { |
1952 Definition* left_defn = left()->definition(); | 2127 Definition* left_defn = left()->definition(); |
1953 | 2128 |
1954 const Range* left_range = left_defn->range(); | 2129 const Range* left_range = left_defn->range(); |
(...skipping 16 matching lines...) Expand all Loading... |
1971 set_can_overflow(overflowed); | 2146 set_can_overflow(overflowed); |
1972 | 2147 |
1973 // Clamp value to be within mint range. | 2148 // Clamp value to be within mint range. |
1974 range->Clamp(RangeBoundary::kRangeBoundaryInt64); | 2149 range->Clamp(RangeBoundary::kRangeBoundaryInt64); |
1975 } | 2150 } |
1976 | 2151 |
1977 | 2152 |
1978 void BoxIntegerInstr::InferRange(RangeAnalysis* analysis, Range* range) { | 2153 void BoxIntegerInstr::InferRange(RangeAnalysis* analysis, Range* range) { |
1979 const Range* input_range = value()->definition()->range(); | 2154 const Range* input_range = value()->definition()->range(); |
1980 if (input_range != NULL) { | 2155 if (input_range != NULL) { |
1981 bool is_smi = !input_range->min().LowerBound().OverflowedSmi() && | 2156 bool is_smi = input_range->Fits(RangeBoundary::kRangeBoundarySmi); |
1982 !input_range->max().UpperBound().OverflowedSmi(); | |
1983 set_is_smi(is_smi); | 2157 set_is_smi(is_smi); |
1984 // The output range is the same as the input range. | 2158 // The output range is the same as the input range. |
1985 *range = *input_range; | 2159 *range = *input_range; |
1986 } | 2160 } |
1987 } | 2161 } |
1988 | 2162 |
1989 | 2163 |
1990 void UnboxIntegerInstr::InferRange(RangeAnalysis* analysis, Range* range) { | 2164 void UnboxIntegerInstr::InferRange(RangeAnalysis* analysis, Range* range) { |
1991 const Range* value_range = value()->definition()->range(); | 2165 const Range* value_range = value()->definition()->range(); |
1992 if (value_range != NULL) { | 2166 if (value_range != NULL) { |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2044 } | 2218 } |
2045 } while (CanonicalizeMaxBoundary(&max) || | 2219 } while (CanonicalizeMaxBoundary(&max) || |
2046 CanonicalizeMinBoundary(&canonical_length)); | 2220 CanonicalizeMinBoundary(&canonical_length)); |
2047 | 2221 |
2048 // Failed to prove that maximum is bounded with array length. | 2222 // Failed to prove that maximum is bounded with array length. |
2049 return false; | 2223 return false; |
2050 } | 2224 } |
2051 | 2225 |
2052 | 2226 |
2053 } // namespace dart | 2227 } // namespace dart |
OLD | NEW |