Commit 0d6aadb2 authored by Santiago Aboy Solanes's avatar Santiago Aboy Solanes Committed by Commit Bot

[cleanup] General cleanup of store-store-elimination.cc

Consistent naming, moved methods, etc.

There is a follow-up CL that moves code from this .cc to the private
part of the class in the .h file.

Bug: v8:9396
Change-Id: I9efac09baff7403bce1be9712c090d2ea70b60f6
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1748734Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Commit-Queue: Santiago Aboy Solanes <solanes@chromium.org>
Cr-Commit-Position: refs/heads/master@{#63203}
parent 1821aff2
...@@ -78,13 +78,14 @@ struct UnobservableStore { ...@@ -78,13 +78,14 @@ struct UnobservableStore {
NodeId id_; NodeId id_;
StoreOffset offset_; StoreOffset offset_;
bool operator==(const UnobservableStore) const; bool operator==(const UnobservableStore other) const {
bool operator<(const UnobservableStore) const; return (id_ == other.id_) && (offset_ == other.offset_);
}; }
} // namespace
namespace { bool operator<(const UnobservableStore other) const {
return (id_ < other.id_) || (id_ == other.id_ && offset_ < other.offset_);
}
};
// Instances of UnobservablesSet are immutable. They represent either a set of // Instances of UnobservablesSet are immutable. They represent either a set of
// UnobservableStores, or the "unvisited empty set". // UnobservableStores, or the "unvisited empty set".
...@@ -98,12 +99,11 @@ namespace { ...@@ -98,12 +99,11 @@ namespace {
// an UnobservablesSet allocates no memory. // an UnobservablesSet allocates no memory.
class UnobservablesSet final { class UnobservablesSet final {
public: public:
static UnobservablesSet Unvisited(); static UnobservablesSet Unvisited() { return UnobservablesSet(); }
static UnobservablesSet VisitedEmpty(Zone* zone); static UnobservablesSet VisitedEmpty(Zone* zone);
UnobservablesSet(); // unvisited
UnobservablesSet(const UnobservablesSet& other) V8_NOEXCEPT = default; UnobservablesSet(const UnobservablesSet& other) V8_NOEXCEPT = default;
UnobservablesSet Intersect(const UnobservablesSet& other,
UnobservablesSet Intersect(const UnobservablesSet& other, Zone* zone) const; const UnobservablesSet& empty, Zone* zone) const;
UnobservablesSet Add(UnobservableStore obs, Zone* zone) const; UnobservablesSet Add(UnobservableStore obs, Zone* zone) const;
UnobservablesSet RemoveSameOffset(StoreOffset off, Zone* zone) const; UnobservablesSet RemoveSameOffset(StoreOffset off, Zone* zone) const;
...@@ -115,19 +115,26 @@ class UnobservablesSet final { ...@@ -115,19 +115,26 @@ class UnobservablesSet final {
return set_ != nullptr && (set_->find(obs) != set_->end()); return set_ != nullptr && (set_->find(obs) != set_->end());
} }
bool operator==(const UnobservablesSet&) const; bool operator==(const UnobservablesSet& other) const {
bool operator!=(const UnobservablesSet&) const; if (IsUnvisited() || other.IsUnvisited()) {
return IsUnvisited() && other.IsUnvisited();
} else {
// Both pointers guaranteed not to be nullptrs.
return *set() == *(other.set());
}
}
bool operator!=(const UnobservablesSet& other) const {
return !(*this == other);
}
private: private:
UnobservablesSet();
explicit UnobservablesSet(const ZoneSet<UnobservableStore>* set) explicit UnobservablesSet(const ZoneSet<UnobservableStore>* set)
: set_(set) {} : set_(set) {}
const ZoneSet<UnobservableStore>* set_; const ZoneSet<UnobservableStore>* set_;
}; };
} // namespace
namespace {
class RedundantStoreFinder final { class RedundantStoreFinder final {
public: public:
RedundantStoreFinder(JSGraph* js_graph, TickCounter* tick_counter, RedundantStoreFinder(JSGraph* js_graph, TickCounter* tick_counter,
...@@ -226,7 +233,6 @@ void StoreStoreElimination::Run(JSGraph* js_graph, TickCounter* tick_counter, ...@@ -226,7 +233,6 @@ void StoreStoreElimination::Run(JSGraph* js_graph, TickCounter* tick_counter,
finder.Find(); finder.Find();
// Remove superfluous nodes // Remove superfluous nodes
for (Node* node : finder.to_remove_const()) { for (Node* node : finder.to_remove_const()) {
if (FLAG_trace_store_elimination) { if (FLAG_trace_store_elimination) {
PrintF("StoreStoreElimination::Run: Eliminating node #%d:%s\n", PrintF("StoreStoreElimination::Run: Eliminating node #%d:%s\n",
...@@ -241,7 +247,6 @@ void StoreStoreElimination::Run(JSGraph* js_graph, TickCounter* tick_counter, ...@@ -241,7 +247,6 @@ void StoreStoreElimination::Run(JSGraph* js_graph, TickCounter* tick_counter,
// Recompute unobservables-set for a node. Will also mark superfluous nodes // Recompute unobservables-set for a node. Will also mark superfluous nodes
// as to be removed. // as to be removed.
UnobservablesSet RedundantStoreFinder::RecomputeSet( UnobservablesSet RedundantStoreFinder::RecomputeSet(
Node* node, const UnobservablesSet& uses) { Node* node, const UnobservablesSet& uses) {
switch (node->op()->opcode()) { switch (node->op()->opcode()) {
...@@ -280,7 +285,6 @@ UnobservablesSet RedundantStoreFinder::RecomputeSet( ...@@ -280,7 +285,6 @@ UnobservablesSet RedundantStoreFinder::RecomputeSet(
loaded_from->id(), offset); loaded_from->id(), offset);
return uses.RemoveSameOffset(offset, temp_zone()); return uses.RemoveSameOffset(offset, temp_zone());
break;
} }
default: default:
if (CannotObserveStoreField(node)) { if (CannotObserveStoreField(node)) {
...@@ -335,13 +339,11 @@ void RedundantStoreFinder::Visit(Node* node) { ...@@ -335,13 +339,11 @@ void RedundantStoreFinder::Visit(Node* node) {
} }
} }
bool isEffectful = (node->op()->EffectInputCount() >= 1); bool is_effectful = node->op()->EffectInputCount() >= 1;
if (isEffectful) { if (is_effectful) {
VisitEffectfulNode(node); VisitEffectfulNode(node);
DCHECK(HasBeenVisited(node)); DCHECK(HasBeenVisited(node));
} } else if (!HasBeenVisited(node)) {
if (!HasBeenVisited(node)) {
// Mark as visited. // Mark as visited.
unobservable_for_id(node->id()) = unobservables_visited_empty_; unobservable_for_id(node->id()) = unobservables_visited_empty_;
} }
...@@ -357,7 +359,7 @@ void RedundantStoreFinder::VisitEffectfulNode(Node* node) { ...@@ -357,7 +359,7 @@ void RedundantStoreFinder::VisitEffectfulNode(Node* node) {
UnobservablesSet stored_for_node = unobservable_for_id(node->id()); UnobservablesSet stored_for_node = unobservable_for_id(node->id());
bool cur_set_changed = bool cur_set_changed =
(stored_for_node.IsUnvisited() || stored_for_node != before_set); stored_for_node.IsUnvisited() || stored_for_node != before_set;
if (!cur_set_changed) { if (!cur_set_changed) {
// We will not be able to update the part of this chain above any more. // We will not be able to update the part of this chain above any more.
// Exit. // Exit.
...@@ -380,76 +382,76 @@ void RedundantStoreFinder::VisitEffectfulNode(Node* node) { ...@@ -380,76 +382,76 @@ void RedundantStoreFinder::VisitEffectfulNode(Node* node) {
// //
// The result UnobservablesSet will always be visited. // The result UnobservablesSet will always be visited.
UnobservablesSet RedundantStoreFinder::RecomputeUseIntersection(Node* node) { UnobservablesSet RedundantStoreFinder::RecomputeUseIntersection(Node* node) {
// There were no effect uses.
if (node->op()->EffectOutputCount() == 0) {
IrOpcode::Value opcode = node->opcode();
// List of opcodes that may end this effect chain. The opcodes are not
// important to the soundness of this optimization; this serves as a
// general sanity check. Add opcodes to this list as it suits you.
//
// Everything is observable after these opcodes; return the empty set.
DCHECK_EXTRA(
opcode == IrOpcode::kReturn || opcode == IrOpcode::kTerminate ||
opcode == IrOpcode::kDeoptimize || opcode == IrOpcode::kThrow,
"for #%d:%s", node->id(), node->op()->mnemonic());
USE(opcode);
return unobservables_visited_empty_;
}
// {first} == true indicates that we haven't looked at any elements yet. // {first} == true indicates that we haven't looked at any elements yet.
// {first} == false indicates that cur_set is the intersection of at least one // {first} == false indicates that cur_set is the intersection of at least one
// thing. // thing.
bool first = true; bool first = true;
UnobservablesSet cur_set = UnobservablesSet::Unvisited(); // irrelevant UnobservablesSet cur_set = UnobservablesSet::Unvisited(); // irrelevant
for (Edge edge : node->use_edges()) { for (Edge edge : node->use_edges()) {
// Skip non-effect edges // Skip non-effect edges
if (!NodeProperties::IsEffectEdge(edge)) { if (!NodeProperties::IsEffectEdge(edge)) {
continue; continue;
} }
// Intersect with the new use node.
Node* use = edge.from(); Node* use = edge.from();
UnobservablesSet new_set = unobservable_for_id(use->id()); UnobservablesSet new_set = unobservable_for_id(use->id());
// Include new_set in the intersection.
if (first) { if (first) {
// Intersection of a one-element set is that one element
first = false; first = false;
cur_set = new_set; cur_set = new_set;
} else { if (cur_set.IsUnvisited()) {
// Take the intersection of cur_set and new_set. cur_set = unobservables_visited_empty_;
cur_set = cur_set.Intersect(new_set, temp_zone());
} }
} else {
cur_set =
cur_set.Intersect(new_set, unobservables_visited_empty_, temp_zone());
} }
if (first) { // Break fast for the empty set since the intersection will always be empty.
// There were no effect uses. if (cur_set.IsEmpty()) {
auto opcode = node->op()->opcode(); break;
// List of opcodes that may end this effect chain. The opcodes are not }
// important to the soundness of this optimization; this serves as a
// general sanity check. Add opcodes to this list as it suits you.
//
// Everything is observable after these opcodes; return the empty set.
DCHECK_EXTRA(
opcode == IrOpcode::kReturn || opcode == IrOpcode::kTerminate ||
opcode == IrOpcode::kDeoptimize || opcode == IrOpcode::kThrow,
"for #%d:%s", node->id(), node->op()->mnemonic());
USE(opcode); // silence warning about unused variable in release mode
return unobservables_visited_empty_;
} else {
if (cur_set.IsUnvisited()) {
cur_set = unobservables_visited_empty_;
} }
DCHECK(!cur_set.IsUnvisited());
return cur_set; return cur_set;
}
} }
UnobservablesSet UnobservablesSet::Unvisited() { return UnobservablesSet(); }
UnobservablesSet::UnobservablesSet() : set_(nullptr) {} UnobservablesSet::UnobservablesSet() : set_(nullptr) {}
// Create a new empty UnobservablesSet. This allocates in the zone, and
// can probably be optimized to use a global singleton.
UnobservablesSet UnobservablesSet::VisitedEmpty(Zone* zone) { UnobservablesSet UnobservablesSet::VisitedEmpty(Zone* zone) {
// Create a new empty UnobservablesSet. This allocates in the zone, and
// can probably be optimized to use a global singleton.
ZoneSet<UnobservableStore>* empty_set = ZoneSet<UnobservableStore>* empty_set =
new (zone->New(sizeof(ZoneSet<UnobservableStore>))) new (zone->New(sizeof(ZoneSet<UnobservableStore>)))
ZoneSet<UnobservableStore>(zone); ZoneSet<UnobservableStore>(zone);
return UnobservablesSet(empty_set); return UnobservablesSet(empty_set);
} }
// Computes the intersection of two UnobservablesSets. May return // Computes the intersection of two UnobservablesSets. If one of the sets is
// UnobservablesSet::Unvisited() instead of an empty UnobservablesSet for // empty, will return empty.
// speed.
UnobservablesSet UnobservablesSet::Intersect(const UnobservablesSet& other, UnobservablesSet UnobservablesSet::Intersect(const UnobservablesSet& other,
const UnobservablesSet& empty,
Zone* zone) const { Zone* zone) const {
if (IsEmpty() || other.IsEmpty()) { if (IsEmpty() || other.IsEmpty()) {
return Unvisited(); return empty;
} else { } else {
ZoneSet<UnobservableStore>* intersection = ZoneSet<UnobservableStore>* intersection =
new (zone->New(sizeof(ZoneSet<UnobservableStore>))) new (zone->New(sizeof(ZoneSet<UnobservableStore>)))
...@@ -465,8 +467,8 @@ UnobservablesSet UnobservablesSet::Intersect(const UnobservablesSet& other, ...@@ -465,8 +467,8 @@ UnobservablesSet UnobservablesSet::Intersect(const UnobservablesSet& other,
UnobservablesSet UnobservablesSet::Add(UnobservableStore obs, UnobservablesSet UnobservablesSet::Add(UnobservableStore obs,
Zone* zone) const { Zone* zone) const {
bool present = (set()->find(obs) != set()->end()); bool found = set()->find(obs) != set()->end();
if (present) { if (found) {
return *this; return *this;
} else { } else {
// Make a new empty set. // Make a new empty set.
...@@ -500,29 +502,6 @@ UnobservablesSet UnobservablesSet::RemoveSameOffset(StoreOffset offset, ...@@ -500,29 +502,6 @@ UnobservablesSet UnobservablesSet::RemoveSameOffset(StoreOffset offset,
return UnobservablesSet(new_set); return UnobservablesSet(new_set);
} }
// Used for debugging.
bool UnobservablesSet::operator==(const UnobservablesSet& other) const {
if (IsUnvisited() || other.IsUnvisited()) {
return IsEmpty() && other.IsEmpty();
} else {
// Both pointers guaranteed not to be nullptrs.
return *set() == *other.set();
}
}
bool UnobservablesSet::operator!=(const UnobservablesSet& other) const {
return !(*this == other);
}
bool UnobservableStore::operator==(const UnobservableStore other) const {
return (id_ == other.id_) && (offset_ == other.offset_);
}
bool UnobservableStore::operator<(const UnobservableStore other) const {
return (id_ < other.id_) || (id_ == other.id_ && offset_ < other.offset_);
}
#undef TRACE #undef TRACE
#undef CHECK_EXTRA #undef CHECK_EXTRA
#undef DCHECK_EXTRA #undef DCHECK_EXTRA
......
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