Commit 630a992b authored by Tobias Tebbi's avatar Tobias Tebbi Committed by Commit Bot

[turbofan] refactor BranchElimination to use a generic stack implementation

Bug: 
Change-Id: Ibd91a61a9fd4b673db1afe13936d68a2b4a096cd
Reviewed-on: https://chromium-review.googlesource.com/892058
Commit-Queue: Tobias Tebbi <tebbi@chromium.org>
Reviewed-by: 's avatarJaroslav Sevcik <jarin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#50983}
parent 007a7354
This diff is collapsed.
......@@ -7,6 +7,7 @@
#include "src/base/compiler-specific.h"
#include "src/compiler/graph-reducer.h"
#include "src/compiler/node-aux-data.h"
#include "src/globals.h"
namespace v8 {
......@@ -17,6 +18,110 @@ namespace compiler {
class CommonOperatorBuilder;
class JSGraph;
// A generic stack implemented as a purely functional singly-linked list, which
// results in an O(1) copy operation. It is the equivalent of functional lists
// in ML-like languages, with the only difference that it also caches the length
// of the list in each node.
// TODO(tebbi): Use this implementation also for RedundancyElimination.
template <class A>
class FunctionalList {
private:
struct Cons : ZoneObject {
Cons(A top, Cons* rest)
: top(std::move(top)), rest(rest), size(1 + (rest ? rest->size : 0)) {}
A const top;
Cons* const rest;
size_t const size;
};
public:
FunctionalList() : elements_(nullptr) {}
bool operator==(const FunctionalList<A>& other) const {
if (Size() != other.Size()) return false;
iterator it = begin();
iterator other_it = other.begin();
while (true) {
if (it == other_it) return true;
if (*it != *other_it) return false;
++it;
++other_it;
}
}
bool operator!=(const FunctionalList<A>& other) const {
return !(*this == other);
}
const A& Front() const {
DCHECK_GT(Size(), 0);
return elements_->top;
}
FunctionalList Rest() const {
FunctionalList result = *this;
result.DropFront();
return result;
}
void DropFront() {
CHECK_GT(Size(), 0);
elements_ = elements_->rest;
}
void PushFront(A a, Zone* zone) {
elements_ = new (zone) Cons(std::move(a), elements_);
}
// If {hint} happens to be exactly what we want to allocate, avoid allocation
// by reusing {hint}.
void PushFront(A a, Zone* zone, FunctionalList hint) {
if (hint.Size() == Size() + 1 && hint.Front() == a &&
hint.Rest() == *this) {
*this = hint;
} else {
PushFront(a, zone);
}
}
// Drop elements until the current stack is equal to the tail shared with
// {other}. The shared tail must not only be equal, but also refer to the
// same memory.
void ResetToCommonAncestor(FunctionalList other) {
while (other.Size() > Size()) other.DropFront();
while (other.Size() < Size()) DropFront();
while (elements_ != other.elements_) {
DropFront();
other.DropFront();
}
}
size_t Size() const { return elements_ ? elements_->size : 0; }
class iterator {
public:
explicit iterator(Cons* cur) : current_(cur) {}
const A& operator*() const { return current_->top; }
iterator& operator++() {
current_ = current_->rest;
return *this;
}
bool operator==(const iterator& other) const {
return this->current_ == other.current_;
}
bool operator!=(const iterator& other) const { return !(*this == other); }
private:
Cons* current_;
};
iterator begin() const { return iterator(elements_); }
iterator end() const { return iterator(nullptr); }
private:
Cons* elements_;
};
class V8_EXPORT_PRIVATE BranchElimination final
: public NON_EXPORTED_BASE(AdvancedReducer) {
public:
......@@ -31,55 +136,24 @@ class V8_EXPORT_PRIVATE BranchElimination final
struct BranchCondition {
Node* condition;
bool is_true;
BranchCondition* next;
BranchCondition(Node* condition, bool is_true, BranchCondition* next)
: condition(condition), is_true(is_true), next(next) {}
bool operator==(BranchCondition other) const {
return condition == other.condition && is_true == other.is_true;
}
bool operator!=(BranchCondition other) const { return !(*this == other); }
};
// Class for tracking information about branch conditions.
// At the moment it is a linked list of conditions and their values
// (true or false).
class ControlPathConditions {
class ControlPathConditions : public FunctionalList<BranchCondition> {
public:
Maybe<bool> LookupCondition(Node* condition) const;
const ControlPathConditions* AddCondition(Zone* zone, Node* condition,
bool is_true) const;
static const ControlPathConditions* Empty(Zone* zone);
void Merge(const ControlPathConditions& other);
bool IsSamePath(BranchCondition* first, BranchCondition* second) const;
bool EqualsAfterAddingCondition(const ControlPathConditions* other,
const Node* new_condition,
bool new_branch_condition) const;
bool operator==(const ControlPathConditions& other) const;
bool operator!=(const ControlPathConditions& other) const {
return !(*this == other);
}
private:
ControlPathConditions(BranchCondition* head, size_t condition_count)
: head_(head), condition_count_(condition_count) {}
BranchCondition* head_;
// We keep track of the list length so that we can find the longest
// common tail easily.
size_t condition_count_;
};
// Maps each control node to the condition information known about the node.
// If the information is nullptr, then we have not calculated the information
// yet.
class PathConditionsForControlNodes {
public:
PathConditionsForControlNodes(Zone* zone, size_t size_hint)
: info_for_node_(size_hint, nullptr, zone) {}
const ControlPathConditions* Get(Node* node) const;
void Set(Node* node, const ControlPathConditions* conditions);
void AddCondition(Zone* zone, Node* condition, bool is_true,
ControlPathConditions hint);
private:
ZoneVector<const ControlPathConditions*> info_for_node_;
using FunctionalList<BranchCondition>::PushFront;
};
Reduction ReduceBranch(Node* node);
......@@ -91,10 +165,8 @@ class V8_EXPORT_PRIVATE BranchElimination final
Reduction ReduceOtherControl(Node* node);
Reduction TakeConditionsFromFirstControl(Node* node);
Reduction UpdateConditions(Node* node,
const ControlPathConditions* conditions);
Reduction UpdateConditions(Node* node,
const ControlPathConditions* prev_conditions,
Reduction UpdateConditions(Node* node, ControlPathConditions conditions);
Reduction UpdateConditions(Node* node, ControlPathConditions prev_conditions,
Node* current_condition, bool is_true_branch);
Node* dead() const { return dead_; }
......@@ -103,7 +175,12 @@ class V8_EXPORT_PRIVATE BranchElimination final
CommonOperatorBuilder* common() const;
JSGraph* const jsgraph_;
PathConditionsForControlNodes node_conditions_;
// Maps each control node to the condition information known about the node.
// If the information is nullptr, then we have not calculated the information
// yet.
NodeAuxData<ControlPathConditions> node_conditions_;
NodeAuxData<bool> reduced_;
Zone* zone_;
Node* dead_;
};
......
......@@ -15,15 +15,27 @@ namespace compiler {
// Forward declarations.
class Node;
template <class T, T def()>
template <class T>
T DefaultConstruct() {
return T();
}
template <class T, T def() = DefaultConstruct<T>>
class NodeAuxData {
public:
explicit NodeAuxData(Zone* zone) : aux_data_(zone) {}
explicit NodeAuxData(size_t initial_size, Zone* zone)
: aux_data_(initial_size, zone) {}
void Set(Node* node, T const& data) {
// Update entry. Returns true iff entry was changed.
bool Set(Node* node, T const& data) {
size_t const id = node->id();
if (id >= aux_data_.size()) aux_data_.resize(id + 1, def());
aux_data_[id] = data;
if (aux_data_[id] != data) {
aux_data_[id] = data;
return true;
}
return false;
}
T Get(Node* node) const {
......
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