| Index: src/hydrogen-gvn.cc
|
| diff --git a/src/hydrogen-gvn.cc b/src/hydrogen-gvn.cc
|
| index bc836890bb136544c560474c222d7b354c9ddb4a..89765545185490d8130dcbf2822154c38037be94 100644
|
| --- a/src/hydrogen-gvn.cc
|
| +++ b/src/hydrogen-gvn.cc
|
| @@ -32,39 +32,39 @@
|
| namespace v8 {
|
| namespace internal {
|
|
|
| -class HValueMap: public ZoneObject {
|
| +class HInstructionMap V8_FINAL : public ZoneObject {
|
| public:
|
| - explicit HValueMap(Zone* zone)
|
| + HInstructionMap(Zone* zone, SideEffectsScope* side_effects_scope)
|
| : array_size_(0),
|
| lists_size_(0),
|
| count_(0),
|
| - present_flags_(0),
|
| array_(NULL),
|
| lists_(NULL),
|
| - free_list_head_(kNil) {
|
| + free_list_head_(kNil),
|
| + side_effects_scope_(side_effects_scope) {
|
| ResizeLists(kInitialSize, zone);
|
| Resize(kInitialSize, zone);
|
| }
|
|
|
| - void Kill(GVNFlagSet flags);
|
| + void Kill(SideEffects side_effects);
|
|
|
| - void Add(HValue* value, Zone* zone) {
|
| - present_flags_.Add(value->gvn_flags());
|
| - Insert(value, zone);
|
| + void Add(HInstruction* instr, Zone* zone) {
|
| + present_depends_on_.Add(side_effects_scope_->ComputeDependsOn(instr));
|
| + Insert(instr, zone);
|
| }
|
|
|
| - HValue* Lookup(HValue* value) const;
|
| + HInstruction* Lookup(HInstruction* instr) const;
|
|
|
| - HValueMap* Copy(Zone* zone) const {
|
| - return new(zone) HValueMap(zone, this);
|
| + HInstructionMap* Copy(Zone* zone) const {
|
| + return new(zone) HInstructionMap(zone, this);
|
| }
|
|
|
| bool IsEmpty() const { return count_ == 0; }
|
|
|
| private:
|
| - // A linked list of HValue* values. Stored in arrays.
|
| - struct HValueMapListElement {
|
| - HValue* value;
|
| + // A linked list of HInstruction* values. Stored in arrays.
|
| + struct HInstructionMapListElement {
|
| + HInstruction* instr;
|
| int next; // Index in the array of the next list element.
|
| };
|
| static const int kNil = -1; // The end of a linked list
|
| @@ -72,34 +72,36 @@ class HValueMap: public ZoneObject {
|
| // Must be a power of 2.
|
| static const int kInitialSize = 16;
|
|
|
| - HValueMap(Zone* zone, const HValueMap* other);
|
| + HInstructionMap(Zone* zone, const HInstructionMap* other);
|
|
|
| void Resize(int new_size, Zone* zone);
|
| void ResizeLists(int new_size, Zone* zone);
|
| - void Insert(HValue* value, Zone* zone);
|
| + void Insert(HInstruction* instr, 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
|
| + int count_; // The number of values stored in the HInstructionMap.
|
| + SideEffects present_depends_on_;
|
| + HInstructionMapListElement* 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.
|
| + HInstructionMapListElement* lists_;
|
| + // The linked lists containing hash collisions.
|
| int free_list_head_; // Unused elements in lists_ are on the free list.
|
| + SideEffectsScope* side_effects_scope_;
|
| };
|
|
|
|
|
| -class HSideEffectMap BASE_EMBEDDED {
|
| +class HSideEffectMap V8_FINAL BASE_EMBEDDED {
|
| public:
|
| HSideEffectMap();
|
| explicit HSideEffectMap(HSideEffectMap* other);
|
| HSideEffectMap& operator= (const HSideEffectMap& other);
|
|
|
| - void Kill(GVNFlagSet flags);
|
| + void Kill(SideEffects side_effects);
|
|
|
| - void Store(GVNFlagSet flags, HInstruction* instr);
|
| + void Store(SideEffects side_effects, HInstruction* instr);
|
|
|
| bool IsEmpty() const { return count_ == 0; }
|
|
|
| @@ -152,35 +154,36 @@ void TraceGVN(const char* msg, ...) {
|
| }
|
|
|
|
|
| -HValueMap::HValueMap(Zone* zone, const HValueMap* other)
|
| +HInstructionMap::HInstructionMap(Zone* zone, const HInstructionMap* other)
|
| : array_size_(other->array_size_),
|
| lists_size_(other->lists_size_),
|
| count_(other->count_),
|
| - present_flags_(other->present_flags_),
|
| - array_(zone->NewArray<HValueMapListElement>(other->array_size_)),
|
| - lists_(zone->NewArray<HValueMapListElement>(other->lists_size_)),
|
| - free_list_head_(other->free_list_head_) {
|
| + present_depends_on_(other->present_depends_on_),
|
| + array_(zone->NewArray<HInstructionMapListElement>(other->array_size_)),
|
| + lists_(zone->NewArray<HInstructionMapListElement>(other->lists_size_)),
|
| + free_list_head_(other->free_list_head_),
|
| + side_effects_scope_(other->side_effects_scope_) {
|
| OS::MemCopy(
|
| - array_, other->array_, array_size_ * sizeof(HValueMapListElement));
|
| + array_, other->array_, array_size_ * sizeof(HInstructionMapListElement));
|
| OS::MemCopy(
|
| - lists_, other->lists_, lists_size_ * sizeof(HValueMapListElement));
|
| + lists_, other->lists_, lists_size_ * sizeof(HInstructionMapListElement));
|
| }
|
|
|
|
|
| -void HValueMap::Kill(GVNFlagSet flags) {
|
| - GVNFlagSet depends_flags = HValue::ConvertChangesToDependsFlags(flags);
|
| - if (!present_flags_.ContainsAnyOf(depends_flags)) return;
|
| - present_flags_.RemoveAll();
|
| +void HInstructionMap::Kill(SideEffects changes) {
|
| + if (!present_depends_on_.ContainsAnyOf(changes)) return;
|
| + present_depends_on_.RemoveAll();
|
| for (int i = 0; i < array_size_; ++i) {
|
| - HValue* value = array_[i].value;
|
| - if (value != NULL) {
|
| + HInstruction* instr = array_[i].instr;
|
| + if (instr != NULL) {
|
| // Clear list of collisions first, so we know if it becomes empty.
|
| int kept = kNil; // List of kept elements.
|
| int next;
|
| for (int current = array_[i].next; current != kNil; current = next) {
|
| next = lists_[current].next;
|
| - HValue* value = lists_[current].value;
|
| - if (value->gvn_flags().ContainsAnyOf(depends_flags)) {
|
| + HInstruction* instr = lists_[current].instr;
|
| + SideEffects depends_on = side_effects_scope_->ComputeDependsOn(instr);
|
| + if (depends_on.ContainsAnyOf(changes)) {
|
| // Drop it.
|
| count_--;
|
| lists_[current].next = free_list_head_;
|
| @@ -189,40 +192,41 @@ void HValueMap::Kill(GVNFlagSet flags) {
|
| // Keep it.
|
| lists_[current].next = kept;
|
| kept = current;
|
| - present_flags_.Add(value->gvn_flags());
|
| + present_depends_on_.Add(depends_on);
|
| }
|
| }
|
| array_[i].next = kept;
|
|
|
| // Now possibly drop directly indexed element.
|
| - value = array_[i].value;
|
| - if (value->gvn_flags().ContainsAnyOf(depends_flags)) { // Drop it.
|
| + instr = array_[i].instr;
|
| + SideEffects depends_on = side_effects_scope_->ComputeDependsOn(instr);
|
| + if (depends_on.ContainsAnyOf(changes)) { // Drop it.
|
| count_--;
|
| int head = array_[i].next;
|
| if (head == kNil) {
|
| - array_[i].value = NULL;
|
| + array_[i].instr = NULL;
|
| } else {
|
| - array_[i].value = lists_[head].value;
|
| + array_[i].instr = lists_[head].instr;
|
| array_[i].next = lists_[head].next;
|
| lists_[head].next = free_list_head_;
|
| free_list_head_ = head;
|
| }
|
| } else {
|
| - present_flags_.Add(value->gvn_flags()); // Keep it.
|
| + present_depends_on_.Add(depends_on); // Keep it.
|
| }
|
| }
|
| }
|
| }
|
|
|
|
|
| -HValue* HValueMap::Lookup(HValue* value) const {
|
| - uint32_t hash = static_cast<uint32_t>(value->Hashcode());
|
| +HInstruction* HInstructionMap::Lookup(HInstruction* instr) const {
|
| + uint32_t hash = static_cast<uint32_t>(instr->Hashcode());
|
| uint32_t pos = Bound(hash);
|
| - if (array_[pos].value != NULL) {
|
| - if (array_[pos].value->Equals(value)) return array_[pos].value;
|
| + if (array_[pos].instr != NULL) {
|
| + if (array_[pos].instr->Equals(instr)) return array_[pos].instr;
|
| int next = array_[pos].next;
|
| while (next != kNil) {
|
| - if (lists_[next].value->Equals(value)) return lists_[next].value;
|
| + if (lists_[next].instr->Equals(instr)) return lists_[next].instr;
|
| next = lists_[next].next;
|
| }
|
| }
|
| @@ -230,7 +234,7 @@ HValue* HValueMap::Lookup(HValue* value) const {
|
| }
|
|
|
|
|
| -void HValueMap::Resize(int new_size, Zone* zone) {
|
| +void HInstructionMap::Resize(int new_size, Zone* zone) {
|
| ASSERT(new_size > count_);
|
| // Hashing the values into the new array has no more collisions than in the
|
| // old hash map, so we can use the existing lists_ array, if we are careful.
|
| @@ -240,33 +244,33 @@ void HValueMap::Resize(int new_size, Zone* zone) {
|
| ResizeLists(lists_size_ << 1, zone);
|
| }
|
|
|
| - HValueMapListElement* new_array =
|
| - zone->NewArray<HValueMapListElement>(new_size);
|
| - memset(new_array, 0, sizeof(HValueMapListElement) * new_size);
|
| + HInstructionMapListElement* new_array =
|
| + zone->NewArray<HInstructionMapListElement>(new_size);
|
| + memset(new_array, 0, sizeof(HInstructionMapListElement) * new_size);
|
|
|
| - HValueMapListElement* old_array = array_;
|
| + HInstructionMapListElement* old_array = array_;
|
| int old_size = array_size_;
|
|
|
| int old_count = count_;
|
| count_ = 0;
|
| - // Do not modify present_flags_. It is currently correct.
|
| + // Do not modify present_depends_on_. It is currently correct.
|
| array_size_ = new_size;
|
| array_ = new_array;
|
|
|
| if (old_array != NULL) {
|
| // Iterate over all the elements in lists, rehashing them.
|
| for (int i = 0; i < old_size; ++i) {
|
| - if (old_array[i].value != NULL) {
|
| + if (old_array[i].instr != NULL) {
|
| int current = old_array[i].next;
|
| while (current != kNil) {
|
| - Insert(lists_[current].value, zone);
|
| + Insert(lists_[current].instr, zone);
|
| int next = lists_[current].next;
|
| lists_[current].next = free_list_head_;
|
| free_list_head_ = current;
|
| current = next;
|
| }
|
| - // Rehash the directly stored value.
|
| - Insert(old_array[i].value, zone);
|
| + // Rehash the directly stored instruction.
|
| + Insert(old_array[i].instr, zone);
|
| }
|
| }
|
| }
|
| @@ -275,21 +279,22 @@ void HValueMap::Resize(int new_size, Zone* zone) {
|
| }
|
|
|
|
|
| -void HValueMap::ResizeLists(int new_size, Zone* zone) {
|
| +void HInstructionMap::ResizeLists(int new_size, Zone* zone) {
|
| ASSERT(new_size > lists_size_);
|
|
|
| - HValueMapListElement* new_lists =
|
| - zone->NewArray<HValueMapListElement>(new_size);
|
| - memset(new_lists, 0, sizeof(HValueMapListElement) * new_size);
|
| + HInstructionMapListElement* new_lists =
|
| + zone->NewArray<HInstructionMapListElement>(new_size);
|
| + memset(new_lists, 0, sizeof(HInstructionMapListElement) * new_size);
|
|
|
| - HValueMapListElement* old_lists = lists_;
|
| + HInstructionMapListElement* old_lists = lists_;
|
| int old_size = lists_size_;
|
|
|
| lists_size_ = new_size;
|
| lists_ = new_lists;
|
|
|
| if (old_lists != NULL) {
|
| - OS::MemCopy(lists_, old_lists, old_size * sizeof(HValueMapListElement));
|
| + OS::MemCopy(
|
| + lists_, old_lists, old_size * sizeof(HInstructionMapListElement));
|
| }
|
| for (int i = old_size; i < lists_size_; ++i) {
|
| lists_[i].next = free_list_head_;
|
| @@ -298,15 +303,15 @@ void HValueMap::ResizeLists(int new_size, Zone* zone) {
|
| }
|
|
|
|
|
| -void HValueMap::Insert(HValue* value, Zone* zone) {
|
| - ASSERT(value != NULL);
|
| +void HInstructionMap::Insert(HInstruction* instr, Zone* zone) {
|
| + ASSERT(instr != NULL);
|
| // Resizing when half of the hashtable is filled up.
|
| if (count_ >= array_size_ >> 1) Resize(array_size_ << 1, zone);
|
| ASSERT(count_ < array_size_);
|
| count_++;
|
| - uint32_t pos = Bound(static_cast<uint32_t>(value->Hashcode()));
|
| - if (array_[pos].value == NULL) {
|
| - array_[pos].value = value;
|
| + uint32_t pos = Bound(static_cast<uint32_t>(instr->Hashcode()));
|
| + if (array_[pos].instr == NULL) {
|
| + array_[pos].instr = instr;
|
| array_[pos].next = kNil;
|
| } else {
|
| if (free_list_head_ == kNil) {
|
| @@ -315,9 +320,9 @@ void HValueMap::Insert(HValue* value, Zone* zone) {
|
| int new_element_pos = free_list_head_;
|
| ASSERT(new_element_pos != kNil);
|
| free_list_head_ = lists_[free_list_head_].next;
|
| - lists_[new_element_pos].value = value;
|
| + lists_[new_element_pos].instr = instr;
|
| lists_[new_element_pos].next = array_[pos].next;
|
| - ASSERT(array_[pos].next == kNil || lists_[array_[pos].next].value != NULL);
|
| + ASSERT(array_[pos].next == kNil || lists_[array_[pos].next].instr != NULL);
|
| array_[pos].next = new_element_pos;
|
| }
|
| }
|
| @@ -341,10 +346,9 @@ HSideEffectMap& HSideEffectMap::operator= (const HSideEffectMap& other) {
|
| }
|
|
|
|
|
| -void HSideEffectMap::Kill(GVNFlagSet flags) {
|
| +void HSideEffectMap::Kill(SideEffects side_effects) {
|
| for (int i = 0; i < kNumberOfTrackedSideEffects; i++) {
|
| - GVNFlag changes_flag = HValue::ChangesFlagFromInt(i);
|
| - if (flags.Contains(changes_flag)) {
|
| + if (side_effects.ContainsFlag(GVNFlagFromInt(i))) {
|
| if (data_[i] != NULL) count_--;
|
| data_[i] = NULL;
|
| }
|
| @@ -352,10 +356,9 @@ void HSideEffectMap::Kill(GVNFlagSet flags) {
|
| }
|
|
|
|
|
| -void HSideEffectMap::Store(GVNFlagSet flags, HInstruction* instr) {
|
| +void HSideEffectMap::Store(SideEffects side_effects, HInstruction* instr) {
|
| for (int i = 0; i < kNumberOfTrackedSideEffects; i++) {
|
| - GVNFlag changes_flag = HValue::ChangesFlagFromInt(i);
|
| - if (flags.Contains(changes_flag)) {
|
| + if (side_effects.ContainsFlag(GVNFlagFromInt(i))) {
|
| if (data_[i] == NULL) count_++;
|
| data_[i] = instr;
|
| }
|
| @@ -363,6 +366,95 @@ void HSideEffectMap::Store(GVNFlagSet flags, HInstruction* instr) {
|
| }
|
|
|
|
|
| +SideEffects SideEffectsScope::ComputeChanges(HInstruction* instr) {
|
| + SideEffects result(instr->ChangesFlags());
|
| + if (result.ContainsFlag(kInobjectFields)) {
|
| + int index;
|
| + if (instr->IsStoreNamedField() &&
|
| + ComputeInobjectField(HStoreNamedField::cast(instr)->access(), &index)) {
|
| + result.RemoveFlag(kInobjectFields);
|
| + result.AddSpecial(index);
|
| + } else {
|
| + result.AddAllSpecial();
|
| + }
|
| + }
|
| + return result;
|
| +}
|
| +
|
| +
|
| +SideEffects SideEffectsScope::ComputeDependsOn(HInstruction* instr) {
|
| + SideEffects result(instr->DependsOnFlags());
|
| + if (result.ContainsFlag(kInobjectFields)) {
|
| + int index;
|
| + if (instr->IsLoadNamedField() &&
|
| + ComputeInobjectField(HLoadNamedField::cast(instr)->access(), &index)) {
|
| + result.RemoveFlag(kInobjectFields);
|
| + result.AddSpecial(index);
|
| + } else {
|
| + result.AddAllSpecial();
|
| + }
|
| + }
|
| + return result;
|
| +}
|
| +
|
| +
|
| +void SideEffectsScope::PrintSideEffectsTo(StringStream* stream,
|
| + SideEffects side_effects) const {
|
| + const char* separator = "";
|
| + stream->Add("[");
|
| + for (int bit = 0; bit < kNumberOfFlags; ++bit) {
|
| + GVNFlag flag = GVNFlagFromInt(bit);
|
| + if (side_effects.ContainsFlag(flag)) {
|
| + stream->Add(separator);
|
| + separator = ", ";
|
| + switch (flag) {
|
| +#define DECLARE_FLAG(Type) \
|
| + case k##Type: \
|
| + stream->Add(#Type); \
|
| + break;
|
| +GVN_TRACKED_FLAG_LIST(DECLARE_FLAG)
|
| +GVN_UNTRACKED_FLAG_LIST(DECLARE_FLAG)
|
| +#undef DECLARE_FLAG
|
| + default:
|
| + break;
|
| + }
|
| + }
|
| + }
|
| + for (int index = 0; index < num_inobject_fields_; ++index) {
|
| + if (side_effects.ContainsSpecial(index)) {
|
| + stream->Add(separator);
|
| + separator = ", ";
|
| + inobject_fields_[index].PrintTo(stream);
|
| + }
|
| + }
|
| + stream->Add("]");
|
| +}
|
| +
|
| +
|
| +bool SideEffectsScope::ComputeInobjectField(HObjectAccess access, int* index) {
|
| + for (int i = 0; i < num_inobject_fields_; ++i) {
|
| + if (access.Equals(inobject_fields_[i])) {
|
| + *index = i;
|
| + return true;
|
| + }
|
| + }
|
| + if (num_inobject_fields_ < SideEffects::kNumberOfSpecials) {
|
| + if (FLAG_trace_gvn) {
|
| + HeapStringAllocator allocator;
|
| + StringStream stream(&allocator);
|
| + stream.Add("Recording inobject field access ");
|
| + access.PrintTo(&stream);
|
| + stream.Add(" (mapped to special index %d)\n", num_inobject_fields_);
|
| + stream.OutputToStdOut();
|
| + }
|
| + *index = num_inobject_fields_;
|
| + inobject_fields_[num_inobject_fields_++] = access;
|
| + return true;
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +
|
| HGlobalValueNumberingPhase::HGlobalValueNumberingPhase(HGraph* graph)
|
| : HPhase("H_Global value numbering", graph),
|
| removed_side_effects_(false),
|
| @@ -370,10 +462,10 @@ HGlobalValueNumberingPhase::HGlobalValueNumberingPhase(HGraph* graph)
|
| loop_side_effects_(graph->blocks()->length(), zone()),
|
| visited_on_paths_(graph->blocks()->length(), zone()) {
|
| ASSERT(!AllowHandleAllocation::IsAllowed());
|
| - block_side_effects_.AddBlock(GVNFlagSet(), graph->blocks()->length(),
|
| - zone());
|
| - loop_side_effects_.AddBlock(GVNFlagSet(), graph->blocks()->length(),
|
| - zone());
|
| + block_side_effects_.AddBlock(
|
| + SideEffects(), graph->blocks()->length(), zone());
|
| + loop_side_effects_.AddBlock(
|
| + SideEffects(), graph->blocks()->length(), zone());
|
| }
|
|
|
|
|
| @@ -409,12 +501,12 @@ void HGlobalValueNumberingPhase::ComputeBlockSideEffects() {
|
| for (int i = graph()->blocks()->length() - 1; i >= 0; --i) {
|
| // Compute side effects for the block.
|
| HBasicBlock* block = graph()->blocks()->at(i);
|
| - GVNFlagSet side_effects;
|
| + SideEffects side_effects;
|
| if (block->IsReachable() && !block->IsDeoptimizing()) {
|
| int id = block->block_id();
|
| for (HInstructionIterator it(block); !it.Done(); it.Advance()) {
|
| HInstruction* instr = it.Current();
|
| - side_effects.Add(instr->ChangesFlags());
|
| + side_effects.Add(side_effects_scope_.ComputeChanges(instr));
|
| }
|
| block_side_effects_[id].Add(side_effects);
|
|
|
| @@ -438,103 +530,22 @@ void HGlobalValueNumberingPhase::ComputeBlockSideEffects() {
|
| }
|
|
|
|
|
| -SmartArrayPointer<char> GetGVNFlagsString(GVNFlagSet flags) {
|
| - char underlying_buffer[kNumberOfFlags * 128];
|
| - Vector<char> buffer(underlying_buffer, sizeof(underlying_buffer));
|
| -#if DEBUG
|
| - int offset = 0;
|
| - const char* separator = "";
|
| - const char* comma = ", ";
|
| - buffer[0] = 0;
|
| - uint32_t set_depends_on = 0;
|
| - uint32_t set_changes = 0;
|
| - for (int bit = 0; bit < kNumberOfFlags; ++bit) {
|
| - if (flags.Contains(static_cast<GVNFlag>(bit))) {
|
| - if (bit % 2 == 0) {
|
| - set_changes++;
|
| - } else {
|
| - set_depends_on++;
|
| - }
|
| - }
|
| - }
|
| - bool positive_changes = set_changes < (kNumberOfFlags / 2);
|
| - bool positive_depends_on = set_depends_on < (kNumberOfFlags / 2);
|
| - if (set_changes > 0) {
|
| - if (positive_changes) {
|
| - offset += OS::SNPrintF(buffer + offset, "changes [");
|
| - } else {
|
| - offset += OS::SNPrintF(buffer + offset, "changes all except [");
|
| - }
|
| - for (int bit = 0; bit < kNumberOfFlags; ++bit) {
|
| - if (flags.Contains(static_cast<GVNFlag>(bit)) == positive_changes) {
|
| - switch (static_cast<GVNFlag>(bit)) {
|
| -#define DECLARE_FLAG(type) \
|
| - case kChanges##type: \
|
| - offset += OS::SNPrintF(buffer + offset, separator); \
|
| - offset += OS::SNPrintF(buffer + offset, #type); \
|
| - separator = comma; \
|
| - break;
|
| -GVN_TRACKED_FLAG_LIST(DECLARE_FLAG)
|
| -GVN_UNTRACKED_FLAG_LIST(DECLARE_FLAG)
|
| -#undef DECLARE_FLAG
|
| - default:
|
| - break;
|
| - }
|
| - }
|
| - }
|
| - offset += OS::SNPrintF(buffer + offset, "]");
|
| - }
|
| - if (set_depends_on > 0) {
|
| - separator = "";
|
| - if (set_changes > 0) {
|
| - offset += OS::SNPrintF(buffer + offset, ", ");
|
| - }
|
| - if (positive_depends_on) {
|
| - offset += OS::SNPrintF(buffer + offset, "depends on [");
|
| - } else {
|
| - offset += OS::SNPrintF(buffer + offset, "depends on all except [");
|
| - }
|
| - for (int bit = 0; bit < kNumberOfFlags; ++bit) {
|
| - if (flags.Contains(static_cast<GVNFlag>(bit)) == positive_depends_on) {
|
| - switch (static_cast<GVNFlag>(bit)) {
|
| -#define DECLARE_FLAG(type) \
|
| - case kDependsOn##type: \
|
| - offset += OS::SNPrintF(buffer + offset, separator); \
|
| - offset += OS::SNPrintF(buffer + offset, #type); \
|
| - separator = comma; \
|
| - break;
|
| -GVN_TRACKED_FLAG_LIST(DECLARE_FLAG)
|
| -GVN_UNTRACKED_FLAG_LIST(DECLARE_FLAG)
|
| -#undef DECLARE_FLAG
|
| - default:
|
| - break;
|
| - }
|
| - }
|
| - }
|
| - offset += OS::SNPrintF(buffer + offset, "]");
|
| - }
|
| -#else
|
| - OS::SNPrintF(buffer, "0x%08X", flags.ToIntegral());
|
| -#endif
|
| - size_t string_len = strlen(underlying_buffer) + 1;
|
| - ASSERT(string_len <= sizeof(underlying_buffer));
|
| - char* result = new char[strlen(underlying_buffer) + 1];
|
| - OS::MemCopy(result, underlying_buffer, string_len);
|
| - return SmartArrayPointer<char>(result);
|
| -}
|
| -
|
| -
|
| void HGlobalValueNumberingPhase::LoopInvariantCodeMotion() {
|
| TRACE_GVN_1("Using optimistic loop invariant code motion: %s\n",
|
| graph()->use_optimistic_licm() ? "yes" : "no");
|
| for (int i = graph()->blocks()->length() - 1; i >= 0; --i) {
|
| HBasicBlock* block = graph()->blocks()->at(i);
|
| if (block->IsLoopHeader()) {
|
| - GVNFlagSet side_effects = loop_side_effects_[block->block_id()];
|
| - TRACE_GVN_2("Try loop invariant motion for block B%d %s\n",
|
| - block->block_id(),
|
| - GetGVNFlagsString(side_effects).get());
|
| -
|
| + SideEffects side_effects = loop_side_effects_[block->block_id()];
|
| + if (FLAG_trace_gvn) {
|
| + HeapStringAllocator allocator;
|
| + StringStream stream(&allocator);
|
| + stream.Add("Try loop invariant motion for block B%d changes ",
|
| + block->block_id());
|
| + side_effects_scope_.PrintSideEffectsTo(&stream, side_effects);
|
| + stream.Add("\n");
|
| + stream.OutputToStdOut();
|
| + }
|
| HBasicBlock* last = block->loop_information()->GetLastBackEdge();
|
| for (int j = block->block_id(); j <= last->block_id(); ++j) {
|
| ProcessLoopBlock(graph()->blocks()->at(j), block, side_effects);
|
| @@ -547,22 +558,37 @@ void HGlobalValueNumberingPhase::LoopInvariantCodeMotion() {
|
| void HGlobalValueNumberingPhase::ProcessLoopBlock(
|
| HBasicBlock* block,
|
| HBasicBlock* loop_header,
|
| - GVNFlagSet loop_kills) {
|
| + SideEffects loop_kills) {
|
| HBasicBlock* pre_header = loop_header->predecessors()->at(0);
|
| - GVNFlagSet depends_flags = HValue::ConvertChangesToDependsFlags(loop_kills);
|
| - TRACE_GVN_2("Loop invariant motion for B%d %s\n",
|
| - block->block_id(),
|
| - GetGVNFlagsString(depends_flags).get());
|
| + if (FLAG_trace_gvn) {
|
| + HeapStringAllocator allocator;
|
| + StringStream stream(&allocator);
|
| + stream.Add("Loop invariant code motion for B%d depends on ",
|
| + block->block_id());
|
| + side_effects_scope_.PrintSideEffectsTo(&stream, loop_kills);
|
| + stream.Add("\n");
|
| + stream.OutputToStdOut();
|
| + }
|
| HInstruction* instr = block->first();
|
| while (instr != NULL) {
|
| HInstruction* next = instr->next();
|
| if (instr->CheckFlag(HValue::kUseGVN)) {
|
| - TRACE_GVN_4("Checking instruction %d (%s) %s. Loop %s\n",
|
| - instr->id(),
|
| - instr->Mnemonic(),
|
| - GetGVNFlagsString(instr->gvn_flags()).get(),
|
| - GetGVNFlagsString(loop_kills).get());
|
| - bool can_hoist = !instr->gvn_flags().ContainsAnyOf(depends_flags);
|
| + SideEffects changes = side_effects_scope_.ComputeChanges(instr);
|
| + SideEffects depends_on = side_effects_scope_.ComputeDependsOn(instr);
|
| + if (FLAG_trace_gvn) {
|
| + HeapStringAllocator allocator;
|
| + StringStream stream(&allocator);
|
| + stream.Add("Checking instruction i%d (%s) changes ",
|
| + instr->id(), instr->Mnemonic());
|
| + side_effects_scope_.PrintSideEffectsTo(&stream, changes);
|
| + stream.Add(", depends on ");
|
| + side_effects_scope_.PrintSideEffectsTo(&stream, depends_on);
|
| + stream.Add(". Loop changes ");
|
| + side_effects_scope_.PrintSideEffectsTo(&stream, loop_kills);
|
| + stream.Add("\n");
|
| + stream.OutputToStdOut();
|
| + }
|
| + bool can_hoist = !depends_on.ContainsAnyOf(loop_kills);
|
| if (can_hoist && !graph()->use_optimistic_licm()) {
|
| can_hoist = block->IsLoopSuccessorDominator();
|
| }
|
| @@ -604,10 +630,10 @@ bool HGlobalValueNumberingPhase::ShouldMove(HInstruction* instr,
|
| }
|
|
|
|
|
| -GVNFlagSet
|
| +SideEffects
|
| HGlobalValueNumberingPhase::CollectSideEffectsOnPathsToDominatedBlock(
|
| HBasicBlock* dominator, HBasicBlock* dominated) {
|
| - GVNFlagSet side_effects;
|
| + SideEffects side_effects;
|
| for (int i = 0; i < dominated->predecessors()->length(); ++i) {
|
| HBasicBlock* block = dominated->predecessors()->at(i);
|
| if (dominator->block_id() < block->block_id() &&
|
| @@ -636,13 +662,13 @@ class GvnBasicBlockState: public ZoneObject {
|
| public:
|
| static GvnBasicBlockState* CreateEntry(Zone* zone,
|
| HBasicBlock* entry_block,
|
| - HValueMap* entry_map) {
|
| + HInstructionMap* entry_map) {
|
| return new(zone)
|
| GvnBasicBlockState(NULL, entry_block, entry_map, NULL, zone);
|
| }
|
|
|
| HBasicBlock* block() { return block_; }
|
| - HValueMap* map() { return map_; }
|
| + HInstructionMap* map() { return map_; }
|
| HSideEffectMap* dominators() { return &dominators_; }
|
|
|
| GvnBasicBlockState* next_in_dominator_tree_traversal(
|
| @@ -669,7 +695,7 @@ class GvnBasicBlockState: public ZoneObject {
|
|
|
| private:
|
| void Initialize(HBasicBlock* block,
|
| - HValueMap* map,
|
| + HInstructionMap* map,
|
| HSideEffectMap* dominators,
|
| bool copy_map,
|
| Zone* zone) {
|
| @@ -685,7 +711,7 @@ class GvnBasicBlockState: public ZoneObject {
|
|
|
| GvnBasicBlockState(GvnBasicBlockState* previous,
|
| HBasicBlock* block,
|
| - HValueMap* map,
|
| + HInstructionMap* map,
|
| HSideEffectMap* dominators,
|
| Zone* zone)
|
| : previous_(previous), next_(NULL) {
|
| @@ -732,7 +758,7 @@ class GvnBasicBlockState: public ZoneObject {
|
| GvnBasicBlockState* previous_;
|
| GvnBasicBlockState* next_;
|
| HBasicBlock* block_;
|
| - HValueMap* map_;
|
| + HInstructionMap* map_;
|
| HSideEffectMap dominators_;
|
| int dominated_index_;
|
| int length_;
|
| @@ -745,13 +771,14 @@ class GvnBasicBlockState: public ZoneObject {
|
| // GvnBasicBlockState instances.
|
| void HGlobalValueNumberingPhase::AnalyzeGraph() {
|
| HBasicBlock* entry_block = graph()->entry_block();
|
| - HValueMap* entry_map = new(zone()) HValueMap(zone());
|
| + HInstructionMap* entry_map =
|
| + new(zone()) HInstructionMap(zone(), &side_effects_scope_);
|
| GvnBasicBlockState* current =
|
| GvnBasicBlockState::CreateEntry(zone(), entry_block, entry_map);
|
|
|
| while (current != NULL) {
|
| HBasicBlock* block = current->block();
|
| - HValueMap* map = current->map();
|
| + HInstructionMap* map = current->map();
|
| HSideEffectMap* dominators = current->dominators();
|
|
|
| TRACE_GVN_2("Analyzing block B%d%s\n",
|
| @@ -770,17 +797,15 @@ void HGlobalValueNumberingPhase::AnalyzeGraph() {
|
| if (instr->CheckFlag(HValue::kTrackSideEffectDominators)) {
|
| for (int i = 0; i < kNumberOfTrackedSideEffects; i++) {
|
| HValue* other = dominators->at(i);
|
| - GVNFlag changes_flag = HValue::ChangesFlagFromInt(i);
|
| - GVNFlag depends_on_flag = HValue::DependsOnFlagFromInt(i);
|
| - if (instr->DependsOnFlags().Contains(depends_on_flag) &&
|
| - (other != NULL)) {
|
| + GVNFlag flag = GVNFlagFromInt(i);
|
| + if (instr->DependsOnFlags().Contains(flag) && other != NULL) {
|
| TRACE_GVN_5("Side-effect #%d in %d (%s) is dominated by %d (%s)\n",
|
| i,
|
| instr->id(),
|
| instr->Mnemonic(),
|
| other->id(),
|
| other->Mnemonic());
|
| - if (instr->HandleSideEffectDominator(changes_flag, other)) {
|
| + if (instr->HandleSideEffectDominator(flag, other)) {
|
| removed_side_effects_ = true;
|
| }
|
| }
|
| @@ -789,21 +814,27 @@ void HGlobalValueNumberingPhase::AnalyzeGraph() {
|
| // Instruction was unlinked during graph traversal.
|
| if (!instr->IsLinked()) continue;
|
|
|
| - GVNFlagSet flags = instr->ChangesFlags();
|
| - if (!flags.IsEmpty()) {
|
| + SideEffects changes = side_effects_scope_.ComputeChanges(instr);
|
| + if (!changes.IsEmpty()) {
|
| // Clear all instructions in the map that are affected by side effects.
|
| // Store instruction as the dominating one for tracked side effects.
|
| - map->Kill(flags);
|
| - dominators->Store(flags, instr);
|
| - TRACE_GVN_2("Instruction %d %s\n", instr->id(),
|
| - GetGVNFlagsString(flags).get());
|
| + map->Kill(changes);
|
| + dominators->Store(changes, instr);
|
| + if (FLAG_trace_gvn) {
|
| + HeapStringAllocator allocator;
|
| + StringStream stream(&allocator);
|
| + stream.Add("Instruction i%d changes ", instr->id());
|
| + side_effects_scope_.PrintSideEffectsTo(&stream, changes);
|
| + stream.Add("\n");
|
| + stream.OutputToStdOut();
|
| + }
|
| }
|
| if (instr->CheckFlag(HValue::kUseGVN)) {
|
| ASSERT(!instr->HasObservableSideEffects());
|
| - HValue* other = map->Lookup(instr);
|
| + HInstruction* other = map->Lookup(instr);
|
| if (other != NULL) {
|
| ASSERT(instr->Equals(other) && other->Equals(instr));
|
| - TRACE_GVN_4("Replacing value %d (%s) with value %d (%s)\n",
|
| + TRACE_GVN_4("Replacing instruction i%d (%s) with i%d (%s)\n",
|
| instr->id(),
|
| instr->Mnemonic(),
|
| other->id(),
|
| @@ -823,7 +854,7 @@ void HGlobalValueNumberingPhase::AnalyzeGraph() {
|
|
|
| if (next != NULL) {
|
| HBasicBlock* dominated = next->block();
|
| - HValueMap* successor_map = next->map();
|
| + HInstructionMap* successor_map = next->map();
|
| HSideEffectMap* successor_dominators = next->dominators();
|
|
|
| // Kill everything killed on any path between this block and the
|
| @@ -834,7 +865,7 @@ void HGlobalValueNumberingPhase::AnalyzeGraph() {
|
| if ((!successor_map->IsEmpty() || !successor_dominators->IsEmpty()) &&
|
| dominator_block->block_id() + 1 < dominated->block_id()) {
|
| visited_on_paths_.Clear();
|
| - GVNFlagSet side_effects_on_all_paths =
|
| + SideEffects side_effects_on_all_paths =
|
| CollectSideEffectsOnPathsToDominatedBlock(dominator_block,
|
| dominated);
|
| successor_map->Kill(side_effects_on_all_paths);
|
|
|