| Index: src/compiler/typer.cc
|
| diff --git a/src/compiler/typer.cc b/src/compiler/typer.cc
|
| index 98cf98ac337a6a1325452742970fc56eba1d3906..22f2788f1ad3f5c7204bdd78a2272d9af4ff4d28 100644
|
| --- a/src/compiler/typer.cc
|
| +++ b/src/compiler/typer.cc
|
| @@ -10,6 +10,7 @@
|
| #include "src/compiler/common-operator.h"
|
| #include "src/compiler/graph-reducer.h"
|
| #include "src/compiler/js-operator.h"
|
| +#include "src/compiler/loop-variable-optimizer.h"
|
| #include "src/compiler/node-properties.h"
|
| #include "src/compiler/node.h"
|
| #include "src/compiler/operation-typer.h"
|
| @@ -77,8 +78,10 @@ Typer::~Typer() {
|
|
|
| class Typer::Visitor : public Reducer {
|
| public:
|
| - explicit Visitor(Typer* typer)
|
| - : typer_(typer), weakened_nodes_(typer->zone()) {}
|
| + explicit Visitor(Typer* typer, LoopVariableOptimizer* induction_vars)
|
| + : typer_(typer),
|
| + induction_vars_(induction_vars),
|
| + weakened_nodes_(typer->zone()) {}
|
|
|
| Reduction Reduce(Node* node) override {
|
| if (node->op()->ValueOutputCount() == 0) return NoChange();
|
| @@ -189,6 +192,7 @@ class Typer::Visitor : public Reducer {
|
|
|
| private:
|
| Typer* typer_;
|
| + LoopVariableOptimizer* induction_vars_;
|
| ZoneSet<NodeId> weakened_nodes_;
|
|
|
| #define DECLARE_METHOD(x) inline Type* Type##x(Node* node);
|
| @@ -308,18 +312,23 @@ class Typer::Visitor : public Reducer {
|
| }
|
| };
|
|
|
| +void Typer::Run() { Run(NodeVector(zone()), nullptr); }
|
|
|
| -void Typer::Run() { Run(NodeVector(zone())); }
|
| -
|
| -
|
| -void Typer::Run(const NodeVector& roots) {
|
| - Visitor visitor(this);
|
| +void Typer::Run(const NodeVector& roots,
|
| + LoopVariableOptimizer* induction_vars) {
|
| + if (induction_vars != nullptr) {
|
| + induction_vars->ChangeToInductionVariablePhis();
|
| + }
|
| + Visitor visitor(this, induction_vars);
|
| GraphReducer graph_reducer(zone(), graph());
|
| graph_reducer.AddReducer(&visitor);
|
| for (Node* const root : roots) graph_reducer.ReduceNode(root);
|
| graph_reducer.ReduceGraph();
|
| -}
|
|
|
| + if (induction_vars != nullptr) {
|
| + induction_vars->ChangeFromInductionVariablePhis();
|
| + }
|
| +}
|
|
|
| void Typer::Decorator::Decorate(Node* node) {
|
| if (node->op()->ValueOutputCount() > 0) {
|
| @@ -327,7 +336,7 @@ void Typer::Decorator::Decorate(Node* node) {
|
| // Other cases will generally require a proper fixpoint iteration with Run.
|
| bool is_typed = NodeProperties::IsTyped(node);
|
| if (is_typed || NodeProperties::AllValueInputsAreTyped(node)) {
|
| - Visitor typing(typer_);
|
| + Visitor typing(typer_, nullptr);
|
| Type* type = typing.TypeNode(node);
|
| if (is_typed) {
|
| type = Type::Intersect(type, NodeProperties::GetType(node),
|
| @@ -736,7 +745,6 @@ Type* Typer::Visitor::TypeSelect(Node* node) {
|
| return Type::Union(Operand(node, 1), Operand(node, 2), zone());
|
| }
|
|
|
| -
|
| Type* Typer::Visitor::TypePhi(Node* node) {
|
| int arity = node->op()->ValueInputCount();
|
| Type* type = Operand(node, 0);
|
| @@ -746,6 +754,89 @@ Type* Typer::Visitor::TypePhi(Node* node) {
|
| return type;
|
| }
|
|
|
| +Type* Typer::Visitor::TypeInductionVariablePhi(Node* node) {
|
| + int arity = NodeProperties::GetControlInput(node)->op()->ControlInputCount();
|
| + DCHECK_EQ(IrOpcode::kLoop, NodeProperties::GetControlInput(node)->opcode());
|
| + DCHECK_EQ(2, NodeProperties::GetControlInput(node)->InputCount());
|
| +
|
| + Type* initial_type = Operand(node, 0);
|
| + Type* increment_type = Operand(node, 2);
|
| +
|
| + // We only handle integer induction variables (otherwise ranges
|
| + // do not apply and we cannot do anything).
|
| + if (!initial_type->Is(typer_->cache_.kInteger) ||
|
| + !increment_type->Is(typer_->cache_.kInteger)) {
|
| + // Fallback to normal phi typing.
|
| + Type* type = Operand(node, 0);
|
| + for (int i = 1; i < arity; ++i) {
|
| + type = Type::Union(type, Operand(node, i), zone());
|
| + }
|
| + return type;
|
| + }
|
| + // If we do not have enough type information for the initial value or
|
| + // the increment, just return the initial value's type.
|
| + if (!initial_type->IsInhabited() || !increment_type->IsInhabited()) {
|
| + return initial_type;
|
| + }
|
| +
|
| + // Now process the bounds.
|
| + auto res = induction_vars_->induction_variables().find(node->id());
|
| + DCHECK(res != induction_vars_->induction_variables().end());
|
| + InductionVariable* induction_var = res->second;
|
| +
|
| + double min = -V8_INFINITY;
|
| + double max = V8_INFINITY;
|
| + if (increment_type->Min() >= 0) {
|
| + min = initial_type->Min();
|
| + for (auto bound : induction_var->upper_bounds()) {
|
| + Type* bound_type = TypeOrNone(bound.bound);
|
| + // If the type is not an integer, just skip the bound.
|
| + if (!bound_type->Is(typer_->cache_.kInteger)) continue;
|
| + // If the type is not inhabited, then we can take the initial value.
|
| + if (!bound_type->IsInhabited()) {
|
| + max = initial_type->Max();
|
| + break;
|
| + }
|
| + double bound_max = bound_type->Max();
|
| + if (bound.kind == InductionVariable::kStrict) {
|
| + bound_max -= 1;
|
| + }
|
| + max = std::min(max, bound_max + increment_type->Max());
|
| + }
|
| + // The upper bound must be at least the initial value's upper bound.
|
| + max = std::max(max, initial_type->Max());
|
| + } else if (increment_type->Max() <= 0) {
|
| + max = initial_type->Max();
|
| + for (auto bound : induction_var->lower_bounds()) {
|
| + Type* bound_type = TypeOrNone(bound.bound);
|
| + // If the type is not an integer, just skip the bound.
|
| + if (!bound_type->Is(typer_->cache_.kInteger)) continue;
|
| + // If the type is not inhabited, then we can take the initial value.
|
| + if (!bound_type->IsInhabited()) {
|
| + min = initial_type->Min();
|
| + break;
|
| + }
|
| + double bound_min = bound_type->Min();
|
| + if (bound.kind == InductionVariable::kStrict) {
|
| + bound_min += 1;
|
| + }
|
| + min = std::max(min, bound_min + increment_type->Min());
|
| + }
|
| + // The lower bound must be at most the initial value's lower bound.
|
| + min = std::min(min, initial_type->Min());
|
| + } else {
|
| + // Shortcut: If the increment can be both positive and negative,
|
| + // the variable can go arbitrarily far, so just return integer.
|
| + return typer_->cache_.kInteger;
|
| + }
|
| + if (FLAG_trace_turbo_loop) {
|
| + OFStream os(stdout);
|
| + os << "Loop (" << NodeProperties::GetControlInput(node)->id()
|
| + << ") variable bounds for phi " << node->id() << ": (" << min << ", "
|
| + << max << ")\n";
|
| + }
|
| + return Type::Range(min, max, typer_->zone());
|
| +}
|
|
|
| Type* Typer::Visitor::TypeEffectPhi(Node* node) {
|
| UNREACHABLE();
|
|
|