[turbofan] Consider field name for aliasing.

In LoadElimination, don't consider two fields as potentially
aliasing if they have different names.

This gives another 5% boost on the Octane/DeltaBlue benchmark,
since the redundant loads and checks on the elms of the
OrderedCollection can be properly eliminated in the chainTest.

Bug: v8:5267
Change-Id: Id2dbb8cac02f9c95a85e5cc8acac3f66b679fd06
Reviewed-on: https://chromium-review.googlesource.com/620727
Reviewed-by: Jaroslav Sevcik <jarin@chromium.org>
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#47424}
This commit is contained in:
Benedikt Meurer 2017-08-18 13:11:10 +02:00 committed by Commit Bot
parent d8a939624e
commit 4dd3d0610b
2 changed files with 89 additions and 50 deletions

View File

@ -312,18 +312,32 @@ void LoadElimination::AbstractElements::Print() const {
Node* LoadElimination::AbstractField::Lookup(Node* object) const {
for (auto pair : info_for_node_) {
if (MustAlias(object, pair.first)) return pair.second;
if (MustAlias(object, pair.first)) return pair.second.value;
}
return nullptr;
}
namespace {
bool MayAlias(MaybeHandle<Name> x, MaybeHandle<Name> y) {
if (!x.address()) return true;
if (!y.address()) return true;
if (x.address() != y.address()) return false;
return true;
}
} // namespace
LoadElimination::AbstractField const* LoadElimination::AbstractField::Kill(
Node* object, Zone* zone) const {
Node* object, MaybeHandle<Name> name, Zone* zone) const {
for (auto pair : this->info_for_node_) {
if (MayAlias(object, pair.first)) {
AbstractField* that = new (zone) AbstractField(zone);
for (auto pair : this->info_for_node_) {
if (!MayAlias(object, pair.first)) that->info_for_node_.insert(pair);
if (!MayAlias(object, pair.first) ||
!MayAlias(name, pair.second.name)) {
that->info_for_node_.insert(pair);
}
}
return that;
}
@ -334,8 +348,8 @@ LoadElimination::AbstractField const* LoadElimination::AbstractField::Kill(
void LoadElimination::AbstractField::Print() const {
for (auto pair : info_for_node_) {
PrintF(" #%d:%s -> #%d:%s\n", pair.first->id(),
pair.first->op()->mnemonic(), pair.second->id(),
pair.second->op()->mnemonic());
pair.first->op()->mnemonic(), pair.second.value->id(),
pair.second.value->op()->mnemonic());
}
}
@ -525,20 +539,22 @@ LoadElimination::AbstractState::KillElement(Node* object, Node* index,
}
LoadElimination::AbstractState const* LoadElimination::AbstractState::AddField(
Node* object, size_t index, Node* value, Zone* zone) const {
Node* object, size_t index, Node* value, MaybeHandle<Name> name,
Zone* zone) const {
AbstractState* that = new (zone) AbstractState(*this);
if (that->fields_[index]) {
that->fields_[index] = that->fields_[index]->Extend(object, value, zone);
that->fields_[index] =
that->fields_[index]->Extend(object, value, name, zone);
} else {
that->fields_[index] = new (zone) AbstractField(object, value, zone);
that->fields_[index] = new (zone) AbstractField(object, value, name, zone);
}
return that;
}
LoadElimination::AbstractState const* LoadElimination::AbstractState::KillField(
Node* object, size_t index, Zone* zone) const {
Node* object, size_t index, MaybeHandle<Name> name, Zone* zone) const {
if (AbstractField const* this_field = this->fields_[index]) {
this_field = this_field->Kill(object, zone);
this_field = this_field->Kill(object, name, zone);
if (this->fields_[index] != this_field) {
AbstractState* that = new (zone) AbstractState(*this);
that->fields_[index] = this_field;
@ -549,17 +565,18 @@ LoadElimination::AbstractState const* LoadElimination::AbstractState::KillField(
}
LoadElimination::AbstractState const*
LoadElimination::AbstractState::KillFields(Node* object, Zone* zone) const {
LoadElimination::AbstractState::KillFields(Node* object, MaybeHandle<Name> name,
Zone* zone) const {
for (size_t i = 0;; ++i) {
if (i == arraysize(fields_)) return this;
if (AbstractField const* this_field = this->fields_[i]) {
AbstractField const* that_field = this_field->Kill(object, zone);
AbstractField const* that_field = this_field->Kill(object, name, zone);
if (that_field != this_field) {
AbstractState* that = new (zone) AbstractState(*this);
that->fields_[i] = that_field;
while (++i < arraysize(fields_)) {
if (this->fields_[i] != nullptr) {
that->fields_[i] = this->fields_[i]->Kill(object, zone);
that->fields_[i] = this->fields_[i]->Kill(object, name, zone);
}
}
return that;
@ -672,11 +689,11 @@ Reduction LoadElimination::ReduceEnsureWritableFastElements(Node* node) {
// We know that the resulting elements have the fixed array map.
state = state->AddMaps(node, fixed_array_maps, zone());
// Kill the previous elements on {object}.
state =
state->KillField(object, FieldIndexOf(JSObject::kElementsOffset), zone());
state = state->KillField(object, FieldIndexOf(JSObject::kElementsOffset),
MaybeHandle<Name>(), zone());
// Add the new elements on {object}.
state = state->AddField(object, FieldIndexOf(JSObject::kElementsOffset), node,
zone());
MaybeHandle<Name>(), zone());
return UpdateState(node, state);
}
@ -697,15 +714,15 @@ Reduction LoadElimination::ReduceMaybeGrowFastElements(Node* node) {
}
if (flags & GrowFastElementsFlag::kArrayObject) {
// Kill the previous Array::length on {object}.
state =
state->KillField(object, FieldIndexOf(JSArray::kLengthOffset), zone());
state = state->KillField(object, FieldIndexOf(JSArray::kLengthOffset),
factory()->length_string(), zone());
}
// Kill the previous elements on {object}.
state =
state->KillField(object, FieldIndexOf(JSObject::kElementsOffset), zone());
state = state->KillField(object, FieldIndexOf(JSObject::kElementsOffset),
MaybeHandle<Name>(), zone());
// Add the new elements on {object}.
state = state->AddField(object, FieldIndexOf(JSObject::kElementsOffset), node,
zone());
MaybeHandle<Name>(), zone());
return UpdateState(node, state);
}
@ -739,7 +756,7 @@ Reduction LoadElimination::ReduceTransitionElementsKind(Node* node) {
case ElementsTransition::kSlowTransition:
// Kill the elements as well.
state = state->KillField(object, FieldIndexOf(JSObject::kElementsOffset),
zone());
MaybeHandle<Name>(), zone());
break;
}
return UpdateState(node, state);
@ -764,8 +781,8 @@ Reduction LoadElimination::ReduceTransitionAndStoreElement(Node* node) {
state = state->AddMaps(object, object_maps, zone());
}
// Kill the elements as well.
state =
state->KillField(object, FieldIndexOf(JSObject::kElementsOffset), zone());
state = state->KillField(object, FieldIndexOf(JSObject::kElementsOffset),
MaybeHandle<Name>(), zone());
return UpdateState(node, state);
}
@ -800,7 +817,7 @@ Reduction LoadElimination::ReduceLoadField(Node* node) {
return Replace(replacement);
}
}
state = state->AddField(object, field_index, node, zone());
state = state->AddField(object, field_index, node, access.name, zone());
}
}
Handle<Map> field_map;
@ -838,11 +855,12 @@ Reduction LoadElimination::ReduceStoreField(Node* node) {
return Replace(effect);
}
// Kill all potentially aliasing fields and record the new value.
state = state->KillField(object, field_index, zone());
state = state->AddField(object, field_index, new_value, zone());
state = state->KillField(object, field_index, access.name, zone());
state =
state->AddField(object, field_index, new_value, access.name, zone());
} else {
// Unsupported StoreField operator.
state = state->KillFields(object, zone());
state = state->KillFields(object, access.name, zone());
}
}
return UpdateState(node, state);
@ -1032,19 +1050,22 @@ LoadElimination::AbstractState const* LoadElimination::ComputeLoopState(
switch (current->opcode()) {
case IrOpcode::kEnsureWritableFastElements: {
Node* const object = NodeProperties::GetValueInput(current, 0);
state = state->KillField(
object, FieldIndexOf(JSObject::kElementsOffset), zone());
state = state->KillField(object,
FieldIndexOf(JSObject::kElementsOffset),
MaybeHandle<Name>(), zone());
break;
}
case IrOpcode::kMaybeGrowFastElements: {
GrowFastElementsFlags flags =
GrowFastElementsFlagsOf(current->op());
Node* const object = NodeProperties::GetValueInput(current, 0);
state = state->KillField(
object, FieldIndexOf(JSObject::kElementsOffset), zone());
state = state->KillField(object,
FieldIndexOf(JSObject::kElementsOffset),
MaybeHandle<Name>(), zone());
if (flags & GrowFastElementsFlag::kArrayObject) {
state = state->KillField(
object, FieldIndexOf(JSArray::kLengthOffset), zone());
state =
state->KillField(object, FieldIndexOf(JSArray::kLengthOffset),
factory()->length_string(), zone());
}
break;
}
@ -1062,7 +1083,8 @@ LoadElimination::AbstractState const* LoadElimination::ComputeLoopState(
case ElementsTransition::kSlowTransition:
// Kill the elements as well.
state = state->KillField(
object, FieldIndexOf(JSObject::kElementsOffset), zone());
object, FieldIndexOf(JSObject::kElementsOffset),
MaybeHandle<Name>(), zone());
break;
}
}
@ -1073,8 +1095,9 @@ LoadElimination::AbstractState const* LoadElimination::ComputeLoopState(
// Invalidate what we know about the {object}s map.
state = state->KillMaps(object, zone());
// Kill the elements as well.
state = state->KillField(
object, FieldIndexOf(JSObject::kElementsOffset), zone());
state = state->KillField(object,
FieldIndexOf(JSObject::kElementsOffset),
MaybeHandle<Name>(), zone());
break;
}
case IrOpcode::kStoreField: {
@ -1086,9 +1109,10 @@ LoadElimination::AbstractState const* LoadElimination::ComputeLoopState(
} else {
int field_index = FieldIndexOf(access);
if (field_index < 0) {
state = state->KillFields(object, zone());
state = state->KillFields(object, access.name, zone());
} else {
state = state->KillField(object, field_index, zone());
state =
state->KillField(object, field_index, access.name, zone());
}
}
break;

View File

@ -130,19 +130,21 @@ class V8_EXPORT_PRIVATE LoadElimination final
class AbstractField final : public ZoneObject {
public:
explicit AbstractField(Zone* zone) : info_for_node_(zone) {}
AbstractField(Node* object, Node* value, Zone* zone)
AbstractField(Node* object, Node* value, MaybeHandle<Name> name, Zone* zone)
: info_for_node_(zone) {
info_for_node_.insert(std::make_pair(object, value));
info_for_node_.insert(std::make_pair(object, Field(value, name)));
}
AbstractField const* Extend(Node* object, Node* value, Zone* zone) const {
AbstractField const* Extend(Node* object, Node* value,
MaybeHandle<Name> name, Zone* zone) const {
AbstractField* that = new (zone) AbstractField(zone);
that->info_for_node_ = this->info_for_node_;
that->info_for_node_.insert(std::make_pair(object, value));
that->info_for_node_.insert(std::make_pair(object, Field(value, name)));
return that;
}
Node* Lookup(Node* object) const;
AbstractField const* Kill(Node* object, Zone* zone) const;
AbstractField const* Kill(Node* object, MaybeHandle<Name> name,
Zone* zone) const;
bool Equals(AbstractField const* that) const {
return this == that || this->info_for_node_ == that->info_for_node_;
}
@ -151,10 +153,10 @@ class V8_EXPORT_PRIVATE LoadElimination final
AbstractField* copy = new (zone) AbstractField(zone);
for (auto this_it : this->info_for_node_) {
Node* this_object = this_it.first;
Node* this_value = this_it.second;
Field this_second = this_it.second;
auto that_it = that->info_for_node_.find(this_object);
if (that_it != that->info_for_node_.end() &&
that_it->second == this_value) {
that_it->second == this_second) {
copy->info_for_node_.insert(this_it);
}
}
@ -164,7 +166,19 @@ class V8_EXPORT_PRIVATE LoadElimination final
void Print() const;
private:
ZoneMap<Node*, Node*> info_for_node_;
struct Field {
Field() {}
Field(Node* value, MaybeHandle<Name> name) : value(value), name(name) {}
bool operator==(const Field& other) const {
return value == other.value && name.address() == other.name.address();
}
Node* value = nullptr;
MaybeHandle<Name> name;
};
ZoneMap<Node*, Field> info_for_node_;
};
static size_t const kMaxTrackedFields = 32;
@ -229,10 +243,11 @@ class V8_EXPORT_PRIVATE LoadElimination final
bool LookupMaps(Node* object, ZoneHandleSet<Map>* object_maps) const;
AbstractState const* AddField(Node* object, size_t index, Node* value,
Zone* zone) const;
MaybeHandle<Name> name, Zone* zone) const;
AbstractState const* KillField(Node* object, size_t index,
Zone* zone) const;
AbstractState const* KillFields(Node* object, Zone* zone) const;
MaybeHandle<Name> name, Zone* zone) const;
AbstractState const* KillFields(Node* object, MaybeHandle<Name> name,
Zone* zone) const;
Node* LookupField(Node* object, size_t index) const;
AbstractState const* AddElement(Node* object, Node* index, Node* value,