Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 64 dominator_(NULL), | 64 dominator_(NULL), |
| 65 dominated_blocks_(4, graph->zone()), | 65 dominated_blocks_(4, graph->zone()), |
| 66 last_environment_(NULL), | 66 last_environment_(NULL), |
| 67 argument_count_(-1), | 67 argument_count_(-1), |
| 68 first_instruction_index_(-1), | 68 first_instruction_index_(-1), |
| 69 last_instruction_index_(-1), | 69 last_instruction_index_(-1), |
| 70 deleted_phis_(4, graph->zone()), | 70 deleted_phis_(4, graph->zone()), |
| 71 parent_loop_header_(NULL), | 71 parent_loop_header_(NULL), |
| 72 is_inline_return_target_(false), | 72 is_inline_return_target_(false), |
| 73 is_deoptimizing_(false), | 73 is_deoptimizing_(false), |
| 74 dominates_loop_successors_(false) { } | 74 dominates_loop_successors_(false), |
| 75 is_osr_entry_(false) { } | |
| 75 | 76 |
| 76 | 77 |
| 77 void HBasicBlock::AttachLoopInformation() { | 78 void HBasicBlock::AttachLoopInformation() { |
| 78 ASSERT(!IsLoopHeader()); | 79 ASSERT(!IsLoopHeader()); |
| 79 loop_information_ = new(zone()) HLoopInformation(this, zone()); | 80 loop_information_ = new(zone()) HLoopInformation(this, zone()); |
| 80 } | 81 } |
| 81 | 82 |
| 82 | 83 |
| 83 void HBasicBlock::DetachLoopInformation() { | 84 void HBasicBlock::DetachLoopInformation() { |
| 84 ASSERT(IsLoopHeader()); | 85 ASSERT(IsLoopHeader()); |
| (...skipping 504 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 589 if (!pointer->is_set()) { | 590 if (!pointer->is_set()) { |
| 590 HConstant* constant = | 591 HConstant* constant = |
| 591 new(zone()) HConstant(value, Representation::Integer32()); | 592 new(zone()) HConstant(value, Representation::Integer32()); |
| 592 constant->InsertAfter(GetConstantUndefined()); | 593 constant->InsertAfter(GetConstantUndefined()); |
| 593 pointer->set(constant); | 594 pointer->set(constant); |
| 594 } | 595 } |
| 595 return pointer->get(); | 596 return pointer->get(); |
| 596 } | 597 } |
| 597 | 598 |
| 598 | 599 |
| 600 HConstant* HGraph::GetConstant0() { | |
| 601 return GetConstantInt32(&constant_0_, 0); | |
| 602 } | |
| 603 | |
| 604 | |
| 599 HConstant* HGraph::GetConstant1() { | 605 HConstant* HGraph::GetConstant1() { |
| 600 return GetConstantInt32(&constant_1_, 1); | 606 return GetConstantInt32(&constant_1_, 1); |
| 601 } | 607 } |
| 602 | 608 |
| 603 | 609 |
| 604 HConstant* HGraph::GetConstantMinus1() { | 610 HConstant* HGraph::GetConstantMinus1() { |
| 605 return GetConstantInt32(&constant_minus1_, -1); | 611 return GetConstantInt32(&constant_minus1_, -1); |
| 606 } | 612 } |
| 607 | 613 |
| 608 | 614 |
| (...skipping 2710 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3319 if (FLAG_use_range) { | 3325 if (FLAG_use_range) { |
| 3320 HRangeAnalysis rangeAnalysis(this); | 3326 HRangeAnalysis rangeAnalysis(this); |
| 3321 rangeAnalysis.Analyze(); | 3327 rangeAnalysis.Analyze(); |
| 3322 } | 3328 } |
| 3323 ComputeMinusZeroChecks(); | 3329 ComputeMinusZeroChecks(); |
| 3324 | 3330 |
| 3325 // Eliminate redundant stack checks on backwards branches. | 3331 // Eliminate redundant stack checks on backwards branches. |
| 3326 HStackCheckEliminator sce(this); | 3332 HStackCheckEliminator sce(this); |
| 3327 sce.Process(); | 3333 sce.Process(); |
| 3328 | 3334 |
| 3329 EliminateRedundantBoundsChecks(); | 3335 if (FLAG_array_bounds_checks_dehoisting) { |
| 3336 EliminateOrDehoistBoundsChecks(); | |
| 3337 } else { | |
| 3338 EliminateRedundantBoundsChecks(); | |
| 3339 } | |
| 3330 DehoistSimpleArrayIndexComputations(); | 3340 DehoistSimpleArrayIndexComputations(); |
| 3331 if (FLAG_dead_code_elimination) DeadCodeElimination(); | 3341 if (FLAG_dead_code_elimination) DeadCodeElimination(); |
| 3332 | 3342 |
| 3333 return true; | 3343 return true; |
| 3334 } | 3344 } |
| 3335 | 3345 |
| 3336 | 3346 |
| 3337 // We try to "factor up" HBoundsCheck instructions towards the root of the | 3347 // We try to "factor up" HBoundsCheck instructions towards the root of the |
| 3338 // dominator tree. | 3348 // dominator tree. |
| 3339 // For now we handle checks where the index is like "exp + int32value". | 3349 // For now we handle checks where the index is like "exp + int32value". |
| (...skipping 323 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3663 } | 3673 } |
| 3664 | 3674 |
| 3665 | 3675 |
| 3666 void HGraph::EliminateRedundantBoundsChecks() { | 3676 void HGraph::EliminateRedundantBoundsChecks() { |
| 3667 HPhase phase("H_Eliminate bounds checks", this); | 3677 HPhase phase("H_Eliminate bounds checks", this); |
| 3668 BoundsCheckTable checks_table(zone()); | 3678 BoundsCheckTable checks_table(zone()); |
| 3669 EliminateRedundantBoundsChecks(entry_block(), &checks_table); | 3679 EliminateRedundantBoundsChecks(entry_block(), &checks_table); |
| 3670 } | 3680 } |
| 3671 | 3681 |
| 3672 | 3682 |
| 3683 // Helper class for array access index manipulation in | |
| 3684 // BoundsCheckValueInfo::CoverCheckWithBase. | |
| 3685 // The indexes have the form "base + constant" and the manipulations involve | |
| 3686 // changing the constant. Since the original constant HValue could be used | |
| 3687 // elsewhere we cannot change it and must create a new one. | |
| 3688 // However we need to create the HAdd only the first time we manipulate an | |
| 3689 // index, and later on we just reuse the instruction. | |
| 3690 class BoundsCheckManipulationData: public ZoneObject { | |
| 3691 public: | |
| 3692 HValue* Base() { return base_; } | |
|
Jakob Kummerow
2012/12/05 15:20:02
nit: lower-case names for simple accessors.
| |
| 3693 HBoundsCheck* Check() { return check_; } | |
|
Jakob Kummerow
2012/12/05 15:20:02
nit: lower-case names for simple accessors.
| |
| 3694 int Offset() { return offset_; } | |
|
Jakob Kummerow
2012/12/05 15:20:02
nit: lower-case names for simple accessors.
| |
| 3695 | |
| 3696 // Change the index to use a new offset. | |
| 3697 void ChangeOffset(int new_offset) { | |
| 3698 HConstant* new_constant = new(zone()) | |
|
Jakob Kummerow
2012/12/05 15:20:02
nit: please break the line after '=', and indent t
| |
| 3699 HConstant(new_offset, Representation::Integer32()); | |
| 3700 if (added_add_ == NULL) { | |
| 3701 new_constant->InsertBefore(Check()); | |
| 3702 added_add_ = new(zone()) HAdd(NULL, Base(), new_constant); | |
| 3703 added_add_->AssumeRepresentation(Check()->index()->representation()); | |
| 3704 added_add_->InsertBefore(Check()); | |
| 3705 } else { | |
| 3706 new_constant->InsertBefore(added_add_); | |
| 3707 added_offset_->DeleteAndReplaceWith(new_constant); | |
| 3708 } | |
| 3709 added_offset_ = new_constant; | |
| 3710 Check()->SetOperandAt(0, added_add_); | |
|
Jakob Kummerow
2012/12/05 15:20:02
I'd prefer introducing a method HBoundsCheck::SetI
| |
| 3711 offset_ = new_offset; | |
| 3712 } | |
| 3713 | |
| 3714 // If we ended up creating an "add zero" instruction we can remove it. | |
| 3715 void RemoveNullAdd() { | |
|
Jakob Kummerow
2012/12/05 15:20:02
Why do we have to do this as an additional step? C
| |
| 3716 if (added_add_ != NULL && added_offset_->Integer32Value() == 0) { | |
| 3717 added_add_->DeleteAndReplaceWith(added_add_->left()); | |
| 3718 added_offset_->DeleteAndReplaceWith(NULL); | |
| 3719 added_add_ = NULL; | |
| 3720 added_offset_ = NULL; | |
| 3721 } | |
| 3722 } | |
| 3723 | |
| 3724 BoundsCheckManipulationData(HValue* base, HBoundsCheck* check, int offset) : | |
|
Jakob Kummerow
2012/12/05 15:20:02
nit: ':' goes on the next line, with 4-space inden
| |
| 3725 base_(base), check_(check), offset_(offset), | |
| 3726 added_add_(NULL), added_offset_(NULL) {} | |
| 3727 | |
| 3728 private: | |
| 3729 HValue* base_; | |
| 3730 HBoundsCheck* check_; | |
| 3731 int offset_; | |
| 3732 HAdd* added_add_; | |
| 3733 HConstant* added_offset_; | |
| 3734 | |
| 3735 Zone* zone() { return Check()->block()->zone(); } | |
|
Jakob Kummerow
2012/12/05 15:20:02
nit: methods before data members
| |
| 3736 }; | |
| 3737 | |
| 3738 | |
| 3739 class BoundsCheckValueInfo; | |
| 3740 | |
| 3741 | |
| 3742 static bool BoundsCheckValueInfoMatch(void* v1, void* v2); | |
| 3743 | |
| 3744 | |
| 3745 // The "knowledge base" used for array bounds check elimination. | |
| 3746 // A hash table indexed by HValue ID and containing a list of known facts for | |
| 3747 // the given value. | |
| 3748 class BoundsCheckValueInfoTable : public ZoneObject { | |
| 3749 public: | |
| 3750 Zone* zone() { return zone_; } | |
| 3751 | |
| 3752 // If the entry is in the table but the list is empty, remove it. | |
| 3753 void CleanupKey(HValue* key); | |
| 3754 | |
| 3755 BoundsCheckValueInfo** LookupKey(HValue* key); | |
| 3756 BoundsCheckValueInfo** LookupOrInsert(HValue* key); | |
| 3757 BoundsCheckValueInfo** Insert(BoundsCheckValueInfo* data); | |
| 3758 void Delete(HValue* key); | |
| 3759 | |
| 3760 explicit BoundsCheckValueInfoTable(Zone* zone) | |
|
Jakob Kummerow
2012/12/05 15:20:02
nit: the constructor should be the first thing in
| |
| 3761 : zone_(zone), | |
| 3762 map_(BoundsCheckValueInfoMatch, | |
| 3763 ZoneHashMap::kDefaultHashMapCapacity, | |
| 3764 ZoneAllocationPolicy(zone)){ } | |
|
Jakob Kummerow
2012/12/05 15:20:02
nit: space before '{'
| |
| 3765 private: | |
|
Jakob Kummerow
2012/12/05 15:20:02
nit: empty line before "private:" (doesn't presubm
| |
| 3766 Zone* zone_; | |
| 3767 ZoneHashMap map_; | |
| 3768 }; | |
| 3769 | |
| 3770 | |
| 3771 enum ValueInfoRelation { | |
| 3772 NONE, | |
| 3773 NE, | |
|
Jakob Kummerow
2012/12/05 15:20:02
Feel free to put all values onto the same line (I
| |
| 3774 GT, | |
| 3775 GE, | |
| 3776 EQ, | |
| 3777 LE, | |
| 3778 LT | |
| 3779 }; | |
| 3780 | |
| 3781 | |
| 3782 class BoundsCheckRemovalBlockContext BASE_EMBEDDED { | |
| 3783 public: | |
| 3784 HBasicBlock* block() { return block_; } | |
| 3785 BoundsCheckValueInfoTable* table() { return table_; } | |
| 3786 BoundsCheckValueInfo* data_list_head() { return bb_data_list_; } | |
| 3787 BoundsCheckValueInfo** data_insertion_point() { return &bb_data_list_; } | |
| 3788 BoundsCheckRemovalBlockContext* previous() { return previous_; } | |
| 3789 | |
| 3790 BoundsCheckValueInfo* NewValueInfo(HValue* v, | |
| 3791 HValue* c, | |
| 3792 ValueInfoRelation r, | |
| 3793 bool is_incremental, | |
| 3794 HBoundsCheck* bounds_check = NULL, | |
| 3795 int check_offset = 0); | |
| 3796 | |
| 3797 BoundsCheckRemovalBlockContext( | |
|
Jakob Kummerow
2012/12/05 15:20:02
again, constructor comes first
| |
| 3798 HBasicBlock* block, | |
| 3799 BoundsCheckRemovalBlockContext* previous) | |
| 3800 : table_(previous != NULL ? previous->table() : | |
|
Jakob Kummerow
2012/12/05 15:20:02
proper indentation please:
: table_(previous
| |
| 3801 new(block->graph()->zone()) | |
| 3802 BoundsCheckValueInfoTable(block->graph()->zone())), | |
| 3803 block_(block), bb_data_list_(NULL), previous_(previous) {} | |
| 3804 | |
| 3805 private: | |
| 3806 BoundsCheckValueInfoTable* table_; | |
| 3807 HBasicBlock* block_; | |
| 3808 BoundsCheckValueInfo* bb_data_list_; | |
| 3809 BoundsCheckRemovalBlockContext* previous_; | |
| 3810 }; | |
| 3811 | |
| 3812 | |
| 3813 // The individual "fact" in the knowledge base. | |
| 3814 // Each fact has the form "value relation constraint", where value and | |
|
Jakob Kummerow
2012/12/05 15:20:02
suggestion:
// Each fact has the form (value, rela
| |
| 3815 // constraint are both HValue instances and "relation" can be one of the | |
| 3816 // usual relational operators (less than, greater than, ecc). | |
| 3817 class BoundsCheckValueInfo: public ZoneObject { | |
| 3818 public: | |
| 3819 HValue* Value() { return value_; } | |
|
Jakob Kummerow
2012/12/05 15:20:02
nit: lower-case names for simple accessors.
| |
| 3820 ValueInfoRelation Relation() { return relation_; } | |
|
Jakob Kummerow
2012/12/05 15:20:02
nit: lower-case names for simple accessors.
| |
| 3821 HValue* Constraint() { return constraint_; } | |
|
Jakob Kummerow
2012/12/05 15:20:02
nit: lower-case names for simple accessors.
| |
| 3822 // True if Value() will "cover" every single integer value in the range | |
|
Jakob Kummerow
2012/12/05 15:20:02
s/"cover"/take/
| |
| 3823 // defined by the relation. | |
| 3824 // This could be used to detect in advance that an array is not holey | |
| 3825 // because a loop will write every single array element. | |
| 3826 bool IsIncremental() { return is_incremental_; } | |
|
Jakob Kummerow
2012/12/05 15:20:02
nit: lower-case names for simple accessors.
| |
| 3827 | |
| 3828 bool ConstraintIsZero() { | |
| 3829 if (!constraint_->IsConstant()) { return false; } | |
| 3830 HConstant* c = HConstant::cast(constraint_); | |
| 3831 return c->DoubleValue() == 0.0; | |
|
Jakob Kummerow
2012/12/05 15:20:02
This won't work for non-number constants. Use "ret
| |
| 3832 } | |
| 3833 Zone* zone() { return Value()->block()->zone(); } | |
| 3834 | |
| 3835 // A HBoundsCheck on the same index; it is equivalent to having... | |
|
Jakob Kummerow
2012/12/05 15:20:02
...?
| |
| 3836 HBoundsCheck* BoundsCheck() { return bounds_check_; } | |
|
Jakob Kummerow
2012/12/05 15:20:02
nit: lower-case names for simple accessors.
| |
| 3837 | |
| 3838 // The following properties are all helpers for CoverCheckWithBase. | |
|
Jakob Kummerow
2012/12/05 15:20:02
If they're helpers for another member, why are the
| |
| 3839 // To make things easier at construction time every list head will just copy | |
| 3840 // the values from the next element (which is the previous one in the | |
| 3841 // dominator tree traversal). | |
| 3842 // This simplifies both searching (the list head always holds current values) | |
| 3843 // and backtracking (the remaining list head has naturally the right values). | |
| 3844 | |
| 3845 // Offset used by CoverCheckWithBase. | |
| 3846 int CheckOffset() { return check_offset_; } | |
|
Jakob Kummerow
2012/12/05 15:20:02
nit: lower-case names for simple accessors.
| |
| 3847 // Lower check used by CoverCheckWithBase. | |
| 3848 BoundsCheckManipulationData* LowerCheck() { return lower_check_; } | |
|
Jakob Kummerow
2012/12/05 15:20:02
nit: lower-case names for simple accessors.
| |
| 3849 // Upper check used by CoverCheckWithBase. | |
| 3850 BoundsCheckManipulationData* UpperCheck() { return upper_check_; } | |
|
Jakob Kummerow
2012/12/05 15:20:02
nit: lower-case names for simple accessors.
| |
| 3851 // Initial state for CoverCheckWithBase (both checks should be NULL). | |
| 3852 bool HasNoBaseHandledCheck() { return lower_check_ == NULL; } | |
|
Jakob Kummerow
2012/12/05 15:20:02
What's a BaseHandledCheck? Why not just "HasNoChec
| |
| 3853 // "single check" state for CoverCheckWithBase. | |
| 3854 bool HasSingleBaseHandledCheck() { | |
| 3855 return lower_check_ != NULL && lower_check_ == upper_check_; | |
| 3856 } | |
| 3857 // End of CoverCheckWithBase helpers. | |
| 3858 | |
| 3859 // Basic block in which this fact was created. | |
| 3860 HBasicBlock* BasicBlock() const { return basic_block_; } | |
|
Jakob Kummerow
2012/12/05 15:20:02
nit: lower-case names for simple accessors.
| |
| 3861 // Next known fact for this value. | |
| 3862 BoundsCheckValueInfo* NextForValue() { return next_for_value_; } | |
|
Jakob Kummerow
2012/12/05 15:20:02
nit: lower-case names for simple accessors.
| |
| 3863 // Next fact created in this basic block. | |
| 3864 BoundsCheckValueInfo* NextInBasicBlock() { return next_in_basic_block_; } | |
|
Jakob Kummerow
2012/12/05 15:20:02
nit: lower-case names for simple accessors.
| |
| 3865 | |
| 3866 | |
| 3867 // This method handles the special case of indexes like "base + constant". | |
| 3868 // For any given HValue "exp", two bounds checks "exp + c1" and exp + c2" | |
| 3869 // will obviously "cover" every other array access where the index value is | |
| 3870 // between "exp + c1" and exp + c2". | |
| 3871 // Now, suppose that we meet an index "exp + c3" which is out of this range. | |
| 3872 // If we are in the same basic block we can easily change either c1 or c2 | |
| 3873 // in one of the two previous checks so that the 3rd check is redundant. | |
| 3874 // (if we are not in the same BB the change would be optimistic and could | |
| 3875 // lead to "unneeded" deoptimizations so we don't do it). | |
| 3876 // This method does exactly that, handling changes between these states: | |
| 3877 // - No previous check was met (HasNoBaseHandledCheck() == true) | |
| 3878 // - We have one previous check (HasSingleBaseHandledCheck() == true) | |
| 3879 // - We have two previous checks. | |
| 3880 // The class BoundsCheckManipulationData helps keeping track of the changed | |
| 3881 // instructions so that it is easy to change than again if needed. | |
|
Jakob Kummerow
2012/12/05 15:20:02
s/than/them/
| |
| 3882 bool CoverCheckWithBase( | |
|
Jakob Kummerow
2012/12/05 15:20:02
nit: for method declarations (as opposed to calls)
| |
| 3883 HValue* base, HBoundsCheck* new_check, int32_t new_offset) { | |
| 3884 ASSERT(new_check->index()->representation().IsInteger32()); | |
| 3885 bool remove_new_check = false; | |
|
Jakob Kummerow
2012/12/05 15:20:02
Why do we need a variable for this? Looks like ass
| |
| 3886 | |
| 3887 if (HasNoBaseHandledCheck()) { | |
| 3888 lower_check_ = new(zone()) | |
| 3889 BoundsCheckManipulationData(base, new_check, new_offset); | |
| 3890 upper_check_ = lower_check_; | |
| 3891 } else { | |
| 3892 if (new_offset > UpperCheck()->Offset()) { | |
| 3893 if (HasSingleBaseHandledCheck() || | |
| 3894 upper_check_->Check()->block() != BasicBlock()) { | |
|
Jakob Kummerow
2012/12/05 15:20:02
Why is this check necessary? BoundsCheckValueInfo
| |
| 3895 upper_check_ = new(zone()) | |
| 3896 BoundsCheckManipulationData(base, new_check, new_offset); | |
| 3897 } else { | |
| 3898 upper_check_->ChangeOffset(new_offset); | |
| 3899 remove_new_check = true; | |
| 3900 } | |
| 3901 } else if (new_offset < LowerCheck()->Offset()) { | |
| 3902 if (HasSingleBaseHandledCheck() || | |
| 3903 lower_check_->Check()->block() != BasicBlock()) { | |
| 3904 lower_check_ = new(zone()) | |
| 3905 BoundsCheckManipulationData(base, new_check, new_offset); | |
| 3906 } else { | |
| 3907 lower_check_->ChangeOffset(new_offset); | |
| 3908 remove_new_check = true; | |
| 3909 } | |
| 3910 } else { | |
| 3911 remove_new_check = true; | |
| 3912 } | |
| 3913 } | |
| 3914 | |
| 3915 return remove_new_check; | |
| 3916 } | |
| 3917 | |
| 3918 void RemoveNullAdds() { | |
| 3919 if (lower_check_ == NULL) return; | |
| 3920 lower_check_->RemoveNullAdd(); | |
| 3921 if (upper_check_ == lower_check_) return; | |
| 3922 upper_check_->RemoveNullAdd(); | |
| 3923 } | |
| 3924 | |
| 3925 uint32_t Hash() { | |
| 3926 return static_cast<uint32_t>(value_->Hashcode()); | |
| 3927 } | |
| 3928 | |
| 3929 // Instead of doing a graph walk we attempt to simplify the index. | |
| 3930 // Since simplifications can be recursive we put a limit on the number | |
| 3931 // of steps we take. | |
| 3932 // This is roughly equivalent to limiting the graph walks to only a | |
| 3933 // given number of steps (but is way easier to implement...). | |
| 3934 static const int kDepthLimit = 3; | |
| 3935 | |
| 3936 // The main method that queries the knowledge base to see if a given value | |
| 3937 // has a relation with a given limit ("value" is the array index and | |
| 3938 // "limit" is the array length). | |
| 3939 // If, as a result, both *lower_covered and *upper_covered are true then the | |
| 3940 // bounds check can be eliminated: the lower part stands for "value >= 0" | |
| 3941 // and the upper part for "value < limit". | |
| 3942 // Either of them is NULL it means that the caller is not interested in that | |
| 3943 // part of the relation. | |
| 3944 // Depth limits the complexity of the attempted value decompositions. | |
| 3945 static void ComputeIndexRelation(HValue* value, | |
| 3946 HValue* limit, | |
| 3947 HBasicBlock* block, | |
| 3948 HValue** hoisted_limit, | |
| 3949 bool* lower_covered, | |
| 3950 bool* upper_covered, | |
| 3951 BoundsCheckValueInfoTable* table, | |
| 3952 int depth) { | |
| 3953 BoundsCheckValueInfo** value_head; | |
| 3954 if (lower_covered == NULL && upper_covered == NULL) return; | |
| 3955 if (depth == 0) { | |
| 3956 value_head = table->LookupOrInsert(value); | |
| 3957 } else if (depth > kDepthLimit) { | |
| 3958 return; | |
| 3959 } else { | |
| 3960 value_head = table->LookupKey(value); | |
| 3961 if (value_head == NULL) { | |
| 3962 return; | |
| 3963 } | |
| 3964 } | |
| 3965 | |
| 3966 for (BoundsCheckValueInfo* value_info = *value_head; | |
| 3967 value_info != NULL; | |
|
Jakob Kummerow
2012/12/05 15:20:02
nit: aligning "value_info" with "BoundsCheckValueI
| |
| 3968 value_info = value_info->NextForValue()) { | |
| 3969 if (lower_covered != NULL) { | |
| 3970 if (value_info->ConstraintIsZero() && value_info->Relation() == GE) { | |
| 3971 *lower_covered = true; | |
| 3972 } | |
| 3973 } | |
| 3974 if (upper_covered != NULL) { | |
|
Jakob Kummerow
2012/12/05 15:20:02
Ugh. 5 levels of nested "if"s? I'd prefer the foll
| |
| 3975 if (value_info->Relation() == LT) { | |
| 3976 if (value_info->Constraint() == limit) { | |
| 3977 *upper_covered = true; | |
| 3978 } else if (hoisted_limit != NULL) { | |
| 3979 HValue* constraint = value_info->Constraint(); | |
| 3980 if (constraint->block()->Dominates( | |
| 3981 block->loop_information()->loop_header())) { | |
| 3982 if (*hoisted_limit == NULL || | |
| 3983 constraint->block()->Dominates((*hoisted_limit)->block())) { | |
| 3984 *hoisted_limit = constraint; | |
| 3985 } | |
| 3986 } | |
| 3987 } | |
| 3988 } | |
| 3989 } | |
| 3990 } | |
| 3991 | |
| 3992 if (!((lower_covered == NULL || *lower_covered) && | |
| 3993 (upper_covered == NULL || *upper_covered))) { | |
|
Jakob Kummerow
2012/12/05 15:20:02
Please indent this so that the indentation reflect
| |
| 3994 bool skip_lower = false; | |
| 3995 bool skip_upper = false; | |
| 3996 int32_t constant; | |
| 3997 HValue* simplified_value = SimplifyValue( | |
| 3998 value, &skip_lower, &skip_upper, &constant); | |
| 3999 if (simplified_value != NULL) { | |
| 4000 ComputeIndexRelation(simplified_value, limit, block, hoisted_limit, | |
| 4001 skip_lower ? NULL : lower_covered, | |
| 4002 skip_upper ? NULL : upper_covered, | |
| 4003 table, depth + 1); | |
| 4004 } | |
| 4005 } | |
| 4006 | |
| 4007 if (!((lower_covered == NULL || *lower_covered) && | |
|
Jakob Kummerow
2012/12/05 15:20:02
same here
| |
| 4008 (upper_covered == NULL || *upper_covered))) { | |
| 4009 if (value->IsPhi()) { | |
| 4010 HPhi* phi = HPhi::cast(value); | |
| 4011 bool lower_skip_state = false; | |
| 4012 bool upper_skip_state = false; | |
| 4013 for (int i = 0; | |
| 4014 i < phi->OperandCount() && !(lower_skip_state && upper_skip_state); | |
| 4015 i++) { | |
| 4016 bool lower_skip_argument = false; | |
| 4017 bool upper_skip_argument = false; | |
| 4018 ComputeIndexRelation(phi->OperandAt(i), limit, block, hoisted_limit, | |
| 4019 &lower_skip_argument, | |
| 4020 &upper_skip_argument, | |
| 4021 table, depth + 1); | |
| 4022 if (lower_skip_argument) { | |
| 4023 lower_skip_state = true; | |
| 4024 } | |
| 4025 if (upper_skip_argument) { | |
| 4026 upper_skip_state = true; | |
| 4027 } | |
| 4028 } | |
| 4029 | |
| 4030 if (lower_covered != NULL && !lower_skip_state) *lower_covered = true; | |
| 4031 if (upper_covered != NULL && !upper_skip_state) *upper_covered = true; | |
| 4032 } | |
| 4033 } | |
| 4034 } | |
| 4035 | |
| 4036 static bool CoverBasePlusConstant(HBoundsCheck* check, | |
|
Jakob Kummerow
2012/12/05 15:20:02
Another method that doesn't tell me what the metho
| |
| 4037 BoundsCheckRemovalBlockContext* context) { | |
| 4038 HValue* index_base; | |
| 4039 int32_t offset; | |
| 4040 if (GetCheckIndexBase(check->index(), &index_base, &offset)) { | |
| 4041 BoundsCheckValueInfo** base_head = | |
| 4042 context->table()->LookupOrInsert(index_base); | |
| 4043 BoundsCheckValueInfo* base_info = *base_head; | |
| 4044 if (base_info == NULL) { | |
| 4045 base_info = context->NewValueInfo( | |
| 4046 index_base, check->length(), NONE, false, check, offset); | |
| 4047 } | |
| 4048 return base_info->CoverCheckWithBase(index_base, check, offset); | |
| 4049 } else { | |
|
Jakob Kummerow
2012/12/05 15:20:02
nit: no need for "else", just "return false".
| |
| 4050 return false; | |
| 4051 } | |
| 4052 } | |
| 4053 | |
| 4054 static void HandleCheck(HBoundsCheck* check, | |
| 4055 BoundsCheckRemovalBlockContext* context) { | |
| 4056 HValue* index = check->index(); | |
| 4057 HValue* length = check->length(); | |
| 4058 bool lower_covered = false; | |
| 4059 bool upper_covered = false; | |
| 4060 HBasicBlock* block = context->block(); | |
| 4061 HValue* hoisted_limit = NULL; | |
| 4062 HValue** hoisted_limit_pointer; | |
|
Jakob Kummerow
2012/12/05 15:20:02
initialize this to NULL here...
| |
| 4063 | |
| 4064 if (block->graph()->use_optimistic_licm() && | |
| 4065 block->loop_information() != NULL && | |
| 4066 length->block()->Dominates(block->loop_information()->loop_header())) { | |
| 4067 hoisted_limit_pointer = &hoisted_limit; | |
| 4068 } else { | |
| 4069 hoisted_limit_pointer = NULL; | |
|
Jakob Kummerow
2012/12/05 15:20:02
...and drop this.
| |
| 4070 } | |
| 4071 | |
| 4072 ComputeIndexRelation( | |
| 4073 index, length, block, hoisted_limit_pointer, | |
|
Jakob Kummerow
2012/12/05 15:20:02
nit: no need to break the first line of arguments
| |
| 4074 &lower_covered, &upper_covered, context->table(), 0); | |
| 4075 | |
| 4076 if (!(lower_covered && upper_covered)) { | |
| 4077 if (CoverBasePlusConstant(check, context)) { | |
| 4078 lower_covered = true; | |
| 4079 upper_covered = true; | |
| 4080 } | |
| 4081 } | |
| 4082 | |
| 4083 if ((!(lower_covered && upper_covered)) && hoisted_limit != NULL) { | |
|
Jakob Kummerow
2012/12/05 15:20:02
simplification: you can remove one set of parenthe
| |
| 4084 HBasicBlock* hoisting_block = | |
| 4085 block->loop_information()->loop_pre_header(); | |
| 4086 BoundsCheckRemovalBlockContext* hoisting_context = context; | |
| 4087 while (hoisting_context != NULL && | |
| 4088 hoisting_context->block() != hoisting_block) { | |
|
Jakob Kummerow
2012/12/05 15:20:02
nit: prefer alignment at '(' (i.e. in this case th
| |
| 4089 hoisting_context = hoisting_context->previous(); | |
| 4090 } | |
| 4091 | |
| 4092 if (hoisting_context != NULL) { | |
| 4093 HBoundsCheck* new_check = | |
| 4094 new(context->table()->zone()) HBoundsCheck(hoisted_limit, length); | |
| 4095 new_check->InsertBefore(hoisting_block->last()); | |
| 4096 context->NewValueInfo( | |
| 4097 index, block->graph()->GetConstant0(), GE, false); | |
| 4098 context->NewValueInfo(index, length, LT, false); | |
| 4099 lower_covered = true; | |
| 4100 upper_covered = true; | |
| 4101 } | |
| 4102 } | |
| 4103 | |
| 4104 bool remove_check = true; | |
| 4105 if (!lower_covered) { | |
| 4106 remove_check = false; | |
| 4107 context->NewValueInfo(index, block->graph()->GetConstant0(), GE, false); | |
| 4108 } | |
| 4109 if (!upper_covered) { | |
| 4110 remove_check = false; | |
| 4111 context->NewValueInfo(index, length, LT, false); | |
| 4112 } | |
| 4113 if (remove_check) { | |
| 4114 check->DeleteAndReplaceWith(NULL); | |
| 4115 } | |
| 4116 } | |
| 4117 | |
| 4118 // Handles a HPhi definition, eventually creating a new fact. | |
| 4119 static void FromPhi(HPhi* phi, | |
|
Jakob Kummerow
2012/12/05 15:20:02
nit: some other name please. We commonly use "stat
| |
| 4120 BoundsCheckRemovalBlockContext* context) { | |
| 4121 if (phi->OperandCount() != 2) return; | |
| 4122 | |
| 4123 ValueInfoRelation relation; | |
| 4124 bool is_incremental; | |
| 4125 | |
| 4126 relation = RelationFromMonotonicOperation( | |
| 4127 phi, phi->OperandAt(0), &is_incremental); | |
| 4128 if (relation != NONE) { | |
| 4129 context->NewValueInfo(phi, phi->OperandAt(1), relation, is_incremental); | |
| 4130 return; | |
| 4131 } | |
| 4132 | |
| 4133 relation = RelationFromMonotonicOperation( | |
| 4134 phi, phi->OperandAt(1), &is_incremental); | |
| 4135 if (relation != NONE) { | |
| 4136 context->NewValueInfo(phi, phi->OperandAt(0), relation, is_incremental); | |
| 4137 return; | |
| 4138 } | |
| 4139 } | |
| 4140 | |
| 4141 // Handles a conditional branch, eventually creating new facts. | |
| 4142 static void FromConditionalBranch( | |
|
Jakob Kummerow
2012/12/05 15:20:02
Again, please choose some name that doesn't sound
| |
| 4143 HCompareIDAndBranch* condition, | |
| 4144 BoundsCheckRemovalBlockContext* context) { | |
| 4145 HValue* value; | |
| 4146 HValue* constraint; | |
| 4147 ValueInfoRelation relation; | |
| 4148 bool isElseBranch; | |
|
Jakob Kummerow
2012/12/05 15:20:02
nit: unix_hacker_style names for variables
| |
| 4149 if (context->block() == condition->SuccessorAt(0)) { | |
| 4150 isElseBranch = false; | |
| 4151 } else if (context->block() == condition->SuccessorAt(1)) { | |
| 4152 isElseBranch = true; | |
| 4153 } else { | |
| 4154 return; | |
| 4155 } | |
| 4156 | |
| 4157 relation = FromToken(condition->token()); | |
| 4158 if (relation == NONE) return; | |
| 4159 | |
| 4160 if (isElseBranch) { | |
| 4161 value = condition->right(); | |
| 4162 constraint = condition->left(); | |
| 4163 } else { | |
| 4164 value = condition->left(); | |
| 4165 constraint = condition->right(); | |
| 4166 } | |
| 4167 | |
| 4168 context->NewValueInfo(value, constraint, relation, false); | |
| 4169 context->NewValueInfo(constraint, value, Switched(relation), false); | |
|
Jakob Kummerow
2012/12/05 15:20:02
Whoa. Do we really need to store every fact twice?
| |
| 4170 } | |
| 4171 | |
| 4172 static const char* RelationName(ValueInfoRelation r) { | |
| 4173 switch (r) { | |
| 4174 case NE: | |
| 4175 return "NE"; | |
| 4176 case GT: | |
| 4177 return "GT"; | |
| 4178 case GE: | |
| 4179 return "GE"; | |
| 4180 case EQ: | |
| 4181 return "EQ"; | |
| 4182 case LE: | |
| 4183 return "LE"; | |
| 4184 case LT: | |
| 4185 return "LT"; | |
| 4186 case NONE: | |
| 4187 return "NONE"; | |
| 4188 default: | |
|
Jakob Kummerow
2012/12/05 15:20:02
since you're handling all cases explicitly, you do
| |
| 4189 UNREACHABLE(); | |
| 4190 return "UNREACHABLE"; | |
| 4191 } | |
| 4192 } | |
| 4193 | |
| 4194 bool UnlinkFromValue() { | |
| 4195 *previous_for_value_ = next_for_value_; | |
|
Jakob Kummerow
2012/12/05 15:20:02
Having different levels of pointer indirection for
| |
| 4196 if (next_for_value_ != NULL) { | |
| 4197 next_for_value_->previous_for_value_ = previous_for_value_; | |
| 4198 } | |
| 4199 bool result = (next_for_value_ == NULL); | |
| 4200 previous_for_value_ = NULL; | |
| 4201 next_for_value_ = NULL; | |
| 4202 RemoveNullAdds(); | |
| 4203 return result; | |
| 4204 } | |
| 4205 | |
| 4206 BoundsCheckValueInfo(HValue* v, | |
|
Jakob Kummerow
2012/12/05 15:20:02
nit: constructor should be the first thing in the
| |
| 4207 HValue* c, | |
|
Jakob Kummerow
2012/12/05 15:20:02
what do "v" and "c" mean?
| |
| 4208 ValueInfoRelation r, | |
| 4209 bool is_incremental, | |
| 4210 BoundsCheckRemovalBlockContext* context, | |
| 4211 HBoundsCheck* bounds_check = NULL, | |
| 4212 int check_offset = 0) : | |
|
Jakob Kummerow
2012/12/05 15:20:02
nit: ':' goes on the next line
| |
| 4213 value_(DiscardOsrValue(v)), constraint_(DiscardOsrValue(c)), | |
| 4214 relation_(r), is_incremental_(is_incremental), | |
| 4215 bounds_check_(bounds_check), | |
| 4216 check_offset_(check_offset), | |
| 4217 basic_block_(context->block()), | |
| 4218 previous_for_value_(context->table()->LookupOrInsert(value_)), | |
| 4219 next_for_value_(*previous_for_value_), | |
| 4220 next_in_basic_block_(*context->data_insertion_point()), | |
| 4221 lower_check_(next_for_value_ != NULL ? | |
|
Jakob Kummerow
2012/12/05 15:20:02
nit: if a ternary operator doesn't fit on one line
| |
| 4222 next_for_value_->LowerCheck() : NULL), | |
| 4223 upper_check_(next_for_value_ != NULL ? | |
| 4224 next_for_value_->UpperCheck() : NULL) { | |
| 4225 if (next_for_value_ != NULL) { | |
| 4226 next_for_value_->previous_for_value_ = &(next_for_value_); | |
| 4227 } | |
| 4228 *previous_for_value_ = this; | |
| 4229 *context->data_insertion_point() = this; | |
| 4230 } | |
| 4231 | |
| 4232 private: | |
| 4233 HValue* value_; | |
|
Jakob Kummerow
2012/12/05 15:20:02
nit: member variables come last in the "private:"
| |
| 4234 HValue* constraint_; | |
| 4235 ValueInfoRelation relation_; | |
| 4236 bool is_incremental_; | |
| 4237 HBoundsCheck* bounds_check_; | |
| 4238 int check_offset_; | |
| 4239 | |
| 4240 HBasicBlock* basic_block_; | |
| 4241 BoundsCheckValueInfo** previous_for_value_; | |
| 4242 BoundsCheckValueInfo* next_for_value_; | |
| 4243 BoundsCheckValueInfo* next_in_basic_block_; | |
| 4244 BoundsCheckManipulationData* lower_check_; | |
| 4245 BoundsCheckManipulationData* upper_check_; | |
| 4246 | |
| 4247 // Detect if a value has the form "base plus constant". | |
| 4248 static bool GetCheckIndexBase(HValue* index, | |
|
Jakob Kummerow
2012/12/05 15:20:02
Another method name that puzzles me, especially in
| |
| 4249 HValue** index_base, | |
| 4250 int32_t* offset) { | |
| 4251 *index_base = NULL; | |
| 4252 *offset = 0; | |
| 4253 if (!index->representation().IsInteger32()) return NULL; | |
| 4254 | |
| 4255 HConstant* constant = NULL; | |
| 4256 bool is_sub = false; | |
| 4257 | |
| 4258 if (index->IsAdd()) { | |
| 4259 HAdd* add = HAdd::cast(index); | |
| 4260 if (add->left()->IsConstant()) { | |
| 4261 constant = HConstant::cast(add->left()); | |
| 4262 *index_base = add->right(); | |
| 4263 } else if (add->right()->IsConstant()) { | |
| 4264 constant = HConstant::cast(add->right()); | |
| 4265 *index_base = add->left(); | |
| 4266 } | |
| 4267 } else if (index->IsSub()) { | |
| 4268 HSub* sub = HSub::cast(index); | |
| 4269 is_sub = true; | |
| 4270 if (sub->left()->IsConstant()) { | |
|
Jakob Kummerow
2012/12/05 15:20:02
This was probably supposed to be sub->right()->IsC
| |
| 4271 constant = HConstant::cast(sub->left()); | |
| 4272 *index_base = sub->right(); | |
| 4273 } | |
| 4274 } | |
| 4275 | |
| 4276 if (constant != NULL && constant->HasInteger32Value()) { | |
| 4277 *offset = is_sub ? - constant->Integer32Value() | |
| 4278 : constant->Integer32Value(); | |
| 4279 return true; | |
| 4280 } | |
| 4281 return false; | |
| 4282 } | |
| 4283 | |
| 4284 // Attempts value simplification or decomposition. | |
| 4285 static HValue* SimplifyValue(HValue* value, | |
| 4286 bool* skip_lower, | |
|
Jakob Kummerow
2012/12/05 15:20:02
nit: indentation
| |
| 4287 bool* skip_upper, | |
| 4288 int32_t* constant) { | |
| 4289 HValue* result = NULL; | |
| 4290 *constant = 0; | |
| 4291 | |
| 4292 if (value->IsAdd()) { | |
| 4293 HAdd* add = HAdd::cast(value); | |
| 4294 HConstant* constant_operand = NULL; | |
| 4295 if (add->left()->IsConstant()) { | |
|
Jakob Kummerow
2012/12/05 15:20:02
This code here is an almost exact duplicate of the
| |
| 4296 result = add->right(); | |
| 4297 constant_operand = HConstant::cast(add->left()); | |
| 4298 } else if (add->right()->IsConstant()) { | |
| 4299 result = add->left(); | |
| 4300 constant_operand = HConstant::cast(add->right()); | |
| 4301 } | |
| 4302 if (constant_operand != NULL && constant_operand->HasInteger32Value()) { | |
| 4303 *constant = constant_operand->Integer32Value(); | |
| 4304 if (*constant > 0) { | |
| 4305 *skip_upper = true; | |
| 4306 } else if (*constant < 0) { | |
| 4307 *skip_lower = true; | |
| 4308 } else { | |
| 4309 result = value; | |
| 4310 } | |
| 4311 } else { | |
| 4312 result = NULL; | |
| 4313 } | |
| 4314 } else if (value->IsSub()) { | |
| 4315 HSub* sub = HSub::cast(value); | |
| 4316 HConstant* constant_operand = NULL; | |
| 4317 if (sub->left()->IsConstant()) { | |
| 4318 result = sub->right(); | |
| 4319 constant_operand = HConstant::cast(sub->left()); | |
| 4320 } else if (sub->right()->IsConstant()) { | |
| 4321 result = sub->left(); | |
| 4322 constant_operand = HConstant::cast(sub->right()); | |
| 4323 } | |
| 4324 if (constant_operand != NULL && constant_operand->HasInteger32Value()) { | |
| 4325 *constant = constant_operand->Integer32Value(); | |
| 4326 if (*constant > 0) { | |
| 4327 *skip_lower = true; | |
| 4328 } else if (*constant > 0) { | |
|
Jakob Kummerow
2012/12/05 15:20:02
This is the same condition as before. You probably
| |
| 4329 *skip_upper = true; | |
| 4330 } else { | |
| 4331 result = value; | |
| 4332 } | |
| 4333 } else { | |
| 4334 result = NULL; | |
| 4335 } | |
| 4336 } | |
| 4337 | |
| 4338 return result; | |
| 4339 } | |
| 4340 | |
| 4341 | |
| 4342 static ValueInfoRelation FromToken(Token::Value token) { | |
|
Jakob Kummerow
2012/12/05 15:20:02
Having such a simple mapping from Token::Value to
| |
| 4343 switch (token) { | |
| 4344 case Token::EQ: | |
| 4345 case Token::EQ_STRICT: | |
| 4346 return EQ; | |
| 4347 case Token::LT: | |
| 4348 return LT; | |
| 4349 case Token::GT: | |
| 4350 return GT; | |
| 4351 case Token::LTE: | |
| 4352 return LE; | |
| 4353 case Token::GTE: | |
| 4354 return GE; | |
| 4355 default: | |
| 4356 return NONE; | |
| 4357 } | |
| 4358 } | |
| 4359 | |
| 4360 // Detects if a HPhi defines a monotonic operation, and if it does | |
| 4361 // returns the appropriate relation. | |
| 4362 // *value_increment is true if the value will assume every integer value | |
| 4363 // in the range. | |
| 4364 static ValueInfoRelation RelationFromMonotonicOperation( | |
| 4365 HPhi* base, HValue* operation, bool* value_increment) { | |
|
Jakob Kummerow
2012/12/05 15:20:02
nit: for method/function declarations, either ever
| |
| 4366 *value_increment = false; | |
| 4367 | |
| 4368 if (operation->opcode() == HValue::kAdd) { | |
| 4369 HAdd* add = HAdd::cast(operation); | |
|
Jakob Kummerow
2012/12/05 15:20:02
nit: indentation
| |
| 4370 HValue* maybe_constant; | |
| 4371 if (add->right() == base) { | |
| 4372 maybe_constant = add->left(); | |
| 4373 } else if (add->left() == base) { | |
| 4374 maybe_constant = add->right(); | |
| 4375 } else { | |
| 4376 return NONE; | |
| 4377 } | |
| 4378 | |
| 4379 if (maybe_constant->IsConstant()) { | |
| 4380 HConstant* c = HConstant::cast(maybe_constant); | |
| 4381 if ((c->DoubleValue() == 1) || (c->DoubleValue() == -1)) | |
|
Jakob Kummerow
2012/12/05 15:20:02
Again:
1) why DoubleValue() and not Integer32Value
| |
| 4382 *value_increment = true; | |
| 4383 if (c->DoubleValue() > 0) { | |
| 4384 return GE; | |
| 4385 } else if (c->DoubleValue() < 0) { | |
| 4386 return LE; | |
| 4387 } else if (c->DoubleValue() == 0) { | |
| 4388 return EQ; | |
| 4389 } else { | |
| 4390 return NONE; | |
| 4391 } | |
| 4392 } | |
| 4393 return NONE; | |
| 4394 } else if (operation->opcode() == HValue::kSub) { | |
| 4395 HSub* sub = HSub::cast(operation); | |
| 4396 if (sub->right() == base && sub->left()->IsConstant()) { | |
|
Jakob Kummerow
2012/12/05 15:20:02
this looks like another left/right mixup.
| |
| 4397 HConstant* c = HConstant::cast(sub->left()); | |
| 4398 if ((c->DoubleValue() == 1) || (c->DoubleValue() == -1)) | |
| 4399 *value_increment = true; | |
| 4400 if (c->DoubleValue() > 0) { | |
| 4401 return LE; | |
| 4402 } else if (c->DoubleValue() < 0) { | |
| 4403 return GE; | |
| 4404 } else if (c->DoubleValue() == 0) { | |
| 4405 return EQ; | |
| 4406 } else { | |
| 4407 return NONE; | |
| 4408 } | |
| 4409 } else { | |
| 4410 return NONE; | |
| 4411 } | |
| 4412 } | |
| 4413 return NONE; | |
| 4414 } | |
| 4415 | |
| 4416 static ValueInfoRelation Switched(ValueInfoRelation other) { | |
|
Jakob Kummerow
2012/12/05 15:20:02
"Switched"? Into shuffle mode?
Also, we already h
| |
| 4417 switch (other) { | |
| 4418 case NE: | |
| 4419 return EQ; | |
| 4420 case GT: | |
| 4421 return LE; | |
| 4422 case GE: | |
| 4423 return LT; | |
| 4424 case EQ: | |
| 4425 return NE; | |
| 4426 case LE: | |
| 4427 return GT; | |
| 4428 case LT: | |
| 4429 return GE; | |
| 4430 default: | |
| 4431 UNREACHABLE(); | |
| 4432 return NONE; | |
| 4433 } | |
| 4434 } | |
| 4435 | |
| 4436 // Helper method to discard a HPhi induced by OSR. | |
| 4437 static HValue* DiscardOsrValue(HValue* v) { | |
| 4438 if (!v->IsPhi()) return v; | |
| 4439 HPhi* phi = HPhi::cast(v); | |
| 4440 if (phi->OperandCount() != 2) return v; | |
| 4441 if (phi->OperandAt(0)->block()->is_osr_entry()) { | |
| 4442 return phi->OperandAt(1); | |
| 4443 } else if (phi->OperandAt(1)->block()->is_osr_entry()) { | |
| 4444 return phi->OperandAt(0); | |
| 4445 } else { | |
| 4446 return v; | |
| 4447 } | |
| 4448 } | |
| 4449 }; | |
| 4450 | |
| 4451 | |
| 4452 BoundsCheckValueInfo* BoundsCheckRemovalBlockContext::NewValueInfo( | |
| 4453 HValue* v, | |
| 4454 HValue* c, | |
|
Jakob Kummerow
2012/12/05 15:20:02
what do "v" and "c" stand for?
| |
| 4455 ValueInfoRelation r, | |
| 4456 bool is_incremental, | |
| 4457 HBoundsCheck* bounds_check, | |
| 4458 int check_offset) { | |
| 4459 return new (table()->zone()) BoundsCheckValueInfo( | |
| 4460 v, c, r, is_incremental, this, bounds_check, check_offset); | |
| 4461 } | |
| 4462 | |
| 4463 | |
| 4464 static bool BoundsCheckValueInfoMatch(void* v1, void* v2) { | |
| 4465 BoundsCheckValueInfo* k1 = static_cast<BoundsCheckValueInfo*>(v1); | |
| 4466 BoundsCheckValueInfo* k2 = static_cast<BoundsCheckValueInfo*>(v2); | |
| 4467 return k1->Value() == k2->Value(); | |
| 4468 } | |
| 4469 | |
| 4470 | |
| 4471 void BoundsCheckValueInfoTable::CleanupKey(HValue* key) { | |
| 4472 ZoneHashMap::Entry* e = map_.Lookup( | |
| 4473 key, static_cast<uint32_t>(key->Hashcode()), false, | |
| 4474 ZoneAllocationPolicy(zone())); | |
| 4475 if (e != NULL && e->value == NULL) { | |
| 4476 map_.Remove(key, key->Hashcode()); | |
| 4477 } | |
| 4478 } | |
| 4479 | |
| 4480 | |
| 4481 BoundsCheckValueInfo** BoundsCheckValueInfoTable::LookupKey(HValue* key) { | |
| 4482 ZoneHashMap::Entry* entry = map_.Lookup( | |
| 4483 key, static_cast<uint32_t>(key->Hashcode()), false, | |
| 4484 ZoneAllocationPolicy(zone())); | |
| 4485 if (entry != NULL) { | |
| 4486 return reinterpret_cast<BoundsCheckValueInfo**>(&(entry->value)); | |
| 4487 } else { | |
| 4488 return NULL; | |
| 4489 } | |
| 4490 } | |
| 4491 | |
| 4492 | |
| 4493 BoundsCheckValueInfo** BoundsCheckValueInfoTable::LookupOrInsert(HValue* key) { | |
| 4494 return reinterpret_cast<BoundsCheckValueInfo**>( | |
| 4495 &(map_.Lookup(key, static_cast<uint32_t>(key->Hashcode()), true, | |
| 4496 ZoneAllocationPolicy(zone()))->value)); | |
|
Jakob Kummerow
2012/12/05 15:20:02
nit: please align with "key"
| |
| 4497 } | |
| 4498 | |
| 4499 | |
| 4500 BoundsCheckValueInfo** BoundsCheckValueInfoTable::Insert( | |
| 4501 BoundsCheckValueInfo* data) { | |
| 4502 BoundsCheckValueInfo** result = LookupOrInsert(data->Value()); | |
| 4503 *result = data; | |
| 4504 return result; | |
| 4505 } | |
| 4506 | |
| 4507 | |
| 4508 void BoundsCheckValueInfoTable::Delete(HValue* key) { | |
| 4509 map_.Remove(key, key->Hashcode()); | |
| 4510 } | |
| 4511 | |
| 4512 | |
| 4513 // Recursive traversal of the dominator tree to remove array bounds checks. | |
| 4514 void HGraph::EliminateOrDehoistBoundsChecks( | |
| 4515 HBasicBlock* bb, | |
| 4516 BoundsCheckRemovalBlockContext* previous_context) { | |
| 4517 BoundsCheckRemovalBlockContext context(bb, previous_context); | |
| 4518 | |
| 4519 // Add facts deduced from conditional branches. | |
| 4520 if (bb->predecessors()->length() == 1) { | |
| 4521 HBasicBlock* predecessor = bb->predecessors()->at(0); | |
| 4522 HInstruction* end = predecessor->last(); | |
| 4523 if (end->IsCompareIDAndBranch()) { | |
| 4524 BoundsCheckValueInfo::FromConditionalBranch( | |
|
Jakob Kummerow
2012/12/05 15:20:02
Looks like "static void Foo::Bar(..., Baz*)" could
| |
| 4525 HCompareIDAndBranch::cast(end), &context); | |
| 4526 } | |
| 4527 } | |
| 4528 | |
| 4529 // Add facts deduced from phi definitions. | |
| 4530 for (int i = 0; i < bb->phis()->length(); i++) { | |
| 4531 BoundsCheckValueInfo::FromPhi(bb->phis()->at(i), &context); | |
|
Jakob Kummerow
2012/12/05 15:20:02
again, why "void A::B(C, &context)" instead of "co
| |
| 4532 } | |
| 4533 | |
| 4534 for (HInstruction* i = bb->first(); i != NULL; i = i->next()) { | |
| 4535 if (!i->IsBoundsCheck()) continue; | |
| 4536 | |
| 4537 HBoundsCheck* check = HBoundsCheck::cast(i); | |
| 4538 check->ReplaceAllUsesWith(check->index()); | |
|
Jakob Kummerow
2012/12/05 15:20:02
Why this line?
| |
| 4539 BoundsCheckValueInfo::HandleCheck(check, &context); | |
|
Jakob Kummerow
2012/12/05 15:20:02
again, why "void A::B(C, &context)" instead of "co
| |
| 4540 } | |
| 4541 | |
| 4542 for (int i = 0; i < bb->dominated_blocks()->length(); ++i) { | |
| 4543 EliminateOrDehoistBoundsChecks( | |
| 4544 bb->dominated_blocks()->at(i), &context); | |
| 4545 } | |
| 4546 | |
| 4547 for (BoundsCheckValueInfo* value_info = context.data_list_head(); | |
| 4548 value_info != NULL; | |
|
Jakob Kummerow
2012/12/05 15:20:02
nit: aligning 'v' with 'B' looks better
| |
| 4549 value_info = value_info->NextInBasicBlock()) { | |
| 4550 if (value_info->UnlinkFromValue()) { | |
| 4551 context.table()->CleanupKey(value_info->Value()); | |
| 4552 } | |
| 4553 } | |
| 4554 } | |
| 4555 | |
| 4556 | |
| 4557 void HGraph::EliminateOrDehoistBoundsChecks() { | |
| 4558 HPhase phase("H_Eliminate or dehoist bounds checks", this); | |
| 4559 EliminateOrDehoistBoundsChecks(entry_block(), NULL); | |
| 4560 } | |
| 4561 | |
| 4562 | |
| 3673 static void DehoistArrayIndex(ArrayInstructionInterface* array_operation) { | 4563 static void DehoistArrayIndex(ArrayInstructionInterface* array_operation) { |
| 3674 HValue* index = array_operation->GetKey(); | 4564 HValue* index = array_operation->GetKey(); |
| 3675 if (!index->representation().IsInteger32()) return; | 4565 if (!index->representation().IsInteger32()) return; |
| 3676 | 4566 |
| 3677 HConstant* constant; | 4567 HConstant* constant; |
| 3678 HValue* subexpression; | 4568 HValue* subexpression; |
| 3679 int32_t sign; | 4569 int32_t sign; |
| 3680 if (index->IsAdd()) { | 4570 if (index->IsAdd()) { |
| 3681 sign = 1; | 4571 sign = 1; |
| 3682 HAdd* add = HAdd::cast(index); | 4572 HAdd* add = HAdd::cast(index); |
| (...skipping 613 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4296 HBasicBlock* non_osr_entry = graph()->CreateBasicBlock(); | 5186 HBasicBlock* non_osr_entry = graph()->CreateBasicBlock(); |
| 4297 HBasicBlock* osr_entry = graph()->CreateBasicBlock(); | 5187 HBasicBlock* osr_entry = graph()->CreateBasicBlock(); |
| 4298 HValue* true_value = graph()->GetConstantTrue(); | 5188 HValue* true_value = graph()->GetConstantTrue(); |
| 4299 HBranch* test = new(zone()) HBranch(true_value, non_osr_entry, osr_entry); | 5189 HBranch* test = new(zone()) HBranch(true_value, non_osr_entry, osr_entry); |
| 4300 current_block()->Finish(test); | 5190 current_block()->Finish(test); |
| 4301 | 5191 |
| 4302 HBasicBlock* loop_predecessor = graph()->CreateBasicBlock(); | 5192 HBasicBlock* loop_predecessor = graph()->CreateBasicBlock(); |
| 4303 non_osr_entry->Goto(loop_predecessor); | 5193 non_osr_entry->Goto(loop_predecessor); |
| 4304 | 5194 |
| 4305 set_current_block(osr_entry); | 5195 set_current_block(osr_entry); |
| 5196 osr_entry->set_osr_entry(); | |
| 4306 BailoutId osr_entry_id = statement->OsrEntryId(); | 5197 BailoutId osr_entry_id = statement->OsrEntryId(); |
| 4307 int first_expression_index = environment()->first_expression_index(); | 5198 int first_expression_index = environment()->first_expression_index(); |
| 4308 int length = environment()->length(); | 5199 int length = environment()->length(); |
| 4309 ZoneList<HUnknownOSRValue*>* osr_values = | 5200 ZoneList<HUnknownOSRValue*>* osr_values = |
| 4310 new(zone()) ZoneList<HUnknownOSRValue*>(length, zone()); | 5201 new(zone()) ZoneList<HUnknownOSRValue*>(length, zone()); |
| 4311 | 5202 |
| 4312 for (int i = 0; i < first_expression_index; ++i) { | 5203 for (int i = 0; i < first_expression_index; ++i) { |
| 4313 HUnknownOSRValue* osr_value = new(zone()) HUnknownOSRValue; | 5204 HUnknownOSRValue* osr_value = new(zone()) HUnknownOSRValue; |
| 4314 AddInstruction(osr_value); | 5205 AddInstruction(osr_value); |
| 4315 environment()->Bind(i, osr_value); | 5206 environment()->Bind(i, osr_value); |
| (...skipping 5743 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 10059 } | 10950 } |
| 10060 } | 10951 } |
| 10061 | 10952 |
| 10062 #ifdef DEBUG | 10953 #ifdef DEBUG |
| 10063 if (graph_ != NULL) graph_->Verify(false); // No full verify. | 10954 if (graph_ != NULL) graph_->Verify(false); // No full verify. |
| 10064 if (allocator_ != NULL) allocator_->Verify(); | 10955 if (allocator_ != NULL) allocator_->Verify(); |
| 10065 #endif | 10956 #endif |
| 10066 } | 10957 } |
| 10067 | 10958 |
| 10068 } } // namespace v8::internal | 10959 } } // namespace v8::internal |
| OLD | NEW |