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 |
11 // with the distribution. | 11 // with the distribution. |
12 // * Neither the name of Google Inc. nor the names of its | 12 // * Neither the name of Google Inc. nor the names of its |
13 // contributors may be used to endorse or promote products derived | 13 // contributors may be used to endorse or promote products derived |
14 // from this software without specific prior written permission. | 14 // from this software without specific prior written permission. |
15 // | 15 // |
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | 27 |
28 #include "hydrogen.h" | 28 #include "hydrogen.h" |
| 29 #include "hydrogen-gvn.h" |
29 | 30 |
30 #include <algorithm> | 31 #include <algorithm> |
31 | 32 |
32 #include "v8.h" | 33 #include "v8.h" |
33 #include "codegen.h" | 34 #include "codegen.h" |
34 #include "full-codegen.h" | 35 #include "full-codegen.h" |
35 #include "hashmap.h" | 36 #include "hashmap.h" |
36 #include "lithium-allocator.h" | 37 #include "lithium-allocator.h" |
37 #include "parser.h" | 38 #include "parser.h" |
38 #include "scopeinfo.h" | 39 #include "scopeinfo.h" |
(...skipping 2711 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2750 TraceRange("Original range was [%d,%d]\n", | 2751 TraceRange("Original range was [%d,%d]\n", |
2751 original_range->lower(), | 2752 original_range->lower(), |
2752 original_range->upper()); | 2753 original_range->upper()); |
2753 } | 2754 } |
2754 TraceRange("New information was [%d,%d]\n", | 2755 TraceRange("New information was [%d,%d]\n", |
2755 range->lower(), | 2756 range->lower(), |
2756 range->upper()); | 2757 range->upper()); |
2757 } | 2758 } |
2758 | 2759 |
2759 | 2760 |
2760 void TraceGVN(const char* msg, ...) { | |
2761 va_list arguments; | |
2762 va_start(arguments, msg); | |
2763 OS::VPrint(msg, arguments); | |
2764 va_end(arguments); | |
2765 } | |
2766 | |
2767 // Wrap TraceGVN in macros to avoid the expense of evaluating its arguments when | |
2768 // --trace-gvn is off. | |
2769 #define TRACE_GVN_1(msg, a1) \ | |
2770 if (FLAG_trace_gvn) { \ | |
2771 TraceGVN(msg, a1); \ | |
2772 } | |
2773 | |
2774 #define TRACE_GVN_2(msg, a1, a2) \ | |
2775 if (FLAG_trace_gvn) { \ | |
2776 TraceGVN(msg, a1, a2); \ | |
2777 } | |
2778 | |
2779 #define TRACE_GVN_3(msg, a1, a2, a3) \ | |
2780 if (FLAG_trace_gvn) { \ | |
2781 TraceGVN(msg, a1, a2, a3); \ | |
2782 } | |
2783 | |
2784 #define TRACE_GVN_4(msg, a1, a2, a3, a4) \ | |
2785 if (FLAG_trace_gvn) { \ | |
2786 TraceGVN(msg, a1, a2, a3, a4); \ | |
2787 } | |
2788 | |
2789 #define TRACE_GVN_5(msg, a1, a2, a3, a4, a5) \ | |
2790 if (FLAG_trace_gvn) { \ | |
2791 TraceGVN(msg, a1, a2, a3, a4, a5); \ | |
2792 } | |
2793 | |
2794 | |
2795 HValueMap::HValueMap(Zone* zone, const HValueMap* other) | |
2796 : array_size_(other->array_size_), | |
2797 lists_size_(other->lists_size_), | |
2798 count_(other->count_), | |
2799 present_flags_(other->present_flags_), | |
2800 array_(zone->NewArray<HValueMapListElement>(other->array_size_)), | |
2801 lists_(zone->NewArray<HValueMapListElement>(other->lists_size_)), | |
2802 free_list_head_(other->free_list_head_) { | |
2803 OS::MemCopy( | |
2804 array_, other->array_, array_size_ * sizeof(HValueMapListElement)); | |
2805 OS::MemCopy( | |
2806 lists_, other->lists_, lists_size_ * sizeof(HValueMapListElement)); | |
2807 } | |
2808 | |
2809 | |
2810 void HValueMap::Kill(GVNFlagSet flags) { | |
2811 GVNFlagSet depends_flags = HValue::ConvertChangesToDependsFlags(flags); | |
2812 if (!present_flags_.ContainsAnyOf(depends_flags)) return; | |
2813 present_flags_.RemoveAll(); | |
2814 for (int i = 0; i < array_size_; ++i) { | |
2815 HValue* value = array_[i].value; | |
2816 if (value != NULL) { | |
2817 // Clear list of collisions first, so we know if it becomes empty. | |
2818 int kept = kNil; // List of kept elements. | |
2819 int next; | |
2820 for (int current = array_[i].next; current != kNil; current = next) { | |
2821 next = lists_[current].next; | |
2822 HValue* value = lists_[current].value; | |
2823 if (value->gvn_flags().ContainsAnyOf(depends_flags)) { | |
2824 // Drop it. | |
2825 count_--; | |
2826 lists_[current].next = free_list_head_; | |
2827 free_list_head_ = current; | |
2828 } else { | |
2829 // Keep it. | |
2830 lists_[current].next = kept; | |
2831 kept = current; | |
2832 present_flags_.Add(value->gvn_flags()); | |
2833 } | |
2834 } | |
2835 array_[i].next = kept; | |
2836 | |
2837 // Now possibly drop directly indexed element. | |
2838 value = array_[i].value; | |
2839 if (value->gvn_flags().ContainsAnyOf(depends_flags)) { // Drop it. | |
2840 count_--; | |
2841 int head = array_[i].next; | |
2842 if (head == kNil) { | |
2843 array_[i].value = NULL; | |
2844 } else { | |
2845 array_[i].value = lists_[head].value; | |
2846 array_[i].next = lists_[head].next; | |
2847 lists_[head].next = free_list_head_; | |
2848 free_list_head_ = head; | |
2849 } | |
2850 } else { | |
2851 present_flags_.Add(value->gvn_flags()); // Keep it. | |
2852 } | |
2853 } | |
2854 } | |
2855 } | |
2856 | |
2857 | |
2858 HValue* HValueMap::Lookup(HValue* value) const { | |
2859 uint32_t hash = static_cast<uint32_t>(value->Hashcode()); | |
2860 uint32_t pos = Bound(hash); | |
2861 if (array_[pos].value != NULL) { | |
2862 if (array_[pos].value->Equals(value)) return array_[pos].value; | |
2863 int next = array_[pos].next; | |
2864 while (next != kNil) { | |
2865 if (lists_[next].value->Equals(value)) return lists_[next].value; | |
2866 next = lists_[next].next; | |
2867 } | |
2868 } | |
2869 return NULL; | |
2870 } | |
2871 | |
2872 | |
2873 void HValueMap::Resize(int new_size, Zone* zone) { | |
2874 ASSERT(new_size > count_); | |
2875 // Hashing the values into the new array has no more collisions than in the | |
2876 // old hash map, so we can use the existing lists_ array, if we are careful. | |
2877 | |
2878 // Make sure we have at least one free element. | |
2879 if (free_list_head_ == kNil) { | |
2880 ResizeLists(lists_size_ << 1, zone); | |
2881 } | |
2882 | |
2883 HValueMapListElement* new_array = | |
2884 zone->NewArray<HValueMapListElement>(new_size); | |
2885 memset(new_array, 0, sizeof(HValueMapListElement) * new_size); | |
2886 | |
2887 HValueMapListElement* old_array = array_; | |
2888 int old_size = array_size_; | |
2889 | |
2890 int old_count = count_; | |
2891 count_ = 0; | |
2892 // Do not modify present_flags_. It is currently correct. | |
2893 array_size_ = new_size; | |
2894 array_ = new_array; | |
2895 | |
2896 if (old_array != NULL) { | |
2897 // Iterate over all the elements in lists, rehashing them. | |
2898 for (int i = 0; i < old_size; ++i) { | |
2899 if (old_array[i].value != NULL) { | |
2900 int current = old_array[i].next; | |
2901 while (current != kNil) { | |
2902 Insert(lists_[current].value, zone); | |
2903 int next = lists_[current].next; | |
2904 lists_[current].next = free_list_head_; | |
2905 free_list_head_ = current; | |
2906 current = next; | |
2907 } | |
2908 // Rehash the directly stored value. | |
2909 Insert(old_array[i].value, zone); | |
2910 } | |
2911 } | |
2912 } | |
2913 USE(old_count); | |
2914 ASSERT(count_ == old_count); | |
2915 } | |
2916 | |
2917 | |
2918 void HValueMap::ResizeLists(int new_size, Zone* zone) { | |
2919 ASSERT(new_size > lists_size_); | |
2920 | |
2921 HValueMapListElement* new_lists = | |
2922 zone->NewArray<HValueMapListElement>(new_size); | |
2923 memset(new_lists, 0, sizeof(HValueMapListElement) * new_size); | |
2924 | |
2925 HValueMapListElement* old_lists = lists_; | |
2926 int old_size = lists_size_; | |
2927 | |
2928 lists_size_ = new_size; | |
2929 lists_ = new_lists; | |
2930 | |
2931 if (old_lists != NULL) { | |
2932 OS::MemCopy(lists_, old_lists, old_size * sizeof(HValueMapListElement)); | |
2933 } | |
2934 for (int i = old_size; i < lists_size_; ++i) { | |
2935 lists_[i].next = free_list_head_; | |
2936 free_list_head_ = i; | |
2937 } | |
2938 } | |
2939 | |
2940 | |
2941 void HValueMap::Insert(HValue* value, Zone* zone) { | |
2942 ASSERT(value != NULL); | |
2943 // Resizing when half of the hashtable is filled up. | |
2944 if (count_ >= array_size_ >> 1) Resize(array_size_ << 1, zone); | |
2945 ASSERT(count_ < array_size_); | |
2946 count_++; | |
2947 uint32_t pos = Bound(static_cast<uint32_t>(value->Hashcode())); | |
2948 if (array_[pos].value == NULL) { | |
2949 array_[pos].value = value; | |
2950 array_[pos].next = kNil; | |
2951 } else { | |
2952 if (free_list_head_ == kNil) { | |
2953 ResizeLists(lists_size_ << 1, zone); | |
2954 } | |
2955 int new_element_pos = free_list_head_; | |
2956 ASSERT(new_element_pos != kNil); | |
2957 free_list_head_ = lists_[free_list_head_].next; | |
2958 lists_[new_element_pos].value = value; | |
2959 lists_[new_element_pos].next = array_[pos].next; | |
2960 ASSERT(array_[pos].next == kNil || lists_[array_[pos].next].value != NULL); | |
2961 array_[pos].next = new_element_pos; | |
2962 } | |
2963 } | |
2964 | |
2965 | |
2966 HSideEffectMap::HSideEffectMap() : count_(0) { | |
2967 memset(data_, 0, kNumberOfTrackedSideEffects * kPointerSize); | |
2968 } | |
2969 | |
2970 | |
2971 HSideEffectMap::HSideEffectMap(HSideEffectMap* other) : count_(other->count_) { | |
2972 *this = *other; // Calls operator=. | |
2973 } | |
2974 | |
2975 | |
2976 HSideEffectMap& HSideEffectMap::operator= (const HSideEffectMap& other) { | |
2977 if (this != &other) { | |
2978 OS::MemCopy(data_, other.data_, kNumberOfTrackedSideEffects * kPointerSize); | |
2979 } | |
2980 return *this; | |
2981 } | |
2982 | |
2983 void HSideEffectMap::Kill(GVNFlagSet flags) { | |
2984 for (int i = 0; i < kNumberOfTrackedSideEffects; i++) { | |
2985 GVNFlag changes_flag = HValue::ChangesFlagFromInt(i); | |
2986 if (flags.Contains(changes_flag)) { | |
2987 if (data_[i] != NULL) count_--; | |
2988 data_[i] = NULL; | |
2989 } | |
2990 } | |
2991 } | |
2992 | |
2993 | |
2994 void HSideEffectMap::Store(GVNFlagSet flags, HInstruction* instr) { | |
2995 for (int i = 0; i < kNumberOfTrackedSideEffects; i++) { | |
2996 GVNFlag changes_flag = HValue::ChangesFlagFromInt(i); | |
2997 if (flags.Contains(changes_flag)) { | |
2998 if (data_[i] == NULL) count_++; | |
2999 data_[i] = instr; | |
3000 } | |
3001 } | |
3002 } | |
3003 | |
3004 | |
3005 class HStackCheckEliminator BASE_EMBEDDED { | 2761 class HStackCheckEliminator BASE_EMBEDDED { |
3006 public: | 2762 public: |
3007 explicit HStackCheckEliminator(HGraph* graph) : graph_(graph) { } | 2763 explicit HStackCheckEliminator(HGraph* graph) : graph_(graph) { } |
3008 | 2764 |
3009 void Process(); | 2765 void Process(); |
3010 | 2766 |
3011 private: | 2767 private: |
3012 HGraph* graph_; | 2768 HGraph* graph_; |
3013 }; | 2769 }; |
3014 | 2770 |
(...skipping 23 matching lines...) Expand all Loading... |
3038 if (dominator == block) break; | 2794 if (dominator == block) break; |
3039 | 2795 |
3040 // Move up the dominator tree. | 2796 // Move up the dominator tree. |
3041 dominator = dominator->dominator(); | 2797 dominator = dominator->dominator(); |
3042 } | 2798 } |
3043 } | 2799 } |
3044 } | 2800 } |
3045 } | 2801 } |
3046 | 2802 |
3047 | 2803 |
3048 // Simple sparse set with O(1) add, contains, and clear. | |
3049 class SparseSet { | |
3050 public: | |
3051 SparseSet(Zone* zone, int capacity) | |
3052 : capacity_(capacity), | |
3053 length_(0), | |
3054 dense_(zone->NewArray<int>(capacity)), | |
3055 sparse_(zone->NewArray<int>(capacity)) { | |
3056 #ifndef NVALGRIND | |
3057 // Initialize the sparse array to make valgrind happy. | |
3058 memset(sparse_, 0, sizeof(sparse_[0]) * capacity); | |
3059 #endif | |
3060 } | |
3061 | |
3062 bool Contains(int n) const { | |
3063 ASSERT(0 <= n && n < capacity_); | |
3064 int d = sparse_[n]; | |
3065 return 0 <= d && d < length_ && dense_[d] == n; | |
3066 } | |
3067 | |
3068 bool Add(int n) { | |
3069 if (Contains(n)) return false; | |
3070 dense_[length_] = n; | |
3071 sparse_[n] = length_; | |
3072 ++length_; | |
3073 return true; | |
3074 } | |
3075 | |
3076 void Clear() { length_ = 0; } | |
3077 | |
3078 private: | |
3079 int capacity_; | |
3080 int length_; | |
3081 int* dense_; | |
3082 int* sparse_; | |
3083 | |
3084 DISALLOW_COPY_AND_ASSIGN(SparseSet); | |
3085 }; | |
3086 | |
3087 | |
3088 class HGlobalValueNumberer BASE_EMBEDDED { | |
3089 public: | |
3090 explicit HGlobalValueNumberer(HGraph* graph, CompilationInfo* info) | |
3091 : graph_(graph), | |
3092 info_(info), | |
3093 removed_side_effects_(false), | |
3094 block_side_effects_(graph->blocks()->length(), graph->zone()), | |
3095 loop_side_effects_(graph->blocks()->length(), graph->zone()), | |
3096 visited_on_paths_(graph->zone(), graph->blocks()->length()) { | |
3097 #ifdef DEBUG | |
3098 ASSERT(info->isolate()->optimizing_compiler_thread()->IsOptimizerThread() || | |
3099 !info->isolate()->heap()->IsAllocationAllowed()); | |
3100 #endif | |
3101 block_side_effects_.AddBlock(GVNFlagSet(), graph_->blocks()->length(), | |
3102 graph_->zone()); | |
3103 loop_side_effects_.AddBlock(GVNFlagSet(), graph_->blocks()->length(), | |
3104 graph_->zone()); | |
3105 } | |
3106 | |
3107 // Returns true if values with side effects are removed. | |
3108 bool Analyze(); | |
3109 | |
3110 private: | |
3111 GVNFlagSet CollectSideEffectsOnPathsToDominatedBlock( | |
3112 HBasicBlock* dominator, | |
3113 HBasicBlock* dominated); | |
3114 void AnalyzeGraph(); | |
3115 void ComputeBlockSideEffects(); | |
3116 void LoopInvariantCodeMotion(); | |
3117 void ProcessLoopBlock(HBasicBlock* block, | |
3118 HBasicBlock* before_loop, | |
3119 GVNFlagSet loop_kills, | |
3120 GVNFlagSet* accumulated_first_time_depends, | |
3121 GVNFlagSet* accumulated_first_time_changes); | |
3122 bool AllowCodeMotion(); | |
3123 bool ShouldMove(HInstruction* instr, HBasicBlock* loop_header); | |
3124 | |
3125 HGraph* graph() { return graph_; } | |
3126 CompilationInfo* info() { return info_; } | |
3127 Zone* zone() const { return graph_->zone(); } | |
3128 | |
3129 HGraph* graph_; | |
3130 CompilationInfo* info_; | |
3131 bool removed_side_effects_; | |
3132 | |
3133 // A map of block IDs to their side effects. | |
3134 ZoneList<GVNFlagSet> block_side_effects_; | |
3135 | |
3136 // A map of loop header block IDs to their loop's side effects. | |
3137 ZoneList<GVNFlagSet> loop_side_effects_; | |
3138 | |
3139 // Used when collecting side effects on paths from dominator to | |
3140 // dominated. | |
3141 SparseSet visited_on_paths_; | |
3142 }; | |
3143 | |
3144 | |
3145 bool HGlobalValueNumberer::Analyze() { | |
3146 removed_side_effects_ = false; | |
3147 ComputeBlockSideEffects(); | |
3148 if (FLAG_loop_invariant_code_motion) { | |
3149 LoopInvariantCodeMotion(); | |
3150 } | |
3151 AnalyzeGraph(); | |
3152 return removed_side_effects_; | |
3153 } | |
3154 | |
3155 | |
3156 void HGlobalValueNumberer::ComputeBlockSideEffects() { | |
3157 // The Analyze phase of GVN can be called multiple times. Clear loop side | |
3158 // effects before computing them to erase the contents from previous Analyze | |
3159 // passes. | |
3160 for (int i = 0; i < loop_side_effects_.length(); ++i) { | |
3161 loop_side_effects_[i].RemoveAll(); | |
3162 } | |
3163 for (int i = graph_->blocks()->length() - 1; i >= 0; --i) { | |
3164 // Compute side effects for the block. | |
3165 HBasicBlock* block = graph_->blocks()->at(i); | |
3166 HInstruction* instr = block->first(); | |
3167 int id = block->block_id(); | |
3168 GVNFlagSet side_effects; | |
3169 while (instr != NULL) { | |
3170 side_effects.Add(instr->ChangesFlags()); | |
3171 if (instr->IsSoftDeoptimize()) { | |
3172 block_side_effects_[id].RemoveAll(); | |
3173 side_effects.RemoveAll(); | |
3174 break; | |
3175 } | |
3176 instr = instr->next(); | |
3177 } | |
3178 block_side_effects_[id].Add(side_effects); | |
3179 | |
3180 // Loop headers are part of their loop. | |
3181 if (block->IsLoopHeader()) { | |
3182 loop_side_effects_[id].Add(side_effects); | |
3183 } | |
3184 | |
3185 // Propagate loop side effects upwards. | |
3186 if (block->HasParentLoopHeader()) { | |
3187 int header_id = block->parent_loop_header()->block_id(); | |
3188 loop_side_effects_[header_id].Add(block->IsLoopHeader() | |
3189 ? loop_side_effects_[id] | |
3190 : side_effects); | |
3191 } | |
3192 } | |
3193 } | |
3194 | |
3195 | |
3196 SmartArrayPointer<char> GetGVNFlagsString(GVNFlagSet flags) { | |
3197 char underlying_buffer[kLastFlag * 128]; | |
3198 Vector<char> buffer(underlying_buffer, sizeof(underlying_buffer)); | |
3199 #if DEBUG | |
3200 int offset = 0; | |
3201 const char* separator = ""; | |
3202 const char* comma = ", "; | |
3203 buffer[0] = 0; | |
3204 uint32_t set_depends_on = 0; | |
3205 uint32_t set_changes = 0; | |
3206 for (int bit = 0; bit < kLastFlag; ++bit) { | |
3207 if ((flags.ToIntegral() & (1 << bit)) != 0) { | |
3208 if (bit % 2 == 0) { | |
3209 set_changes++; | |
3210 } else { | |
3211 set_depends_on++; | |
3212 } | |
3213 } | |
3214 } | |
3215 bool positive_changes = set_changes < (kLastFlag / 2); | |
3216 bool positive_depends_on = set_depends_on < (kLastFlag / 2); | |
3217 if (set_changes > 0) { | |
3218 if (positive_changes) { | |
3219 offset += OS::SNPrintF(buffer + offset, "changes ["); | |
3220 } else { | |
3221 offset += OS::SNPrintF(buffer + offset, "changes all except ["); | |
3222 } | |
3223 for (int bit = 0; bit < kLastFlag; ++bit) { | |
3224 if (((flags.ToIntegral() & (1 << bit)) != 0) == positive_changes) { | |
3225 switch (static_cast<GVNFlag>(bit)) { | |
3226 #define DECLARE_FLAG(type) \ | |
3227 case kChanges##type: \ | |
3228 offset += OS::SNPrintF(buffer + offset, separator); \ | |
3229 offset += OS::SNPrintF(buffer + offset, #type); \ | |
3230 separator = comma; \ | |
3231 break; | |
3232 GVN_TRACKED_FLAG_LIST(DECLARE_FLAG) | |
3233 GVN_UNTRACKED_FLAG_LIST(DECLARE_FLAG) | |
3234 #undef DECLARE_FLAG | |
3235 default: | |
3236 break; | |
3237 } | |
3238 } | |
3239 } | |
3240 offset += OS::SNPrintF(buffer + offset, "]"); | |
3241 } | |
3242 if (set_depends_on > 0) { | |
3243 separator = ""; | |
3244 if (set_changes > 0) { | |
3245 offset += OS::SNPrintF(buffer + offset, ", "); | |
3246 } | |
3247 if (positive_depends_on) { | |
3248 offset += OS::SNPrintF(buffer + offset, "depends on ["); | |
3249 } else { | |
3250 offset += OS::SNPrintF(buffer + offset, "depends on all except ["); | |
3251 } | |
3252 for (int bit = 0; bit < kLastFlag; ++bit) { | |
3253 if (((flags.ToIntegral() & (1 << bit)) != 0) == positive_depends_on) { | |
3254 switch (static_cast<GVNFlag>(bit)) { | |
3255 #define DECLARE_FLAG(type) \ | |
3256 case kDependsOn##type: \ | |
3257 offset += OS::SNPrintF(buffer + offset, separator); \ | |
3258 offset += OS::SNPrintF(buffer + offset, #type); \ | |
3259 separator = comma; \ | |
3260 break; | |
3261 GVN_TRACKED_FLAG_LIST(DECLARE_FLAG) | |
3262 GVN_UNTRACKED_FLAG_LIST(DECLARE_FLAG) | |
3263 #undef DECLARE_FLAG | |
3264 default: | |
3265 break; | |
3266 } | |
3267 } | |
3268 } | |
3269 offset += OS::SNPrintF(buffer + offset, "]"); | |
3270 } | |
3271 #else | |
3272 OS::SNPrintF(buffer, "0x%08X", flags.ToIntegral()); | |
3273 #endif | |
3274 size_t string_len = strlen(underlying_buffer) + 1; | |
3275 ASSERT(string_len <= sizeof(underlying_buffer)); | |
3276 char* result = new char[strlen(underlying_buffer) + 1]; | |
3277 OS::MemCopy(result, underlying_buffer, string_len); | |
3278 return SmartArrayPointer<char>(result); | |
3279 } | |
3280 | |
3281 | |
3282 void HGlobalValueNumberer::LoopInvariantCodeMotion() { | |
3283 TRACE_GVN_1("Using optimistic loop invariant code motion: %s\n", | |
3284 graph_->use_optimistic_licm() ? "yes" : "no"); | |
3285 for (int i = graph_->blocks()->length() - 1; i >= 0; --i) { | |
3286 HBasicBlock* block = graph_->blocks()->at(i); | |
3287 if (block->IsLoopHeader()) { | |
3288 GVNFlagSet side_effects = loop_side_effects_[block->block_id()]; | |
3289 TRACE_GVN_2("Try loop invariant motion for block B%d %s\n", | |
3290 block->block_id(), | |
3291 *GetGVNFlagsString(side_effects)); | |
3292 | |
3293 GVNFlagSet accumulated_first_time_depends; | |
3294 GVNFlagSet accumulated_first_time_changes; | |
3295 HBasicBlock* last = block->loop_information()->GetLastBackEdge(); | |
3296 for (int j = block->block_id(); j <= last->block_id(); ++j) { | |
3297 ProcessLoopBlock(graph_->blocks()->at(j), block, side_effects, | |
3298 &accumulated_first_time_depends, | |
3299 &accumulated_first_time_changes); | |
3300 } | |
3301 } | |
3302 } | |
3303 } | |
3304 | |
3305 | |
3306 void HGlobalValueNumberer::ProcessLoopBlock( | |
3307 HBasicBlock* block, | |
3308 HBasicBlock* loop_header, | |
3309 GVNFlagSet loop_kills, | |
3310 GVNFlagSet* first_time_depends, | |
3311 GVNFlagSet* first_time_changes) { | |
3312 HBasicBlock* pre_header = loop_header->predecessors()->at(0); | |
3313 GVNFlagSet depends_flags = HValue::ConvertChangesToDependsFlags(loop_kills); | |
3314 TRACE_GVN_2("Loop invariant motion for B%d %s\n", | |
3315 block->block_id(), | |
3316 *GetGVNFlagsString(depends_flags)); | |
3317 HInstruction* instr = block->first(); | |
3318 while (instr != NULL) { | |
3319 HInstruction* next = instr->next(); | |
3320 bool hoisted = false; | |
3321 if (instr->CheckFlag(HValue::kUseGVN)) { | |
3322 TRACE_GVN_4("Checking instruction %d (%s) %s. Loop %s\n", | |
3323 instr->id(), | |
3324 instr->Mnemonic(), | |
3325 *GetGVNFlagsString(instr->gvn_flags()), | |
3326 *GetGVNFlagsString(loop_kills)); | |
3327 bool can_hoist = !instr->gvn_flags().ContainsAnyOf(depends_flags); | |
3328 if (can_hoist && !graph()->use_optimistic_licm()) { | |
3329 can_hoist = block->IsLoopSuccessorDominator(); | |
3330 } | |
3331 | |
3332 if (can_hoist) { | |
3333 bool inputs_loop_invariant = true; | |
3334 for (int i = 0; i < instr->OperandCount(); ++i) { | |
3335 if (instr->OperandAt(i)->IsDefinedAfter(pre_header)) { | |
3336 inputs_loop_invariant = false; | |
3337 } | |
3338 } | |
3339 | |
3340 if (inputs_loop_invariant && ShouldMove(instr, loop_header)) { | |
3341 TRACE_GVN_1("Hoisting loop invariant instruction %d\n", instr->id()); | |
3342 // Move the instruction out of the loop. | |
3343 instr->Unlink(); | |
3344 instr->InsertBefore(pre_header->end()); | |
3345 if (instr->HasSideEffects()) removed_side_effects_ = true; | |
3346 hoisted = true; | |
3347 } | |
3348 } | |
3349 } | |
3350 if (!hoisted) { | |
3351 // If an instruction is not hoisted, we have to account for its side | |
3352 // effects when hoisting later HTransitionElementsKind instructions. | |
3353 GVNFlagSet previous_depends = *first_time_depends; | |
3354 GVNFlagSet previous_changes = *first_time_changes; | |
3355 first_time_depends->Add(instr->DependsOnFlags()); | |
3356 first_time_changes->Add(instr->ChangesFlags()); | |
3357 if (!(previous_depends == *first_time_depends)) { | |
3358 TRACE_GVN_1("Updated first-time accumulated %s\n", | |
3359 *GetGVNFlagsString(*first_time_depends)); | |
3360 } | |
3361 if (!(previous_changes == *first_time_changes)) { | |
3362 TRACE_GVN_1("Updated first-time accumulated %s\n", | |
3363 *GetGVNFlagsString(*first_time_changes)); | |
3364 } | |
3365 } | |
3366 instr = next; | |
3367 } | |
3368 } | |
3369 | |
3370 | |
3371 bool HGlobalValueNumberer::AllowCodeMotion() { | |
3372 return info()->IsStub() || info()->opt_count() + 1 < FLAG_max_opt_count; | |
3373 } | |
3374 | |
3375 | |
3376 bool HGlobalValueNumberer::ShouldMove(HInstruction* instr, | |
3377 HBasicBlock* loop_header) { | |
3378 // If we've disabled code motion or we're in a block that unconditionally | |
3379 // deoptimizes, don't move any instructions. | |
3380 return AllowCodeMotion() && !instr->block()->IsDeoptimizing(); | |
3381 } | |
3382 | |
3383 | |
3384 GVNFlagSet HGlobalValueNumberer::CollectSideEffectsOnPathsToDominatedBlock( | |
3385 HBasicBlock* dominator, HBasicBlock* dominated) { | |
3386 GVNFlagSet side_effects; | |
3387 for (int i = 0; i < dominated->predecessors()->length(); ++i) { | |
3388 HBasicBlock* block = dominated->predecessors()->at(i); | |
3389 if (dominator->block_id() < block->block_id() && | |
3390 block->block_id() < dominated->block_id() && | |
3391 visited_on_paths_.Add(block->block_id())) { | |
3392 side_effects.Add(block_side_effects_[block->block_id()]); | |
3393 if (block->IsLoopHeader()) { | |
3394 side_effects.Add(loop_side_effects_[block->block_id()]); | |
3395 } | |
3396 side_effects.Add(CollectSideEffectsOnPathsToDominatedBlock( | |
3397 dominator, block)); | |
3398 } | |
3399 } | |
3400 return side_effects; | |
3401 } | |
3402 | |
3403 | |
3404 // Each instance of this class is like a "stack frame" for the recursive | |
3405 // traversal of the dominator tree done during GVN (the stack is handled | |
3406 // as a double linked list). | |
3407 // We reuse frames when possible so the list length is limited by the depth | |
3408 // of the dominator tree but this forces us to initialize each frame calling | |
3409 // an explicit "Initialize" method instead of a using constructor. | |
3410 class GvnBasicBlockState: public ZoneObject { | |
3411 public: | |
3412 static GvnBasicBlockState* CreateEntry(Zone* zone, | |
3413 HBasicBlock* entry_block, | |
3414 HValueMap* entry_map) { | |
3415 return new(zone) | |
3416 GvnBasicBlockState(NULL, entry_block, entry_map, NULL, zone); | |
3417 } | |
3418 | |
3419 HBasicBlock* block() { return block_; } | |
3420 HValueMap* map() { return map_; } | |
3421 HSideEffectMap* dominators() { return &dominators_; } | |
3422 | |
3423 GvnBasicBlockState* next_in_dominator_tree_traversal( | |
3424 Zone* zone, | |
3425 HBasicBlock** dominator) { | |
3426 // This assignment needs to happen before calling next_dominated() because | |
3427 // that call can reuse "this" if we are at the last dominated block. | |
3428 *dominator = block(); | |
3429 GvnBasicBlockState* result = next_dominated(zone); | |
3430 if (result == NULL) { | |
3431 GvnBasicBlockState* dominator_state = pop(); | |
3432 if (dominator_state != NULL) { | |
3433 // This branch is guaranteed not to return NULL because pop() never | |
3434 // returns a state where "is_done() == true". | |
3435 *dominator = dominator_state->block(); | |
3436 result = dominator_state->next_dominated(zone); | |
3437 } else { | |
3438 // Unnecessary (we are returning NULL) but done for cleanness. | |
3439 *dominator = NULL; | |
3440 } | |
3441 } | |
3442 return result; | |
3443 } | |
3444 | |
3445 private: | |
3446 void Initialize(HBasicBlock* block, | |
3447 HValueMap* map, | |
3448 HSideEffectMap* dominators, | |
3449 bool copy_map, | |
3450 Zone* zone) { | |
3451 block_ = block; | |
3452 map_ = copy_map ? map->Copy(zone) : map; | |
3453 dominated_index_ = -1; | |
3454 length_ = block->dominated_blocks()->length(); | |
3455 if (dominators != NULL) { | |
3456 dominators_ = *dominators; | |
3457 } | |
3458 } | |
3459 bool is_done() { return dominated_index_ >= length_; } | |
3460 | |
3461 GvnBasicBlockState(GvnBasicBlockState* previous, | |
3462 HBasicBlock* block, | |
3463 HValueMap* map, | |
3464 HSideEffectMap* dominators, | |
3465 Zone* zone) | |
3466 : previous_(previous), next_(NULL) { | |
3467 Initialize(block, map, dominators, true, zone); | |
3468 } | |
3469 | |
3470 GvnBasicBlockState* next_dominated(Zone* zone) { | |
3471 dominated_index_++; | |
3472 if (dominated_index_ == length_ - 1) { | |
3473 // No need to copy the map for the last child in the dominator tree. | |
3474 Initialize(block_->dominated_blocks()->at(dominated_index_), | |
3475 map(), | |
3476 dominators(), | |
3477 false, | |
3478 zone); | |
3479 return this; | |
3480 } else if (dominated_index_ < length_) { | |
3481 return push(zone, | |
3482 block_->dominated_blocks()->at(dominated_index_), | |
3483 dominators()); | |
3484 } else { | |
3485 return NULL; | |
3486 } | |
3487 } | |
3488 | |
3489 GvnBasicBlockState* push(Zone* zone, | |
3490 HBasicBlock* block, | |
3491 HSideEffectMap* dominators) { | |
3492 if (next_ == NULL) { | |
3493 next_ = | |
3494 new(zone) GvnBasicBlockState(this, block, map(), dominators, zone); | |
3495 } else { | |
3496 next_->Initialize(block, map(), dominators, true, zone); | |
3497 } | |
3498 return next_; | |
3499 } | |
3500 GvnBasicBlockState* pop() { | |
3501 GvnBasicBlockState* result = previous_; | |
3502 while (result != NULL && result->is_done()) { | |
3503 TRACE_GVN_2("Backtracking from block B%d to block b%d\n", | |
3504 block()->block_id(), | |
3505 previous_->block()->block_id()) | |
3506 result = result->previous_; | |
3507 } | |
3508 return result; | |
3509 } | |
3510 | |
3511 GvnBasicBlockState* previous_; | |
3512 GvnBasicBlockState* next_; | |
3513 HBasicBlock* block_; | |
3514 HValueMap* map_; | |
3515 HSideEffectMap dominators_; | |
3516 int dominated_index_; | |
3517 int length_; | |
3518 }; | |
3519 | |
3520 // This is a recursive traversal of the dominator tree but it has been turned | |
3521 // into a loop to avoid stack overflows. | |
3522 // The logical "stack frames" of the recursion are kept in a list of | |
3523 // GvnBasicBlockState instances. | |
3524 void HGlobalValueNumberer::AnalyzeGraph() { | |
3525 HBasicBlock* entry_block = graph_->entry_block(); | |
3526 HValueMap* entry_map = new(zone()) HValueMap(zone()); | |
3527 GvnBasicBlockState* current = | |
3528 GvnBasicBlockState::CreateEntry(zone(), entry_block, entry_map); | |
3529 | |
3530 while (current != NULL) { | |
3531 HBasicBlock* block = current->block(); | |
3532 HValueMap* map = current->map(); | |
3533 HSideEffectMap* dominators = current->dominators(); | |
3534 | |
3535 TRACE_GVN_2("Analyzing block B%d%s\n", | |
3536 block->block_id(), | |
3537 block->IsLoopHeader() ? " (loop header)" : ""); | |
3538 | |
3539 // If this is a loop header kill everything killed by the loop. | |
3540 if (block->IsLoopHeader()) { | |
3541 map->Kill(loop_side_effects_[block->block_id()]); | |
3542 } | |
3543 | |
3544 // Go through all instructions of the current block. | |
3545 HInstruction* instr = block->first(); | |
3546 while (instr != NULL) { | |
3547 HInstruction* next = instr->next(); | |
3548 GVNFlagSet flags = instr->ChangesFlags(); | |
3549 if (!flags.IsEmpty()) { | |
3550 // Clear all instructions in the map that are affected by side effects. | |
3551 // Store instruction as the dominating one for tracked side effects. | |
3552 map->Kill(flags); | |
3553 dominators->Store(flags, instr); | |
3554 TRACE_GVN_2("Instruction %d %s\n", instr->id(), | |
3555 *GetGVNFlagsString(flags)); | |
3556 } | |
3557 if (instr->CheckFlag(HValue::kUseGVN)) { | |
3558 ASSERT(!instr->HasObservableSideEffects()); | |
3559 HValue* other = map->Lookup(instr); | |
3560 if (other != NULL) { | |
3561 ASSERT(instr->Equals(other) && other->Equals(instr)); | |
3562 TRACE_GVN_4("Replacing value %d (%s) with value %d (%s)\n", | |
3563 instr->id(), | |
3564 instr->Mnemonic(), | |
3565 other->id(), | |
3566 other->Mnemonic()); | |
3567 if (instr->HasSideEffects()) removed_side_effects_ = true; | |
3568 instr->DeleteAndReplaceWith(other); | |
3569 } else { | |
3570 map->Add(instr, zone()); | |
3571 } | |
3572 } | |
3573 if (instr->IsLinked() && | |
3574 instr->CheckFlag(HValue::kTrackSideEffectDominators)) { | |
3575 for (int i = 0; i < kNumberOfTrackedSideEffects; i++) { | |
3576 HValue* other = dominators->at(i); | |
3577 GVNFlag changes_flag = HValue::ChangesFlagFromInt(i); | |
3578 GVNFlag depends_on_flag = HValue::DependsOnFlagFromInt(i); | |
3579 if (instr->DependsOnFlags().Contains(depends_on_flag) && | |
3580 (other != NULL)) { | |
3581 TRACE_GVN_5("Side-effect #%d in %d (%s) is dominated by %d (%s)\n", | |
3582 i, | |
3583 instr->id(), | |
3584 instr->Mnemonic(), | |
3585 other->id(), | |
3586 other->Mnemonic()); | |
3587 instr->SetSideEffectDominator(changes_flag, other); | |
3588 } | |
3589 } | |
3590 } | |
3591 instr = next; | |
3592 } | |
3593 | |
3594 HBasicBlock* dominator_block; | |
3595 GvnBasicBlockState* next = | |
3596 current->next_in_dominator_tree_traversal(zone(), &dominator_block); | |
3597 | |
3598 if (next != NULL) { | |
3599 HBasicBlock* dominated = next->block(); | |
3600 HValueMap* successor_map = next->map(); | |
3601 HSideEffectMap* successor_dominators = next->dominators(); | |
3602 | |
3603 // Kill everything killed on any path between this block and the | |
3604 // dominated block. We don't have to traverse these paths if the | |
3605 // value map and the dominators list is already empty. If the range | |
3606 // of block ids (block_id, dominated_id) is empty there are no such | |
3607 // paths. | |
3608 if ((!successor_map->IsEmpty() || !successor_dominators->IsEmpty()) && | |
3609 dominator_block->block_id() + 1 < dominated->block_id()) { | |
3610 visited_on_paths_.Clear(); | |
3611 GVNFlagSet side_effects_on_all_paths = | |
3612 CollectSideEffectsOnPathsToDominatedBlock(dominator_block, | |
3613 dominated); | |
3614 successor_map->Kill(side_effects_on_all_paths); | |
3615 successor_dominators->Kill(side_effects_on_all_paths); | |
3616 } | |
3617 } | |
3618 current = next; | |
3619 } | |
3620 } | |
3621 | |
3622 | |
3623 void HInferRepresentation::AddToWorklist(HValue* current) { | 2804 void HInferRepresentation::AddToWorklist(HValue* current) { |
3624 if (current->representation().IsTagged()) return; | 2805 if (current->representation().IsTagged()) return; |
3625 if (!current->CheckFlag(HValue::kFlexibleRepresentation)) return; | 2806 if (!current->CheckFlag(HValue::kFlexibleRepresentation)) return; |
3626 if (in_worklist_.Contains(current->id())) return; | 2807 if (in_worklist_.Contains(current->id())) return; |
3627 worklist_.Add(current, zone()); | 2808 worklist_.Add(current, zone()); |
3628 in_worklist_.Add(current->id()); | 2809 in_worklist_.Add(current->id()); |
3629 } | 2810 } |
3630 | 2811 |
3631 | 2812 |
3632 void HInferRepresentation::Analyze() { | 2813 void HInferRepresentation::Analyze() { |
(...skipping 8705 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12338 } | 11519 } |
12339 } | 11520 } |
12340 | 11521 |
12341 #ifdef DEBUG | 11522 #ifdef DEBUG |
12342 if (graph_ != NULL) graph_->Verify(false); // No full verify. | 11523 if (graph_ != NULL) graph_->Verify(false); // No full verify. |
12343 if (allocator_ != NULL) allocator_->Verify(); | 11524 if (allocator_ != NULL) allocator_->Verify(); |
12344 #endif | 11525 #endif |
12345 } | 11526 } |
12346 | 11527 |
12347 } } // namespace v8::internal | 11528 } } // namespace v8::internal |
OLD | NEW |