Upgrade V8 to version 4.9.385.28

https://chromium.googlesource.com/v8/v8/+/4.9.385.28

FPIIM-449

Change-Id: I4b2e74289d4bf3667f2f3dc8aa2e541f63e26eb4
diff --git a/src/compiler/simplified-lowering.cc b/src/compiler/simplified-lowering.cc
index 1461709..653fea8 100644
--- a/src/compiler/simplified-lowering.cc
+++ b/src/compiler/simplified-lowering.cc
@@ -10,22 +10,25 @@
 #include "src/code-factory.h"
 #include "src/compiler/common-operator.h"
 #include "src/compiler/diamond.h"
-#include "src/compiler/graph-inl.h"
 #include "src/compiler/linkage.h"
 #include "src/compiler/node-matchers.h"
-#include "src/compiler/node-properties-inl.h"
+#include "src/compiler/node-properties.h"
+#include "src/compiler/operator-properties.h"
 #include "src/compiler/representation-change.h"
-#include "src/compiler/simplified-lowering.h"
 #include "src/compiler/simplified-operator.h"
+#include "src/compiler/source-position.h"
 #include "src/objects.h"
+#include "src/type-cache.h"
 
 namespace v8 {
 namespace internal {
 namespace compiler {
 
 // Macro for outputting trace information from representation inference.
-#define TRACE(x) \
-  if (FLAG_trace_representation) PrintF x
+#define TRACE(...)                                      \
+  do {                                                  \
+    if (FLAG_trace_representation) PrintF(__VA_ARGS__); \
+  } while (false)
 
 // Representation selection and lowering of {Simplified} operators to machine
 // operators are interwined. We use a fixpoint calculation to compute both the
@@ -54,64 +57,329 @@
 };
 
 
+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 Float32() {
+    return UseInfo(MachineRepresentation::kFloat32, Truncation::Float32());
+  }
+  static UseInfo Float64() {
+    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());
+  }
+
+  // Truncation to a representation that is smaller than the preferred
+  // one.
+  static UseInfo Float64TruncatingToWord32() {
+    return UseInfo(MachineRepresentation::kFloat64, Truncation::Word32());
+  }
+  static UseInfo Word64TruncatingToWord32() {
+    return UseInfo(MachineRepresentation::kWord64, Truncation::Word32());
+  }
+  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) {
+    case MachineRepresentation::kTagged:
+      return UseInfo::AnyTagged();
+    case MachineRepresentation::kFloat64:
+    return UseInfo::Float64();
+    case MachineRepresentation::kFloat32:
+      return UseInfo::Float32();
+    case MachineRepresentation::kWord64:
+    return UseInfo::TruncatingWord64();
+    case MachineRepresentation::kWord8:
+    case MachineRepresentation::kWord16:
+    case MachineRepresentation::kWord32:
+    return UseInfo::TruncatingWord32();
+    case MachineRepresentation::kBit:
+      return UseInfo::Bool();
+    case MachineRepresentation::kNone:
+      break;
+  }
+  UNREACHABLE();
+  return UseInfo::None();
+}
+
+
+UseInfo UseInfoForBasePointer(const FieldAccess& access) {
+  return access.tag() != 0 ? UseInfo::AnyTagged() : UseInfo::PointerInt();
+}
+
+
+UseInfo UseInfoForBasePointer(const ElementAccess& access) {
+  return access.tag() != 0 ? UseInfo::AnyTagged() : UseInfo::PointerInt();
+}
+
+
+#ifdef DEBUG
+// Helpers for monotonicity checking.
+bool MachineRepresentationIsSubtype(MachineRepresentation r1,
+                                    MachineRepresentation r2) {
+  switch (r1) {
+    case MachineRepresentation::kNone:
+      return true;
+    case MachineRepresentation::kBit:
+      return r2 == MachineRepresentation::kBit ||
+             r2 == MachineRepresentation::kTagged;
+    case MachineRepresentation::kWord8:
+      return r2 == MachineRepresentation::kWord8 ||
+             r2 == MachineRepresentation::kWord16 ||
+             r2 == MachineRepresentation::kWord32 ||
+             r2 == MachineRepresentation::kWord64 ||
+             r2 == MachineRepresentation::kFloat32 ||
+             r2 == MachineRepresentation::kFloat64 ||
+             r2 == MachineRepresentation::kTagged;
+    case MachineRepresentation::kWord16:
+      return r2 == MachineRepresentation::kWord16 ||
+             r2 == MachineRepresentation::kWord32 ||
+             r2 == MachineRepresentation::kWord64 ||
+             r2 == MachineRepresentation::kFloat32 ||
+             r2 == MachineRepresentation::kFloat64 ||
+             r2 == MachineRepresentation::kTagged;
+    case MachineRepresentation::kWord32:
+      return r2 == MachineRepresentation::kWord32 ||
+             r2 == MachineRepresentation::kWord64 ||
+             r2 == MachineRepresentation::kFloat64 ||
+             r2 == MachineRepresentation::kTagged;
+    case MachineRepresentation::kWord64:
+      return r2 == MachineRepresentation::kWord64;
+    case MachineRepresentation::kFloat32:
+      return r2 == MachineRepresentation::kFloat32 ||
+             r2 == MachineRepresentation::kFloat64 ||
+             r2 == MachineRepresentation::kTagged;
+    case MachineRepresentation::kFloat64:
+      return r2 == MachineRepresentation::kFloat64 ||
+             r2 == MachineRepresentation::kTagged;
+    case MachineRepresentation::kTagged:
+      return r2 == MachineRepresentation::kTagged;
+  }
+  UNREACHABLE();
+  return false;
+}
+
+
+class InputUseInfos {
+ public:
+  explicit InputUseInfos(Zone* zone) : input_use_infos_(zone) {}
+
+  void SetAndCheckInput(Node* node, int index, UseInfo use_info) {
+    if (input_use_infos_.empty()) {
+      input_use_infos_.resize(node->InputCount(), UseInfo::None());
+    }
+    // Check that the new use informatin is a super-type of the old
+    // one.
+    CHECK(IsUseLessGeneral(input_use_infos_[index], use_info));
+    input_use_infos_[index] = use_info;
+  }
+
+ private:
+  ZoneVector<UseInfo> input_use_infos_;
+
+  static bool IsUseLessGeneral(UseInfo use1, UseInfo use2) {
+    return MachineRepresentationIsSubtype(use1.preferred(), use2.preferred()) &&
+           use1.truncation().IsLessGeneralThan(use2.truncation());
+  }
+};
+
+#endif  // DEBUG
+
+}  // namespace
+
+
 class RepresentationSelector {
  public:
   // Information for each node tracked during the fixpoint.
-  struct NodeInfo {
-    MachineTypeUnion use : 15;     // Union of all usages for the node.
-    bool queued : 1;           // Bookkeeping for the traversal.
-    bool visited : 1;          // Bookkeeping for the traversal.
-    MachineTypeUnion output : 15;  // Output type of the node.
+  class NodeOutputInfo {
+   public:
+    NodeOutputInfo(MachineRepresentation representation, Type* type)
+        : type_(type), representation_(representation) {}
+    NodeOutputInfo()
+        : type_(Type::None()), representation_(MachineRepresentation::kNone) {}
+
+    MachineRepresentation representation() const { return representation_; }
+    Type* type() const { return type_; }
+
+    static NodeOutputInfo None() {
+      return NodeOutputInfo(MachineRepresentation::kNone, Type::None());
+    }
+
+    static NodeOutputInfo Float32() {
+      return NodeOutputInfo(MachineRepresentation::kFloat32, Type::Number());
+    }
+
+    static NodeOutputInfo Float64() {
+      return NodeOutputInfo(MachineRepresentation::kFloat64, Type::Number());
+    }
+
+    static NodeOutputInfo NumberTruncatedToWord32() {
+      return NodeOutputInfo(MachineRepresentation::kWord32, Type::Number());
+    }
+
+    static NodeOutputInfo Int32() {
+      return NodeOutputInfo(MachineRepresentation::kWord32, Type::Signed32());
+    }
+
+    static NodeOutputInfo Uint32() {
+      return NodeOutputInfo(MachineRepresentation::kWord32, Type::Unsigned32());
+    }
+
+    static NodeOutputInfo Bool() {
+      return NodeOutputInfo(MachineRepresentation::kBit, Type::Boolean());
+    }
+
+    static NodeOutputInfo Int64() {
+      // TODO(jarin) Fix once we have a real int64 type.
+      return NodeOutputInfo(MachineRepresentation::kWord64, Type::Internal());
+    }
+
+    static NodeOutputInfo Uint64() {
+      // TODO(jarin) Fix once we have a real uint64 type.
+      return NodeOutputInfo(MachineRepresentation::kWord64, Type::Internal());
+    }
+
+    static NodeOutputInfo AnyTagged() {
+      return NodeOutputInfo(MachineRepresentation::kTagged, Type::Any());
+    }
+
+    static NodeOutputInfo NumberTagged() {
+      return NodeOutputInfo(MachineRepresentation::kTagged, Type::Number());
+    }
+
+    static NodeOutputInfo Pointer() {
+      return NodeOutputInfo(MachineType::PointerRepresentation(), Type::Any());
+    }
+
+   private:
+    Type* type_;
+    MachineRepresentation representation_;
+  };
+
+  class NodeInfo {
+   public:
+    // Adds new use to the node. Returns true if something has changed
+    // and the node has to be requeued.
+    bool AddUse(UseInfo info) {
+      Truncation old_truncation = truncation_;
+      truncation_ = Truncation::Generalize(truncation_, info.truncation());
+      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_; }
+    Truncation truncation() const { return truncation_; }
+    void set_output_type(NodeOutputInfo output) { output_ = output; }
+
+    Type* output_type() const { return output_.type(); }
+    MachineRepresentation representation() const {
+      return output_.representation();
+    }
+
+   private:
+    bool queued_ = false;                  // Bookkeeping for the traversal.
+    bool visited_ = false;                 // Bookkeeping for the traversal.
+    NodeOutputInfo output_;                // Output type and representation.
+    Truncation truncation_ = Truncation::None();  // Information about uses.
   };
 
   RepresentationSelector(JSGraph* jsgraph, Zone* zone,
-                         RepresentationChanger* changer)
+                         RepresentationChanger* changer,
+                         SourcePositionTable* source_positions)
       : jsgraph_(jsgraph),
         count_(jsgraph->graph()->NodeCount()),
-        info_(zone->NewArray<NodeInfo>(count_)),
+        info_(count_, zone),
+#ifdef DEBUG
+        node_input_use_infos_(count_, InputUseInfos(zone), zone),
+#endif
         nodes_(zone),
         replacements_(zone),
         phase_(PROPAGATE),
         changer_(changer),
-        queue_(zone) {
-    memset(info_, 0, sizeof(NodeInfo) * count_);
-
-    Factory* f = zone->isolate()->factory();
-    safe_bit_range_ =
-        Type::Union(Type::Boolean(),
-                    Type::Range(f->NewNumber(0), f->NewNumber(1), zone), zone);
-    safe_int_additive_range_ =
-        Type::Range(f->NewNumber(-std::pow(2.0, 52.0)),
-                    f->NewNumber(std::pow(2.0, 52.0)), zone);
+        queue_(zone),
+        source_positions_(source_positions),
+        type_cache_(TypeCache::Get()) {
   }
 
   void Run(SimplifiedLowering* lowering) {
     // Run propagation phase to a fixpoint.
-    TRACE(("--{Propagation phase}--\n"));
+    TRACE("--{Propagation phase}--\n");
     phase_ = PROPAGATE;
-    Enqueue(jsgraph_->graph()->end());
+    EnqueueInitial(jsgraph_->graph()->end());
     // Process nodes from the queue until it is empty.
     while (!queue_.empty()) {
       Node* node = queue_.front();
       NodeInfo* info = GetInfo(node);
       queue_.pop();
-      info->queued = false;
-      TRACE((" visit #%d: %s\n", node->id(), node->op()->mnemonic()));
-      VisitNode(node, info->use, NULL);
-      TRACE(("  ==> output "));
-      PrintInfo(info->output);
-      TRACE(("\n"));
+      info->set_queued(false);
+      TRACE(" visit #%d: %s\n", node->id(), node->op()->mnemonic());
+      VisitNode(node, info->truncation(), nullptr);
+      TRACE("  ==> output ");
+      PrintOutputInfo(info);
+      TRACE("\n");
     }
 
     // Run lowering and change insertion phase.
-    TRACE(("--{Simplified lowering phase}--\n"));
+    TRACE("--{Simplified lowering phase}--\n");
     phase_ = LOWER;
     // Process nodes from the collected {nodes_} vector.
     for (NodeVector::iterator i = nodes_.begin(); i != nodes_.end(); ++i) {
       Node* node = *i;
-      TRACE((" visit #%d: %s\n", node->id(), node->op()->mnemonic()));
+      NodeInfo* info = GetInfo(node);
+      TRACE(" visit #%d: %s\n", node->id(), node->op()->mnemonic());
       // Reuse {VisitNode()} so the representation rules are in one place.
-      VisitNode(node, GetUseInfo(node), lowering);
+      SourcePositionTable::Scope scope(
+          source_positions_, source_positions_->GetSourcePosition(node));
+      VisitNode(node, info->truncation(), lowering);
     }
 
     // Perform the final replacements.
@@ -120,108 +388,181 @@
       Node* node = *i;
       Node* replacement = *(++i);
       node->ReplaceUses(replacement);
+      // We also need to replace the node in the rest of the vector.
+      for (NodeVector::iterator j = i + 1; j != replacements_.end(); ++j) {
+        ++j;
+        if (*j == node) *j = replacement;
+      }
     }
   }
 
-  // Enqueue {node} if the {use} contains new information for that node.
-  // Add {node} to {nodes_} if this is the first time it's been visited.
-  void Enqueue(Node* node, MachineTypeUnion use = 0) {
+  void EnqueueInitial(Node* node) {
+    NodeInfo* info = GetInfo(node);
+    info->set_visited();
+    info->set_queued(true);
+    nodes_.push_back(node);
+    queue_.push(node);
+  }
+
+  // Enqueue {use_node}'s {index} input if the {use} contains new information
+  // for that input node. Add the input to {nodes_} if this is the first time
+  // it's been visited.
+  void EnqueueInput(Node* use_node, int index,
+                    UseInfo use_info = UseInfo::None()) {
+    Node* node = use_node->InputAt(index);
     if (phase_ != PROPAGATE) return;
     NodeInfo* info = GetInfo(node);
-    if (!info->visited) {
+#ifdef DEBUG
+    // Check monotonicity of input requirements.
+    node_input_use_infos_[use_node->id()].SetAndCheckInput(use_node, index,
+                                                           use_info);
+#endif  // DEBUG
+    if (!info->visited()) {
       // First visit of this node.
-      info->visited = true;
-      info->queued = true;
+      info->set_visited();
+      info->set_queued(true);
       nodes_.push_back(node);
       queue_.push(node);
-      TRACE(("  initial: "));
-      info->use |= use;
-      PrintUseInfo(node);
+      TRACE("  initial: ");
+      info->AddUse(use_info);
+      PrintTruncation(info->truncation());
       return;
     }
-    TRACE(("   queue?: "));
-    PrintUseInfo(node);
-    if ((info->use & use) != use) {
+    TRACE("   queue?: ");
+    PrintTruncation(info->truncation());
+    if (info->AddUse(use_info)) {
       // New usage information for the node is available.
-      if (!info->queued) {
+      if (!info->queued()) {
         queue_.push(node);
-        info->queued = true;
-        TRACE(("   added: "));
+        info->set_queued(true);
+        TRACE("   added: ");
       } else {
-        TRACE((" inqueue: "));
+        TRACE(" inqueue: ");
       }
-      info->use |= use;
-      PrintUseInfo(node);
+      PrintTruncation(info->truncation());
     }
   }
 
   bool lower() { return phase_ == LOWER; }
 
-  void Enqueue(Node* node, MachineType use) {
-    Enqueue(node, static_cast<MachineTypeUnion>(use));
-  }
-
-  void SetOutput(Node* node, MachineTypeUnion output) {
-    // Every node should have at most one output representation. Note that
-    // phis can have 0, if they have not been used in a representation-inducing
-    // instruction.
-    DCHECK((output & kRepMask) == 0 ||
-           base::bits::IsPowerOfTwo32(output & kRepMask));
-    GetInfo(node)->output = output;
-  }
-
-  bool BothInputsAre(Node* node, Type* type) {
-    DCHECK_EQ(2, node->InputCount());
-    return NodeProperties::GetBounds(node->InputAt(0)).upper->Is(type) &&
-           NodeProperties::GetBounds(node->InputAt(1)).upper->Is(type);
-  }
-
-  void ProcessTruncateWord32Input(Node* node, int index, MachineTypeUnion use) {
-    Node* input = node->InputAt(index);
-    if (phase_ == PROPAGATE) {
-      // In the propagate phase, propagate the usage information backward.
-      Enqueue(input, use);
-    } else {
-      // In the change phase, insert a change before the use if necessary.
-      MachineTypeUnion output = GetInfo(input)->output;
-      if ((output & (kRepBit | kRepWord8 | kRepWord16 | kRepWord32)) == 0) {
-        // Output representation doesn't match usage.
-        TRACE(("  truncate-to-int32: #%d:%s(@%d #%d:%s) ", node->id(),
-               node->op()->mnemonic(), index, input->id(),
-               input->op()->mnemonic()));
-        TRACE((" from "));
-        PrintInfo(output);
-        TRACE((" to "));
-        PrintInfo(use);
-        TRACE(("\n"));
-        Node* n = changer_->GetTruncatedWord32For(input, output);
-        node->ReplaceInput(index, n);
+  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 ProcessInput(Node* node, int index, MachineTypeUnion use) {
+  void SetOutputFromMachineType(Node* node, MachineType machine_type) {
+    Type* type = Type::None();
+    switch (machine_type.semantic()) {
+      case MachineSemantic::kNone:
+        type = Type::None();
+        break;
+      case MachineSemantic::kBool:
+        type = Type::Boolean();
+        break;
+      case MachineSemantic::kInt32:
+        type = Type::Signed32();
+        break;
+      case MachineSemantic::kUint32:
+        type = Type::Unsigned32();
+        break;
+      case MachineSemantic::kInt64:
+        // TODO(jarin) Fix once we have proper int64.
+        type = Type::Internal();
+        break;
+      case MachineSemantic::kUint64:
+        // TODO(jarin) Fix once we have proper uint64.
+        type = Type::Internal();
+        break;
+      case MachineSemantic::kNumber:
+        type = Type::Number();
+        break;
+      case MachineSemantic::kAny:
+        type = Type::Any();
+        break;
+    }
+    return SetOutput(node, NodeOutputInfo(machine_type.representation(), type));
+  }
+
+  void SetOutput(Node* node, NodeOutputInfo output_info) {
+    // Every node should have at most one output representation. Note that
+    // phis can have 0, if they have not been used in a representation-inducing
+    // instruction.
+    Type* output_type = output_info.type();
+    if (NodeProperties::IsTyped(node)) {
+      output_type = Type::Intersect(NodeProperties::GetType(node),
+                                    output_info.type(), jsgraph_->zone());
+    }
+    NodeInfo* info = GetInfo(node);
+    DCHECK(info->output_type()->Is(output_type));
+    DCHECK(MachineRepresentationIsSubtype(info->representation(),
+                                          output_info.representation()));
+    if (!output_type->Is(info->output_type()) ||
+        output_info.representation() != info->representation()) {
+      EnqueueUses(node);
+    }
+    info->set_output_type(
+        NodeOutputInfo(output_info.representation(), output_type));
+  }
+
+  bool BothInputsAreSigned32(Node* node) {
+    DCHECK_EQ(2, node->InputCount());
+    return GetInfo(node->InputAt(0))->output_type()->Is(Type::Signed32()) &&
+           GetInfo(node->InputAt(1))->output_type()->Is(Type::Signed32());
+  }
+
+  bool BothInputsAreUnsigned32(Node* node) {
+    DCHECK_EQ(2, node->InputCount());
+    return GetInfo(node->InputAt(0))->output_type()->Is(Type::Unsigned32()) &&
+           GetInfo(node->InputAt(1))->output_type()->Is(Type::Unsigned32());
+  }
+
+  bool BothInputsAre(Node* node, Type* type) {
+    DCHECK_EQ(2, node->InputCount());
+    return GetInfo(node->InputAt(0))->output_type()->Is(type) &&
+           GetInfo(node->InputAt(1))->output_type()->Is(type);
+  }
+
+  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)
+      return;  // No input requirement on the use.
+    NodeInfo* input_info = GetInfo(input);
+    MachineRepresentation input_rep = input_info->representation();
+    if (input_rep != use.preferred()) {
+      // Output representation doesn't match usage.
+      TRACE("  change: #%d:%s(@%d #%d:%s) ", node->id(), node->op()->mnemonic(),
+            index, input->id(), input->op()->mnemonic());
+      TRACE(" from ");
+      PrintOutputInfo(input_info);
+      TRACE(" to ");
+      PrintUseInfo(use);
+      TRACE("\n");
+      Node* n = changer_->GetRepresentationFor(
+          input, input_info->representation(), input_info->output_type(),
+          use.preferred(), use.truncation());
+      node->ReplaceInput(index, n);
+    }
+  }
+
+  void ProcessInput(Node* node, int index, UseInfo use) {
     if (phase_ == PROPAGATE) {
-      // In the propagate phase, propagate the usage information backward.
-      Enqueue(input, use);
+      EnqueueInput(node, index, use);
     } else {
-      // In the change phase, insert a change before the use if necessary.
-      if ((use & kRepMask) == 0) return;  // No input requirement on the use.
-      MachineTypeUnion output = GetInfo(input)->output;
-      if ((output & kRepMask & use) == 0) {
-        // Output representation doesn't match usage.
-        TRACE(("  change: #%d:%s(@%d #%d:%s) ", node->id(),
-               node->op()->mnemonic(), index, input->id(),
-               input->op()->mnemonic()));
-        TRACE((" from "));
-        PrintInfo(output);
-        TRACE((" to "));
-        PrintInfo(use);
-        TRACE(("\n"));
-        Node* n = changer_->GetRepresentationFor(input, output, use);
-        node->ReplaceInput(index, n);
-      }
+      ConvertInput(node, index, use);
     }
   }
 
@@ -230,175 +571,246 @@
     DCHECK_GE(index, NodeProperties::PastContextIndex(node));
     for (int i = std::max(index, NodeProperties::FirstEffectIndex(node));
          i < NodeProperties::PastEffectIndex(node); ++i) {
-      Enqueue(node->InputAt(i));  // Effect inputs: just visit
+      EnqueueInput(node, i);  // Effect inputs: just visit
     }
     for (int i = std::max(index, NodeProperties::FirstControlIndex(node));
          i < NodeProperties::PastControlIndex(node); ++i) {
-      Enqueue(node->InputAt(i));  // Control inputs: just visit
+      EnqueueInput(node, i);  // Control inputs: just visit
     }
   }
 
   // The default, most general visitation case. For {node}, process all value,
-  // context, effect, and control inputs, assuming that value inputs should have
-  // {kRepTagged} representation and can observe all output values {kTypeAny}.
+  // context, frame state, effect, and control inputs, assuming that value
+  // inputs should have {kRepTagged} representation and can observe all output
+  // values {kTypeAny}.
   void VisitInputs(Node* node) {
-    auto i = node->input_edges().begin();
-    for (int j = node->op()->ValueInputCount(); j > 0; ++i, j--) {
-      ProcessInput(node, (*i).index(), kMachAnyTagged);  // Value inputs
+    int tagged_count = node->op()->ValueInputCount() +
+                       OperatorProperties::GetContextInputCount(node->op());
+    // Visit value and context inputs as tagged.
+    for (int i = 0; i < tagged_count; i++) {
+      ProcessInput(node, i, UseInfo::AnyTagged());
     }
-    for (int j = OperatorProperties::GetContextInputCount(node->op()); j > 0;
-         ++i, j--) {
-      ProcessInput(node, (*i).index(), kMachAnyTagged);  // Context inputs
+    // Only enqueue other inputs (framestates, effects, control).
+    for (int i = tagged_count; i < node->InputCount(); i++) {
+      EnqueueInput(node, i);
     }
-    for (int j = node->op()->EffectInputCount(); j > 0; ++i, j--) {
-      Enqueue((*i).to());  // Effect inputs: just visit
-    }
-    for (int j = node->op()->ControlInputCount(); j > 0; ++i, j--) {
-      Enqueue((*i).to());  // Control inputs: just visit
-    }
-    SetOutput(node, kMachAnyTagged);
   }
 
-  // Helper for binops of the I x I -> O variety.
-  void VisitBinop(Node* node, MachineTypeUnion input_use,
-                  MachineTypeUnion output) {
-    DCHECK_EQ(2, node->InputCount());
-    ProcessInput(node, 0, input_use);
-    ProcessInput(node, 1, input_use);
+  // Helper for binops of the R x L -> O variety.
+  void VisitBinop(Node* node, UseInfo left_use, UseInfo right_use,
+                  NodeOutputInfo output) {
+    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);
   }
 
+  // Helper for binops of the I x I -> O variety.
+  void VisitBinop(Node* node, UseInfo input_use, NodeOutputInfo output) {
+    VisitBinop(node, input_use, input_use, output);
+  }
+
   // Helper for unops of the I -> O variety.
-  void VisitUnop(Node* node, MachineTypeUnion input_use,
-                 MachineTypeUnion output) {
+  void VisitUnop(Node* node, UseInfo input_use, NodeOutputInfo output) {
     DCHECK_EQ(1, node->InputCount());
     ProcessInput(node, 0, input_use);
     SetOutput(node, output);
   }
 
   // Helper for leaf nodes.
-  void VisitLeaf(Node* node, MachineTypeUnion output) {
+  void VisitLeaf(Node* node, NodeOutputInfo output) {
     DCHECK_EQ(0, node->InputCount());
     SetOutput(node, output);
   }
 
   // Helpers for specific types of binops.
   void VisitFloat64Binop(Node* node) {
-    VisitBinop(node, kMachFloat64, kMachFloat64);
+    VisitBinop(node, UseInfo::Float64(), NodeOutputInfo::Float64());
   }
-  void VisitInt32Binop(Node* node) { VisitBinop(node, kMachInt32, kMachInt32); }
+  void VisitInt32Binop(Node* node) {
+    VisitBinop(node, UseInfo::TruncatingWord32(), NodeOutputInfo::Int32());
+  }
+  void VisitWord32TruncatingBinop(Node* node) {
+    VisitBinop(node, UseInfo::TruncatingWord32(),
+               NodeOutputInfo::NumberTruncatedToWord32());
+  }
   void VisitUint32Binop(Node* node) {
-    VisitBinop(node, kMachUint32, kMachUint32);
+    VisitBinop(node, UseInfo::TruncatingWord32(), NodeOutputInfo::Uint32());
   }
-  void VisitInt64Binop(Node* node) { VisitBinop(node, kMachInt64, kMachInt64); }
+  void VisitInt64Binop(Node* node) {
+    VisitBinop(node, UseInfo::TruncatingWord64(), NodeOutputInfo::Int64());
+  }
   void VisitUint64Binop(Node* node) {
-    VisitBinop(node, kMachUint64, kMachUint64);
+    VisitBinop(node, UseInfo::TruncatingWord64(), NodeOutputInfo::Uint64());
   }
-  void VisitFloat64Cmp(Node* node) { VisitBinop(node, kMachFloat64, kRepBit); }
-  void VisitInt32Cmp(Node* node) { VisitBinop(node, kMachInt32, kRepBit); }
-  void VisitUint32Cmp(Node* node) { VisitBinop(node, kMachUint32, kRepBit); }
-  void VisitInt64Cmp(Node* node) { VisitBinop(node, kMachInt64, kRepBit); }
-  void VisitUint64Cmp(Node* node) { VisitBinop(node, kMachUint64, kRepBit); }
+  void VisitFloat64Cmp(Node* node) {
+    VisitBinop(node, UseInfo::Float64(), NodeOutputInfo::Bool());
+  }
+  void VisitInt32Cmp(Node* node) {
+    VisitBinop(node, UseInfo::TruncatingWord32(), NodeOutputInfo::Bool());
+  }
+  void VisitUint32Cmp(Node* node) {
+    VisitBinop(node, UseInfo::TruncatingWord32(), NodeOutputInfo::Bool());
+  }
+  void VisitInt64Cmp(Node* node) {
+    VisitBinop(node, UseInfo::TruncatingWord64(), NodeOutputInfo::Bool());
+  }
+  void VisitUint64Cmp(Node* node) {
+    VisitBinop(node, UseInfo::TruncatingWord64(), NodeOutputInfo::Bool());
+  }
 
   // Infer representation for phi-like nodes.
-  MachineType GetRepresentationForPhi(Node* node, MachineTypeUnion use) {
-    // Phis adapt to the output representation their uses demand.
-    Type* upper = NodeProperties::GetBounds(node).upper;
-    if ((use & kRepMask) == kRepTagged) {
-      // only tagged uses.
-      return kRepTagged;
-    } else if (upper->Is(Type::Integral32())) {
-      // Integer within [-2^31, 2^32[ range.
-      if ((use & kRepMask) == kRepFloat64) {
-        // only float64 uses.
-        return kRepFloat64;
-      } else if (upper->Is(Type::Signed32()) || upper->Is(Type::Unsigned32())) {
-        // multiple uses, but we are within 32 bits range => pick kRepWord32.
-        return kRepWord32;
-      } else if ((use & kRepMask) == kRepWord32 ||
-                 (use & kTypeMask) == kTypeInt32 ||
-                 (use & kTypeMask) == kTypeUint32) {
-        // We only use 32 bits or we use the result consistently.
-        return kRepWord32;
-      } else {
-        return kRepFloat64;
-      }
-    } else if (IsSafeBitOperand(node)) {
-      // multiple uses => pick kRepBit.
-      return kRepBit;
-    } else if (upper->Is(Type::Number())) {
-      // multiple uses => pick kRepFloat64.
-      return kRepFloat64;
+  NodeOutputInfo GetOutputInfoForPhi(Node* node, Truncation use) {
+    // Compute the type.
+    Type* type = GetInfo(node->InputAt(0))->output_type();
+    for (int i = 1; i < node->op()->ValueInputCount(); ++i) {
+      type = Type::Union(type, GetInfo(node->InputAt(i))->output_type(),
+                         jsgraph_->zone());
     }
-    return kRepTagged;
+
+    // Compute the representation.
+    MachineRepresentation rep = MachineRepresentation::kTagged;
+    if (type->Is(Type::None())) {
+      rep = MachineRepresentation::kNone;
+    } else if (type->Is(Type::Signed32()) || type->Is(Type::Unsigned32())) {
+      rep = MachineRepresentation::kWord32;
+    } else if (use.TruncatesToWord32()) {
+      rep = MachineRepresentation::kWord32;
+    } else if (type->Is(Type::Boolean())) {
+      rep = MachineRepresentation::kBit;
+    } else if (type->Is(Type::Number())) {
+      rep = MachineRepresentation::kFloat64;
+    } else if (type->Is(Type::Internal())) {
+      // We mark (u)int64 as Type::Internal.
+      // TODO(jarin) This is a workaround for our lack of (u)int64
+      // types. This can be removed once we can represent (u)int64
+      // unambiguously. (At the moment internal objects, such as the hole,
+      // are also Type::Internal()).
+      bool is_word64 = GetInfo(node->InputAt(0))->representation() ==
+                       MachineRepresentation::kWord64;
+#ifdef DEBUG
+      // Check that all the inputs agree on being Word64.
+      for (int i = 1; i < node->op()->ValueInputCount(); i++) {
+        DCHECK_EQ(is_word64, GetInfo(node->InputAt(i))->representation() ==
+                                 MachineRepresentation::kWord64);
+      }
+#endif
+      rep = is_word64 ? MachineRepresentation::kWord64
+                      : MachineRepresentation::kTagged;
+    }
+    return NodeOutputInfo(rep, type);
   }
 
   // Helper for handling selects.
-  void VisitSelect(Node* node, MachineTypeUnion use,
+  void VisitSelect(Node* node, Truncation truncation,
                    SimplifiedLowering* lowering) {
-    ProcessInput(node, 0, kRepBit);
-    MachineType output = GetRepresentationForPhi(node, use);
+    ProcessInput(node, 0, UseInfo::Bool());
 
-    Type* upper = NodeProperties::GetBounds(node).upper;
-    MachineType output_type =
-        static_cast<MachineType>(changer_->TypeFromUpperBound(upper) | output);
-    SetOutput(node, output_type);
+    NodeOutputInfo output = GetOutputInfoForPhi(node, truncation);
+    SetOutput(node, output);
 
     if (lower()) {
       // Update the select operator.
       SelectParameters p = SelectParametersOf(node->op());
-      MachineType type = static_cast<MachineType>(output_type);
-      if (type != p.type()) {
-        node->set_op(lowering->common()->Select(type, p.hint()));
+      if (output.representation() != p.representation()) {
+        NodeProperties::ChangeOp(node, lowering->common()->Select(
+                                           output.representation(), p.hint()));
       }
-
-      // Convert inputs to the output representation of this select.
-      ProcessInput(node, 1, output_type);
-      ProcessInput(node, 2, output_type);
-    } else {
-      // Propagate {use} of the select to value inputs.
-      MachineType use_type =
-          static_cast<MachineType>((use & kTypeMask) | output);
-      ProcessInput(node, 1, use_type);
-      ProcessInput(node, 2, use_type);
     }
+    // Convert inputs to the output representation of this phi, pass the
+    // truncation truncation along.
+    UseInfo input_use(output.representation(), truncation);
+    ProcessInput(node, 1, input_use);
+    ProcessInput(node, 2, input_use);
   }
 
   // Helper for handling phis.
-  void VisitPhi(Node* node, MachineTypeUnion use,
+  void VisitPhi(Node* node, Truncation truncation,
                 SimplifiedLowering* lowering) {
-    MachineType output = GetRepresentationForPhi(node, use);
-
-    Type* upper = NodeProperties::GetBounds(node).upper;
-    MachineType output_type =
-        static_cast<MachineType>(changer_->TypeFromUpperBound(upper) | output);
-    SetOutput(node, output_type);
+    NodeOutputInfo output = GetOutputInfoForPhi(node, truncation);
+    SetOutput(node, output);
 
     int values = node->op()->ValueInputCount();
-
     if (lower()) {
       // Update the phi operator.
-      MachineType type = static_cast<MachineType>(output_type);
-      if (type != OpParameter<MachineType>(node)) {
-        node->set_op(lowering->common()->Phi(type, values));
-      }
-
-      // Convert inputs to the output representation of this phi.
-      for (Edge const edge : node->input_edges()) {
-        // TODO(titzer): it'd be nice to have distinguished edge kinds here.
-        ProcessInput(node, edge.index(), values > 0 ? output_type : 0);
-        values--;
-      }
-    } else {
-      // Propagate {use} of the phi to value inputs, and 0 to control.
-      MachineType use_type =
-          static_cast<MachineType>((use & kTypeMask) | output);
-      for (Edge const edge : node->input_edges()) {
-        // TODO(titzer): it'd be nice to have distinguished edge kinds here.
-        ProcessInput(node, edge.index(), values > 0 ? use_type : 0);
-        values--;
+      if (output.representation() != PhiRepresentationOf(node->op())) {
+        NodeProperties::ChangeOp(
+            node, lowering->common()->Phi(output.representation(), values));
       }
     }
+
+    // Convert inputs to the output representation of this phi, pass the
+    // truncation truncation along.
+    UseInfo input_use(output.representation(), truncation);
+    for (int i = 0; i < node->InputCount(); i++) {
+      ProcessInput(node, i, i < values ? input_use : UseInfo::None());
+    }
+  }
+
+  void VisitCall(Node* node, SimplifiedLowering* lowering) {
+    const CallDescriptor* desc = OpParameter<const CallDescriptor*>(node->op());
+    const MachineSignature* sig = desc->GetMachineSignature();
+    int params = static_cast<int>(sig->parameter_count());
+    // Propagate representation information from call descriptor.
+    for (int i = 0; i < node->InputCount(); i++) {
+      if (i == 0) {
+        // The target of the call.
+        ProcessInput(node, i, UseInfo::None());
+      } else if ((i - 1) < params) {
+        ProcessInput(node, i, TruncatingUseInfoFromRepresentation(
+                                  sig->GetParam(i - 1).representation()));
+      } else {
+        ProcessInput(node, i, UseInfo::None());
+      }
+    }
+
+    if (sig->return_count() > 0) {
+      SetOutputFromMachineType(node, desc->GetMachineSignature()->GetReturn());
+    } else {
+      SetOutput(node, NodeOutputInfo::AnyTagged());
+    }
+  }
+
+  MachineSemantic DeoptValueSemanticOf(Type* type) {
+    CHECK(!type->Is(Type::None()));
+    // We only need signedness to do deopt correctly.
+    if (type->Is(Type::Signed32())) {
+      return MachineSemantic::kInt32;
+    } else if (type->Is(Type::Unsigned32())) {
+      return MachineSemantic::kUint32;
+    } else {
+      return MachineSemantic::kAny;
+    }
+  }
+
+  void VisitStateValues(Node* node) {
+    if (phase_ == PROPAGATE) {
+      for (int i = 0; i < node->InputCount(); i++) {
+        EnqueueInput(node, i, UseInfo::Any());
+      }
+    } else {
+      Zone* zone = jsgraph_->zone();
+      ZoneVector<MachineType>* types =
+          new (zone->New(sizeof(ZoneVector<MachineType>)))
+              ZoneVector<MachineType>(node->InputCount(), zone);
+      for (int i = 0; i < node->InputCount(); i++) {
+        NodeInfo* input_info = GetInfo(node->InputAt(i));
+        MachineType machine_type(
+            input_info->representation(),
+            DeoptValueSemanticOf(input_info->output_type()));
+        DCHECK(machine_type.representation() !=
+                   MachineRepresentation::kWord32 ||
+               machine_type.semantic() == MachineSemantic::kInt32 ||
+               machine_type.semantic() == MachineSemantic::kUint32);
+        (*types)[i] = machine_type;
+      }
+      NodeProperties::ChangeOp(node,
+                               jsgraph_->common()->TypedStateValues(types));
+    }
+    SetOutput(node, NodeOutputInfo::AnyTagged());
   }
 
   const Operator* Int32Op(Node* node) {
@@ -413,60 +825,9 @@
     return changer_->Float64OperatorFor(node->opcode());
   }
 
-  bool CanLowerToInt32Binop(Node* node, MachineTypeUnion use) {
-    return BothInputsAre(node, Type::Signed32()) && !CanObserveNonInt32(use);
-  }
-
-  bool IsSafeBitOperand(Node* node) {
-    Type* type = NodeProperties::GetBounds(node).upper;
-    return type->Is(safe_bit_range_);
-  }
-
-  bool IsSafeIntAdditiveOperand(Node* node) {
-    Type* type = NodeProperties::GetBounds(node).upper;
-    // TODO(jarin): Unfortunately, bitset types are not subtypes of larger
-    // range types, so we have to explicitly check for Integral32 here
-    // (in addition to the safe integer range). Once we fix subtyping for
-    // ranges, we should simplify this.
-    return type->Is(safe_int_additive_range_) || type->Is(Type::Integral32());
-  }
-
-  bool CanLowerToInt32AdditiveBinop(Node* node, MachineTypeUnion use) {
-    return IsSafeIntAdditiveOperand(node->InputAt(0)) &&
-           IsSafeIntAdditiveOperand(node->InputAt(1)) &&
-           !CanObserveNonInt32(use);
-  }
-
-  bool CanLowerToUint32Binop(Node* node, MachineTypeUnion use) {
-    return BothInputsAre(node, Type::Unsigned32()) && !CanObserveNonUint32(use);
-  }
-
-  bool CanLowerToUint32AdditiveBinop(Node* node, MachineTypeUnion use) {
-    return IsSafeIntAdditiveOperand(node->InputAt(0)) &&
-           IsSafeIntAdditiveOperand(node->InputAt(1)) &&
-           !CanObserveNonUint32(use);
-  }
-
-  bool CanObserveNonInt32(MachineTypeUnion use) {
-    return (use & (kTypeUint32 | kTypeNumber | kTypeAny)) != 0;
-  }
-
-  bool CanObserveMinusZero(MachineTypeUnion use) {
-    // TODO(turbofan): technically Uint32 cannot observe minus zero either.
-    return (use & (kTypeUint32 | kTypeNumber | kTypeAny)) != 0;
-  }
-
-  bool CanObserveNaN(MachineTypeUnion use) {
-    return (use & (kTypeNumber | kTypeAny)) != 0;
-  }
-
-  bool CanObserveNonUint32(MachineTypeUnion use) {
-    return (use & (kTypeInt32 | kTypeNumber | kTypeAny)) != 0;
-  }
-
   // 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, MachineTypeUnion use,
+  void VisitNode(Node* node, Truncation truncation,
                  SimplifiedLowering* lowering) {
     switch (node->opcode()) {
       //------------------------------------------------------------------
@@ -474,43 +835,43 @@
       //------------------------------------------------------------------
       case IrOpcode::kStart:
       case IrOpcode::kDead:
-        return VisitLeaf(node, 0);
+        return VisitLeaf(node, NodeOutputInfo::None());
       case IrOpcode::kParameter: {
         // TODO(titzer): use representation from linkage.
-        Type* upper = NodeProperties::GetBounds(node).upper;
-        ProcessInput(node, 0, 0);
-        SetOutput(node, kRepTagged | changer_->TypeFromUpperBound(upper));
+        Type* type = NodeProperties::GetType(node);
+        ProcessInput(node, 0, UseInfo::None());
+        SetOutput(node, NodeOutputInfo(MachineRepresentation::kTagged, type));
         return;
       }
       case IrOpcode::kInt32Constant:
-        return VisitLeaf(node, kRepWord32);
+        return VisitLeaf(node, NodeOutputInfo::Int32());
       case IrOpcode::kInt64Constant:
-        return VisitLeaf(node, kRepWord64);
+        return VisitLeaf(node, NodeOutputInfo::Int64());
+      case IrOpcode::kFloat32Constant:
+        return VisitLeaf(node, NodeOutputInfo::Float32());
       case IrOpcode::kFloat64Constant:
-        return VisitLeaf(node, kRepFloat64);
+        return VisitLeaf(node, NodeOutputInfo::Float64());
       case IrOpcode::kExternalConstant:
-        return VisitLeaf(node, kMachPtr);
+        return VisitLeaf(node, NodeOutputInfo::Pointer());
       case IrOpcode::kNumberConstant:
-        return VisitLeaf(node, kRepTagged);
+        return VisitLeaf(node, NodeOutputInfo::NumberTagged());
       case IrOpcode::kHeapConstant:
-        return VisitLeaf(node, kRepTagged);
-
-      case IrOpcode::kEnd:
-      case IrOpcode::kIfTrue:
-      case IrOpcode::kIfFalse:
-      case IrOpcode::kReturn:
-      case IrOpcode::kMerge:
-      case IrOpcode::kThrow:
-        return VisitInputs(node);  // default visit for all node inputs.
+        return VisitLeaf(node, NodeOutputInfo::AnyTagged());
 
       case IrOpcode::kBranch:
-        ProcessInput(node, 0, kRepBit);
-        Enqueue(NodeProperties::GetControlInput(node, 0));
+        ProcessInput(node, 0, UseInfo::Bool());
+        EnqueueInput(node, NodeProperties::FirstControlIndex(node));
+        break;
+      case IrOpcode::kSwitch:
+        ProcessInput(node, 0, UseInfo::TruncatingWord32());
+        EnqueueInput(node, NodeProperties::FirstControlIndex(node));
         break;
       case IrOpcode::kSelect:
-        return VisitSelect(node, use, lowering);
+        return VisitSelect(node, truncation, lowering);
       case IrOpcode::kPhi:
-        return VisitPhi(node, use, lowering);
+        return VisitPhi(node, truncation, lowering);
+      case IrOpcode::kCall:
+        return VisitCall(node, lowering);
 
 //------------------------------------------------------------------
 // JavaScript operators.
@@ -524,67 +885,45 @@
         JS_OP_LIST(DEFINE_JS_CASE)
 #undef DEFINE_JS_CASE
         VisitInputs(node);
-        return SetOutput(node, kRepTagged);
+        return SetOutput(node, NodeOutputInfo::AnyTagged());
 
       //------------------------------------------------------------------
       // Simplified operators.
       //------------------------------------------------------------------
-      case IrOpcode::kAnyToBoolean: {
-        if (IsSafeBitOperand(node->InputAt(0))) {
-          VisitUnop(node, kRepBit, kRepBit);
-          if (lower()) DeferReplacement(node, node->InputAt(0));
-        } else {
-          VisitUnop(node, kMachAnyTagged, kTypeBool | kRepTagged);
-          if (lower()) {
-            // AnyToBoolean(x) => Call(ToBooleanStub, x, no-context)
-            Operator::Properties properties = node->op()->properties();
-            Callable callable = CodeFactory::ToBoolean(
-                jsgraph_->isolate(), ToBooleanStub::RESULT_AS_ODDBALL);
-            CallDescriptor::Flags flags = CallDescriptor::kPatchableCallSite;
-            CallDescriptor* desc = Linkage::GetStubCallDescriptor(
-                callable.descriptor(), 0, flags, properties, jsgraph_->zone());
-            node->set_op(jsgraph_->common()->Call(desc));
-            node->InsertInput(jsgraph_->zone(), 0,
-                              jsgraph_->HeapConstant(callable.code()));
-            node->AppendInput(jsgraph_->zone(), jsgraph_->NoContextConstant());
-          }
-        }
-        break;
-      }
       case IrOpcode::kBooleanNot: {
         if (lower()) {
-          MachineTypeUnion input = GetInfo(node->InputAt(0))->output;
-          if (input & kRepBit) {
+          NodeInfo* input_info = GetInfo(node->InputAt(0));
+          if (input_info->representation() == MachineRepresentation::kBit) {
             // BooleanNot(x: kRepBit) => Word32Equal(x, #0)
-            node->set_op(lowering->machine()->Word32Equal());
             node->AppendInput(jsgraph_->zone(), jsgraph_->Int32Constant(0));
+            NodeProperties::ChangeOp(node, lowering->machine()->Word32Equal());
           } else {
             // BooleanNot(x: kRepTagged) => WordEqual(x, #false)
-            node->set_op(lowering->machine()->WordEqual());
             node->AppendInput(jsgraph_->zone(), jsgraph_->FalseConstant());
+            NodeProperties::ChangeOp(node, lowering->machine()->WordEqual());
           }
         } else {
           // No input representation requirement; adapt during lowering.
-          ProcessInput(node, 0, kTypeBool);
-          SetOutput(node, kRepBit);
+          ProcessInput(node, 0, UseInfo::AnyTruncatingToBool());
+          SetOutput(node, NodeOutputInfo::Bool());
         }
         break;
       }
       case IrOpcode::kBooleanToNumber: {
         if (lower()) {
-          MachineTypeUnion input = GetInfo(node->InputAt(0))->output;
-          if (input & kRepBit) {
+          NodeInfo* input_info = GetInfo(node->InputAt(0));
+          if (input_info->representation() == MachineRepresentation::kBit) {
             // BooleanToNumber(x: kRepBit) => x
             DeferReplacement(node, node->InputAt(0));
           } else {
             // BooleanToNumber(x: kRepTagged) => WordEqual(x, #true)
-            node->set_op(lowering->machine()->WordEqual());
             node->AppendInput(jsgraph_->zone(), jsgraph_->TrueConstant());
+            NodeProperties::ChangeOp(node, lowering->machine()->WordEqual());
           }
         } else {
           // No input representation requirement; adapt during lowering.
-          ProcessInput(node, 0, kTypeBool);
-          SetOutput(node, kMachInt32);
+          ProcessInput(node, 0, UseInfo::AnyTruncatingToBool());
+          SetOutput(node, NodeOutputInfo::Int32());
         }
         break;
       }
@@ -592,288 +931,319 @@
       case IrOpcode::kNumberLessThan:
       case IrOpcode::kNumberLessThanOrEqual: {
         // Number comparisons reduce to integer comparisons for integer inputs.
-        if (BothInputsAre(node, Type::Signed32())) {
+        if (BothInputsAreSigned32(node)) {
           // => signed Int32Cmp
           VisitInt32Cmp(node);
-          if (lower()) node->set_op(Int32Op(node));
-        } else if (BothInputsAre(node, Type::Unsigned32())) {
+          if (lower()) NodeProperties::ChangeOp(node, Int32Op(node));
+        } else if (BothInputsAreUnsigned32(node)) {
           // => unsigned Int32Cmp
           VisitUint32Cmp(node);
-          if (lower()) node->set_op(Uint32Op(node));
+          if (lower()) NodeProperties::ChangeOp(node, Uint32Op(node));
         } else {
           // => Float64Cmp
           VisitFloat64Cmp(node);
-          if (lower()) node->set_op(Float64Op(node));
+          if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
         }
         break;
       }
       case IrOpcode::kNumberAdd:
       case IrOpcode::kNumberSubtract: {
-        // Add and subtract reduce to Int32Add/Sub if the inputs
-        // are already integers and all uses are truncating.
-        if (CanLowerToInt32Binop(node, use)) {
+        if (BothInputsAre(node, Type::Signed32()) &&
+            NodeProperties::GetType(node)->Is(Type::Signed32())) {
+          // int32 + int32 = int32
           // => signed Int32Add/Sub
           VisitInt32Binop(node);
-          if (lower()) node->set_op(Int32Op(node));
-        } else if (CanLowerToInt32AdditiveBinop(node, use)) {
-          // => signed Int32Add/Sub, truncating inputs
-          ProcessTruncateWord32Input(node, 0, kTypeInt32);
-          ProcessTruncateWord32Input(node, 1, kTypeInt32);
-          SetOutput(node, kMachInt32);
-          if (lower()) node->set_op(Int32Op(node));
-        } else if (CanLowerToUint32Binop(node, use)) {
-          // => unsigned Int32Add/Sub
-          VisitUint32Binop(node);
-          if (lower()) node->set_op(Uint32Op(node));
-        } else if (CanLowerToUint32AdditiveBinop(node, use)) {
-          // => signed Int32Add/Sub, truncating inputs
-          ProcessTruncateWord32Input(node, 0, kTypeUint32);
-          ProcessTruncateWord32Input(node, 1, kTypeUint32);
-          SetOutput(node, kMachUint32);
-          if (lower()) node->set_op(Uint32Op(node));
+          if (lower()) NodeProperties::ChangeOp(node, Int32Op(node));
+        } else if (BothInputsAre(node, type_cache_.kAdditiveSafeInteger) &&
+                   truncation.TruncatesToWord32()) {
+          // safe-int + safe-int = x (truncated to int32)
+          // => signed Int32Add/Sub (truncated)
+          VisitWord32TruncatingBinop(node);
+          if (lower()) NodeProperties::ChangeOp(node, Int32Op(node));
         } else {
           // => Float64Add/Sub
           VisitFloat64Binop(node);
-          if (lower()) node->set_op(Float64Op(node));
+          if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
         }
         break;
       }
       case IrOpcode::kNumberMultiply: {
-        NumberMatcher right(node->InputAt(1));
-        if (right.IsInRange(-1048576, 1048576)) {  // must fit double mantissa.
-          if (CanLowerToInt32Binop(node, use)) {
-            // => signed Int32Mul
+        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()) node->set_op(Int32Op(node));
+            if (lower()) NodeProperties::ChangeOp(node, Int32Op(node));
+            break;
+          }
+          if (truncation.TruncatesToWord32() &&
+              NodeProperties::GetType(node)->Is(type_cache_.kSafeInteger)) {
+            // 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;
           }
         }
         // => Float64Mul
         VisitFloat64Binop(node);
-        if (lower()) node->set_op(Float64Op(node));
+        if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
         break;
       }
       case IrOpcode::kNumberDivide: {
-        if (CanLowerToInt32Binop(node, use)) {
+        if (BothInputsAreSigned32(node)) {
+          if (NodeProperties::GetType(node)->Is(Type::Signed32())) {
           // => signed Int32Div
           VisitInt32Binop(node);
           if (lower()) DeferReplacement(node, lowering->Int32Div(node));
           break;
+          }
+          if (truncation.TruncatesToWord32()) {
+            // => signed Int32Div
+            VisitWord32TruncatingBinop(node);
+            if (lower()) DeferReplacement(node, lowering->Int32Div(node));
+            break;
+          }
         }
-        if (BothInputsAre(node, Type::Unsigned32()) && !CanObserveNaN(use)) {
+        if (BothInputsAreUnsigned32(node) && truncation.TruncatesToWord32()) {
           // => unsigned Uint32Div
-          VisitUint32Binop(node);
+          VisitWord32TruncatingBinop(node);
           if (lower()) DeferReplacement(node, lowering->Uint32Div(node));
           break;
         }
         // => Float64Div
         VisitFloat64Binop(node);
-        if (lower()) node->set_op(Float64Op(node));
+        if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
         break;
       }
       case IrOpcode::kNumberModulus: {
-        if (CanLowerToInt32Binop(node, use)) {
-          // => signed Int32Mod
-          VisitInt32Binop(node);
-          if (lower()) DeferReplacement(node, lowering->Int32Mod(node));
-          break;
+        if (BothInputsAreSigned32(node)) {
+          if (NodeProperties::GetType(node)->Is(Type::Signed32())) {
+            // => signed Int32Mod
+            VisitInt32Binop(node);
+            if (lower()) DeferReplacement(node, lowering->Int32Mod(node));
+            break;
+          }
+          if (truncation.TruncatesToWord32()) {
+            // => signed Int32Mod
+            VisitWord32TruncatingBinop(node);
+            if (lower()) DeferReplacement(node, lowering->Int32Mod(node));
+            break;
+          }
         }
-        if (BothInputsAre(node, Type::Unsigned32()) && !CanObserveNaN(use)) {
+        if (BothInputsAreUnsigned32(node) && truncation.TruncatesToWord32()) {
           // => unsigned Uint32Mod
-          VisitUint32Binop(node);
+          VisitWord32TruncatingBinop(node);
           if (lower()) DeferReplacement(node, lowering->Uint32Mod(node));
           break;
         }
         // => Float64Mod
         VisitFloat64Binop(node);
-        if (lower()) node->set_op(Float64Op(node));
+        if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
         break;
       }
-      case IrOpcode::kNumberToInt32: {
-        MachineTypeUnion use_rep = use & kRepMask;
-        Node* input = node->InputAt(0);
-        Type* in_upper = NodeProperties::GetBounds(input).upper;
-        MachineTypeUnion in = GetInfo(input)->output;
-        if (in_upper->Is(Type::Signed32())) {
-          // If the input has type int32, pass through representation.
-          VisitUnop(node, kTypeInt32 | use_rep, kTypeInt32 | use_rep);
-          if (lower()) DeferReplacement(node, node->InputAt(0));
-        } else if ((in & kTypeMask) == kTypeUint32 ||
-                   in_upper->Is(Type::Unsigned32())) {
-          // Just change representation if necessary.
-          VisitUnop(node, kTypeUint32 | kRepWord32, kTypeInt32 | kRepWord32);
-          if (lower()) DeferReplacement(node, node->InputAt(0));
-        } else if ((in & kTypeMask) == kTypeInt32 ||
-                   (in & kRepMask) == kRepWord32) {
-          // Just change representation if necessary.
-          VisitUnop(node, kTypeInt32 | kRepWord32, kTypeInt32 | kRepWord32);
-          if (lower()) DeferReplacement(node, node->InputAt(0));
-        } else {
-          // Require the input in float64 format and perform truncation.
-          // TODO(turbofan): avoid a truncation with a smi check.
-          VisitUnop(node, kTypeInt32 | kRepFloat64, kTypeInt32 | kRepWord32);
-          if (lower())
-            node->set_op(lowering->machine()->TruncateFloat64ToInt32());
+      case IrOpcode::kNumberBitwiseOr:
+      case IrOpcode::kNumberBitwiseXor:
+      case IrOpcode::kNumberBitwiseAnd: {
+        VisitInt32Binop(node);
+        if (lower()) NodeProperties::ChangeOp(node, Int32Op(node));
+        break;
+      }
+      case IrOpcode::kNumberShiftLeft: {
+        Type* rhs_type = GetInfo(node->InputAt(1))->output_type();
+        VisitBinop(node, UseInfo::TruncatingWord32(),
+                   UseInfo::TruncatingWord32(), NodeOutputInfo::Int32());
+        if (lower()) {
+          lowering->DoShift(node, lowering->machine()->Word32Shl(), rhs_type);
         }
         break;
       }
+      case IrOpcode::kNumberShiftRight: {
+        Type* rhs_type = GetInfo(node->InputAt(1))->output_type();
+        VisitBinop(node, UseInfo::TruncatingWord32(),
+                   UseInfo::TruncatingWord32(), NodeOutputInfo::Int32());
+        if (lower()) {
+          lowering->DoShift(node, lowering->machine()->Word32Sar(), rhs_type);
+        }
+        break;
+      }
+      case IrOpcode::kNumberShiftRightLogical: {
+        Type* rhs_type = GetInfo(node->InputAt(1))->output_type();
+        VisitBinop(node, UseInfo::TruncatingWord32(),
+                   UseInfo::TruncatingWord32(), NodeOutputInfo::Uint32());
+        if (lower()) {
+          lowering->DoShift(node, lowering->machine()->Word32Shr(), rhs_type);
+        }
+        break;
+      }
+      case IrOpcode::kNumberToInt32: {
+        // Just change representation if necessary.
+        VisitUnop(node, UseInfo::TruncatingWord32(), NodeOutputInfo::Int32());
+        if (lower()) DeferReplacement(node, node->InputAt(0));
+        break;
+      }
       case IrOpcode::kNumberToUint32: {
-        MachineTypeUnion use_rep = use & kRepMask;
-        Node* input = node->InputAt(0);
-        Type* in_upper = NodeProperties::GetBounds(input).upper;
-        MachineTypeUnion in = GetInfo(input)->output;
-        if (in_upper->Is(Type::Unsigned32())) {
-          // If the input has type uint32, pass through representation.
-          VisitUnop(node, kTypeUint32 | use_rep, kTypeUint32 | use_rep);
-          if (lower()) DeferReplacement(node, node->InputAt(0));
-        } else if ((in & kTypeMask) == kTypeUint32 ||
-                   in_upper->Is(Type::Unsigned32())) {
-          // Just change representation if necessary.
-          VisitUnop(node, kTypeUint32 | kRepWord32, kTypeUint32 | kRepWord32);
-          if (lower()) DeferReplacement(node, node->InputAt(0));
-        } else if ((in & kTypeMask) == kTypeInt32 ||
-                   (in & kRepMask) == kRepWord32) {
-          // Just change representation if necessary.
-          VisitUnop(node, kTypeInt32 | kRepWord32, kTypeUint32 | kRepWord32);
-          if (lower()) DeferReplacement(node, node->InputAt(0));
-        } else {
-          // Require the input in float64 format and perform truncation.
-          // TODO(turbofan): avoid a truncation with a smi check.
-          VisitUnop(node, kTypeUint32 | kRepFloat64, kTypeUint32 | kRepWord32);
-          if (lower())
-            node->set_op(lowering->machine()->TruncateFloat64ToInt32());
+        // Just change representation if necessary.
+        VisitUnop(node, UseInfo::TruncatingWord32(), NodeOutputInfo::Uint32());
+        if (lower()) DeferReplacement(node, node->InputAt(0));
+        break;
+      }
+      case IrOpcode::kNumberIsHoleNaN: {
+        VisitUnop(node, UseInfo::Float64(), NodeOutputInfo::Bool());
+        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;
+      }
+      case IrOpcode::kPlainPrimitiveToNumber: {
+        VisitUnop(node, UseInfo::AnyTagged(), NodeOutputInfo::NumberTagged());
+        if (lower()) {
+          // PlainPrimitiveToNumber(x) => Call(ToNumberStub, x, no-context)
+          Operator::Properties properties = node->op()->properties();
+          Callable callable = CodeFactory::ToNumber(jsgraph_->isolate());
+          CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
+          CallDescriptor* desc = Linkage::GetStubCallDescriptor(
+              jsgraph_->isolate(), jsgraph_->zone(), callable.descriptor(), 0,
+              flags, properties);
+          node->InsertInput(jsgraph_->zone(), 0,
+                            jsgraph_->HeapConstant(callable.code()));
+          node->AppendInput(jsgraph_->zone(), jsgraph_->NoContextConstant());
+          NodeProperties::ChangeOp(node, jsgraph_->common()->Call(desc));
         }
         break;
       }
       case IrOpcode::kReferenceEqual: {
-        VisitBinop(node, kMachAnyTagged, kRepBit);
-        if (lower()) node->set_op(lowering->machine()->WordEqual());
+        VisitBinop(node, UseInfo::AnyTagged(), NodeOutputInfo::Bool());
+        if (lower()) {
+          NodeProperties::ChangeOp(node, lowering->machine()->WordEqual());
+        }
         break;
       }
       case IrOpcode::kStringEqual: {
-        VisitBinop(node, kMachAnyTagged, kRepBit);
+        VisitBinop(node, UseInfo::AnyTagged(), NodeOutputInfo::Bool());
         if (lower()) lowering->DoStringEqual(node);
         break;
       }
       case IrOpcode::kStringLessThan: {
-        VisitBinop(node, kMachAnyTagged, kRepBit);
+        VisitBinop(node, UseInfo::AnyTagged(), NodeOutputInfo::Bool());
         if (lower()) lowering->DoStringLessThan(node);
         break;
       }
       case IrOpcode::kStringLessThanOrEqual: {
-        VisitBinop(node, kMachAnyTagged, kRepBit);
+        VisitBinop(node, UseInfo::AnyTagged(), NodeOutputInfo::Bool());
         if (lower()) lowering->DoStringLessThanOrEqual(node);
         break;
       }
-      case IrOpcode::kStringAdd: {
-        VisitBinop(node, kMachAnyTagged, kMachAnyTagged);
-        if (lower()) lowering->DoStringAdd(node);
+      case IrOpcode::kAllocate: {
+        ProcessInput(node, 0, UseInfo::AnyTagged());
+        ProcessRemainingInputs(node, 1);
+        SetOutput(node, NodeOutputInfo::AnyTagged());
         break;
       }
       case IrOpcode::kLoadField: {
         FieldAccess access = FieldAccessOf(node->op());
-        ProcessInput(node, 0, changer_->TypeForBasePointer(access));
+        ProcessInput(node, 0, UseInfoForBasePointer(access));
         ProcessRemainingInputs(node, 1);
-        SetOutput(node, access.machine_type);
-        if (lower()) lowering->DoLoadField(node);
+        SetOutputFromMachineType(node, access.machine_type);
         break;
       }
       case IrOpcode::kStoreField: {
         FieldAccess access = FieldAccessOf(node->op());
-        ProcessInput(node, 0, changer_->TypeForBasePointer(access));
-        ProcessInput(node, 1, access.machine_type);
+        ProcessInput(node, 0, UseInfoForBasePointer(access));
+        ProcessInput(node, 1, TruncatingUseInfoFromRepresentation(
+                                  access.machine_type.representation()));
         ProcessRemainingInputs(node, 2);
-        SetOutput(node, 0);
-        if (lower()) lowering->DoStoreField(node);
+        SetOutput(node, NodeOutputInfo::None());
         break;
       }
       case IrOpcode::kLoadBuffer: {
         BufferAccess access = BufferAccessOf(node->op());
-        ProcessInput(node, 0, kMachPtr);    // buffer
-        ProcessInput(node, 1, kMachInt32);  // offset
-        ProcessInput(node, 2, kMachInt32);  // length
+        ProcessInput(node, 0, UseInfo::PointerInt());        // buffer
+        ProcessInput(node, 1, UseInfo::TruncatingWord32());  // offset
+        ProcessInput(node, 2, UseInfo::TruncatingWord32());  // length
         ProcessRemainingInputs(node, 3);
-        // Tagged overrides everything if we have to do a typed array bounds
-        // check, because we may need to return undefined then.
-        MachineType output_type;
-        if (use & kRepTagged) {
-          output_type = kMachAnyTagged;
-        } else if (use & kRepFloat64) {
-          if (access.machine_type() & kRepFloat32) {
-            output_type = access.machine_type();
+
+        NodeOutputInfo output_info;
+        if (truncation.TruncatesUndefinedToZeroOrNaN()) {
+          if (truncation.TruncatesNaNToZero()) {
+            // If undefined is truncated to a non-NaN number, we can use
+            // the load's representation.
+            output_info = NodeOutputInfo(access.machine_type().representation(),
+                                         NodeProperties::GetType(node));
           } else {
-            output_type = kMachFloat64;
+            // If undefined is truncated to a number, but the use can
+            // observe NaN, we need to output at least the float32
+            // representation.
+            if (access.machine_type().representation() ==
+                MachineRepresentation::kFloat32) {
+              output_info =
+                  NodeOutputInfo(access.machine_type().representation(),
+                                 NodeProperties::GetType(node));
+            } else {
+              output_info = NodeOutputInfo::Float64();
+            }
           }
-        } else if (use & kRepFloat32) {
-          output_type = kMachFloat32;
         } else {
-          output_type = access.machine_type();
+          // If undefined is not truncated away, we need to have the tagged
+          // representation.
+          output_info = NodeOutputInfo::AnyTagged();
         }
-        SetOutput(node, output_type);
-        if (lower()) lowering->DoLoadBuffer(node, output_type, changer_);
+        SetOutput(node, output_info);
+        if (lower())
+          lowering->DoLoadBuffer(node, output_info.representation(), changer_);
         break;
       }
       case IrOpcode::kStoreBuffer: {
         BufferAccess access = BufferAccessOf(node->op());
-        ProcessInput(node, 0, kMachPtr);               // buffer
-        ProcessInput(node, 1, kMachInt32);             // offset
-        ProcessInput(node, 2, kMachInt32);             // length
-        ProcessInput(node, 3, access.machine_type());  // value
+        ProcessInput(node, 0, UseInfo::PointerInt());        // buffer
+        ProcessInput(node, 1, UseInfo::TruncatingWord32());  // offset
+        ProcessInput(node, 2, UseInfo::TruncatingWord32());  // length
+        ProcessInput(node, 3,
+                     TruncatingUseInfoFromRepresentation(
+                         access.machine_type().representation()));  // value
         ProcessRemainingInputs(node, 4);
-        SetOutput(node, 0);
+        SetOutput(node, NodeOutputInfo::None());
         if (lower()) lowering->DoStoreBuffer(node);
         break;
       }
       case IrOpcode::kLoadElement: {
         ElementAccess access = ElementAccessOf(node->op());
-        ProcessInput(node, 0, changer_->TypeForBasePointer(access));  // base
-        ProcessInput(node, 1, kMachInt32);                            // index
+        ProcessInput(node, 0, UseInfoForBasePointer(access));  // base
+        ProcessInput(node, 1, UseInfo::TruncatingWord32());    // index
         ProcessRemainingInputs(node, 2);
-        SetOutput(node, access.machine_type);
-        if (lower()) lowering->DoLoadElement(node);
+        SetOutputFromMachineType(node, access.machine_type);
         break;
       }
       case IrOpcode::kStoreElement: {
         ElementAccess access = ElementAccessOf(node->op());
-        ProcessInput(node, 0, changer_->TypeForBasePointer(access));  // base
-        ProcessInput(node, 1, kMachInt32);                            // index
-        ProcessInput(node, 2, access.machine_type);                   // value
+        ProcessInput(node, 0, UseInfoForBasePointer(access));  // base
+        ProcessInput(node, 1, UseInfo::TruncatingWord32());    // index
+        ProcessInput(node, 2,
+                     TruncatingUseInfoFromRepresentation(
+                         access.machine_type.representation()));  // value
         ProcessRemainingInputs(node, 3);
-        SetOutput(node, 0);
-        if (lower()) lowering->DoStoreElement(node);
+        SetOutput(node, NodeOutputInfo::None());
+        break;
+      }
+      case IrOpcode::kObjectIsNumber: {
+        ProcessInput(node, 0, UseInfo::AnyTagged());
+        SetOutput(node, NodeOutputInfo::Bool());
+        if (lower()) lowering->DoObjectIsNumber(node);
         break;
       }
       case IrOpcode::kObjectIsSmi: {
-        ProcessInput(node, 0, kMachAnyTagged);
-        SetOutput(node, kRepBit | kTypeBool);
-        if (lower()) {
-          Node* is_tagged = jsgraph_->graph()->NewNode(
-              jsgraph_->machine()->WordAnd(), node->InputAt(0),
-              jsgraph_->Int32Constant(static_cast<int>(kSmiTagMask)));
-          Node* is_smi = jsgraph_->graph()->NewNode(
-              jsgraph_->machine()->WordEqual(), is_tagged,
-              jsgraph_->Int32Constant(kSmiTag));
-          DeferReplacement(node, is_smi);
-        }
-        break;
-      }
-      case IrOpcode::kObjectIsNonNegativeSmi: {
-        ProcessInput(node, 0, kMachAnyTagged);
-        SetOutput(node, kRepBit | kTypeBool);
-        if (lower()) {
-          Node* is_tagged = jsgraph_->graph()->NewNode(
-              jsgraph_->machine()->WordAnd(), node->InputAt(0),
-              jsgraph_->Int32Constant(static_cast<int>(kSmiTagMask)));
-          Node* is_smi = jsgraph_->graph()->NewNode(
-              jsgraph_->machine()->WordEqual(), is_tagged,
-              jsgraph_->Int32Constant(kSmiTag));
-          Node* is_non_neg = jsgraph_->graph()->NewNode(
-              jsgraph_->machine()->IntLessThanOrEqual(),
-              jsgraph_->Int32Constant(0), node->InputAt(0));
-          Node* is_non_neg_smi = jsgraph_->graph()->NewNode(
-              jsgraph_->machine()->Word32And(), is_smi, is_non_neg);
-          DeferReplacement(node, is_non_neg_smi);
-        }
+        ProcessInput(node, 0, UseInfo::AnyTagged());
+        SetOutput(node, NodeOutputInfo::Bool());
+        if (lower()) lowering->DoObjectIsSmi(node);
         break;
       }
 
@@ -881,29 +1251,31 @@
       // Machine-level operators.
       //------------------------------------------------------------------
       case IrOpcode::kLoad: {
-        // TODO(titzer): machine loads/stores need to know BaseTaggedness!?
-        MachineTypeUnion tBase = kRepTagged | kMachPtr;
-        LoadRepresentation rep = OpParameter<LoadRepresentation>(node);
-        ProcessInput(node, 0, tBase);   // pointer or object
-        ProcessInput(node, 1, kMachInt32);  // index
+        // TODO(jarin) Eventually, we should get rid of all machine stores
+        // from the high-level phases, then this becomes UNREACHABLE.
+        LoadRepresentation rep = LoadRepresentationOf(node->op());
+        ProcessInput(node, 0, UseInfo::AnyTagged());   // tagged pointer
+        ProcessInput(node, 1, UseInfo::PointerInt());  // index
         ProcessRemainingInputs(node, 2);
-        SetOutput(node, rep);
+        SetOutputFromMachineType(node, rep);
         break;
       }
       case IrOpcode::kStore: {
-        // TODO(titzer): machine loads/stores need to know BaseTaggedness!?
-        MachineTypeUnion tBase = kRepTagged | kMachPtr;
-        StoreRepresentation rep = OpParameter<StoreRepresentation>(node);
-        ProcessInput(node, 0, tBase);   // pointer or object
-        ProcessInput(node, 1, kMachInt32);  // index
-        ProcessInput(node, 2, rep.machine_type());
+        // TODO(jarin) Eventually, we should get rid of all machine stores
+        // from the high-level phases, then this becomes UNREACHABLE.
+        StoreRepresentation rep = StoreRepresentationOf(node->op());
+        ProcessInput(node, 0, UseInfo::AnyTagged());   // tagged pointer
+        ProcessInput(node, 1, UseInfo::PointerInt());  // index
+        ProcessInput(node, 2,
+                     TruncatingUseInfoFromRepresentation(rep.representation()));
         ProcessRemainingInputs(node, 3);
-        SetOutput(node, 0);
+        SetOutput(node, NodeOutputInfo::None());
         break;
       }
       case IrOpcode::kWord32Shr:
         // We output unsigned int32 for shift right because JavaScript.
-        return VisitBinop(node, kMachUint32, kMachUint32);
+        return VisitBinop(node, UseInfo::TruncatingWord32(),
+                          NodeOutputInfo::Uint32());
       case IrOpcode::kWord32And:
       case IrOpcode::kWord32Or:
       case IrOpcode::kWord32Xor:
@@ -912,9 +1284,15 @@
         // We use signed int32 as the output type for these word32 operations,
         // though the machine bits are the same for either signed or unsigned,
         // because JavaScript considers the result from these operations signed.
-        return VisitBinop(node, kRepWord32, kRepWord32 | kTypeInt32);
+        return VisitBinop(node, UseInfo::TruncatingWord32(),
+                          NodeOutputInfo::Int32());
       case IrOpcode::kWord32Equal:
-        return VisitBinop(node, kRepWord32, kRepBit);
+        return VisitBinop(node, UseInfo::TruncatingWord32(),
+                          NodeOutputInfo::Bool());
+
+      case IrOpcode::kWord32Clz:
+        return VisitUnop(node, UseInfo::TruncatingWord32(),
+                         NodeOutputInfo::Uint32());
 
       case IrOpcode::kInt32Add:
       case IrOpcode::kInt32Sub:
@@ -958,222 +1336,187 @@
       case IrOpcode::kWord64Shl:
       case IrOpcode::kWord64Shr:
       case IrOpcode::kWord64Sar:
-        return VisitBinop(node, kRepWord64, kRepWord64);
+        return VisitBinop(node, UseInfo::TruncatingWord64(),
+                          NodeOutputInfo::Int64());
       case IrOpcode::kWord64Equal:
-        return VisitBinop(node, kRepWord64, kRepBit);
+        return VisitBinop(node, UseInfo::TruncatingWord64(),
+                          NodeOutputInfo::Bool());
 
       case IrOpcode::kChangeInt32ToInt64:
-        return VisitUnop(node, kTypeInt32 | kRepWord32,
-                         kTypeInt32 | kRepWord64);
+        return VisitUnop(
+            node, UseInfo::TruncatingWord32(),
+            NodeOutputInfo(MachineRepresentation::kWord64, Type::Signed32()));
       case IrOpcode::kChangeUint32ToUint64:
-        return VisitUnop(node, kTypeUint32 | kRepWord32,
-                         kTypeUint32 | kRepWord64);
+        return VisitUnop(
+            node, UseInfo::TruncatingWord32(),
+            NodeOutputInfo(MachineRepresentation::kWord64, Type::Unsigned32()));
       case IrOpcode::kTruncateFloat64ToFloat32:
-        return VisitUnop(node, kTypeNumber | kRepFloat64,
-                         kTypeNumber | kRepFloat32);
+        return VisitUnop(node, UseInfo::Float64(), NodeOutputInfo::Float32());
+      case IrOpcode::kTruncateFloat64ToInt32:
+        return VisitUnop(node, UseInfo::Float64(), NodeOutputInfo::Int32());
       case IrOpcode::kTruncateInt64ToInt32:
         // TODO(titzer): Is kTypeInt32 correct here?
-        return VisitUnop(node, kTypeInt32 | kRepWord64,
-                         kTypeInt32 | kRepWord32);
+        return VisitUnop(node, UseInfo::Word64TruncatingToWord32(),
+                         NodeOutputInfo::Int32());
 
       case IrOpcode::kChangeFloat32ToFloat64:
-        return VisitUnop(node, kTypeNumber | kRepFloat32,
-                         kTypeNumber | kRepFloat64);
+        return VisitUnop(node, UseInfo::Float32(), NodeOutputInfo::Float64());
       case IrOpcode::kChangeInt32ToFloat64:
-        return VisitUnop(node, kTypeInt32 | kRepWord32,
-                         kTypeInt32 | kRepFloat64);
+        return VisitUnop(
+            node, UseInfo::TruncatingWord32(),
+            NodeOutputInfo(MachineRepresentation::kFloat64, Type::Signed32()));
       case IrOpcode::kChangeUint32ToFloat64:
-        return VisitUnop(node, kTypeUint32 | kRepWord32,
-                         kTypeUint32 | kRepFloat64);
+        return VisitUnop(node, UseInfo::TruncatingWord32(),
+                         NodeOutputInfo(MachineRepresentation::kFloat64,
+                                        Type::Unsigned32()));
       case IrOpcode::kChangeFloat64ToInt32:
-        return VisitUnop(node, kTypeInt32 | kRepFloat64,
-                         kTypeInt32 | kRepWord32);
+        return VisitUnop(node, UseInfo::Float64TruncatingToWord32(),
+                         NodeOutputInfo::Int32());
       case IrOpcode::kChangeFloat64ToUint32:
-        return VisitUnop(node, kTypeUint32 | kRepFloat64,
-                         kTypeUint32 | kRepWord32);
+        return VisitUnop(node, UseInfo::Float64TruncatingToWord32(),
+                         NodeOutputInfo::Uint32());
 
       case IrOpcode::kFloat64Add:
       case IrOpcode::kFloat64Sub:
       case IrOpcode::kFloat64Mul:
       case IrOpcode::kFloat64Div:
       case IrOpcode::kFloat64Mod:
+      case IrOpcode::kFloat64Min:
         return VisitFloat64Binop(node);
+      case IrOpcode::kFloat64Abs:
       case IrOpcode::kFloat64Sqrt:
-      case IrOpcode::kFloat64Floor:
-      case IrOpcode::kFloat64Ceil:
+      case IrOpcode::kFloat64RoundDown:
       case IrOpcode::kFloat64RoundTruncate:
       case IrOpcode::kFloat64RoundTiesAway:
-        return VisitUnop(node, kMachFloat64, kMachFloat64);
+        return VisitUnop(node, UseInfo::Float64(), NodeOutputInfo::Float64());
       case IrOpcode::kFloat64Equal:
       case IrOpcode::kFloat64LessThan:
       case IrOpcode::kFloat64LessThanOrEqual:
         return VisitFloat64Cmp(node);
+      case IrOpcode::kFloat64ExtractLowWord32:
+      case IrOpcode::kFloat64ExtractHighWord32:
+        return VisitUnop(node, UseInfo::Float64(), NodeOutputInfo::Int32());
+      case IrOpcode::kFloat64InsertLowWord32:
+      case IrOpcode::kFloat64InsertHighWord32:
+        return VisitBinop(node, UseInfo::Float64(), UseInfo::TruncatingWord32(),
+                          NodeOutputInfo::Float64());
       case IrOpcode::kLoadStackPointer:
-        return VisitLeaf(node, kMachPtr);
+      case IrOpcode::kLoadFramePointer:
+        return VisitLeaf(node, NodeOutputInfo::Pointer());
       case IrOpcode::kStateValues:
-        for (int i = 0; i < node->InputCount(); i++) {
-          ProcessInput(node, i, kTypeAny);
-        }
-        SetOutput(node, kMachAnyTagged);
+        VisitStateValues(node);
         break;
       default:
         VisitInputs(node);
+        // Assume the output is tagged.
+        SetOutput(node, NodeOutputInfo::AnyTagged());
         break;
     }
   }
 
   void DeferReplacement(Node* node, Node* replacement) {
-    if (FLAG_trace_representation) {
-      TRACE(("defer replacement #%d:%s with #%d:%s\n", node->id(),
-             node->op()->mnemonic(), replacement->id(),
-             replacement->op()->mnemonic()));
-    }
-    if (replacement->id() < count_) {
-      // Replace with a previously existing node eagerly.
+    TRACE("defer replacement #%d:%s with #%d:%s\n", node->id(),
+          node->op()->mnemonic(), replacement->id(),
+          replacement->op()->mnemonic());
+
+    if (replacement->id() < count_ &&
+        GetInfo(node)->output_type()->Is(GetInfo(replacement)->output_type())) {
+      // Replace with a previously existing node eagerly only if the type is the
+      // same.
       node->ReplaceUses(replacement);
     } else {
       // Otherwise, we are replacing a node with a representation change.
       // Such a substitution must be done after all lowering is done, because
-      // new nodes do not have {NodeInfo} entries, and that would confuse
-      // the representation change insertion for uses of it.
+      // changing the type could confuse the representation change
+      // insertion for uses of the node.
       replacements_.push_back(node);
       replacements_.push_back(replacement);
     }
-    // TODO(titzer) node->RemoveAllInputs();  // Node is now dead.
+    node->NullAllInputs();  // Node is now dead.
   }
 
-  void PrintUseInfo(Node* node) {
-    TRACE(("#%d:%-20s ", node->id(), node->op()->mnemonic()));
-    PrintInfo(GetUseInfo(node));
-    TRACE(("\n"));
-  }
-
-  void PrintInfo(MachineTypeUnion info) {
+  void PrintOutputInfo(NodeInfo* info) {
     if (FLAG_trace_representation) {
       OFStream os(stdout);
-      os << static_cast<MachineType>(info);
+      os << info->representation() << " (";
+      info->output_type()->PrintTo(os, Type::SEMANTIC_DIM);
+      os << ")";
+    }
+  }
+
+  void PrintRepresentation(MachineRepresentation rep) {
+    if (FLAG_trace_representation) {
+      OFStream os(stdout);
+      os << rep;
+    }
+  }
+
+  void PrintTruncation(Truncation truncation) {
+    if (FLAG_trace_representation) {
+      OFStream os(stdout);
+      os << truncation.description();
+    }
+  }
+
+  void PrintUseInfo(UseInfo info) {
+    if (FLAG_trace_representation) {
+      OFStream os(stdout);
+      os << info.preferred() << ":" << info.truncation().description();
     }
   }
 
  private:
   JSGraph* jsgraph_;
-  int count_;                       // number of nodes in the graph
-  NodeInfo* info_;                  // node id -> usage information
+  size_t const count_;              // number of nodes in the graph
+  ZoneVector<NodeInfo> info_;       // node id -> usage information
+#ifdef DEBUG
+  ZoneVector<InputUseInfos> node_input_use_infos_;  // Debug information about
+                                                    // requirements on inputs.
+#endif                                              // DEBUG
   NodeVector nodes_;                // collected nodes
   NodeVector replacements_;         // replacements to be done after lowering
   Phase phase_;                     // current phase of algorithm
   RepresentationChanger* changer_;  // for inserting representation changes
   ZoneQueue<Node*> queue_;          // queue for traversing the graph
-  Type* safe_bit_range_;
-  Type* safe_int_additive_range_;
+  // 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
+  // lowering. Once this phase becomes a vanilla reducer, it should get source
+  // position information via the SourcePositionWrapper like all other reducers.
+  SourcePositionTable* source_positions_;
+  TypeCache const& type_cache_;
 
   NodeInfo* GetInfo(Node* node) {
     DCHECK(node->id() >= 0);
     DCHECK(node->id() < count_);
     return &info_[node->id()];
   }
-
-  MachineTypeUnion GetUseInfo(Node* node) { return GetInfo(node)->use; }
 };
 
 
-Node* SimplifiedLowering::IsTagged(Node* node) {
-  // TODO(titzer): factor this out to a TaggingScheme abstraction.
-  STATIC_ASSERT(kSmiTagMask == 1);  // Only works if tag is the low bit.
-  return graph()->NewNode(machine()->WordAnd(), node,
-                          jsgraph()->Int32Constant(kSmiTagMask));
-}
+SimplifiedLowering::SimplifiedLowering(JSGraph* jsgraph, Zone* zone,
+                                       SourcePositionTable* source_positions)
+    : jsgraph_(jsgraph),
+      zone_(zone),
+      type_cache_(TypeCache::Get()),
+      source_positions_(source_positions) {}
 
 
 void SimplifiedLowering::LowerAllNodes() {
-  SimplifiedOperatorBuilder simplified(graph()->zone());
-  RepresentationChanger changer(jsgraph(), &simplified,
-                                graph()->zone()->isolate());
-  RepresentationSelector selector(jsgraph(), zone_, &changer);
+  RepresentationChanger changer(jsgraph(), jsgraph()->isolate());
+  RepresentationSelector selector(jsgraph(), zone_, &changer,
+                                  source_positions_);
   selector.Run(this);
 }
 
 
-Node* SimplifiedLowering::Untag(Node* node) {
-  // TODO(titzer): factor this out to a TaggingScheme abstraction.
-  Node* shift_amount = jsgraph()->Int32Constant(kSmiTagSize + kSmiShiftSize);
-  return graph()->NewNode(machine()->WordSar(), node, shift_amount);
-}
-
-
-Node* SimplifiedLowering::SmiTag(Node* node) {
-  // TODO(titzer): factor this out to a TaggingScheme abstraction.
-  Node* shift_amount = jsgraph()->Int32Constant(kSmiTagSize + kSmiShiftSize);
-  return graph()->NewNode(machine()->WordShl(), node, shift_amount);
-}
-
-
-Node* SimplifiedLowering::OffsetMinusTagConstant(int32_t offset) {
-  return jsgraph()->Int32Constant(offset - kHeapObjectTag);
-}
-
-
-static WriteBarrierKind ComputeWriteBarrierKind(BaseTaggedness base_is_tagged,
-                                                MachineType representation,
-                                                Type* type) {
-  // TODO(turbofan): skip write barriers for Smis, etc.
-  if (base_is_tagged == kTaggedBase &&
-      RepresentationOf(representation) == kRepTagged) {
-    // Write barriers are only for writes into heap objects (i.e. tagged base).
-    return kFullWriteBarrier;
-  }
-  return kNoWriteBarrier;
-}
-
-
-void SimplifiedLowering::DoLoadField(Node* node) {
-  const FieldAccess& access = FieldAccessOf(node->op());
-  node->set_op(machine()->Load(access.machine_type));
-  Node* offset = jsgraph()->IntPtrConstant(access.offset - access.tag());
-  node->InsertInput(graph()->zone(), 1, offset);
-}
-
-
-void SimplifiedLowering::DoStoreField(Node* node) {
-  const FieldAccess& access = FieldAccessOf(node->op());
-  WriteBarrierKind kind = ComputeWriteBarrierKind(
-      access.base_is_tagged, access.machine_type, access.type);
-  node->set_op(
-      machine()->Store(StoreRepresentation(access.machine_type, kind)));
-  Node* offset = jsgraph()->IntPtrConstant(access.offset - access.tag());
-  node->InsertInput(graph()->zone(), 1, offset);
-}
-
-
-Node* SimplifiedLowering::ComputeIndex(const ElementAccess& access,
-                                       Node* const key) {
-  Node* index = key;
-  const int element_size_shift = ElementSizeLog2Of(access.machine_type);
-  if (element_size_shift) {
-    index = graph()->NewNode(machine()->Word32Shl(), index,
-                             jsgraph()->Int32Constant(element_size_shift));
-  }
-  const int fixed_offset = access.header_size - access.tag();
-  if (fixed_offset) {
-    index = graph()->NewNode(machine()->Int32Add(), index,
-                             jsgraph()->Int32Constant(fixed_offset));
-  }
-  if (machine()->Is64()) {
-    // TODO(turbofan): This is probably only correct for typed arrays, and only
-    // if the typed arrays are at most 2GiB in size, which happens to match
-    // exactly our current situation.
-    index = graph()->NewNode(machine()->ChangeUint32ToUint64(), index);
-  }
-  return index;
-}
-
-
-void SimplifiedLowering::DoLoadBuffer(Node* node, MachineType output_type,
+void SimplifiedLowering::DoLoadBuffer(Node* node,
+                                      MachineRepresentation output_rep,
                                       RepresentationChanger* changer) {
   DCHECK_EQ(IrOpcode::kLoadBuffer, node->opcode());
-  DCHECK_NE(kMachNone, RepresentationOf(output_type));
-  MachineType const type = BufferAccessOf(node->op()).machine_type();
-  if (output_type != type) {
+  DCHECK_NE(MachineRepresentation::kNone, output_rep);
+  MachineType const access_type = BufferAccessOf(node->op()).machine_type();
+  if (output_rep != access_type.representation()) {
     Node* const buffer = node->InputAt(0);
     Node* const offset = node->InputAt(1);
     Node* const length = node->InputAt(2);
@@ -1189,19 +1532,21 @@
         graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
 
     Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
-    Node* etrue =
-        graph()->NewNode(machine()->Load(type), buffer, index, effect, if_true);
-    Node* vtrue = changer->GetRepresentationFor(etrue, type, output_type);
+    Node* etrue = graph()->NewNode(machine()->Load(access_type), buffer, index,
+                                   effect, if_true);
+    Node* vtrue = changer->GetRepresentationFor(
+        etrue, access_type.representation(), NodeProperties::GetType(node),
+        output_rep, Truncation::None());
 
     Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
     Node* efalse = effect;
     Node* vfalse;
-    if (output_type & kRepTagged) {
+    if (output_rep == MachineRepresentation::kTagged) {
       vfalse = jsgraph()->UndefinedConstant();
-    } else if (output_type & kRepFloat64) {
+    } else if (output_rep == MachineRepresentation::kFloat64) {
       vfalse =
           jsgraph()->Float64Constant(std::numeric_limits<double>::quiet_NaN());
-    } else if (output_type & kRepFloat32) {
+    } else if (output_rep == MachineRepresentation::kFloat32) {
       vfalse =
           jsgraph()->Float32Constant(std::numeric_limits<float>::quiet_NaN());
     } else {
@@ -1212,82 +1557,83 @@
     Node* ephi = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, merge);
 
     // Replace effect uses of {node} with the {ephi}.
-    NodeProperties::ReplaceWithValue(node, node, ephi);
+    NodeProperties::ReplaceUses(node, node, ephi);
 
     // Turn the {node} into a Phi.
-    node->set_op(common()->Phi(output_type, 2));
     node->ReplaceInput(0, vtrue);
     node->ReplaceInput(1, vfalse);
     node->ReplaceInput(2, merge);
     node->TrimInputCount(3);
+    NodeProperties::ChangeOp(node, common()->Phi(output_rep, 2));
   } else {
-    node->set_op(machine()->CheckedLoad(type));
+    NodeProperties::ChangeOp(node, machine()->CheckedLoad(access_type));
   }
 }
 
 
 void SimplifiedLowering::DoStoreBuffer(Node* node) {
   DCHECK_EQ(IrOpcode::kStoreBuffer, node->opcode());
-  MachineType const type = BufferAccessOf(node->op()).machine_type();
-  node->set_op(machine()->CheckedStore(type));
+  MachineRepresentation const rep =
+      BufferAccessOf(node->op()).machine_type().representation();
+  NodeProperties::ChangeOp(node, machine()->CheckedStore(rep));
 }
 
 
-void SimplifiedLowering::DoLoadElement(Node* node) {
-  const ElementAccess& access = ElementAccessOf(node->op());
-  node->set_op(machine()->Load(access.machine_type));
-  node->ReplaceInput(1, ComputeIndex(access, node->InputAt(1)));
+void SimplifiedLowering::DoObjectIsNumber(Node* node) {
+  Node* input = NodeProperties::GetValueInput(node, 0);
+  // TODO(bmeurer): Optimize somewhat based on input type.
+  Node* check =
+      graph()->NewNode(machine()->WordEqual(),
+                       graph()->NewNode(machine()->WordAnd(), input,
+                                        jsgraph()->IntPtrConstant(kSmiTagMask)),
+                       jsgraph()->IntPtrConstant(kSmiTag));
+  Node* branch = graph()->NewNode(common()->Branch(), check, graph()->start());
+  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
+  Node* vtrue = jsgraph()->Int32Constant(1);
+  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
+  Node* vfalse = graph()->NewNode(
+      machine()->WordEqual(),
+      graph()->NewNode(
+          machine()->Load(MachineType::AnyTagged()), input,
+          jsgraph()->IntPtrConstant(HeapObject::kMapOffset - kHeapObjectTag),
+          graph()->start(), if_false),
+      jsgraph()->HeapConstant(isolate()->factory()->heap_number_map()));
+  Node* control = graph()->NewNode(common()->Merge(2), if_true, if_false);
+  node->ReplaceInput(0, vtrue);
+  node->AppendInput(graph()->zone(), vfalse);
+  node->AppendInput(graph()->zone(), control);
+  NodeProperties::ChangeOp(node, common()->Phi(MachineRepresentation::kBit, 2));
 }
 
 
-void SimplifiedLowering::DoStoreElement(Node* node) {
-  const ElementAccess& access = ElementAccessOf(node->op());
-  node->set_op(machine()->Store(StoreRepresentation(
-      access.machine_type,
-      ComputeWriteBarrierKind(access.base_is_tagged, access.machine_type,
-                              access.type))));
-  node->ReplaceInput(1, ComputeIndex(access, node->InputAt(1)));
+void SimplifiedLowering::DoObjectIsSmi(Node* node) {
+  node->ReplaceInput(0,
+                     graph()->NewNode(machine()->WordAnd(), node->InputAt(0),
+                                      jsgraph()->IntPtrConstant(kSmiTagMask)));
+  node->AppendInput(graph()->zone(), jsgraph()->IntPtrConstant(kSmiTag));
+  NodeProperties::ChangeOp(node, machine()->WordEqual());
 }
 
 
-void SimplifiedLowering::DoStringAdd(Node* node) {
+Node* SimplifiedLowering::StringComparison(Node* node) {
   Operator::Properties properties = node->op()->properties();
-  Callable callable = CodeFactory::StringAdd(
-      zone()->isolate(), STRING_ADD_CHECK_NONE, NOT_TENURED);
+  Callable callable = CodeFactory::StringCompare(isolate());
   CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
   CallDescriptor* desc = Linkage::GetStubCallDescriptor(
-      callable.descriptor(), 0, flags, properties, zone());
-  node->set_op(common()->Call(desc));
-  node->InsertInput(graph()->zone(), 0,
-                    jsgraph()->HeapConstant(callable.code()));
-  node->AppendInput(graph()->zone(), jsgraph()->UndefinedConstant());
-  node->AppendInput(graph()->zone(), graph()->start());
-  node->AppendInput(graph()->zone(), graph()->start());
-}
-
-
-Node* SimplifiedLowering::StringComparison(Node* node, bool requires_ordering) {
-  CEntryStub stub(zone()->isolate(), 1);
-  Runtime::FunctionId f =
-      requires_ordering ? Runtime::kStringCompare : Runtime::kStringEquals;
-  ExternalReference ref(f, zone()->isolate());
-  Operator::Properties props = node->op()->properties();
-  // TODO(mstarzinger): We should call StringCompareStub here instead, once an
-  // interface descriptor is available for it.
-  CallDescriptor* desc = Linkage::GetRuntimeCallDescriptor(f, 2, props, zone());
-  return graph()->NewNode(common()->Call(desc),
-                          jsgraph()->HeapConstant(stub.GetCode()),
-                          NodeProperties::GetValueInput(node, 0),
-                          NodeProperties::GetValueInput(node, 1),
-                          jsgraph()->ExternalConstant(ref),
-                          jsgraph()->Int32Constant(2),
-                          jsgraph()->UndefinedConstant());
+      isolate(), zone(), callable.descriptor(), 0, flags, properties);
+  return graph()->NewNode(
+      common()->Call(desc), jsgraph()->HeapConstant(callable.code()),
+      NodeProperties::GetValueInput(node, 0),
+      NodeProperties::GetValueInput(node, 1), jsgraph()->NoContextConstant(),
+      NodeProperties::GetEffectInput(node),
+      NodeProperties::GetControlInput(node));
 }
 
 
 Node* SimplifiedLowering::Int32Div(Node* const node) {
   Int32BinopMatcher m(node);
   Node* const zero = jsgraph()->Int32Constant(0);
+  Node* const minus_one = jsgraph()->Int32Constant(-1);
   Node* const lhs = m.left().node();
   Node* const rhs = m.right().node();
 
@@ -1299,20 +1645,62 @@
     return graph()->NewNode(machine()->Int32Div(), lhs, rhs, graph()->start());
   }
 
-  Diamond if_zero(graph(), common(),
-                  graph()->NewNode(machine()->Word32Equal(), rhs, zero),
-                  BranchHint::kFalse);
+  // General case for signed integer division.
+  //
+  //    if 0 < rhs then
+  //      lhs / rhs
+  //    else
+  //      if rhs < -1 then
+  //        lhs / rhs
+  //      else if rhs == 0 then
+  //        0
+  //      else
+  //        0 - lhs
+  //
+  // Note: We do not use the Diamond helper class here, because it really hurts
+  // readability with nested diamonds.
+  const Operator* const merge_op = common()->Merge(2);
+  const Operator* const phi_op =
+      common()->Phi(MachineRepresentation::kWord32, 2);
 
-  Diamond if_minus_one(graph(), common(),
-                       graph()->NewNode(machine()->Word32Equal(), rhs,
-                                        jsgraph()->Int32Constant(-1)),
-                       BranchHint::kFalse);
-  if_minus_one.Nest(if_zero, false);
-  Node* sub = graph()->NewNode(machine()->Int32Sub(), zero, lhs);
-  Node* div =
-      graph()->NewNode(machine()->Int32Div(), lhs, rhs, if_minus_one.if_false);
+  Node* check0 = graph()->NewNode(machine()->Int32LessThan(), zero, rhs);
+  Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kTrue), check0,
+                                   graph()->start());
 
-  return if_zero.Phi(kMachInt32, zero, if_minus_one.Phi(kMachInt32, sub, div));
+  Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
+  Node* true0 = graph()->NewNode(machine()->Int32Div(), lhs, rhs, if_true0);
+
+  Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
+  Node* false0;
+  {
+    Node* check1 = graph()->NewNode(machine()->Int32LessThan(), rhs, minus_one);
+    Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0);
+
+    Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
+    Node* true1 = graph()->NewNode(machine()->Int32Div(), lhs, rhs, if_true1);
+
+    Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
+    Node* false1;
+    {
+      Node* check2 = graph()->NewNode(machine()->Word32Equal(), rhs, zero);
+      Node* branch2 = graph()->NewNode(common()->Branch(), check2, if_false1);
+
+      Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
+      Node* true2 = zero;
+
+      Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
+      Node* false2 = graph()->NewNode(machine()->Int32Sub(), zero, lhs);
+
+      if_false1 = graph()->NewNode(merge_op, if_true2, if_false2);
+      false1 = graph()->NewNode(phi_op, true2, false2, if_false1);
+    }
+
+    if_false0 = graph()->NewNode(merge_op, if_true1, if_false1);
+    false0 = graph()->NewNode(phi_op, true1, false1, if_false0);
+  }
+
+  Node* merge0 = graph()->NewNode(merge_op, if_true0, if_false0);
+  return graph()->NewNode(phi_op, true0, false0, merge0);
 }
 
 
@@ -1350,7 +1738,8 @@
   // Note: We do not use the Diamond helper class here, because it really hurts
   // readability with nested diamonds.
   const Operator* const merge_op = common()->Merge(2);
-  const Operator* const phi_op = common()->Phi(kMachInt32, 2);
+  const Operator* const phi_op =
+      common()->Phi(MachineRepresentation::kWord32, 2);
 
   Node* check0 = graph()->NewNode(machine()->Int32LessThan(), zero, rhs);
   Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kTrue), check0,
@@ -1429,7 +1818,7 @@
   Node* check = graph()->NewNode(machine()->Word32Equal(), rhs, zero);
   Diamond d(graph(), common(), check, BranchHint::kFalse);
   Node* div = graph()->NewNode(machine()->Uint32Div(), lhs, rhs, d.if_false);
-  return d.Phi(kMachUint32, zero, div);
+  return d.Phi(MachineRepresentation::kWord32, zero, div);
 }
 
 
@@ -1461,7 +1850,8 @@
   // Note: We do not use the Diamond helper class here, because it really hurts
   // readability with nested diamonds.
   const Operator* const merge_op = common()->Merge(2);
-  const Operator* const phi_op = common()->Phi(kMachInt32, 2);
+  const Operator* const phi_op =
+      common()->Phi(MachineRepresentation::kWord32, 2);
 
   Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kTrue), rhs,
                                    graph()->start());
@@ -1492,24 +1882,61 @@
 }
 
 
+void SimplifiedLowering::DoShift(Node* node, Operator const* op,
+                                 Type* rhs_type) {
+  Node* const rhs = NodeProperties::GetValueInput(node, 1);
+  if (!rhs_type->Is(type_cache_.kZeroToThirtyOne)) {
+    node->ReplaceInput(1, graph()->NewNode(machine()->Word32And(), rhs,
+                                           jsgraph()->Int32Constant(0x1f)));
+  }
+  NodeProperties::ChangeOp(node, op);
+}
+
+
+namespace {
+
+void ReplaceEffectUses(Node* node, Node* replacement) {
+  // Requires distinguishing between value and effect edges.
+  DCHECK(replacement->op()->EffectOutputCount() > 0);
+  for (Edge edge : node->use_edges()) {
+    if (NodeProperties::IsEffectEdge(edge)) {
+      edge.UpdateTo(replacement);
+    } else {
+      DCHECK(NodeProperties::IsValueEdge(edge));
+    }
+  }
+}
+
+}  // namespace
+
+
 void SimplifiedLowering::DoStringEqual(Node* node) {
-  node->set_op(machine()->WordEqual());
-  node->ReplaceInput(0, StringComparison(node, false));
+  Node* comparison = StringComparison(node);
+  ReplaceEffectUses(node, comparison);
+  node->ReplaceInput(0, comparison);
   node->ReplaceInput(1, jsgraph()->SmiConstant(EQUAL));
+  node->TrimInputCount(2);
+  NodeProperties::ChangeOp(node, machine()->WordEqual());
 }
 
 
 void SimplifiedLowering::DoStringLessThan(Node* node) {
-  node->set_op(machine()->IntLessThan());
-  node->ReplaceInput(0, StringComparison(node, true));
+  Node* comparison = StringComparison(node);
+  ReplaceEffectUses(node, comparison);
+  node->ReplaceInput(0, comparison);
   node->ReplaceInput(1, jsgraph()->SmiConstant(EQUAL));
+  node->TrimInputCount(2);
+  NodeProperties::ChangeOp(node, machine()->IntLessThan());
 }
 
 
 void SimplifiedLowering::DoStringLessThanOrEqual(Node* node) {
-  node->set_op(machine()->IntLessThanOrEqual());
-  node->ReplaceInput(0, StringComparison(node, true));
+  Node* comparison = StringComparison(node);
+  ReplaceEffectUses(node, comparison);
+  node->ReplaceInput(0, comparison);
   node->ReplaceInput(1, jsgraph()->SmiConstant(EQUAL));
+  node->TrimInputCount(2);
+  NodeProperties::ChangeOp(node, machine()->IntLessThanOrEqual());
 }
 
 }  // namespace compiler