Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Side by Side Diff: src/hydrogen.cc

Issue 16095004: Extract GlobalValueNumberer and helper classes from hydrogen.cc and move to hydrogen-gvn.cc. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Introduce hydrogen-gvn.h as well. Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/hydrogen.h ('k') | src/hydrogen-gvn.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
OLDNEW
« no previous file with comments | « src/hydrogen.h ('k') | src/hydrogen-gvn.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698