Index: src/hydrogen.h |
diff --git a/src/hydrogen.h b/src/hydrogen.h |
index a8afdc2e22bc5bea18a800e50edb4ca7b3e1b897..da6092851dd23aa6d330e65d978db7f9b90afc21 100644 |
--- a/src/hydrogen.h |
+++ b/src/hydrogen.h |
@@ -1798,90 +1798,6 @@ class HOptimizedGraphBuilder: public HGraphBuilder, public AstVisitor { |
Zone* AstContext::zone() const { return owner_->zone(); } |
-class HValueMap: public ZoneObject { |
- public: |
- explicit HValueMap(Zone* zone) |
- : array_size_(0), |
- lists_size_(0), |
- count_(0), |
- present_flags_(0), |
- array_(NULL), |
- lists_(NULL), |
- free_list_head_(kNil) { |
- ResizeLists(kInitialSize, zone); |
- Resize(kInitialSize, zone); |
- } |
- |
- void Kill(GVNFlagSet flags); |
- |
- void Add(HValue* value, Zone* zone) { |
- present_flags_.Add(value->gvn_flags()); |
- Insert(value, zone); |
- } |
- |
- HValue* Lookup(HValue* value) const; |
- |
- HValueMap* Copy(Zone* zone) const { |
- return new(zone) HValueMap(zone, this); |
- } |
- |
- bool IsEmpty() const { return count_ == 0; } |
- |
- private: |
- // A linked list of HValue* values. Stored in arrays. |
- struct HValueMapListElement { |
- HValue* value; |
- int next; // Index in the array of the next list element. |
- }; |
- static const int kNil = -1; // The end of a linked list |
- |
- // Must be a power of 2. |
- static const int kInitialSize = 16; |
- |
- HValueMap(Zone* zone, const HValueMap* other); |
- |
- void Resize(int new_size, Zone* zone); |
- void ResizeLists(int new_size, Zone* zone); |
- void Insert(HValue* value, Zone* zone); |
- uint32_t Bound(uint32_t value) const { return value & (array_size_ - 1); } |
- |
- int array_size_; |
- int lists_size_; |
- int count_; // The number of values stored in the HValueMap. |
- GVNFlagSet present_flags_; // All flags that are in any value in the |
- // HValueMap. |
- HValueMapListElement* array_; // Primary store - contains the first value |
- // with a given hash. Colliding elements are stored in linked lists. |
- HValueMapListElement* lists_; // The linked lists containing hash collisions. |
- int free_list_head_; // Unused elements in lists_ are on the free list. |
-}; |
- |
- |
-class HSideEffectMap BASE_EMBEDDED { |
- public: |
- HSideEffectMap(); |
- explicit HSideEffectMap(HSideEffectMap* other); |
- HSideEffectMap& operator= (const HSideEffectMap& other); |
- |
- void Kill(GVNFlagSet flags); |
- |
- void Store(GVNFlagSet flags, HInstruction* instr); |
- |
- bool IsEmpty() const { return count_ == 0; } |
- |
- inline HInstruction* operator[](int i) const { |
- ASSERT(0 <= i); |
- ASSERT(i < kNumberOfTrackedSideEffects); |
- return data_[i]; |
- } |
- inline HInstruction* at(int i) const { return operator[](i); } |
- |
- private: |
- int count_; |
- HInstruction* data_[kNumberOfTrackedSideEffects]; |
-}; |
- |
- |
class HStatistics: public Malloced { |
public: |
HStatistics() |
@@ -2029,6 +1945,103 @@ class HTracer: public Malloced { |
}; |
+// Simple sparse set with O(1) add, contains, and clear. |
+class SparseSet { |
Sven Panne
2013/05/27 11:41:23
I think it makes sense to move this to a separate
titzer
2013/05/27 12:22:09
As discussed in-person, we can move this datastruc
|
+ public: |
+ SparseSet(Zone* zone, int capacity) |
+ : capacity_(capacity), |
+ length_(0), |
+ dense_(zone->NewArray<int>(capacity)), |
+ sparse_(zone->NewArray<int>(capacity)) { |
+#ifndef NVALGRIND |
+ // Initialize the sparse array to make valgrind happy. |
+ memset(sparse_, 0, sizeof(sparse_[0]) * capacity); |
+#endif |
+ } |
+ |
+ bool Contains(int n) const { |
+ ASSERT(0 <= n && n < capacity_); |
+ int d = sparse_[n]; |
+ return 0 <= d && d < length_ && dense_[d] == n; |
+ } |
+ |
+ bool Add(int n) { |
+ if (Contains(n)) return false; |
+ dense_[length_] = n; |
+ sparse_[n] = length_; |
+ ++length_; |
+ return true; |
+ } |
+ |
+ void Clear() { length_ = 0; } |
+ |
+ private: |
+ int capacity_; |
+ int length_; |
+ int* dense_; |
+ int* sparse_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(SparseSet); |
+}; |
+ |
+ |
+class HGlobalValueNumberer BASE_EMBEDDED { |
Sven Panne
2013/05/27 11:41:23
To be consistent, this should really live in a new
titzer
2013/05/27 12:22:09
Done.
|
+ public: |
+ explicit HGlobalValueNumberer(HGraph* graph, CompilationInfo* info) |
+ : graph_(graph), |
+ info_(info), |
+ removed_side_effects_(false), |
+ block_side_effects_(graph->blocks()->length(), graph->zone()), |
+ loop_side_effects_(graph->blocks()->length(), graph->zone()), |
+ visited_on_paths_(graph->zone(), graph->blocks()->length()) { |
+#ifdef DEBUG |
+ ASSERT(info->isolate()->optimizing_compiler_thread()->IsOptimizerThread() || |
+ !info->isolate()->heap()->IsAllocationAllowed()); |
+#endif |
+ block_side_effects_.AddBlock(GVNFlagSet(), graph_->blocks()->length(), |
+ graph_->zone()); |
+ loop_side_effects_.AddBlock(GVNFlagSet(), graph_->blocks()->length(), |
+ graph_->zone()); |
+ } |
+ |
+ // Returns true if values with side effects are removed. |
+ bool Analyze(); |
+ |
+ private: |
+ GVNFlagSet CollectSideEffectsOnPathsToDominatedBlock( |
+ HBasicBlock* dominator, |
+ HBasicBlock* dominated); |
+ void AnalyzeGraph(); |
+ void ComputeBlockSideEffects(); |
+ void LoopInvariantCodeMotion(); |
+ void ProcessLoopBlock(HBasicBlock* block, |
+ HBasicBlock* before_loop, |
+ GVNFlagSet loop_kills, |
+ GVNFlagSet* accumulated_first_time_depends, |
+ GVNFlagSet* accumulated_first_time_changes); |
+ bool AllowCodeMotion(); |
+ bool ShouldMove(HInstruction* instr, HBasicBlock* loop_header); |
+ |
+ HGraph* graph() { return graph_; } |
+ CompilationInfo* info() { return info_; } |
+ Zone* zone() const { return graph_->zone(); } |
+ |
+ HGraph* graph_; |
+ CompilationInfo* info_; |
+ bool removed_side_effects_; |
+ |
+ // A map of block IDs to their side effects. |
+ ZoneList<GVNFlagSet> block_side_effects_; |
+ |
+ // A map of loop header block IDs to their loop's side effects. |
+ ZoneList<GVNFlagSet> loop_side_effects_; |
+ |
+ // Used when collecting side effects on paths from dominator to |
+ // dominated. |
+ SparseSet visited_on_paths_; |
+}; |
+ |
+ |
} } // namespace v8::internal |
#endif // V8_HYDROGEN_H_ |