Merge V8 5.3.332.45.  DO NOT MERGE

Test: Manual

FPIIM-449

Change-Id: Id3254828b068abdea3cb10442e0172a8c9a98e03
(cherry picked from commit 13e2dadd00298019ed862f2b2fc5068bba730bcf)
diff --git a/src/compiler/simplified-lowering.cc b/src/compiler/simplified-lowering.cc
index a76d3e2..c56494c 100644
--- a/src/compiler/simplified-lowering.cc
+++ b/src/compiler/simplified-lowering.cc
@@ -15,6 +15,7 @@
 #include "src/compiler/linkage.h"
 #include "src/compiler/node-matchers.h"
 #include "src/compiler/node-properties.h"
+#include "src/compiler/operation-typer.h"
 #include "src/compiler/operator-properties.h"
 #include "src/compiler/representation-change.h"
 #include "src/compiler/simplified-operator.h"
@@ -62,63 +63,6 @@
 
 namespace {
 
-// The {UseInfo} class is used to describe a use of an input of a node.
-//
-// This information is used in two different ways, based on the phase:
-//
-// 1. During propagation, the use info is used to inform the input node
-//    about what part of the input is used (we call this truncation) and what
-//    is the preferred representation.
-//
-// 2. During lowering, the use info is used to properly convert the input
-//    to the preferred representation. The preferred representation might be
-//    insufficient to do the conversion (e.g. word32->float64 conv), so we also
-//    need the signedness information to produce the correct value.
-class UseInfo {
- public:
-  UseInfo(MachineRepresentation preferred, Truncation truncation)
-      : preferred_(preferred), truncation_(truncation) {}
-  static UseInfo TruncatingWord32() {
-    return UseInfo(MachineRepresentation::kWord32, Truncation::Word32());
-  }
-  static UseInfo TruncatingWord64() {
-    return UseInfo(MachineRepresentation::kWord64, Truncation::Word64());
-  }
-  static UseInfo Bool() {
-    return UseInfo(MachineRepresentation::kBit, Truncation::Bool());
-  }
-  static UseInfo TruncatingFloat32() {
-    return UseInfo(MachineRepresentation::kFloat32, Truncation::Float32());
-  }
-  static UseInfo TruncatingFloat64() {
-    return UseInfo(MachineRepresentation::kFloat64, Truncation::Float64());
-  }
-  static UseInfo PointerInt() {
-    return kPointerSize == 4 ? TruncatingWord32() : TruncatingWord64();
-  }
-  static UseInfo AnyTagged() {
-    return UseInfo(MachineRepresentation::kTagged, Truncation::Any());
-  }
-
-  // Undetermined representation.
-  static UseInfo Any() {
-    return UseInfo(MachineRepresentation::kNone, Truncation::Any());
-  }
-  static UseInfo None() {
-    return UseInfo(MachineRepresentation::kNone, Truncation::None());
-  }
-  static UseInfo AnyTruncatingToBool() {
-    return UseInfo(MachineRepresentation::kNone, Truncation::Bool());
-  }
-
-  MachineRepresentation preferred() const { return preferred_; }
-  Truncation truncation() const { return truncation_; }
-
- private:
-  MachineRepresentation preferred_;
-  Truncation truncation_;
-};
-
 
 UseInfo TruncatingUseInfoFromRepresentation(MachineRepresentation rep) {
   switch (rep) {
@@ -223,7 +167,8 @@
   ZoneVector<UseInfo> input_use_infos_;
 
   static bool IsUseLessGeneral(UseInfo use1, UseInfo use2) {
-    return MachineRepresentationIsSubtype(use1.preferred(), use2.preferred()) &&
+    return MachineRepresentationIsSubtype(use1.representation(),
+                                          use2.representation()) &&
            use1.truncation().IsLessGeneralThan(use2.truncation());
   }
 };
@@ -246,27 +191,43 @@
       return truncation_ != old_truncation;
     }
 
-    void set_queued(bool value) { queued_ = value; }
-    bool queued() const { return queued_; }
-    void set_visited() { visited_ = true; }
-    bool visited() const { return visited_; }
+    void set_queued() { state_ = kQueued; }
+    void set_visited() { state_ = kVisited; }
+    void set_pushed() { state_ = kPushed; }
+    void reset_state() { state_ = kUnvisited; }
+    bool visited() const { return state_ == kVisited; }
+    bool queued() const { return state_ == kQueued; }
+    bool unvisited() const { return state_ == kUnvisited; }
     Truncation truncation() const { return truncation_; }
     void set_output(MachineRepresentation output) { representation_ = output; }
 
     MachineRepresentation representation() const { return representation_; }
 
+    // Helpers for feedback typing.
+    void set_feedback_type(Type* type) { feedback_type_ = type; }
+    Type* feedback_type() { return feedback_type_; }
+    void set_weakened() { weakened_ = true; }
+    bool weakened() { return weakened_; }
+    TypeCheckKind type_check() { return type_check_; }
+    void set_type_check(TypeCheckKind type_check) { type_check_ = type_check; }
+
    private:
-    bool queued_ = false;   // Bookkeeping for the traversal.
-    bool visited_ = false;  // Bookkeeping for the traversal.
+    enum State : uint8_t { kUnvisited, kPushed, kVisited, kQueued };
+    State state_ = kUnvisited;
     MachineRepresentation representation_ =
         MachineRepresentation::kNone;             // Output representation.
     Truncation truncation_ = Truncation::None();  // Information about uses.
+    TypeCheckKind type_check_ = TypeCheckKind::kNone;  // Runtime check kind.
+
+    Type* feedback_type_ = nullptr;
+    bool weakened_ = false;
   };
 
   RepresentationSelector(JSGraph* jsgraph, Zone* zone,
                          RepresentationChanger* changer,
                          SourcePositionTable* source_positions)
       : jsgraph_(jsgraph),
+        zone_(zone),
         count_(jsgraph->graph()->NodeCount()),
         info_(count_, zone),
 #ifdef DEBUG
@@ -277,11 +238,320 @@
         phase_(PROPAGATE),
         changer_(changer),
         queue_(zone),
+        typing_stack_(zone),
         source_positions_(source_positions),
-        type_cache_(TypeCache::Get()) {
+        type_cache_(TypeCache::Get()),
+        op_typer_(jsgraph->isolate(), graph_zone()) {
   }
 
-  void Run(SimplifiedLowering* lowering) {
+  // Forward propagation of types from type feedback.
+  void RunTypePropagationPhase() {
+    DCHECK(typing_stack_.empty());
+
+    typing_stack_.push({graph()->end(), 0});
+    GetInfo(graph()->end())->set_pushed();
+    while (!typing_stack_.empty()) {
+      NodeState& current = typing_stack_.top();
+
+      // If there is an unvisited input, push it and continue.
+      bool pushed_unvisited = false;
+      while (current.input_index < current.node->InputCount()) {
+        Node* input = current.node->InputAt(current.input_index);
+        NodeInfo* input_info = GetInfo(input);
+        current.input_index++;
+        if (input_info->unvisited()) {
+          input_info->set_pushed();
+          typing_stack_.push({input, 0});
+          pushed_unvisited = true;
+          break;
+        }
+      }
+      if (pushed_unvisited) continue;
+
+      // Process the top of the stack.
+      Node* node = current.node;
+      typing_stack_.pop();
+      NodeInfo* info = GetInfo(node);
+      info->set_visited();
+      bool updated = UpdateFeedbackType(node);
+      if (updated) {
+        for (Node* const user : node->uses()) {
+          if (GetInfo(user)->visited()) {
+            GetInfo(user)->set_queued();
+            queue_.push(user);
+          }
+        }
+      }
+    }
+
+    // Process the revisit queue.
+    while (!queue_.empty()) {
+      Node* node = queue_.front();
+      queue_.pop();
+      NodeInfo* info = GetInfo(node);
+      info->set_visited();
+      bool updated = UpdateFeedbackType(node);
+      if (updated) {
+        for (Node* const user : node->uses()) {
+          if (GetInfo(user)->visited()) {
+            GetInfo(user)->set_queued();
+            queue_.push(user);
+          }
+        }
+      }
+    }
+  }
+
+  void ResetNodeInfoState() {
+    // Clean up for the next phase.
+    for (NodeInfo& info : info_) {
+      info.reset_state();
+    }
+  }
+
+  Type* TypeOf(Node* node) {
+    Type* type = GetInfo(node)->feedback_type();
+    return type == nullptr ? NodeProperties::GetType(node) : type;
+  }
+
+  Type* FeedbackTypeOf(Node* node) {
+    Type* type = GetInfo(node)->feedback_type();
+    return type == nullptr ? Type::None() : type;
+  }
+
+  Type* TypePhi(Node* node) {
+    int arity = node->op()->ValueInputCount();
+    Type* type = FeedbackTypeOf(node->InputAt(0));
+    for (int i = 1; i < arity; ++i) {
+      type = op_typer_.Merge(type, FeedbackTypeOf(node->InputAt(i)));
+    }
+    return type;
+  }
+
+  Type* TypeSelect(Node* node) {
+    return op_typer_.Merge(FeedbackTypeOf(node->InputAt(1)),
+                           FeedbackTypeOf(node->InputAt(2)));
+  }
+
+  static Type* TypeOfSpeculativeOp(TypeCheckKind type_check) {
+    switch (type_check) {
+      case TypeCheckKind::kNone:
+        return Type::Any();
+      case TypeCheckKind::kSigned32:
+        return Type::Signed32();
+      case TypeCheckKind::kNumber:
+        return Type::Number();
+      // Unexpected cases.
+      case TypeCheckKind::kNumberOrUndefined:
+        FATAL("Unexpected checked type.");
+        break;
+    }
+    UNREACHABLE();
+    return nullptr;
+  }
+
+  bool UpdateFeedbackType(Node* node) {
+    if (node->op()->ValueOutputCount() == 0) return false;
+
+    NodeInfo* info = GetInfo(node);
+    Type* type = info->feedback_type();
+    Type* new_type = type;
+
+    switch (node->opcode()) {
+      case IrOpcode::kSpeculativeNumberAdd: {
+        Type* lhs = FeedbackTypeOf(node->InputAt(0));
+        Type* rhs = FeedbackTypeOf(node->InputAt(1));
+        if (lhs->Is(Type::None()) || rhs->Is(Type::None())) return false;
+        // TODO(jarin) The ToNumber conversion is too conservative here,
+        // e.g. it will treat true as 1 even though the number check will
+        // fail on a boolean. OperationTyper should have a function that
+        // computes a more precise type.
+        lhs = op_typer_.ToNumber(lhs);
+        rhs = op_typer_.ToNumber(rhs);
+        Type* static_type = op_typer_.NumericAdd(lhs, rhs);
+        if (info->type_check() == TypeCheckKind::kNone) {
+          new_type = static_type;
+        } else {
+          Type* feedback_type = TypeOfSpeculativeOp(info->type_check());
+          new_type = Type::Intersect(static_type, feedback_type, graph_zone());
+        }
+        break;
+      }
+
+      case IrOpcode::kSpeculativeNumberSubtract: {
+        Type* lhs = FeedbackTypeOf(node->InputAt(0));
+        Type* rhs = FeedbackTypeOf(node->InputAt(1));
+        if (lhs->Is(Type::None()) || rhs->Is(Type::None())) return false;
+        // TODO(jarin) The ToNumber conversion is too conservative here,
+        // e.g. it will treat true as 1 even though the number check will
+        // fail on a boolean. OperationTyper should have a function that
+        // computes a more precise type.
+        lhs = op_typer_.ToNumber(lhs);
+        rhs = op_typer_.ToNumber(rhs);
+        Type* static_type = op_typer_.NumericSubtract(lhs, rhs);
+        if (info->type_check() == TypeCheckKind::kNone) {
+          new_type = static_type;
+        } else {
+          Type* feedback_type = TypeOfSpeculativeOp(info->type_check());
+          new_type = Type::Intersect(static_type, feedback_type, graph_zone());
+        }
+        break;
+      }
+
+      case IrOpcode::kSpeculativeNumberMultiply: {
+        Type* lhs = FeedbackTypeOf(node->InputAt(0));
+        Type* rhs = FeedbackTypeOf(node->InputAt(1));
+        if (lhs->Is(Type::None()) || rhs->Is(Type::None())) return false;
+        // TODO(jarin) The ToNumber conversion is too conservative here,
+        // e.g. it will treat true as 1 even though the number check will
+        // fail on a boolean. OperationTyper should have a function that
+        // computes a more precise type.
+        lhs = op_typer_.ToNumber(lhs);
+        rhs = op_typer_.ToNumber(rhs);
+        Type* static_type = op_typer_.NumericMultiply(lhs, rhs);
+        if (info->type_check() == TypeCheckKind::kNone) {
+          new_type = static_type;
+        } else {
+          Type* feedback_type = TypeOfSpeculativeOp(info->type_check());
+          new_type = Type::Intersect(static_type, feedback_type, graph_zone());
+        }
+        break;
+      }
+
+      case IrOpcode::kSpeculativeNumberDivide: {
+        Type* lhs = FeedbackTypeOf(node->InputAt(0));
+        Type* rhs = FeedbackTypeOf(node->InputAt(1));
+        if (lhs->Is(Type::None()) || rhs->Is(Type::None())) return false;
+        // TODO(jarin) The ToNumber conversion is too conservative here,
+        // e.g. it will treat true as 1 even though the number check will
+        // fail on a boolean. OperationTyper should have a function that
+        // computes a more precise type.
+        lhs = op_typer_.ToNumber(lhs);
+        rhs = op_typer_.ToNumber(rhs);
+        Type* static_type = op_typer_.NumericDivide(lhs, rhs);
+        if (info->type_check() == TypeCheckKind::kNone) {
+          new_type = static_type;
+        } else {
+          Type* feedback_type = TypeOfSpeculativeOp(info->type_check());
+          new_type = Type::Intersect(static_type, feedback_type, graph_zone());
+        }
+        break;
+      }
+
+      case IrOpcode::kSpeculativeNumberModulus: {
+        Type* lhs = FeedbackTypeOf(node->InputAt(0));
+        Type* rhs = FeedbackTypeOf(node->InputAt(1));
+        if (lhs->Is(Type::None()) || rhs->Is(Type::None())) return false;
+        // TODO(jarin) The ToNumber conversion is too conservative here,
+        // e.g. it will treat true as 1 even though the number check will
+        // fail on a boolean. OperationTyper should have a function that
+        // computes a more precise type.
+        lhs = op_typer_.ToNumber(lhs);
+        rhs = op_typer_.ToNumber(rhs);
+        Type* static_type = op_typer_.NumericModulus(lhs, rhs);
+        if (info->type_check() == TypeCheckKind::kNone) {
+          new_type = static_type;
+        } else {
+          Type* feedback_type = TypeOfSpeculativeOp(info->type_check());
+          new_type = Type::Intersect(static_type, feedback_type, graph_zone());
+        }
+        break;
+      }
+
+      case IrOpcode::kPhi: {
+        new_type = TypePhi(node);
+        if (type != nullptr) {
+          new_type = Weaken(node, type, new_type);
+        }
+        // Recompute the phi representation based on the new type.
+        MachineRepresentation output =
+            GetOutputInfoForPhi(node, GetInfo(node)->truncation(), new_type);
+        ResetOutput(node, output);
+        break;
+      }
+
+      case IrOpcode::kSelect: {
+        new_type = TypeSelect(node);
+        // Recompute representation based on the new type.
+        MachineRepresentation output =
+            GetOutputInfoForPhi(node, GetInfo(node)->truncation(), new_type);
+        ResetOutput(node, output);
+        break;
+      }
+
+      default:
+        // Shortcut for operations that we do not handle.
+        if (type == nullptr) {
+          GetInfo(node)->set_feedback_type(NodeProperties::GetType(node));
+          return true;
+        }
+        return false;
+    }
+    if (type != nullptr && new_type->Is(type)) return false;
+    GetInfo(node)->set_feedback_type(new_type);
+    if (FLAG_trace_representation) {
+      PrintNodeFeedbackType(node);
+    }
+    return true;
+  }
+
+  void PrintNodeFeedbackType(Node* n) {
+    OFStream os(stdout);
+    os << "#" << n->id() << ":" << *n->op() << "(";
+    int j = 0;
+    for (Node* const i : n->inputs()) {
+      if (j++ > 0) os << ", ";
+      os << "#" << i->id() << ":" << i->op()->mnemonic();
+    }
+    os << ")";
+    if (NodeProperties::IsTyped(n)) {
+      os << "  [Static type: ";
+      Type* static_type = NodeProperties::GetType(n);
+      static_type->PrintTo(os);
+      Type* feedback_type = GetInfo(n)->feedback_type();
+      if (feedback_type != nullptr && feedback_type != static_type) {
+        os << ", Feedback type: ";
+        feedback_type->PrintTo(os);
+      }
+      os << "]";
+    }
+    os << std::endl;
+  }
+
+  Type* Weaken(Node* node, Type* previous_type, Type* current_type) {
+    // If the types have nothing to do with integers, return the types.
+    Type* const integer = type_cache_.kInteger;
+    if (!previous_type->Maybe(integer)) {
+      return current_type;
+    }
+    DCHECK(current_type->Maybe(integer));
+
+    Type* current_integer =
+        Type::Intersect(current_type, integer, graph_zone());
+    Type* previous_integer =
+        Type::Intersect(previous_type, integer, graph_zone());
+
+    // Once we start weakening a node, we should always weaken.
+    if (!GetInfo(node)->weakened()) {
+      // Only weaken if there is range involved; we should converge quickly
+      // for all other types (the exception is a union of many constants,
+      // but we currently do not increase the number of constants in unions).
+      Type* previous = previous_integer->GetRange();
+      Type* current = current_integer->GetRange();
+      if (current == nullptr || previous == nullptr) {
+        return current_type;
+      }
+      // Range is involved => we are weakening.
+      GetInfo(node)->set_weakened();
+    }
+
+    return Type::Union(current_type,
+                       op_typer_.WeakenRange(previous_integer, current_integer),
+                       graph_zone());
+  }
+
+  // Backward propagation of truncations.
+  void RunTruncationPropagationPhase() {
     // Run propagation phase to a fixpoint.
     TRACE("--{Propagation phase}--\n");
     phase_ = PROPAGATE;
@@ -291,13 +561,22 @@
       Node* node = queue_.front();
       NodeInfo* info = GetInfo(node);
       queue_.pop();
-      info->set_queued(false);
+      info->set_visited();
       TRACE(" visit #%d: %s\n", node->id(), node->op()->mnemonic());
       VisitNode(node, info->truncation(), nullptr);
       TRACE("  ==> output ");
       PrintOutputInfo(info);
       TRACE("\n");
     }
+  }
+
+  void Run(SimplifiedLowering* lowering) {
+    RunTruncationPropagationPhase();
+
+    if (lowering->flags() & SimplifiedLowering::kTypeFeedbackEnabled) {
+      ResetNodeInfoState();
+      RunTypePropagationPhase();
+    }
 
     // Run lowering and change insertion phase.
     TRACE("--{Simplified lowering phase}--\n");
@@ -319,6 +598,7 @@
       Node* node = *i;
       Node* replacement = *(++i);
       node->ReplaceUses(replacement);
+      node->Kill();
       // We also need to replace the node in the rest of the vector.
       for (NodeVector::iterator j = i + 1; j != replacements_.end(); ++j) {
         ++j;
@@ -329,8 +609,7 @@
 
   void EnqueueInitial(Node* node) {
     NodeInfo* info = GetInfo(node);
-    info->set_visited();
-    info->set_queued(true);
+    info->set_queued();
     nodes_.push_back(node);
     queue_.push(node);
   }
@@ -348,10 +627,9 @@
     node_input_use_infos_[use_node->id()].SetAndCheckInput(use_node, index,
                                                            use_info);
 #endif  // DEBUG
-    if (!info->visited()) {
+    if (info->unvisited()) {
       // First visit of this node.
-      info->set_visited();
-      info->set_queued(true);
+      info->set_queued();
       nodes_.push_back(node);
       queue_.push(node);
       TRACE("  initial: ");
@@ -365,7 +643,7 @@
       // New usage information for the node is available.
       if (!info->queued()) {
         queue_.push(node);
-        info->set_queued(true);
+        info->set_queued();
         TRACE("   added: ");
       } else {
         TRACE(" inqueue: ");
@@ -375,48 +653,39 @@
   }
 
   bool lower() { return phase_ == LOWER; }
+  bool propagate() { return phase_ == PROPAGATE; }
 
-  void EnqueueUses(Node* node) {
-    for (Edge edge : node->use_edges()) {
-      if (NodeProperties::IsValueEdge(edge)) {
-        Node* const user = edge.from();
-        if (user->id() < count_) {
-          // New type information for the node is available.
-          NodeInfo* info = GetInfo(user);
-          // Enqueue the node only if we are sure it is reachable from
-          // the end and it has not been queued yet.
-          if (info->visited() && !info->queued()) {
-            queue_.push(user);
-            info->set_queued(true);
-          }
-        }
-      }
-    }
+  void SetOutput(Node* node, MachineRepresentation representation,
+                 TypeCheckKind type_check = TypeCheckKind::kNone) {
+    DCHECK(MachineRepresentationIsSubtype(GetInfo(node)->representation(),
+                                          representation));
+    ResetOutput(node, representation, type_check);
   }
 
-  void SetOutput(Node* node, MachineRepresentation representation) {
+  void ResetOutput(Node* node, MachineRepresentation representation,
+                   TypeCheckKind type_check = TypeCheckKind::kNone) {
     NodeInfo* info = GetInfo(node);
-    DCHECK(
-        MachineRepresentationIsSubtype(info->representation(), representation));
     info->set_output(representation);
+    info->set_type_check(type_check);
   }
 
   Type* GetUpperBound(Node* node) { return NodeProperties::GetType(node); }
 
+  bool InputIs(Node* node, Type* type) {
+    DCHECK_EQ(1, node->op()->ValueInputCount());
+    return GetUpperBound(node->InputAt(0))->Is(type);
+  }
+
   bool BothInputsAreSigned32(Node* node) {
-    DCHECK_EQ(2, node->InputCount());
-    return GetUpperBound(node->InputAt(0))->Is(Type::Signed32()) &&
-           GetUpperBound(node->InputAt(1))->Is(Type::Signed32());
+    return BothInputsAre(node, Type::Signed32());
   }
 
   bool BothInputsAreUnsigned32(Node* node) {
-    DCHECK_EQ(2, node->InputCount());
-    return GetUpperBound(node->InputAt(0))->Is(Type::Unsigned32()) &&
-           GetUpperBound(node->InputAt(1))->Is(Type::Unsigned32());
+    return BothInputsAre(node, Type::Unsigned32());
   }
 
   bool BothInputsAre(Node* node, Type* type) {
-    DCHECK_EQ(2, node->InputCount());
+    DCHECK_EQ(2, node->op()->ValueInputCount());
     return GetUpperBound(node->InputAt(0))->Is(type) &&
            GetUpperBound(node->InputAt(1))->Is(type);
   }
@@ -424,11 +693,13 @@
   void ConvertInput(Node* node, int index, UseInfo use) {
     Node* input = node->InputAt(index);
     // In the change phase, insert a change before the use if necessary.
-    if (use.preferred() == MachineRepresentation::kNone)
+    if (use.representation() == MachineRepresentation::kNone)
       return;  // No input requirement on the use.
+    DCHECK_NOT_NULL(input);
     NodeInfo* input_info = GetInfo(input);
     MachineRepresentation input_rep = input_info->representation();
-    if (input_rep != use.preferred()) {
+    if (input_rep != use.representation() ||
+        use.type_check() != TypeCheckKind::kNone) {
       // Output representation doesn't match usage.
       TRACE("  change: #%d:%s(@%d #%d:%s) ", node->id(), node->op()->mnemonic(),
             index, input->id(), input->op()->mnemonic());
@@ -438,8 +709,7 @@
       PrintUseInfo(use);
       TRACE("\n");
       Node* n = changer_->GetRepresentationFor(
-          input, input_info->representation(), GetUpperBound(input),
-          use.preferred(), use.truncation());
+          input, input_info->representation(), TypeOf(input), node, use);
       node->ReplaceInput(index, n);
     }
   }
@@ -484,25 +754,28 @@
 
   // Helper for binops of the R x L -> O variety.
   void VisitBinop(Node* node, UseInfo left_use, UseInfo right_use,
-                  MachineRepresentation output) {
+                  MachineRepresentation output,
+                  TypeCheckKind type_check = TypeCheckKind::kNone) {
     DCHECK_EQ(2, node->op()->ValueInputCount());
     ProcessInput(node, 0, left_use);
     ProcessInput(node, 1, right_use);
     for (int i = 2; i < node->InputCount(); i++) {
       EnqueueInput(node, i);
     }
-    SetOutput(node, output);
+    SetOutput(node, output, type_check);
   }
 
   // Helper for binops of the I x I -> O variety.
-  void VisitBinop(Node* node, UseInfo input_use, MachineRepresentation output) {
-    VisitBinop(node, input_use, input_use, output);
+  void VisitBinop(Node* node, UseInfo input_use, MachineRepresentation output,
+                  TypeCheckKind type_check = TypeCheckKind::kNone) {
+    VisitBinop(node, input_use, input_use, output, type_check);
   }
 
   // Helper for unops of the I -> O variety.
   void VisitUnop(Node* node, UseInfo input_use, MachineRepresentation output) {
-    DCHECK_EQ(1, node->InputCount());
+    DCHECK_EQ(1, node->op()->ValueInputCount());
     ProcessInput(node, 0, input_use);
+    ProcessRemainingInputs(node, 1);
     SetOutput(node, output);
   }
 
@@ -554,9 +827,12 @@
   }
 
   // Infer representation for phi-like nodes.
-  MachineRepresentation GetOutputInfoForPhi(Node* node, Truncation use) {
+  MachineRepresentation GetOutputInfoForPhi(Node* node, Truncation use,
+                                            Type* type = nullptr) {
     // Compute the representation.
-    Type* type = GetUpperBound(node);
+    if (type == nullptr) {
+      type = TypeOf(node);
+    }
     if (type->Is(Type::None())) {
       return MachineRepresentation::kNone;
     } else if (type->Is(Type::Signed32()) || type->Is(Type::Unsigned32())) {
@@ -579,6 +855,7 @@
                        MachineRepresentation::kWord64;
 #ifdef DEBUG
       // Check that all the inputs agree on being Word64.
+      DCHECK_EQ(IrOpcode::kPhi, node->opcode());  // This only works for phis.
       for (int i = 1; i < node->op()->ValueInputCount(); i++) {
         DCHECK_EQ(is_word64, GetInfo(node->InputAt(i))->representation() ==
                                  MachineRepresentation::kWord64);
@@ -617,6 +894,8 @@
   void VisitPhi(Node* node, Truncation truncation,
                 SimplifiedLowering* lowering) {
     MachineRepresentation output = GetOutputInfoForPhi(node, truncation);
+    // Only set the output representation if not running with type
+    // feedback. (Feedback typing will set the representation.)
     SetOutput(node, output);
 
     int values = node->op()->ValueInputCount();
@@ -686,7 +965,7 @@
         Node* input = node->InputAt(i);
         NodeInfo* input_info = GetInfo(input);
         MachineType machine_type(input_info->representation(),
-                                 DeoptValueSemanticOf(GetUpperBound(input)));
+                                 DeoptValueSemanticOf(TypeOf(input)));
         DCHECK(machine_type.representation() !=
                    MachineRepresentation::kWord32 ||
                machine_type.semantic() == MachineSemantic::kInt32 ||
@@ -703,6 +982,10 @@
     return changer_->Int32OperatorFor(node->opcode());
   }
 
+  const Operator* Int32OverflowOp(Node* node) {
+    return changer_->Int32OverflowOperatorFor(node->opcode());
+  }
+
   const Operator* Uint32Op(Node* node) {
     return changer_->Uint32OperatorFor(node->opcode());
   }
@@ -776,6 +1059,102 @@
                                field_type, value);
   }
 
+  Graph* graph() const { return jsgraph_->graph(); }
+  CommonOperatorBuilder* common() const { return jsgraph_->common(); }
+  SimplifiedOperatorBuilder* simplified() const {
+    return jsgraph_->simplified();
+  }
+
+  void ReplaceEffectControlUses(Node* node, Node* effect, Node* control) {
+    for (Edge edge : node->use_edges()) {
+      if (NodeProperties::IsControlEdge(edge)) {
+        edge.UpdateTo(control);
+      } else if (NodeProperties::IsEffectEdge(edge)) {
+        edge.UpdateTo(effect);
+      } else {
+        DCHECK(NodeProperties::IsValueEdge(edge));
+      }
+    }
+  }
+
+  void ChangeToPureOp(Node* node, const Operator* new_op) {
+    if (node->op()->EffectInputCount() > 0) {
+      DCHECK_LT(0, node->op()->ControlInputCount());
+      // Disconnect the node from effect and control chains.
+      Node* control = NodeProperties::GetControlInput(node);
+      Node* effect = NodeProperties::GetEffectInput(node);
+      ReplaceEffectControlUses(node, effect, control);
+      node->TrimInputCount(new_op->ValueInputCount());
+    } else {
+      DCHECK_EQ(0, node->op()->ControlInputCount());
+    }
+
+    NodeProperties::ChangeOp(node, new_op);
+  }
+
+  void ChangeToInt32OverflowOp(Node* node, const Operator* new_op) {
+    NodeProperties::ChangeOp(node, new_op);
+  }
+
+  void VisitSpeculativeAdditiveOp(Node* node, Truncation truncation,
+                                  SimplifiedLowering* lowering) {
+    if (BothInputsAre(node, type_cache_.kSigned32OrMinusZero) &&
+        NodeProperties::GetType(node)->Is(Type::Signed32())) {
+      // int32 + int32 = int32   ==>   signed Int32Add/Sub
+      VisitInt32Binop(node);
+      if (lower()) ChangeToPureOp(node, Int32Op(node));
+      return;
+    }
+
+    // Use truncation if available.
+    if (BothInputsAre(node, type_cache_.kAdditiveSafeIntegerOrMinusZero) &&
+        truncation.TruncatesToWord32()) {
+      // safe-int + safe-int = x (truncated to int32)
+      // => signed Int32Add/Sub (truncated)
+      VisitWord32TruncatingBinop(node);
+      if (lower()) ChangeToPureOp(node, Int32Op(node));
+      return;
+    }
+
+    // Try to use type feedback.
+    BinaryOperationHints::Hint hint = BinaryOperationHintOf(node->op());
+
+    // Handle the case when no int32 checks on inputs are necessary
+    // (but an overflow check is needed on the output).
+    if (BothInputsAre(node, Type::Signed32()) ||
+        (BothInputsAre(node, type_cache_.kSigned32OrMinusZero) &&
+         NodeProperties::GetType(node)->Is(type_cache_.kSafeInteger))) {
+      // If both the inputs the feedback are int32, use the overflow op.
+      if (hint == BinaryOperationHints::kSignedSmall ||
+          hint == BinaryOperationHints::kSigned32) {
+        VisitBinop(node, UseInfo::TruncatingWord32(),
+                   MachineRepresentation::kWord32, TypeCheckKind::kSigned32);
+        if (lower()) {
+          ChangeToInt32OverflowOp(node, Int32OverflowOp(node));
+        }
+        return;
+      }
+    }
+
+    if (hint == BinaryOperationHints::kSignedSmall ||
+        hint == BinaryOperationHints::kSigned32) {
+      VisitBinop(node, UseInfo::CheckedSigned32AsWord32(),
+                 MachineRepresentation::kWord32, TypeCheckKind::kSigned32);
+      if (lower()) {
+        ChangeToInt32OverflowOp(node, Int32OverflowOp(node));
+      }
+      return;
+    }
+
+    // default case => Float64Add/Sub
+    VisitBinop(node, UseInfo::CheckedNumberOrUndefinedAsFloat64(),
+               MachineRepresentation::kFloat64, TypeCheckKind::kNumber);
+    if (lower()) {
+      ChangeToPureOp(node, Float64Op(node));
+    }
+    return;
+  }
+
   // Dispatching routine for visiting the node {node} with the usage {use}.
   // Depending on the operator, propagate new usage info to the inputs.
   void VisitNode(Node* node, Truncation truncation,
@@ -813,15 +1192,15 @@
         ProcessInput(node, 0, UseInfo::Bool());
         ProcessInput(node, 1, UseInfo::AnyTagged());
         ProcessRemainingInputs(node, 2);
-        break;
+        return;
       case IrOpcode::kBranch:
         ProcessInput(node, 0, UseInfo::Bool());
         EnqueueInput(node, NodeProperties::FirstControlIndex(node));
-        break;
+        return;
       case IrOpcode::kSwitch:
         ProcessInput(node, 0, UseInfo::TruncatingWord32());
         EnqueueInput(node, NodeProperties::FirstControlIndex(node));
-        break;
+        return;
       case IrOpcode::kSelect:
         return VisitSelect(node, truncation, lowering);
       case IrOpcode::kPhi:
@@ -844,7 +1223,7 @@
         } else {
           SetOutput(node, MachineRepresentation::kTagged);
         }
-        break;
+        return;
       }
 
       //------------------------------------------------------------------
@@ -867,7 +1246,7 @@
           ProcessInput(node, 0, UseInfo::AnyTruncatingToBool());
           SetOutput(node, MachineRepresentation::kBit);
         }
-        break;
+        return;
       }
       case IrOpcode::kBooleanToNumber: {
         if (lower()) {
@@ -885,17 +1264,19 @@
           ProcessInput(node, 0, UseInfo::AnyTruncatingToBool());
           SetOutput(node, MachineRepresentation::kWord32);
         }
-        break;
+        return;
       }
       case IrOpcode::kNumberEqual:
       case IrOpcode::kNumberLessThan:
       case IrOpcode::kNumberLessThanOrEqual: {
         // Number comparisons reduce to integer comparisons for integer inputs.
-        if (BothInputsAreSigned32(node)) {
+        if (TypeOf(node->InputAt(0))->Is(Type::Signed32()) &&
+            TypeOf(node->InputAt(1))->Is(Type::Signed32())) {
           // => signed Int32Cmp
           VisitInt32Cmp(node);
           if (lower()) NodeProperties::ChangeOp(node, Int32Op(node));
-        } else if (BothInputsAreUnsigned32(node)) {
+        } else if (TypeOf(node->InputAt(0))->Is(Type::Unsigned32()) &&
+                   TypeOf(node->InputAt(1))->Is(Type::Unsigned32())) {
           // => unsigned Int32Cmp
           VisitUint32Cmp(node);
           if (lower()) NodeProperties::ChangeOp(node, Uint32Op(node));
@@ -904,8 +1285,47 @@
           VisitFloat64Cmp(node);
           if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
         }
-        break;
+        return;
       }
+
+      case IrOpcode::kSpeculativeNumberAdd:
+      case IrOpcode::kSpeculativeNumberSubtract:
+        return VisitSpeculativeAdditiveOp(node, truncation, lowering);
+
+      case IrOpcode::kSpeculativeNumberLessThan:
+      case IrOpcode::kSpeculativeNumberLessThanOrEqual:
+      case IrOpcode::kSpeculativeNumberEqual: {
+        // Number comparisons reduce to integer comparisons for integer inputs.
+        if (TypeOf(node->InputAt(0))->Is(Type::Signed32()) &&
+            TypeOf(node->InputAt(1))->Is(Type::Signed32())) {
+          // => signed Int32Cmp
+          VisitInt32Cmp(node);
+          if (lower()) ChangeToPureOp(node, Int32Op(node));
+          return;
+        } else if (TypeOf(node->InputAt(0))->Is(Type::Unsigned32()) &&
+                   TypeOf(node->InputAt(1))->Is(Type::Unsigned32())) {
+          // => unsigned Int32Cmp
+          VisitUint32Cmp(node);
+          if (lower()) ChangeToPureOp(node, Uint32Op(node));
+          return;
+        }
+        // Try to use type feedback.
+        CompareOperationHints::Hint hint = CompareOperationHintOf(node->op());
+
+        if (hint == CompareOperationHints::kSignedSmall) {
+          VisitBinop(node, UseInfo::CheckedSigned32AsWord32(),
+                     MachineRepresentation::kBit);
+          if (lower()) ChangeToPureOp(node, Int32Op(node));
+          return;
+        }
+        DCHECK_EQ(CompareOperationHints::kNumber, hint);
+        // default case => Float64 comparison
+        VisitBinop(node, UseInfo::CheckedNumberOrUndefinedAsFloat64(),
+                   MachineRepresentation::kBit);
+        if (lower()) ChangeToPureOp(node, Float64Op(node));
+        return;
+      }
+
       case IrOpcode::kNumberAdd:
       case IrOpcode::kNumberSubtract: {
         if (BothInputsAre(node, Type::Signed32()) &&
@@ -914,7 +1334,8 @@
           // => signed Int32Add/Sub
           VisitInt32Binop(node);
           if (lower()) NodeProperties::ChangeOp(node, Int32Op(node));
-        } else if (BothInputsAre(node, type_cache_.kAdditiveSafeInteger) &&
+        } else if (BothInputsAre(node,
+                                 type_cache_.kAdditiveSafeIntegerOrMinusZero) &&
                    truncation.TruncatesToWord32()) {
           // safe-int + safe-int = x (truncated to int32)
           // => signed Int32Add/Sub (truncated)
@@ -925,90 +1346,119 @@
           VisitFloat64Binop(node);
           if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
         }
-        break;
+        return;
       }
+      case IrOpcode::kSpeculativeNumberMultiply:
       case IrOpcode::kNumberMultiply: {
         if (BothInputsAreSigned32(node)) {
           if (NodeProperties::GetType(node)->Is(Type::Signed32())) {
             // Multiply reduces to Int32Mul if the inputs and the output
             // are integers.
             VisitInt32Binop(node);
-            if (lower()) NodeProperties::ChangeOp(node, Int32Op(node));
-            break;
+            if (lower()) ChangeToPureOp(node, Int32Op(node));
+            return;
           }
           if (truncation.TruncatesToWord32() &&
-              NodeProperties::GetType(node)->Is(type_cache_.kSafeInteger)) {
+              NodeProperties::GetType(node)->Is(
+                  type_cache_.kSafeIntegerOrMinusZero)) {
             // Multiply reduces to Int32Mul if the inputs are integers,
             // the uses are truncating and the result is in the safe
             // integer range.
             VisitWord32TruncatingBinop(node);
-            if (lower()) NodeProperties::ChangeOp(node, Int32Op(node));
-            break;
+            if (lower()) ChangeToPureOp(node, Int32Op(node));
+            return;
           }
         }
-        // => Float64Mul
-        VisitFloat64Binop(node);
-        if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
-        break;
+        // Number x Number => Float64Mul
+        if (BothInputsAre(node, Type::NumberOrUndefined())) {
+          VisitFloat64Binop(node);
+          if (lower()) ChangeToPureOp(node, Float64Op(node));
+          return;
+        }
+        // Checked float64 x float64 => float64
+        DCHECK_EQ(IrOpcode::kSpeculativeNumberMultiply, node->opcode());
+        VisitBinop(node, UseInfo::CheckedNumberOrUndefinedAsFloat64(),
+                   MachineRepresentation::kFloat64, TypeCheckKind::kNumber);
+        if (lower()) ChangeToPureOp(node, Float64Op(node));
+        return;
       }
+      case IrOpcode::kSpeculativeNumberDivide:
       case IrOpcode::kNumberDivide: {
         if (BothInputsAreSigned32(node)) {
           if (NodeProperties::GetType(node)->Is(Type::Signed32())) {
           // => signed Int32Div
           VisitInt32Binop(node);
           if (lower()) DeferReplacement(node, lowering->Int32Div(node));
-          break;
+          return;
           }
           if (truncation.TruncatesToWord32()) {
             // => signed Int32Div
             VisitWord32TruncatingBinop(node);
             if (lower()) DeferReplacement(node, lowering->Int32Div(node));
-            break;
+            return;
           }
         }
         if (BothInputsAreUnsigned32(node) && truncation.TruncatesToWord32()) {
           // => unsigned Uint32Div
           VisitWord32TruncatingBinop(node);
           if (lower()) DeferReplacement(node, lowering->Uint32Div(node));
-          break;
+          return;
         }
-        // => Float64Div
-        VisitFloat64Binop(node);
-        if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
-        break;
+        // Number x Number => Float64Div
+        if (BothInputsAre(node, Type::NumberOrUndefined())) {
+          VisitFloat64Binop(node);
+          if (lower()) ChangeToPureOp(node, Float64Op(node));
+          return;
+        }
+        // Checked float64 x float64 => float64
+        DCHECK_EQ(IrOpcode::kSpeculativeNumberDivide, node->opcode());
+        VisitBinop(node, UseInfo::CheckedNumberOrUndefinedAsFloat64(),
+                   MachineRepresentation::kFloat64, TypeCheckKind::kNumber);
+        if (lower()) ChangeToPureOp(node, Float64Op(node));
+        return;
       }
+      case IrOpcode::kSpeculativeNumberModulus:
       case IrOpcode::kNumberModulus: {
         if (BothInputsAreSigned32(node)) {
           if (NodeProperties::GetType(node)->Is(Type::Signed32())) {
             // => signed Int32Mod
             VisitInt32Binop(node);
             if (lower()) DeferReplacement(node, lowering->Int32Mod(node));
-            break;
+            return;
           }
           if (truncation.TruncatesToWord32()) {
             // => signed Int32Mod
             VisitWord32TruncatingBinop(node);
             if (lower()) DeferReplacement(node, lowering->Int32Mod(node));
-            break;
+            return;
           }
         }
         if (BothInputsAreUnsigned32(node) && truncation.TruncatesToWord32()) {
           // => unsigned Uint32Mod
           VisitWord32TruncatingBinop(node);
           if (lower()) DeferReplacement(node, lowering->Uint32Mod(node));
-          break;
+          return;
         }
-        // => Float64Mod
-        VisitFloat64Binop(node);
-        if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
-        break;
+        // Number x Number => Float64Mod
+        if (BothInputsAre(node, Type::NumberOrUndefined())) {
+          // => Float64Mod
+          VisitFloat64Binop(node);
+          if (lower()) ChangeToPureOp(node, Float64Op(node));
+          return;
+        }
+        // Checked float64 x float64 => float64
+        DCHECK_EQ(IrOpcode::kSpeculativeNumberModulus, node->opcode());
+        VisitBinop(node, UseInfo::CheckedNumberOrUndefinedAsFloat64(),
+                   MachineRepresentation::kFloat64, TypeCheckKind::kNumber);
+        if (lower()) ChangeToPureOp(node, Float64Op(node));
+        return;
       }
       case IrOpcode::kNumberBitwiseOr:
       case IrOpcode::kNumberBitwiseXor:
       case IrOpcode::kNumberBitwiseAnd: {
         VisitInt32Binop(node);
         if (lower()) NodeProperties::ChangeOp(node, Int32Op(node));
-        break;
+        return;
       }
       case IrOpcode::kNumberShiftLeft: {
         Type* rhs_type = GetUpperBound(node->InputAt(1));
@@ -1017,7 +1467,7 @@
         if (lower()) {
           lowering->DoShift(node, lowering->machine()->Word32Shl(), rhs_type);
         }
-        break;
+        return;
       }
       case IrOpcode::kNumberShiftRight: {
         Type* rhs_type = GetUpperBound(node->InputAt(1));
@@ -1026,7 +1476,7 @@
         if (lower()) {
           lowering->DoShift(node, lowering->machine()->Word32Sar(), rhs_type);
         }
-        break;
+        return;
       }
       case IrOpcode::kNumberShiftRightLogical: {
         Type* rhs_type = GetUpperBound(node->InputAt(1));
@@ -1035,87 +1485,127 @@
         if (lower()) {
           lowering->DoShift(node, lowering->machine()->Word32Shr(), rhs_type);
         }
-        break;
+        return;
+      }
+      case IrOpcode::kNumberAbs: {
+        if (InputIs(node, Type::Unsigned32())) {
+          VisitUnop(node, UseInfo::TruncatingWord32(),
+                    MachineRepresentation::kWord32);
+          if (lower()) DeferReplacement(node, node->InputAt(0));
+        } else if (InputIs(node, type_cache_.kSafeSigned32)) {
+          VisitUnop(node, UseInfo::TruncatingWord32(),
+                    MachineRepresentation::kWord32);
+          if (lower()) DeferReplacement(node, lowering->Int32Abs(node));
+        } else if (InputIs(node,
+                           type_cache_.kPositiveIntegerOrMinusZeroOrNaN)) {
+          VisitUnop(node, UseInfo::TruncatingFloat64(),
+                    MachineRepresentation::kFloat64);
+          if (lower()) DeferReplacement(node, node->InputAt(0));
+        } else {
+          VisitUnop(node, UseInfo::TruncatingFloat64(),
+                    MachineRepresentation::kFloat64);
+          if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
+        }
+        return;
       }
       case IrOpcode::kNumberClz32: {
         VisitUnop(node, UseInfo::TruncatingWord32(),
                   MachineRepresentation::kWord32);
         if (lower()) NodeProperties::ChangeOp(node, Uint32Op(node));
-        break;
+        return;
       }
       case IrOpcode::kNumberImul: {
         VisitBinop(node, UseInfo::TruncatingWord32(),
                    UseInfo::TruncatingWord32(), MachineRepresentation::kWord32);
         if (lower()) NodeProperties::ChangeOp(node, Uint32Op(node));
-        break;
+        return;
       }
       case IrOpcode::kNumberCeil: {
         VisitUnop(node, UseInfo::TruncatingFloat64(),
                   MachineRepresentation::kFloat64);
         if (lower()) DeferReplacement(node, lowering->Float64Ceil(node));
-        break;
+        return;
       }
       case IrOpcode::kNumberFloor: {
         VisitUnop(node, UseInfo::TruncatingFloat64(),
                   MachineRepresentation::kFloat64);
         if (lower()) DeferReplacement(node, lowering->Float64Floor(node));
-        break;
+        return;
+      }
+      case IrOpcode::kNumberFround: {
+        VisitUnop(node, UseInfo::TruncatingFloat64(),
+                  MachineRepresentation::kFloat32);
+        if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
+        return;
+      }
+      case IrOpcode::kNumberAtan2: {
+        VisitBinop(node, UseInfo::TruncatingFloat64(),
+                   MachineRepresentation::kFloat64);
+        if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
+        return;
+      }
+      case IrOpcode::kNumberAtan:
+      case IrOpcode::kNumberAtanh:
+      case IrOpcode::kNumberCos:
+      case IrOpcode::kNumberExp:
+      case IrOpcode::kNumberExpm1:
+      case IrOpcode::kNumberLog:
+      case IrOpcode::kNumberLog1p:
+      case IrOpcode::kNumberLog2:
+      case IrOpcode::kNumberLog10:
+      case IrOpcode::kNumberCbrt:
+      case IrOpcode::kNumberSin:
+      case IrOpcode::kNumberTan: {
+        VisitUnop(node, UseInfo::TruncatingFloat64(),
+                  MachineRepresentation::kFloat64);
+        if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
+        return;
       }
       case IrOpcode::kNumberRound: {
         VisitUnop(node, UseInfo::TruncatingFloat64(),
                   MachineRepresentation::kFloat64);
         if (lower()) DeferReplacement(node, lowering->Float64Round(node));
-        break;
+        return;
+      }
+      case IrOpcode::kNumberSqrt: {
+        VisitUnop(node, UseInfo::TruncatingFloat64(),
+                  MachineRepresentation::kFloat64);
+        if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
+        return;
       }
       case IrOpcode::kNumberTrunc: {
         VisitUnop(node, UseInfo::TruncatingFloat64(),
                   MachineRepresentation::kFloat64);
         if (lower()) DeferReplacement(node, lowering->Float64Trunc(node));
-        break;
+        return;
       }
       case IrOpcode::kNumberToInt32: {
         // Just change representation if necessary.
         VisitUnop(node, UseInfo::TruncatingWord32(),
                   MachineRepresentation::kWord32);
         if (lower()) DeferReplacement(node, node->InputAt(0));
-        break;
+        return;
       }
       case IrOpcode::kNumberToUint32: {
         // Just change representation if necessary.
         VisitUnop(node, UseInfo::TruncatingWord32(),
                   MachineRepresentation::kWord32);
         if (lower()) DeferReplacement(node, node->InputAt(0));
-        break;
-      }
-      case IrOpcode::kNumberIsHoleNaN: {
-        VisitUnop(node, UseInfo::TruncatingFloat64(),
-                  MachineRepresentation::kBit);
-        if (lower()) {
-          // NumberIsHoleNaN(x) => Word32Equal(Float64ExtractLowWord32(x),
-          //                                   #HoleNaNLower32)
-          node->ReplaceInput(0,
-                             jsgraph_->graph()->NewNode(
-                                 lowering->machine()->Float64ExtractLowWord32(),
-                                 node->InputAt(0)));
-          node->AppendInput(jsgraph_->zone(),
-                            jsgraph_->Int32Constant(kHoleNanLower32));
-          NodeProperties::ChangeOp(node, jsgraph_->machine()->Word32Equal());
-        }
-        break;
+        return;
       }
       case IrOpcode::kReferenceEqual: {
         VisitBinop(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
         if (lower()) {
           NodeProperties::ChangeOp(node, lowering->machine()->WordEqual());
         }
-        break;
+        return;
       }
       case IrOpcode::kStringEqual: {
         VisitBinop(node, UseInfo::AnyTagged(), MachineRepresentation::kTagged);
         if (lower()) {
           // StringEqual(x, y) => Call(StringEqualStub, x, y, no-context)
           Operator::Properties properties =
-              Operator::kCommutative | Operator::kNoThrow;
+              Operator::kCommutative | Operator::kEliminatable;
           Callable callable = CodeFactory::StringEqual(jsgraph_->isolate());
           CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
           CallDescriptor* desc = Linkage::GetStubCallDescriptor(
@@ -1125,16 +1615,15 @@
                             jsgraph_->HeapConstant(callable.code()));
           node->AppendInput(jsgraph_->zone(), jsgraph_->NoContextConstant());
           node->AppendInput(jsgraph_->zone(), jsgraph_->graph()->start());
-          node->AppendInput(jsgraph_->zone(), jsgraph_->graph()->start());
           NodeProperties::ChangeOp(node, jsgraph_->common()->Call(desc));
         }
-        break;
+        return;
       }
       case IrOpcode::kStringLessThan: {
         VisitBinop(node, UseInfo::AnyTagged(), MachineRepresentation::kTagged);
         if (lower()) {
           // StringLessThan(x, y) => Call(StringLessThanStub, x, y, no-context)
-          Operator::Properties properties = Operator::kNoThrow;
+          Operator::Properties properties = Operator::kEliminatable;
           Callable callable = CodeFactory::StringLessThan(jsgraph_->isolate());
           CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
           CallDescriptor* desc = Linkage::GetStubCallDescriptor(
@@ -1144,17 +1633,16 @@
                             jsgraph_->HeapConstant(callable.code()));
           node->AppendInput(jsgraph_->zone(), jsgraph_->NoContextConstant());
           node->AppendInput(jsgraph_->zone(), jsgraph_->graph()->start());
-          node->AppendInput(jsgraph_->zone(), jsgraph_->graph()->start());
           NodeProperties::ChangeOp(node, jsgraph_->common()->Call(desc));
         }
-        break;
+        return;
       }
       case IrOpcode::kStringLessThanOrEqual: {
         VisitBinop(node, UseInfo::AnyTagged(), MachineRepresentation::kTagged);
         if (lower()) {
           // StringLessThanOrEqual(x, y)
           //   => Call(StringLessThanOrEqualStub, x, y, no-context)
-          Operator::Properties properties = Operator::kNoThrow;
+          Operator::Properties properties = Operator::kEliminatable;
           Callable callable =
               CodeFactory::StringLessThanOrEqual(jsgraph_->isolate());
           CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
@@ -1165,16 +1653,20 @@
                             jsgraph_->HeapConstant(callable.code()));
           node->AppendInput(jsgraph_->zone(), jsgraph_->NoContextConstant());
           node->AppendInput(jsgraph_->zone(), jsgraph_->graph()->start());
-          node->AppendInput(jsgraph_->zone(), jsgraph_->graph()->start());
           NodeProperties::ChangeOp(node, jsgraph_->common()->Call(desc));
         }
-        break;
+        return;
+      }
+      case IrOpcode::kStringFromCharCode: {
+        VisitUnop(node, UseInfo::TruncatingWord32(),
+                  MachineRepresentation::kTagged);
+        return;
       }
       case IrOpcode::kStringToNumber: {
         VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kTagged);
         if (lower()) {
-          // StringToNumber(x) => Call(StringToNumberStub, x, no-context)
-          Operator::Properties properties = Operator::kNoThrow;
+          // StringToNumber(x) => Call(StringToNumber, x, no-context)
+          Operator::Properties properties = Operator::kEliminatable;
           Callable callable = CodeFactory::StringToNumber(jsgraph_->isolate());
           CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
           CallDescriptor* desc = Linkage::GetStubCallDescriptor(
@@ -1184,23 +1676,54 @@
                             jsgraph_->HeapConstant(callable.code()));
           node->AppendInput(jsgraph_->zone(), jsgraph_->NoContextConstant());
           node->AppendInput(jsgraph_->zone(), jsgraph_->graph()->start());
-          node->AppendInput(jsgraph_->zone(), jsgraph_->graph()->start());
           NodeProperties::ChangeOp(node, jsgraph_->common()->Call(desc));
         }
-        break;
+        return;
       }
+
+      case IrOpcode::kCheckBounds: {
+        VisitBinop(node, UseInfo::CheckedSigned32AsWord32(),
+                   UseInfo::TruncatingWord32(), MachineRepresentation::kWord32);
+        return;
+      }
+      case IrOpcode::kCheckTaggedPointer: {
+        VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kTagged);
+        if (lower()) {
+          if (InputIs(node, Type::TaggedPointer())) {
+            DeferReplacement(node, node->InputAt(0));
+          }
+        }
+        return;
+      }
+      case IrOpcode::kCheckTaggedSigned: {
+        if (SmiValuesAre32Bits() && truncation.TruncatesToWord32()) {
+          // TODO(jarin,bmeurer): Add CheckedSignedSmallAsWord32?
+          VisitUnop(node, UseInfo::CheckedSigned32AsWord32(),
+                    MachineRepresentation::kWord32);
+          if (lower()) DeferReplacement(node, node->InputAt(0));
+        } else {
+          VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kTagged);
+          if (lower()) {
+            if (InputIs(node, Type::TaggedSigned())) {
+              DeferReplacement(node, node->InputAt(0));
+            }
+          }
+        }
+        return;
+      }
+
       case IrOpcode::kAllocate: {
         ProcessInput(node, 0, UseInfo::TruncatingWord32());
         ProcessRemainingInputs(node, 1);
         SetOutput(node, MachineRepresentation::kTagged);
-        break;
+        return;
       }
       case IrOpcode::kLoadField: {
         FieldAccess access = FieldAccessOf(node->op());
         ProcessInput(node, 0, UseInfoForBasePointer(access));
         ProcessRemainingInputs(node, 1);
         SetOutput(node, access.machine_type.representation());
-        break;
+        return;
       }
       case IrOpcode::kStoreField: {
         FieldAccess access = FieldAccessOf(node->op());
@@ -1219,7 +1742,7 @@
                 node, jsgraph_->simplified()->StoreField(access));
           }
         }
-        break;
+        return;
       }
       case IrOpcode::kLoadBuffer: {
         BufferAccess access = BufferAccessOf(node->op());
@@ -1252,7 +1775,7 @@
         }
         SetOutput(node, output);
         if (lower()) lowering->DoLoadBuffer(node, output, changer_);
-        break;
+        return;
       }
       case IrOpcode::kStoreBuffer: {
         BufferAccess access = BufferAccessOf(node->op());
@@ -1265,7 +1788,7 @@
         ProcessRemainingInputs(node, 4);
         SetOutput(node, MachineRepresentation::kNone);
         if (lower()) lowering->DoStoreBuffer(node);
-        break;
+        return;
       }
       case IrOpcode::kLoadElement: {
         ElementAccess access = ElementAccessOf(node->op());
@@ -1273,7 +1796,7 @@
         ProcessInput(node, 1, UseInfo::TruncatingWord32());    // index
         ProcessRemainingInputs(node, 2);
         SetOutput(node, access.machine_type.representation());
-        break;
+        return;
       }
       case IrOpcode::kStoreElement: {
         ElementAccess access = ElementAccessOf(node->op());
@@ -1294,8 +1817,41 @@
                 node, jsgraph_->simplified()->StoreElement(access));
           }
         }
-        break;
+        return;
       }
+      case IrOpcode::kPlainPrimitiveToNumber:
+        if (truncation.TruncatesToWord32()) {
+          // TODO(jarin): Extend this to Number \/ Oddball
+          if (InputIs(node, Type::NumberOrUndefined())) {
+            VisitUnop(node, UseInfo::TruncatingWord32(),
+                      MachineRepresentation::kWord32);
+            if (lower()) DeferReplacement(node, node->InputAt(0));
+          } else {
+            VisitUnop(node, UseInfo::AnyTagged(),
+                      MachineRepresentation::kWord32);
+            if (lower()) {
+              NodeProperties::ChangeOp(node,
+                                       simplified()->PlainPrimitiveToWord32());
+            }
+          }
+        } else if (truncation.TruncatesToFloat64()) {
+          // TODO(jarin): Extend this to Number \/ Oddball
+          if (InputIs(node, Type::NumberOrUndefined())) {
+            VisitUnop(node, UseInfo::TruncatingFloat64(),
+                      MachineRepresentation::kFloat64);
+            if (lower()) DeferReplacement(node, node->InputAt(0));
+          } else {
+            VisitUnop(node, UseInfo::AnyTagged(),
+                      MachineRepresentation::kFloat64);
+            if (lower()) {
+              NodeProperties::ChangeOp(node,
+                                       simplified()->PlainPrimitiveToFloat64());
+            }
+          }
+        } else {
+          VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kTagged);
+        }
+        return;
       case IrOpcode::kObjectIsCallable:
       case IrOpcode::kObjectIsNumber:
       case IrOpcode::kObjectIsReceiver:
@@ -1304,7 +1860,33 @@
       case IrOpcode::kObjectIsUndetectable: {
         ProcessInput(node, 0, UseInfo::AnyTagged());
         SetOutput(node, MachineRepresentation::kBit);
-        break;
+        return;
+      }
+      case IrOpcode::kCheckFloat64Hole: {
+        CheckFloat64HoleMode mode = CheckFloat64HoleModeOf(node->op());
+        ProcessInput(node, 0, UseInfo::TruncatingFloat64());
+        ProcessRemainingInputs(node, 1);
+        SetOutput(node, MachineRepresentation::kFloat64);
+        if (truncation.TruncatesToFloat64() &&
+            mode == CheckFloat64HoleMode::kAllowReturnHole) {
+          if (lower()) DeferReplacement(node, node->InputAt(0));
+        }
+        return;
+      }
+      case IrOpcode::kCheckTaggedHole: {
+        CheckTaggedHoleMode mode = CheckTaggedHoleModeOf(node->op());
+        if (truncation.TruncatesToWord32() &&
+            mode == CheckTaggedHoleMode::kConvertHoleToUndefined) {
+          ProcessInput(node, 0, UseInfo::CheckedSigned32AsWord32());
+          ProcessRemainingInputs(node, 1);
+          SetOutput(node, MachineRepresentation::kWord32);
+          if (lower()) DeferReplacement(node, node->InputAt(0));
+        } else {
+          ProcessInput(node, 0, UseInfo::AnyTagged());
+          ProcessRemainingInputs(node, 1);
+          SetOutput(node, MachineRepresentation::kTagged);
+        }
+        return;
       }
 
       //------------------------------------------------------------------
@@ -1317,8 +1899,7 @@
         ProcessInput(node, 0, UseInfo::AnyTagged());   // tagged pointer
         ProcessInput(node, 1, UseInfo::PointerInt());  // index
         ProcessRemainingInputs(node, 2);
-        SetOutput(node, rep.representation());
-        break;
+        return SetOutput(node, rep.representation());
       }
       case IrOpcode::kStore: {
         // TODO(jarin) Eventually, we should get rid of all machine stores
@@ -1329,8 +1910,7 @@
         ProcessInput(node, 2,
                      TruncatingUseInfoFromRepresentation(rep.representation()));
         ProcessRemainingInputs(node, 3);
-        SetOutput(node, MachineRepresentation::kNone);
-        break;
+        return SetOutput(node, MachineRepresentation::kNone);
       }
       case IrOpcode::kWord32Shr:
         // We output unsigned int32 for shift right because JavaScript.
@@ -1415,10 +1995,6 @@
         return VisitUnop(node, UseInfo::TruncatingFloat64(),
                          MachineRepresentation::kWord32);
 
-      case IrOpcode::kChangeFloat32ToFloat64:
-        UNREACHABLE();
-        return VisitUnop(node, UseInfo::TruncatingFloat32(),
-                         MachineRepresentation::kFloat64);
       case IrOpcode::kChangeInt32ToFloat64:
         return VisitUnop(node, UseInfo::TruncatingWord32(),
                          MachineRepresentation::kFloat64);
@@ -1440,6 +2016,9 @@
       case IrOpcode::kFloat64RoundUp:
         return VisitUnop(node, UseInfo::TruncatingFloat64(),
                          MachineRepresentation::kFloat64);
+      case IrOpcode::kFloat64SilenceNaN:
+        return VisitUnop(node, UseInfo::TruncatingFloat64(),
+                         MachineRepresentation::kFloat64);
       case IrOpcode::kFloat64Equal:
       case IrOpcode::kFloat64LessThan:
       case IrOpcode::kFloat64LessThanOrEqual:
@@ -1453,13 +2032,17 @@
         return VisitBinop(node, UseInfo::TruncatingFloat64(),
                           UseInfo::TruncatingWord32(),
                           MachineRepresentation::kFloat64);
+      case IrOpcode::kNumberSilenceNaN:
+        VisitUnop(node, UseInfo::TruncatingFloat64(),
+                  MachineRepresentation::kFloat64);
+        if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
+        return;
       case IrOpcode::kLoadStackPointer:
       case IrOpcode::kLoadFramePointer:
       case IrOpcode::kLoadParentFramePointer:
         return VisitLeaf(node, MachineType::PointerRepresentation());
       case IrOpcode::kStateValues:
-        VisitStateValues(node);
-        break;
+        return VisitStateValues(node);
 
       // The following opcodes are not produced before representation
       // inference runs, so we do not have any real test coverage.
@@ -1467,14 +2050,24 @@
       case IrOpcode::kChangeFloat64ToInt32:
       case IrOpcode::kChangeFloat64ToUint32:
       case IrOpcode::kTruncateInt64ToInt32:
+      case IrOpcode::kChangeFloat32ToFloat64:
+      case IrOpcode::kCheckedInt32Add:
+      case IrOpcode::kCheckedInt32Sub:
+      case IrOpcode::kCheckedUint32ToInt32:
+      case IrOpcode::kCheckedFloat64ToInt32:
+      case IrOpcode::kCheckedTaggedToInt32:
+      case IrOpcode::kCheckedTaggedToFloat64:
+      case IrOpcode::kPlainPrimitiveToWord32:
+      case IrOpcode::kPlainPrimitiveToFloat64:
         FATAL("Representation inference: unsupported opcodes.");
+        break;
 
       default:
         VisitInputs(node);
         // Assume the output is tagged.
-        SetOutput(node, MachineRepresentation::kTagged);
-        break;
+        return SetOutput(node, MachineRepresentation::kTagged);
     }
+    UNREACHABLE();
   }
 
   void DeferReplacement(Node* node, Node* replacement) {
@@ -1482,8 +2075,20 @@
           node->op()->mnemonic(), replacement->id(),
           replacement->op()->mnemonic());
 
+    // Disconnect the node from effect and control chains, if necessary.
+    if (node->op()->EffectInputCount() > 0) {
+      DCHECK_LT(0, node->op()->ControlInputCount());
+      // Disconnect the node from effect and control chains.
+      Node* control = NodeProperties::GetControlInput(node);
+      Node* effect = NodeProperties::GetEffectInput(node);
+      ReplaceEffectControlUses(node, effect, control);
+    } else {
+      DCHECK_EQ(0, node->op()->ControlInputCount());
+    }
+
     if (replacement->id() < count_ &&
-        GetUpperBound(node)->Is(GetUpperBound(replacement))) {
+        GetUpperBound(node)->Is(GetUpperBound(replacement)) &&
+        TypeOf(node)->Is(TypeOf(replacement))) {
       // Replace with a previously existing node eagerly only if the type is the
       // same.
       node->ReplaceUses(replacement);
@@ -1515,19 +2120,20 @@
   void PrintTruncation(Truncation truncation) {
     if (FLAG_trace_representation) {
       OFStream os(stdout);
-      os << truncation.description();
+      os << truncation.description() << std::endl;
     }
   }
 
   void PrintUseInfo(UseInfo info) {
     if (FLAG_trace_representation) {
       OFStream os(stdout);
-      os << info.preferred() << ":" << info.truncation().description();
+      os << info.representation() << ":" << info.truncation().description();
     }
   }
 
  private:
   JSGraph* jsgraph_;
+  Zone* zone_;                      // Temporary zone.
   size_t const count_;              // number of nodes in the graph
   ZoneVector<NodeInfo> info_;       // node id -> usage information
 #ifdef DEBUG
@@ -1539,6 +2145,12 @@
   Phase phase_;                     // current phase of algorithm
   RepresentationChanger* changer_;  // for inserting representation changes
   ZoneQueue<Node*> queue_;          // queue for traversing the graph
+
+  struct NodeState {
+    Node* node;
+    int input_index;
+  };
+  ZoneStack<NodeState> typing_stack_;  // stack for graph typing.
   // TODO(danno): RepresentationSelector shouldn't know anything about the
   // source positions table, but must for now since there currently is no other
   // way to pass down source position information to nodes created during
@@ -1546,23 +2158,26 @@
   // position information via the SourcePositionWrapper like all other reducers.
   SourcePositionTable* source_positions_;
   TypeCache const& type_cache_;
+  OperationTyper op_typer_;  // helper for the feedback typer
 
   NodeInfo* GetInfo(Node* node) {
     DCHECK(node->id() >= 0);
     DCHECK(node->id() < count_);
     return &info_[node->id()];
   }
+  Zone* zone() { return zone_; }
+  Zone* graph_zone() { return jsgraph_->zone(); }
 };
 
-
 SimplifiedLowering::SimplifiedLowering(JSGraph* jsgraph, Zone* zone,
-                                       SourcePositionTable* source_positions)
+                                       SourcePositionTable* source_positions,
+                                       Flags flags)
     : jsgraph_(jsgraph),
       zone_(zone),
       type_cache_(TypeCache::Get()),
+      flags_(flags),
       source_positions_(source_positions) {}
 
-
 void SimplifiedLowering::LowerAllNodes() {
   RepresentationChanger changer(jsgraph(), jsgraph()->isolate());
   RepresentationSelector selector(jsgraph(), zone_, &changer,
@@ -1758,8 +2373,8 @@
     Type* element_type =
         Type::Intersect(NodeProperties::GetType(node), Type::Number(), zone());
     Node* vtrue = changer->GetRepresentationFor(
-        etrue, access_type.representation(), element_type, output_rep,
-        Truncation::None());
+        etrue, access_type.representation(), element_type, node,
+        UseInfo(output_rep, Truncation::None()));
 
     Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
     Node* efalse = effect;
@@ -2188,6 +2803,17 @@
                           vtrue0, vfalse0, merge0);
 }
 
+Node* SimplifiedLowering::Int32Abs(Node* const node) {
+  Node* const zero = jsgraph()->Int32Constant(0);
+  Node* const input = node->InputAt(0);
+
+  // if 0 < input then input else 0 - input
+  return graph()->NewNode(
+      common()->Select(MachineRepresentation::kWord32, BranchHint::kTrue),
+      graph()->NewNode(machine()->Int32LessThan(), zero, input), input,
+      graph()->NewNode(machine()->Int32Sub(), zero, input));
+}
+
 Node* SimplifiedLowering::Int32Div(Node* const node) {
   Int32BinopMatcher m(node);
   Node* const zero = jsgraph()->Int32Constant(0);