Commit cd1b7df6 authored by bmeurer@chromium.org's avatar bmeurer@chromium.org

Improve inobject field tracking during GVN.

Now stores to inobject fields do no longer prevent hoisting
and combining of loads from other inobject fields.

R=mstarzinger@chromium.org

Review URL: https://codereview.chromium.org/144423010

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@19247 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent f6852ee2
......@@ -103,8 +103,8 @@ class HCheckTable : public ZoneObject {
}
default: {
// If the instruction changes maps uncontrollably, drop everything.
if (instr->CheckGVNFlag(kChangesMaps) ||
instr->CheckGVNFlag(kChangesOsrEntries)) {
if (instr->CheckChangesFlag(kMaps) ||
instr->CheckChangesFlag(kOsrEntries)) {
Kill();
}
}
......@@ -387,7 +387,7 @@ class HCheckTable : public ZoneObject {
Insert(object, MapConstant(instr->value()));
} else {
// If the instruction changes maps, it should be handled above.
CHECK(!instr->CheckGVNFlag(kChangesMaps));
CHECK(!instr->CheckChangesFlag(kMaps));
}
}
......@@ -571,8 +571,8 @@ class HCheckMapsEffects : public ZoneObject {
maps_stored_ = true;
}
default: {
maps_stored_ |= (instr->CheckGVNFlag(kChangesMaps) |
instr->CheckGVNFlag(kChangesElementsKind));
maps_stored_ |= (instr->CheckChangesFlag(kMaps) |
instr->CheckChangesFlag(kElementsKind));
}
}
}
......
......@@ -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, SideEffectsTracker* side_effects_tracker)
: 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_tracker_(side_effects_tracker) {
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_tracker_->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.
SideEffectsTracker* side_effects_tracker_;
};
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_tracker_(other->side_effects_tracker_) {
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_tracker_->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_tracker_->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,96 @@ void HSideEffectMap::Store(GVNFlagSet flags, HInstruction* instr) {
}
SideEffects SideEffectsTracker::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 SideEffectsTracker::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 SideEffectsTracker::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 SideEffectsTracker::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("Tracking 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 +463,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 +502,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_tracker_.ComputeChanges(instr));
}
block_side_effects_[id].Add(side_effects);
......@@ -438,103 +531,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_tracker_.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 +559,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_tracker_.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_tracker_.ComputeChanges(instr);
SideEffects depends_on = side_effects_tracker_.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_tracker_.PrintSideEffectsTo(&stream, changes);
stream.Add(", depends on ");
side_effects_tracker_.PrintSideEffectsTo(&stream, depends_on);
stream.Add(". Loop changes ");
side_effects_tracker_.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 +631,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 +663,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 +696,7 @@ class GvnBasicBlockState: public ZoneObject {
private:
void Initialize(HBasicBlock* block,
HValueMap* map,
HInstructionMap* map,
HSideEffectMap* dominators,
bool copy_map,
Zone* zone) {
......@@ -685,7 +712,7 @@ class GvnBasicBlockState: public ZoneObject {
GvnBasicBlockState(GvnBasicBlockState* previous,
HBasicBlock* block,
HValueMap* map,
HInstructionMap* map,
HSideEffectMap* dominators,
Zone* zone)
: previous_(previous), next_(NULL) {
......@@ -732,7 +759,7 @@ class GvnBasicBlockState: public ZoneObject {
GvnBasicBlockState* previous_;
GvnBasicBlockState* next_;
HBasicBlock* block_;
HValueMap* map_;
HInstructionMap* map_;
HSideEffectMap dominators_;
int dominated_index_;
int length_;
......@@ -745,13 +772,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_tracker_);
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 +798,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 +815,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_tracker_.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_tracker_.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 +855,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 +866,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);
......
......@@ -36,15 +36,76 @@
namespace v8 {
namespace internal {
// This class extends GVNFlagSet with additional "special" dynamic side effects,
// which can be used to represent side effects that cannot be expressed using
// the GVNFlags of an HInstruction. These special side effects are tracked by a
// SideEffectsTracker (see below).
class SideEffects V8_FINAL {
public:
static const int kNumberOfSpecials = 64 - kNumberOfFlags;
SideEffects() : bits_(0) {}
explicit SideEffects(GVNFlagSet flags) : bits_(flags.ToIntegral()) {}
bool IsEmpty() const { return bits_ == 0; }
bool ContainsFlag(GVNFlag flag) const {
return (bits_ & MaskFlag(flag)) != 0;
}
bool ContainsSpecial(int special) const {
return (bits_ & MaskSpecial(special)) != 0;
}
bool ContainsAnyOf(SideEffects set) const { return (bits_ & set.bits_) != 0; }
void Add(SideEffects set) { bits_ |= set.bits_; }
void AddSpecial(int special) { bits_ |= MaskSpecial(special); }
void AddAllSpecial() { bits_ |= ~static_cast<uint64_t>(0) << kNumberOfFlags; }
void RemoveFlag(GVNFlag flag) { bits_ &= ~MaskFlag(flag); }
void RemoveAll() { bits_ = 0; }
uint64_t ToIntegral() const { return bits_; }
void PrintTo(StringStream* stream) const;
private:
uint64_t MaskFlag(GVNFlag flag) const {
return static_cast<uint64_t>(1) << static_cast<unsigned>(flag);
}
uint64_t MaskSpecial(int special) const {
ASSERT(special >= 0);
ASSERT(special < kNumberOfSpecials);
return static_cast<uint64_t>(1) << static_cast<unsigned>(
special + kNumberOfFlags);
}
uint64_t bits_;
STATIC_ASSERT(kNumberOfFlags + kNumberOfSpecials == sizeof(bits_) * CHAR_BIT);
};
// Tracks inobject field loads/stores in a fine grained fashion, and represents
// them using the "special" dynamic side effects of the SideEffects class (see
// above). This way unrelated inobject field stores don't prevent hoisting and
// merging of inobject field loads.
class SideEffectsTracker V8_FINAL BASE_EMBEDDED {
public:
SideEffectsTracker() : num_inobject_fields_(0) {}
SideEffects ComputeChanges(HInstruction* instr);
SideEffects ComputeDependsOn(HInstruction* instr);
void PrintSideEffectsTo(StringStream* stream, SideEffects side_effects) const;
private:
bool ComputeInobjectField(HObjectAccess access, int* index);
HObjectAccess inobject_fields_[SideEffects::kNumberOfSpecials];
int num_inobject_fields_;
};
// Perform common subexpression elimination and loop-invariant code motion.
class HGlobalValueNumberingPhase : public HPhase {
class HGlobalValueNumberingPhase V8_FINAL : public HPhase {
public:
explicit HGlobalValueNumberingPhase(HGraph* graph);
void Run();
private:
GVNFlagSet CollectSideEffectsOnPathsToDominatedBlock(
SideEffects CollectSideEffectsOnPathsToDominatedBlock(
HBasicBlock* dominator,
HBasicBlock* dominated);
void AnalyzeGraph();
......@@ -52,17 +113,18 @@ class HGlobalValueNumberingPhase : public HPhase {
void LoopInvariantCodeMotion();
void ProcessLoopBlock(HBasicBlock* block,
HBasicBlock* before_loop,
GVNFlagSet loop_kills);
SideEffects loop_kills);
bool AllowCodeMotion();
bool ShouldMove(HInstruction* instr, HBasicBlock* loop_header);
SideEffectsTracker side_effects_tracker_;
bool removed_side_effects_;
// A map of block IDs to their side effects.
ZoneList<GVNFlagSet> block_side_effects_;
ZoneList<SideEffects> block_side_effects_;
// A map of loop header block IDs to their loop's side effects.
ZoneList<GVNFlagSet> loop_side_effects_;
ZoneList<SideEffects> loop_side_effects_;
// Used when collecting side effects on paths from dominator to
// dominated.
......@@ -71,7 +133,6 @@ class HGlobalValueNumberingPhase : public HPhase {
DISALLOW_COPY_AND_ASSIGN(HGlobalValueNumberingPhase);
};
} } // namespace v8::internal
#endif // V8_HYDROGEN_GVN_H_
......@@ -604,11 +604,11 @@ void HValue::PrintChangesTo(StringStream* stream) {
stream->Add("*");
} else {
bool add_comma = false;
#define PRINT_DO(type) \
if (changes_flags.Contains(kChanges##type)) { \
if (add_comma) stream->Add(","); \
add_comma = true; \
stream->Add(#type); \
#define PRINT_DO(Type) \
if (changes_flags.Contains(k##Type)) { \
if (add_comma) stream->Add(","); \
add_comma = true; \
stream->Add(#Type); \
}
GVN_TRACKED_FLAG_LIST(PRINT_DO);
GVN_UNTRACKED_FLAG_LIST(PRINT_DO);
......@@ -1516,7 +1516,7 @@ void HCheckInstanceType::GetCheckMaskAndTag(uint8_t* mask, uint8_t* tag) {
bool HCheckMaps::HandleSideEffectDominator(GVNFlag side_effect,
HValue* dominator) {
ASSERT(side_effect == kChangesMaps);
ASSERT(side_effect == kMaps);
// TODO(mstarzinger): For now we specialize on HStoreNamedField, but once
// type information is rich enough we should generalize this to any HType
// for which the map is known.
......@@ -1624,7 +1624,7 @@ Range* HChange::InferRange(Zone* zone) {
input_range != NULL &&
input_range->IsInSmiRange()))) {
set_type(HType::Smi());
ClearGVNFlag(kChangesNewSpacePromotion);
ClearChangesFlag(kNewSpacePromotion);
}
Range* result = (input_range != NULL)
? input_range->Copy(zone)
......@@ -3412,7 +3412,7 @@ Representation HUnaryMathOperation::RepresentationFromInputs() {
bool HAllocate::HandleSideEffectDominator(GVNFlag side_effect,
HValue* dominator) {
ASSERT(side_effect == kChangesNewSpacePromotion);
ASSERT(side_effect == kNewSpacePromotion);
Zone* zone = block()->zone();
if (!FLAG_use_allocation_folding) return false;
......@@ -4394,52 +4394,76 @@ void HObjectAccess::SetGVNFlags(HValue *instr, PropertyAccessType access_type) {
// set the appropriate GVN flags for a given load or store instruction
if (access_type == STORE) {
// track dominating allocations in order to eliminate write barriers
instr->SetGVNFlag(kDependsOnNewSpacePromotion);
instr->SetDependsOnFlag(::v8::internal::kNewSpacePromotion);
instr->SetFlag(HValue::kTrackSideEffectDominators);
} else {
// try to GVN loads, but don't hoist above map changes
instr->SetFlag(HValue::kUseGVN);
instr->SetGVNFlag(kDependsOnMaps);
instr->SetDependsOnFlag(::v8::internal::kMaps);
}
switch (portion()) {
case kArrayLengths:
instr->SetGVNFlag(access_type == STORE
? kChangesArrayLengths : kDependsOnArrayLengths);
if (access_type == STORE) {
instr->SetChangesFlag(::v8::internal::kArrayLengths);
} else {
instr->SetDependsOnFlag(::v8::internal::kArrayLengths);
}
break;
case kStringLengths:
instr->SetGVNFlag(access_type == STORE
? kChangesStringLengths : kDependsOnStringLengths);
if (access_type == STORE) {
instr->SetChangesFlag(::v8::internal::kStringLengths);
} else {
instr->SetDependsOnFlag(::v8::internal::kStringLengths);
}
break;
case kInobject:
instr->SetGVNFlag(access_type == STORE
? kChangesInobjectFields : kDependsOnInobjectFields);
if (access_type == STORE) {
instr->SetChangesFlag(::v8::internal::kInobjectFields);
} else {
instr->SetDependsOnFlag(::v8::internal::kInobjectFields);
}
break;
case kDouble:
instr->SetGVNFlag(access_type == STORE
? kChangesDoubleFields : kDependsOnDoubleFields);
if (access_type == STORE) {
instr->SetChangesFlag(::v8::internal::kDoubleFields);
} else {
instr->SetDependsOnFlag(::v8::internal::kDoubleFields);
}
break;
case kBackingStore:
instr->SetGVNFlag(access_type == STORE
? kChangesBackingStoreFields : kDependsOnBackingStoreFields);
if (access_type == STORE) {
instr->SetChangesFlag(::v8::internal::kBackingStoreFields);
} else {
instr->SetDependsOnFlag(::v8::internal::kBackingStoreFields);
}
break;
case kElementsPointer:
instr->SetGVNFlag(access_type == STORE
? kChangesElementsPointer : kDependsOnElementsPointer);
if (access_type == STORE) {
instr->SetChangesFlag(::v8::internal::kElementsPointer);
} else {
instr->SetDependsOnFlag(::v8::internal::kElementsPointer);
}
break;
case kMaps:
instr->SetGVNFlag(access_type == STORE
? kChangesMaps : kDependsOnMaps);
if (access_type == STORE) {
instr->SetChangesFlag(::v8::internal::kMaps);
} else {
instr->SetDependsOnFlag(::v8::internal::kMaps);
}
break;
case kExternalMemory:
instr->SetGVNFlag(access_type == STORE
? kChangesExternalMemory : kDependsOnExternalMemory);
if (access_type == STORE) {
instr->SetChangesFlag(::v8::internal::kExternalMemory);
} else {
instr->SetDependsOnFlag(::v8::internal::kExternalMemory);
}
break;
}
}
void HObjectAccess::PrintTo(StringStream* stream) {
void HObjectAccess::PrintTo(StringStream* stream) const {
stream->Add(".");
switch (portion()) {
......
......@@ -476,22 +476,28 @@ class HUseIterator V8_FINAL BASE_EMBEDDED {
};
// There must be one corresponding kDepends flag for every kChanges flag and
// the order of the kChanges flags must be exactly the same as of the kDepends
// flags. All tracked flags should appear before untracked ones.
// All tracked flags should appear before untracked ones.
enum GVNFlag {
// Declare global value numbering flags.
#define DECLARE_FLAG(type) kChanges##type, kDependsOn##type,
#define DECLARE_FLAG(Type) k##Type,
GVN_TRACKED_FLAG_LIST(DECLARE_FLAG)
GVN_UNTRACKED_FLAG_LIST(DECLARE_FLAG)
#undef DECLARE_FLAG
kNumberOfFlags,
#define COUNT_FLAG(type) + 1
kNumberOfTrackedSideEffects = 0 GVN_TRACKED_FLAG_LIST(COUNT_FLAG)
#define COUNT_FLAG(Type) + 1
kNumberOfTrackedSideEffects = 0 GVN_TRACKED_FLAG_LIST(COUNT_FLAG),
kNumberOfUntrackedSideEffects = 0 GVN_UNTRACKED_FLAG_LIST(COUNT_FLAG),
#undef COUNT_FLAG
kNumberOfFlags = kNumberOfTrackedSideEffects + kNumberOfUntrackedSideEffects
};
static inline GVNFlag GVNFlagFromInt(int i) {
ASSERT(i >= 0);
ASSERT(i < kNumberOfFlags);
return static_cast<GVNFlag>(i);
}
class DecompositionResult V8_FINAL BASE_EMBEDDED {
public:
DecompositionResult() : base_(NULL), offset_(0), scale_(0) {}
......@@ -537,7 +543,7 @@ class DecompositionResult V8_FINAL BASE_EMBEDDED {
};
typedef EnumSet<GVNFlag, int64_t> GVNFlagSet;
typedef EnumSet<GVNFlag, int32_t> GVNFlagSet;
class HValue : public ZoneObject {
......@@ -588,18 +594,6 @@ class HValue : public ZoneObject {
STATIC_ASSERT(kLastFlag < kBitsPerInt);
static const int kChangesToDependsFlagsLeftShift = 1;
static GVNFlag ChangesFlagFromInt(int x) {
return static_cast<GVNFlag>(x * 2);
}
static GVNFlag DependsOnFlagFromInt(int x) {
return static_cast<GVNFlag>(x * 2 + 1);
}
static GVNFlagSet ConvertChangesToDependsFlags(GVNFlagSet flags) {
return GVNFlagSet(flags.ToIntegral() << kChangesToDependsFlagsLeftShift);
}
static HValue* cast(HValue* value) { return value; }
enum Opcode {
......@@ -775,43 +769,38 @@ class HValue : public ZoneObject {
// of uses is non-empty.
bool HasAtLeastOneUseWithFlagAndNoneWithout(Flag f) const;
GVNFlagSet gvn_flags() const { return gvn_flags_; }
void SetGVNFlag(GVNFlag f) { gvn_flags_.Add(f); }
void ClearGVNFlag(GVNFlag f) { gvn_flags_.Remove(f); }
bool CheckGVNFlag(GVNFlag f) const { return gvn_flags_.Contains(f); }
void SetAllSideEffects() { gvn_flags_.Add(AllSideEffectsFlagSet()); }
GVNFlagSet ChangesFlags() const { return changes_flags_; }
GVNFlagSet DependsOnFlags() const { return depends_on_flags_; }
void SetChangesFlag(GVNFlag f) { changes_flags_.Add(f); }
void SetDependsOnFlag(GVNFlag f) { depends_on_flags_.Add(f); }
void ClearChangesFlag(GVNFlag f) { changes_flags_.Remove(f); }
void ClearDependsOnFlag(GVNFlag f) { depends_on_flags_.Remove(f); }
bool CheckChangesFlag(GVNFlag f) const {
return changes_flags_.Contains(f);
}
bool CheckDependsOnFlag(GVNFlag f) const {
return depends_on_flags_.Contains(f);
}
void SetAllSideEffects() { changes_flags_.Add(AllSideEffectsFlagSet()); }
void ClearAllSideEffects() {
gvn_flags_.Remove(AllSideEffectsFlagSet());
changes_flags_.Remove(AllSideEffectsFlagSet());
}
bool HasSideEffects() const {
return gvn_flags_.ContainsAnyOf(AllSideEffectsFlagSet());
return changes_flags_.ContainsAnyOf(AllSideEffectsFlagSet());
}
bool HasObservableSideEffects() const {
return !CheckFlag(kHasNoObservableSideEffects) &&
gvn_flags_.ContainsAnyOf(AllObservableSideEffectsFlagSet());
}
GVNFlagSet DependsOnFlags() const {
GVNFlagSet result = gvn_flags_;
result.Intersect(AllDependsOnFlagSet());
return result;
changes_flags_.ContainsAnyOf(AllObservableSideEffectsFlagSet());
}
GVNFlagSet SideEffectFlags() const {
GVNFlagSet result = gvn_flags_;
GVNFlagSet result = ChangesFlags();
result.Intersect(AllSideEffectsFlagSet());
return result;
}
GVNFlagSet ChangesFlags() const {
GVNFlagSet result = gvn_flags_;
result.Intersect(AllChangesFlagSet());
return result;
}
GVNFlagSet ObservableChangesFlags() const {
GVNFlagSet result = gvn_flags_;
result.Intersect(AllChangesFlagSet());
GVNFlagSet result = ChangesFlags();
result.Intersect(AllObservableSideEffectsFlagSet());
return result;
}
......@@ -952,20 +941,9 @@ class HValue : public ZoneObject {
representation_ = r;
}
static GVNFlagSet AllDependsOnFlagSet() {
GVNFlagSet result;
// Create changes mask.
#define ADD_FLAG(type) result.Add(kDependsOn##type);
GVN_TRACKED_FLAG_LIST(ADD_FLAG)
GVN_UNTRACKED_FLAG_LIST(ADD_FLAG)
#undef ADD_FLAG
return result;
}
static GVNFlagSet AllChangesFlagSet() {
static GVNFlagSet AllFlagSet() {
GVNFlagSet result;
// Create changes mask.
#define ADD_FLAG(type) result.Add(kChanges##type);
#define ADD_FLAG(Type) result.Add(k##Type);
GVN_TRACKED_FLAG_LIST(ADD_FLAG)
GVN_UNTRACKED_FLAG_LIST(ADD_FLAG)
#undef ADD_FLAG
......@@ -974,19 +952,19 @@ class HValue : public ZoneObject {
// A flag mask to mark an instruction as having arbitrary side effects.
static GVNFlagSet AllSideEffectsFlagSet() {
GVNFlagSet result = AllChangesFlagSet();
result.Remove(kChangesOsrEntries);
GVNFlagSet result = AllFlagSet();
result.Remove(kOsrEntries);
return result;
}
// A flag mask of all side effects that can make observable changes in
// an executing program (i.e. are not safe to repeat, move or remove);
static GVNFlagSet AllObservableSideEffectsFlagSet() {
GVNFlagSet result = AllChangesFlagSet();
result.Remove(kChangesNewSpacePromotion);
result.Remove(kChangesElementsKind);
result.Remove(kChangesElementsPointer);
result.Remove(kChangesMaps);
GVNFlagSet result = AllFlagSet();
result.Remove(kNewSpacePromotion);
result.Remove(kElementsKind);
result.Remove(kElementsPointer);
result.Remove(kMaps);
return result;
}
......@@ -1007,7 +985,8 @@ class HValue : public ZoneObject {
HUseListNode* use_list_;
Range* range_;
int flags_;
GVNFlagSet gvn_flags_;
GVNFlagSet changes_flags_;
GVNFlagSet depends_on_flags_;
private:
virtual bool IsDeletable() const { return false; }
......@@ -1261,7 +1240,7 @@ class HInstruction : public HValue {
next_(NULL),
previous_(NULL),
position_(RelocInfo::kNoPosition) {
SetGVNFlag(kDependsOnOsrEntries);
SetDependsOnFlag(kOsrEntries);
}
virtual void DeleteFromGraph() V8_OVERRIDE { Unlink(); }
......@@ -1721,7 +1700,7 @@ class HChange V8_FINAL : public HUnaryOperation {
set_type(HType::Smi());
} else {
set_type(HType::TaggedNumber());
if (to.IsTagged()) SetGVNFlag(kChangesNewSpacePromotion);
if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion);
}
}
......@@ -1967,7 +1946,7 @@ class HStackCheck V8_FINAL : public HTemplateInstruction<1> {
private:
HStackCheck(HValue* context, Type type) : type_(type) {
SetOperandAt(0, context);
SetGVNFlag(kChangesNewSpacePromotion);
SetChangesFlag(kNewSpacePromotion);
}
Type type_;
......@@ -2515,7 +2494,7 @@ class HMapEnumLength V8_FINAL : public HUnaryOperation {
: HUnaryOperation(value, HType::Smi()) {
set_representation(Representation::Smi());
SetFlag(kUseGVN);
SetGVNFlag(kDependsOnMaps);
SetDependsOnFlag(kMaps);
}
virtual bool IsDeletable() const V8_OVERRIDE { return true; }
......@@ -2589,7 +2568,7 @@ class HUnaryMathOperation V8_FINAL : public HTemplateInstruction<2> {
SetFlag(kFlexibleRepresentation);
// TODO(svenpanne) This flag is actually only needed if representation()
// is tagged, and not when it is an unboxed double or unboxed integer.
SetGVNFlag(kChangesNewSpacePromotion);
SetChangesFlag(kNewSpacePromotion);
break;
case kMathLog:
case kMathExp:
......@@ -2638,7 +2617,7 @@ class HLoadRoot V8_FINAL : public HTemplateInstruction<0> {
SetFlag(kUseGVN);
// TODO(bmeurer): We'll need kDependsOnRoots once we add the
// corresponding HStoreRoot instruction.
SetGVNFlag(kDependsOnCalls);
SetDependsOnFlag(kCalls);
}
virtual bool IsDeletable() const V8_OVERRIDE { return true; }
......@@ -2703,7 +2682,7 @@ class HCheckMaps V8_FINAL : public HTemplateInstruction<2> {
map_set_.Add(Unique<Map>(map), zone);
if (!has_migration_target_ && map->is_migration_target()) {
has_migration_target_ = true;
SetGVNFlag(kChangesNewSpacePromotion);
SetChangesFlag(kNewSpacePromotion);
}
}
......@@ -2717,8 +2696,8 @@ class HCheckMaps V8_FINAL : public HTemplateInstruction<2> {
set_representation(Representation::Tagged());
SetFlag(kUseGVN);
SetFlag(kTrackSideEffectDominators);
SetGVNFlag(kDependsOnMaps);
SetGVNFlag(kDependsOnElementsKind);
SetDependsOnFlag(kMaps);
SetDependsOnFlag(kElementsKind);
}
bool omit_;
......@@ -3322,7 +3301,7 @@ class HCapturedObject V8_FINAL : public HDematerializedObject {
void ReuseSideEffectsFromStore(HInstruction* store) {
ASSERT(store->HasObservableSideEffects());
ASSERT(store->IsStoreNamedField());
gvn_flags_.Add(store->gvn_flags());
changes_flags_.Add(store->ChangesFlags());
}
// Replay effects of this instruction on the given environment.
......@@ -3955,7 +3934,7 @@ class HBitwiseBinaryOperation : public HBinaryOperation {
}
virtual void RepresentationChanged(Representation to) V8_OVERRIDE {
if (to.IsTagged()) SetGVNFlag(kChangesNewSpacePromotion);
if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion);
if (to.IsTagged() &&
(left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved())) {
SetAllSideEffects();
......@@ -4032,7 +4011,7 @@ class HArithmeticBinaryOperation : public HBinaryOperation {
}
virtual void RepresentationChanged(Representation to) V8_OVERRIDE {
if (to.IsTagged()) SetGVNFlag(kChangesNewSpacePromotion);
if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion);
if (to.IsTagged() &&
(left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved())) {
SetAllSideEffects();
......@@ -4357,7 +4336,7 @@ class HStringCompareAndBranch : public HTemplateControlInstruction<2, 3> {
SetOperandAt(1, left);
SetOperandAt(2, right);
set_representation(Representation::Tagged());
SetGVNFlag(kChangesNewSpacePromotion);
SetChangesFlag(kNewSpacePromotion);
}
Token::Value token_;
......@@ -4582,7 +4561,7 @@ class HPower V8_FINAL : public HTemplateInstruction<2> {
SetOperandAt(1, right);
set_representation(Representation::Double());
SetFlag(kUseGVN);
SetGVNFlag(kChangesNewSpacePromotion);
SetChangesFlag(kNewSpacePromotion);
}
virtual bool IsDeletable() const V8_OVERRIDE {
......@@ -4624,7 +4603,7 @@ class HAdd V8_FINAL : public HArithmeticBinaryOperation {
virtual void RepresentationChanged(Representation to) V8_OVERRIDE {
if (to.IsTagged()) {
SetGVNFlag(kChangesNewSpacePromotion);
SetChangesFlag(kNewSpacePromotion);
ClearFlag(kAllowUndefinedAsNaN);
}
if (to.IsTagged() &&
......@@ -5081,8 +5060,8 @@ class HOsrEntry V8_FINAL : public HTemplateInstruction<0> {
private:
explicit HOsrEntry(BailoutId ast_id) : ast_id_(ast_id) {
SetGVNFlag(kChangesOsrEntries);
SetGVNFlag(kChangesNewSpacePromotion);
SetChangesFlag(kOsrEntries);
SetChangesFlag(kNewSpacePromotion);
}
BailoutId ast_id_;
......@@ -5224,7 +5203,7 @@ class HLoadGlobalCell V8_FINAL : public HTemplateInstruction<0> {
: cell_(Unique<Cell>::CreateUninitialized(cell)), details_(details) {
set_representation(Representation::Tagged());
SetFlag(kUseGVN);
SetGVNFlag(kDependsOnGlobalVars);
SetDependsOnFlag(kGlobalVars);
}
virtual bool IsDeletable() const V8_OVERRIDE { return !RequiresHoleCheck(); }
......@@ -5376,8 +5355,8 @@ class HAllocate V8_FINAL : public HTemplateInstruction<2> {
SetOperandAt(1, size);
set_representation(Representation::Tagged());
SetFlag(kTrackSideEffectDominators);
SetGVNFlag(kChangesNewSpacePromotion);
SetGVNFlag(kDependsOnNewSpacePromotion);
SetChangesFlag(kNewSpacePromotion);
SetDependsOnFlag(kNewSpacePromotion);
if (FLAG_trace_pretenuring) {
PrintF("HAllocate with AllocationSite %p %s\n",
......@@ -5575,7 +5554,7 @@ class HStoreGlobalCell V8_FINAL : public HUnaryOperation {
: HUnaryOperation(value),
cell_(Unique<PropertyCell>::CreateUninitialized(cell)),
details_(details) {
SetGVNFlag(kChangesGlobalVars);
SetChangesFlag(kGlobalVars);
}
Unique<PropertyCell> cell_;
......@@ -5614,7 +5593,7 @@ class HLoadContextSlot V8_FINAL : public HUnaryOperation {
}
set_representation(Representation::Tagged());
SetFlag(kUseGVN);
SetGVNFlag(kDependsOnContextSlots);
SetDependsOnFlag(kContextSlots);
}
int slot_index() const { return slot_index_; }
......@@ -5698,7 +5677,7 @@ class HStoreContextSlot V8_FINAL : public HTemplateInstruction<2> {
: slot_index_(slot_index), mode_(mode) {
SetOperandAt(0, context);
SetOperandAt(1, value);
SetGVNFlag(kChangesContextSlots);
SetChangesFlag(kContextSlots);
}
int slot_index_;
......@@ -5976,7 +5955,7 @@ class HObjectAccess V8_FINAL {
return HObjectAccess(kInobject, GlobalObject::kNativeContextOffset);
}
void PrintTo(StringStream* stream);
void PrintTo(StringStream* stream) const;
inline bool Equals(HObjectAccess that) const {
return value_ == that.value_; // portion and offset must match
......@@ -5998,6 +5977,8 @@ class HObjectAccess V8_FINAL {
kExternalMemory // some field in external memory
};
HObjectAccess() : value_(0) {}
HObjectAccess(Portion portion, int offset,
Representation representation = Representation::Tagged(),
Handle<String> name = Handle<String>::null(),
......@@ -6030,6 +6011,7 @@ class HObjectAccess V8_FINAL {
friend class HLoadNamedField;
friend class HStoreNamedField;
friend class SideEffectsScope;
inline Portion portion() const {
return PortionField::decode(value_);
......@@ -6166,7 +6148,7 @@ class HLoadFunctionPrototype V8_FINAL : public HUnaryOperation {
: HUnaryOperation(function) {
set_representation(Representation::Tagged());
SetFlag(kUseGVN);
SetGVNFlag(kDependsOnCalls);
SetDependsOnFlag(kCalls);
}
};
......@@ -6311,10 +6293,10 @@ class HLoadKeyed V8_FINAL
set_representation(Representation::Tagged());
}
SetGVNFlag(kDependsOnArrayElements);
SetDependsOnFlag(kArrayElements);
} else {
set_representation(Representation::Double());
SetGVNFlag(kDependsOnDoubleArrayElements);
SetDependsOnFlag(kDoubleArrayElements);
}
} else {
if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
......@@ -6327,14 +6309,14 @@ class HLoadKeyed V8_FINAL
}
if (is_external()) {
SetGVNFlag(kDependsOnExternalMemory);
SetDependsOnFlag(kExternalMemory);
} else if (is_fixed_typed_array()) {
SetGVNFlag(kDependsOnTypedArrayElements);
SetDependsOnFlag(kTypedArrayElements);
} else {
UNREACHABLE();
}
// Native code could change the specialized array.
SetGVNFlag(kDependsOnCalls);
SetDependsOnFlag(kCalls);
}
SetFlag(kUseGVN);
......@@ -6458,7 +6440,7 @@ class HStoreNamedField V8_FINAL : public HTemplateInstruction<3> {
}
virtual bool HandleSideEffectDominator(GVNFlag side_effect,
HValue* dominator) V8_OVERRIDE {
ASSERT(side_effect == kChangesNewSpacePromotion);
ASSERT(side_effect == kNewSpacePromotion);
new_space_dominator_ = dominator;
return false;
}
......@@ -6690,7 +6672,7 @@ class HStoreKeyed V8_FINAL
virtual bool HandleSideEffectDominator(GVNFlag side_effect,
HValue* dominator) V8_OVERRIDE {
ASSERT(side_effect == kChangesNewSpacePromotion);
ASSERT(side_effect == kNewSpacePromotion);
new_space_dominator_ = dominator;
return false;
}
......@@ -6733,20 +6715,20 @@ class HStoreKeyed V8_FINAL
if (IsFastObjectElementsKind(elements_kind)) {
SetFlag(kTrackSideEffectDominators);
SetGVNFlag(kDependsOnNewSpacePromotion);
SetDependsOnFlag(kNewSpacePromotion);
}
if (is_external()) {
SetGVNFlag(kChangesExternalMemory);
SetChangesFlag(kExternalMemory);
SetFlag(kAllowUndefinedAsNaN);
} else if (IsFastDoubleElementsKind(elements_kind)) {
SetGVNFlag(kChangesDoubleArrayElements);
SetChangesFlag(kDoubleArrayElements);
} else if (IsFastSmiElementsKind(elements_kind)) {
SetGVNFlag(kChangesArrayElements);
SetChangesFlag(kArrayElements);
} else if (is_fixed_typed_array()) {
SetGVNFlag(kChangesTypedArrayElements);
SetChangesFlag(kTypedArrayElements);
SetFlag(kAllowUndefinedAsNaN);
} else {
SetGVNFlag(kChangesArrayElements);
SetChangesFlag(kArrayElements);
}
// EXTERNAL_{UNSIGNED_,}{BYTE,SHORT,INT}_ELEMENTS are truncating.
......@@ -6850,10 +6832,10 @@ class HTransitionElementsKind V8_FINAL : public HTemplateInstruction<2> {
SetOperandAt(0, object);
SetOperandAt(1, context);
SetFlag(kUseGVN);
SetGVNFlag(kChangesElementsKind);
SetChangesFlag(kElementsKind);
if (!IsSimpleMapChangeTransition(from_kind_, to_kind_)) {
SetGVNFlag(kChangesElementsPointer);
SetGVNFlag(kChangesNewSpacePromotion);
SetChangesFlag(kElementsPointer);
SetChangesFlag(kNewSpacePromotion);
}
set_representation(Representation::Tagged());
}
......@@ -6904,8 +6886,8 @@ class HStringAdd V8_FINAL : public HBinaryOperation {
flags_(flags), pretenure_flag_(pretenure_flag) {
set_representation(Representation::Tagged());
SetFlag(kUseGVN);
SetGVNFlag(kDependsOnMaps);
SetGVNFlag(kChangesNewSpacePromotion);
SetDependsOnFlag(kMaps);
SetChangesFlag(kNewSpacePromotion);
if (FLAG_trace_pretenuring) {
PrintF("HStringAdd with AllocationSite %p %s\n",
allocation_site.is_null()
......@@ -6956,9 +6938,9 @@ class HStringCharCodeAt V8_FINAL : public HTemplateInstruction<3> {
SetOperandAt(2, index);
set_representation(Representation::Integer32());
SetFlag(kUseGVN);
SetGVNFlag(kDependsOnMaps);
SetGVNFlag(kDependsOnStringChars);
SetGVNFlag(kChangesNewSpacePromotion);
SetDependsOnFlag(kMaps);
SetDependsOnFlag(kStringChars);
SetChangesFlag(kNewSpacePromotion);
}
// No side effects: runtime function assumes string + number inputs.
......@@ -6992,7 +6974,7 @@ class HStringCharFromCode V8_FINAL : public HTemplateInstruction<2> {
SetOperandAt(1, char_code);
set_representation(Representation::Tagged());
SetFlag(kUseGVN);
SetGVNFlag(kChangesNewSpacePromotion);
SetChangesFlag(kNewSpacePromotion);
}
virtual bool IsDeletable() const V8_OVERRIDE {
......@@ -7101,7 +7083,7 @@ class HFunctionLiteral V8_FINAL : public HTemplateInstruction<1> {
language_mode_(shared->language_mode()) {
SetOperandAt(0, context);
set_representation(Representation::Tagged());
SetGVNFlag(kChangesNewSpacePromotion);
SetChangesFlag(kNewSpacePromotion);
}
virtual bool IsDeletable() const V8_OVERRIDE { return true; }
......@@ -7172,7 +7154,7 @@ class HToFastProperties V8_FINAL : public HUnaryOperation {
private:
explicit HToFastProperties(HValue* value) : HUnaryOperation(value) {
set_representation(Representation::Tagged());
SetGVNFlag(kChangesNewSpacePromotion);
SetChangesFlag(kNewSpacePromotion);
// This instruction is not marked as kChangesMaps, but does
// change the map of the input operand. Use it only when creating
......@@ -7251,7 +7233,7 @@ class HSeqStringGetChar V8_FINAL : public HTemplateInstruction<2> {
SetOperandAt(1, index);
set_representation(Representation::Integer32());
SetFlag(kUseGVN);
SetGVNFlag(kDependsOnStringChars);
SetDependsOnFlag(kStringChars);
}
virtual bool IsDeletable() const V8_OVERRIDE { return true; }
......@@ -7290,7 +7272,7 @@ class HSeqStringSetChar V8_FINAL : public HTemplateInstruction<4> {
SetOperandAt(2, index);
SetOperandAt(3, value);
set_representation(Representation::Tagged());
SetGVNFlag(kChangesStringChars);
SetChangesFlag(kStringChars);
}
String::Encoding encoding_;
......@@ -7330,8 +7312,8 @@ class HCheckMapValue V8_FINAL : public HTemplateInstruction<2> {
SetOperandAt(1, map);
set_representation(Representation::Tagged());
SetFlag(kUseGVN);
SetGVNFlag(kDependsOnMaps);
SetGVNFlag(kDependsOnElementsKind);
SetDependsOnFlag(kMaps);
SetDependsOnFlag(kElementsKind);
}
};
......
......@@ -99,25 +99,25 @@ class HLoadEliminationTable : public ZoneObject {
break;
}
default: {
if (instr->CheckGVNFlag(kChangesInobjectFields)) {
if (instr->CheckChangesFlag(kInobjectFields)) {
TRACE((" kill-all i%d\n", instr->id()));
Kill();
break;
}
if (instr->CheckGVNFlag(kChangesMaps)) {
if (instr->CheckChangesFlag(kMaps)) {
TRACE((" kill-maps i%d\n", instr->id()));
KillOffset(JSObject::kMapOffset);
}
if (instr->CheckGVNFlag(kChangesElementsKind)) {
if (instr->CheckChangesFlag(kElementsKind)) {
TRACE((" kill-elements-kind i%d\n", instr->id()));
KillOffset(JSObject::kMapOffset);
KillOffset(JSObject::kElementsOffset);
}
if (instr->CheckGVNFlag(kChangesElementsPointer)) {
if (instr->CheckChangesFlag(kElementsPointer)) {
TRACE((" kill-elements i%d\n", instr->id()));
KillOffset(JSObject::kElementsOffset);
}
if (instr->CheckGVNFlag(kChangesOsrEntries)) {
if (instr->CheckChangesFlag(kOsrEntries)) {
TRACE((" kill-osr i%d\n", instr->id()));
Kill();
}
......@@ -454,11 +454,11 @@ class HLoadEliminationEffects : public ZoneObject {
elements_stored_ = true;
}
default: {
fields_stored_ |= instr->CheckGVNFlag(kChangesInobjectFields);
maps_stored_ |= instr->CheckGVNFlag(kChangesMaps);
maps_stored_ |= instr->CheckGVNFlag(kChangesElementsKind);
elements_stored_ |= instr->CheckGVNFlag(kChangesElementsKind);
elements_stored_ |= instr->CheckGVNFlag(kChangesElementsPointer);
fields_stored_ |= instr->CheckChangesFlag(kInobjectFields);
maps_stored_ |= instr->CheckChangesFlag(kMaps);
maps_stored_ |= instr->CheckChangesFlag(kElementsKind);
elements_stored_ |= instr->CheckChangesFlag(kElementsKind);
elements_stored_ |= instr->CheckChangesFlag(kElementsPointer);
}
}
}
......
......@@ -2174,7 +2174,7 @@ HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess(
// generated store code.
if ((elements_kind == FAST_HOLEY_ELEMENTS) ||
(elements_kind == FAST_ELEMENTS && access_type == STORE)) {
checked_object->ClearGVNFlag(kDependsOnElementsKind);
checked_object->ClearDependsOnFlag(kElementsKind);
}
bool fast_smi_only_elements = IsFastSmiElementsKind(elements_kind);
......@@ -2184,7 +2184,7 @@ HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess(
store_mode != STORE_NO_TRANSITION_HANDLE_COW) {
HCheckMaps* check_cow_map = Add<HCheckMaps>(
elements, isolate()->factory()->fixed_array_map(), top_info());
check_cow_map->ClearGVNFlag(kDependsOnElementsKind);
check_cow_map->ClearDependsOnFlag(kElementsKind);
}
HInstruction* length = NULL;
if (is_js_array) {
......@@ -2258,7 +2258,7 @@ HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess(
} else {
HCheckMaps* check_cow_map = Add<HCheckMaps>(
elements, isolate()->factory()->fixed_array_map(), top_info());
check_cow_map->ClearGVNFlag(kDependsOnElementsKind);
check_cow_map->ClearDependsOnFlag(kElementsKind);
}
}
}
......@@ -5309,7 +5309,7 @@ HInstruction* HOptimizedGraphBuilder::BuildStoreNamedField(
if (transition_to_field) {
HConstant* transition_constant = Add<HConstant>(info->transition());
instr->SetTransition(transition_constant, top_info());
instr->SetGVNFlag(kChangesMaps);
instr->SetChangesFlag(kMaps);
}
return instr;
}
......@@ -6208,7 +6208,7 @@ HInstruction* HOptimizedGraphBuilder::BuildMonomorphicElementAccess(
HCheckMaps* checked_object = Add<HCheckMaps>(object, map, top_info(),
dependency);
if (dependency) {
checked_object->ClearGVNFlag(kDependsOnElementsKind);
checked_object->ClearDependsOnFlag(kElementsKind);
}
if (access_type == STORE && map->prototype()->IsJSObject()) {
......@@ -6688,7 +6688,7 @@ HInstruction* HGraphBuilder::BuildConstantMapCheck(Handle<JSObject> constant,
AddInstruction(constant_value);
HCheckMaps* check =
Add<HCheckMaps>(constant_value, handle(constant->map()), info);
check->ClearGVNFlag(kDependsOnElementsKind);
check->ClearDependsOnFlag(kElementsKind);
return check;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment