Cleanups to Verifier.
authortitzer@chromium.org <titzer@chromium.org>
Wed, 22 Oct 2014 14:39:41 +0000 (14:39 +0000)
committertitzer@chromium.org <titzer@chromium.org>
Wed, 22 Oct 2014 14:39:41 +0000 (14:39 +0000)
This CL broadens the checks done by the verifier in untyped mode and introduces some subroutines to shorten the code a bit.

Introduce routines CheckUpperIs() CheckUpperMaybe() and CheckValueInputIs() that are called unconditionally by the verifier. If the typing mode is untyped, then don't check anything.

Also added a couple checks for Merge and Loop nodes that catch bugs where the operator and the node disagree on input counts (a bug encountered today).

R=mstarzinger@chromium.org, rossberg@chromium.org
BUG=

Review URL: https://codereview.chromium.org/669073002

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24809 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/compiler/verifier.cc

index f2ad4ba..ab70ade 100644 (file)
@@ -6,6 +6,8 @@
 
 #include <deque>
 #include <queue>
+#include <sstream>
+#include <string>
 
 #include "src/compiler/generic-algorithm.h"
 #include "src/compiler/generic-node-inl.h"
@@ -20,6 +22,7 @@
 #include "src/compiler/schedule.h"
 #include "src/compiler/simplified-operator.h"
 #include "src/data-flow.h"
+#include "src/ostreams.h"
 
 namespace v8 {
 namespace internal {
@@ -56,10 +59,8 @@ class Verifier::Visitor : public NullNodeVisitor {
 
  private:
   // TODO(rossberg): Get rid of these once we got rid of NodeProperties.
-  Bounds bounds(Node* node) {
-    return NodeProperties::GetBounds(node);
-  }
-  Node* Operand(Node* node, int i = 0) {
+  Bounds bounds(Node* node) { return NodeProperties::GetBounds(node); }
+  Node* ValueInput(Node* node, int i = 0) {
     return NodeProperties::GetValueInput(node, i);
   }
   FieldAccess Field(Node* node) {
@@ -72,6 +73,50 @@ class Verifier::Visitor : public NullNodeVisitor {
            node->opcode() == IrOpcode::kStoreElement);
     return OpParameter<ElementAccess>(node);
   }
+  void CheckNotTyped(Node* node) {
+    if (NodeProperties::IsTyped(node)) {
+      std::ostringstream str;
+      str << "TypeError: node #" << node->opcode() << ":"
+          << node->op()->mnemonic() << " should never have a type";
+      V8_Fatal(__FILE__, __LINE__, str.str().c_str());
+    }
+  }
+  void CheckUpperIs(Node* node, Type* type) {
+    if (typing == TYPED && !bounds(node).upper->Is(type)) {
+      std::ostringstream str;
+      str << "TypeError: node #" << node->opcode() << ":"
+          << node->op()->mnemonic() << " upper bound ";
+      bounds(node).upper->PrintTo(str);
+      str << " is not ";
+      type->PrintTo(str);
+      V8_Fatal(__FILE__, __LINE__, str.str().c_str());
+    }
+  }
+  void CheckUpperMaybe(Node* node, Type* type) {
+    if (typing == TYPED && !bounds(node).upper->Maybe(type)) {
+      std::ostringstream str;
+      str << "TypeError: node #" << node->opcode() << ":"
+          << node->op()->mnemonic() << " upper bound ";
+      bounds(node).upper->PrintTo(str);
+      str << " must intersect ";
+      type->PrintTo(str);
+      V8_Fatal(__FILE__, __LINE__, str.str().c_str());
+    }
+  }
+  void CheckValueInputIs(Node* node, int i, Type* type) {
+    Node* input = ValueInput(node, i);
+    if (typing == TYPED && !bounds(input).upper->Is(type)) {
+      std::ostringstream str;
+      str << "TypeError: node #" << node->opcode() << ":"
+          << node->op()->mnemonic() << "(input @" << i << " = "
+          << input->opcode() << ":" << input->op()->mnemonic()
+          << ") upper bound ";
+      bounds(input).upper->PrintTo(str);
+      str << " is not ";
+      type->PrintTo(str);
+      V8_Fatal(__FILE__, __LINE__, str.str().c_str());
+    }
+  }
 };
 
 
@@ -141,527 +186,532 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
     }
   }
 
-  if (typing == TYPED) {
-    switch (node->opcode()) {
-      // Control operators
-      // -----------------
-      case IrOpcode::kStart:
-        // Start has no inputs.
-        CHECK_EQ(0, input_count);
-        // Type is a tuple.
-        // TODO(rossberg): Multiple outputs are currently typed as Internal.
-        CHECK(bounds(node).upper->Is(Type::Internal()));
-        break;
-      case IrOpcode::kEnd:
-        // End has no outputs.
-        CHECK(!OperatorProperties::HasValueOutput(node->op()));
-        CHECK(!OperatorProperties::HasEffectOutput(node->op()));
-        CHECK(!OperatorProperties::HasControlOutput(node->op()));
-        // Type is empty.
-        CHECK(!NodeProperties::IsTyped(node));
-        break;
-      case IrOpcode::kDead:
-        // Dead is never connected to the graph.
-        UNREACHABLE();
-      case IrOpcode::kBranch: {
-        // Branch uses are IfTrue and IfFalse.
-        Node::Uses uses = node->uses();
-        int count_true = 0, count_false = 0;
-        for (Node::Uses::iterator it = uses.begin(); it != uses.end(); ++it) {
-          CHECK((*it)->opcode() == IrOpcode::kIfTrue ||
-                (*it)->opcode() == IrOpcode::kIfFalse);
-          if ((*it)->opcode() == IrOpcode::kIfTrue) ++count_true;
-          if ((*it)->opcode() == IrOpcode::kIfFalse) ++count_false;
-        }
-        CHECK(count_true == 1 && count_false == 1);
-        // Type is empty.
-        CHECK(!NodeProperties::IsTyped(node));
-        break;
+  switch (node->opcode()) {
+    case IrOpcode::kStart:
+      // Start has no inputs.
+      CHECK_EQ(0, input_count);
+      // Type is a tuple.
+      // TODO(rossberg): Multiple outputs are currently typed as Internal.
+      CheckUpperIs(node, Type::Internal());
+      break;
+    case IrOpcode::kEnd:
+      // End has no outputs.
+      CHECK(!OperatorProperties::HasValueOutput(node->op()));
+      CHECK(!OperatorProperties::HasEffectOutput(node->op()));
+      CHECK(!OperatorProperties::HasControlOutput(node->op()));
+      // Type is empty.
+      CheckNotTyped(node);
+      break;
+    case IrOpcode::kDead:
+      // Dead is never connected to the graph.
+      UNREACHABLE();
+    case IrOpcode::kBranch: {
+      // Branch uses are IfTrue and IfFalse.
+      Node::Uses uses = node->uses();
+      int count_true = 0, count_false = 0;
+      for (Node::Uses::iterator it = uses.begin(); it != uses.end(); ++it) {
+        CHECK((*it)->opcode() == IrOpcode::kIfTrue ||
+              (*it)->opcode() == IrOpcode::kIfFalse);
+        if ((*it)->opcode() == IrOpcode::kIfTrue) ++count_true;
+        if ((*it)->opcode() == IrOpcode::kIfFalse) ++count_false;
       }
-      case IrOpcode::kIfTrue:
-      case IrOpcode::kIfFalse:
-        CHECK_EQ(IrOpcode::kBranch,
-                 NodeProperties::GetControlInput(node, 0)->opcode());
-        // Type is empty.
-        CHECK(!NodeProperties::IsTyped(node));
-        break;
-      case IrOpcode::kLoop:
-      case IrOpcode::kMerge:
-        // Type is empty.
-        CHECK(!NodeProperties::IsTyped(node));
-        break;
-      case IrOpcode::kReturn:
-        // TODO(rossberg): check successor is End
-        // Type is empty.
-        CHECK(!NodeProperties::IsTyped(node));
-        break;
-      case IrOpcode::kThrow:
-        // TODO(rossberg): what are the constraints on these?
-        // Type is empty.
-        CHECK(!NodeProperties::IsTyped(node));
-        break;
-
-      // Common operators
-      // ----------------
-      case IrOpcode::kParameter: {
-        // Parameters have the start node as inputs.
-        CHECK_EQ(1, input_count);
-        CHECK_EQ(IrOpcode::kStart,
-                 NodeProperties::GetValueInput(node, 0)->opcode());
-        // Parameter has an input that produces enough values.
-        int index = OpParameter<int>(node);
-        Node* input = NodeProperties::GetValueInput(node, 0);
-        // Currently, parameter indices start at -1 instead of 0.
-        CHECK_GT(
-            OperatorProperties::GetValueOutputCount(input->op()), index + 1);
-        // Type can be anything.
-        CHECK(bounds(node).upper->Is(Type::Any()));
-        break;
-      }
-      case IrOpcode::kInt32Constant:  // TODO(rossberg): rename Word32Constant?
-        // Constants have no inputs.
-        CHECK_EQ(0, input_count);
-        // Type is a 32 bit integer, signed or unsigned.
-        CHECK(bounds(node).upper->Is(Type::Integral32()));
-        break;
-      case IrOpcode::kInt64Constant:
-        // Constants have no inputs.
-        CHECK_EQ(0, input_count);
-        // Type is internal.
-        // TODO(rossberg): Introduce proper Int64 type.
-        CHECK(bounds(node).upper->Is(Type::Internal()));
-        break;
-      case IrOpcode::kFloat32Constant:
-      case IrOpcode::kFloat64Constant:
-      case IrOpcode::kNumberConstant:
-        // Constants have no inputs.
-        CHECK_EQ(0, input_count);
-        // Type is a number.
-        CHECK(bounds(node).upper->Is(Type::Number()));
-        break;
-      case IrOpcode::kHeapConstant:
-        // Constants have no inputs.
-        CHECK_EQ(0, input_count);
-        // Type can be anything represented as a heap pointer.
-        CHECK(bounds(node).upper->Is(Type::TaggedPtr()));
-        break;
-      case IrOpcode::kExternalConstant:
-        // Constants have no inputs.
-        CHECK_EQ(0, input_count);
-        // Type is considered internal.
-        CHECK(bounds(node).upper->Is(Type::Internal()));
-        break;
-      case IrOpcode::kProjection: {
-        // Projection has an input that produces enough values.
-        int index = OpParameter<int>(node->op());
-        Node* input = NodeProperties::GetValueInput(node, 0);
-        CHECK_GT(OperatorProperties::GetValueOutputCount(input->op()), index);
-        // Type can be anything.
-        // TODO(rossberg): Introduce tuple types for this.
-        CHECK(bounds(node).upper->Is(Type::Any()));
-        break;
-      }
-      case IrOpcode::kPhi: {
-        // Phi input count matches parent control node.
-        CHECK_EQ(1, control_count);
-        Node* control = NodeProperties::GetControlInput(node, 0);
-        CHECK_EQ(value_count,
-                 OperatorProperties::GetControlInputCount(control->op()));
-        // Type must be subsumed by all input types.
-        // TODO(rossberg): for now at least, narrowing does not really hold.
-        /*
-        for (int i = 0; i < value_count; ++i) {
-          // TODO(rossberg, jarin): Figure out what to do about lower bounds.
-          // CHECK(bounds(node).lower->Is(bounds(Operand(node, i)).lower));
-          CHECK(bounds(Operand(node, i)).upper->Is(bounds(node).upper));
-        }
-        */
-        break;
-      }
-      case IrOpcode::kEffectPhi: {
-        // EffectPhi input count matches parent control node.
-        CHECK_EQ(1, control_count);
-        Node* control = NodeProperties::GetControlInput(node, 0);
-        CHECK_EQ(effect_count,
-                 OperatorProperties::GetControlInputCount(control->op()));
-        break;
-      }
-      case IrOpcode::kValueEffect:
-        // TODO(rossberg): what are the constraints on these?
-        break;
-      case IrOpcode::kFinish: {
-        // TODO(rossberg): what are the constraints on these?
-        // Type must be subsumed by input type.
-        CHECK(bounds(Operand(node)).lower->Is(bounds(node).lower));
-        CHECK(bounds(Operand(node)).upper->Is(bounds(node).upper));
-        break;
+      CHECK(count_true == 1 && count_false == 1);
+      // Type is empty.
+      CheckNotTyped(node);
+      break;
+    }
+    case IrOpcode::kIfTrue:
+    case IrOpcode::kIfFalse:
+      CHECK_EQ(IrOpcode::kBranch,
+               NodeProperties::GetControlInput(node, 0)->opcode());
+      // Type is empty.
+      CheckNotTyped(node);
+      break;
+    case IrOpcode::kLoop:
+    case IrOpcode::kMerge:
+      CHECK_EQ(control_count, input_count);
+      // Type is empty.
+      CheckNotTyped(node);
+      break;
+    case IrOpcode::kReturn:
+      // TODO(rossberg): check successor is End
+      // Type is empty.
+      CheckNotTyped(node);
+      break;
+    case IrOpcode::kThrow:
+      // TODO(rossberg): what are the constraints on these?
+      // Type is empty.
+      CheckNotTyped(node);
+      break;
+
+    // Common operators
+    // ----------------
+    case IrOpcode::kParameter: {
+      // Parameters have the start node as inputs.
+      CHECK_EQ(1, input_count);
+      CHECK_EQ(IrOpcode::kStart,
+               NodeProperties::GetValueInput(node, 0)->opcode());
+      // Parameter has an input that produces enough values.
+      int index = OpParameter<int>(node);
+      Node* input = NodeProperties::GetValueInput(node, 0);
+      // Currently, parameter indices start at -1 instead of 0.
+      CHECK_GT(OperatorProperties::GetValueOutputCount(input->op()), index + 1);
+      // Type can be anything.
+      CheckUpperIs(node, Type::Any());
+      break;
+    }
+    case IrOpcode::kInt32Constant:  // TODO(rossberg): rename Word32Constant?
+      // Constants have no inputs.
+      CHECK_EQ(0, input_count);
+      // Type is a 32 bit integer, signed or unsigned.
+      CheckUpperIs(node, Type::Integral32());
+      break;
+    case IrOpcode::kInt64Constant:
+      // Constants have no inputs.
+      CHECK_EQ(0, input_count);
+      // Type is internal.
+      // TODO(rossberg): Introduce proper Int64 type.
+      CheckUpperIs(node, Type::Internal());
+      break;
+    case IrOpcode::kFloat32Constant:
+    case IrOpcode::kFloat64Constant:
+    case IrOpcode::kNumberConstant:
+      // Constants have no inputs.
+      CHECK_EQ(0, input_count);
+      // Type is a number.
+      CheckUpperIs(node, Type::Number());
+      break;
+    case IrOpcode::kHeapConstant:
+      // Constants have no inputs.
+      CHECK_EQ(0, input_count);
+      // Type can be anything represented as a heap pointer.
+      CheckUpperIs(node, Type::TaggedPtr());
+      break;
+    case IrOpcode::kExternalConstant:
+      // Constants have no inputs.
+      CHECK_EQ(0, input_count);
+      // Type is considered internal.
+      CheckUpperIs(node, Type::Internal());
+      break;
+    case IrOpcode::kProjection: {
+      // Projection has an input that produces enough values.
+      int index = OpParameter<int>(node->op());
+      Node* input = NodeProperties::GetValueInput(node, 0);
+      CHECK_GT(OperatorProperties::GetValueOutputCount(input->op()), index);
+      // Type can be anything.
+      // TODO(rossberg): Introduce tuple types for this.
+      // TODO(titzer): Convince rossberg not to.
+      CheckUpperIs(node, Type::Any());
+      break;
+    }
+    case IrOpcode::kPhi: {
+      // Phi input count matches parent control node.
+      CHECK_EQ(0, effect_count);
+      CHECK_EQ(1, control_count);
+      Node* control = NodeProperties::GetControlInput(node, 0);
+      CHECK_EQ(value_count,
+               OperatorProperties::GetControlInputCount(control->op()));
+      CHECK_EQ(input_count, 1 + value_count);
+      // Type must be subsumed by all input types.
+      // TODO(rossberg): for now at least, narrowing does not really hold.
+      /*
+      for (int i = 0; i < value_count; ++i) {
+        // TODO(rossberg, jarin): Figure out what to do about lower bounds.
+        // CHECK(bounds(node).lower->Is(bounds(ValueInput(node, i)).lower));
+        CHECK(bounds(ValueInput(node, i)).upper->Is(bounds(node).upper));
       }
-      case IrOpcode::kFrameState:
-        // TODO(jarin): what are the constraints on these?
-        break;
-      case IrOpcode::kStateValues:
-        // TODO(jarin): what are the constraints on these?
-        break;
-      case IrOpcode::kCall:
-        // TODO(rossberg): what are the constraints on these?
-        break;
-
-      // JavaScript operators
-      // --------------------
-      case IrOpcode::kJSEqual:
-      case IrOpcode::kJSNotEqual:
-      case IrOpcode::kJSStrictEqual:
-      case IrOpcode::kJSStrictNotEqual:
-      case IrOpcode::kJSLessThan:
-      case IrOpcode::kJSGreaterThan:
-      case IrOpcode::kJSLessThanOrEqual:
-      case IrOpcode::kJSGreaterThanOrEqual:
-      case IrOpcode::kJSUnaryNot:
-        // Type is Boolean.
-        CHECK(bounds(node).upper->Is(Type::Boolean()));
-        break;
-
-      case IrOpcode::kJSBitwiseOr:
-      case IrOpcode::kJSBitwiseXor:
-      case IrOpcode::kJSBitwiseAnd:
-      case IrOpcode::kJSShiftLeft:
-      case IrOpcode::kJSShiftRight:
-      case IrOpcode::kJSShiftRightLogical:
-        // Type is 32 bit integral.
-        CHECK(bounds(node).upper->Is(Type::Integral32()));
-        break;
-      case IrOpcode::kJSAdd:
-        // Type is Number or String.
-        CHECK(bounds(node).upper->Is(Type::NumberOrString()));
-        break;
-      case IrOpcode::kJSSubtract:
-      case IrOpcode::kJSMultiply:
-      case IrOpcode::kJSDivide:
-      case IrOpcode::kJSModulus:
-        // Type is Number.
-        CHECK(bounds(node).upper->Is(Type::Number()));
-        break;
-
-      case IrOpcode::kJSToBoolean:
-        // Type is Boolean.
-        CHECK(bounds(node).upper->Is(Type::Boolean()));
-        break;
-      case IrOpcode::kJSToNumber:
-        // Type is Number.
-        CHECK(bounds(node).upper->Is(Type::Number()));
-        break;
-      case IrOpcode::kJSToString:
-        // Type is String.
-        CHECK(bounds(node).upper->Is(Type::String()));
-        break;
-      case IrOpcode::kJSToName:
-        // Type is Name.
-        CHECK(bounds(node).upper->Is(Type::Name()));
-        break;
-      case IrOpcode::kJSToObject:
-        // Type is Receiver.
-        CHECK(bounds(node).upper->Is(Type::Receiver()));
-        break;
-
-      case IrOpcode::kJSCreate:
-        // Type is Object.
-        CHECK(bounds(node).upper->Is(Type::Object()));
-        break;
-      case IrOpcode::kJSLoadProperty:
-      case IrOpcode::kJSLoadNamed:
-        // Type can be anything.
-        CHECK(bounds(node).upper->Is(Type::Any()));
-        break;
-      case IrOpcode::kJSStoreProperty:
-      case IrOpcode::kJSStoreNamed:
-        // Type is empty.
-        CHECK(!NodeProperties::IsTyped(node));
-        break;
-      case IrOpcode::kJSDeleteProperty:
-      case IrOpcode::kJSHasProperty:
-      case IrOpcode::kJSInstanceOf:
-        // Type is Boolean.
-        CHECK(bounds(node).upper->Is(Type::Boolean()));
-        break;
-      case IrOpcode::kJSTypeOf:
-        // Type is String.
-        CHECK(bounds(node).upper->Is(Type::String()));
-        break;
-
-      case IrOpcode::kJSLoadContext:
-        // Type can be anything.
-        CHECK(bounds(node).upper->Is(Type::Any()));
-        break;
-      case IrOpcode::kJSStoreContext:
-        // Type is empty.
-        CHECK(!NodeProperties::IsTyped(node));
-        break;
-      case IrOpcode::kJSCreateFunctionContext:
-      case IrOpcode::kJSCreateCatchContext:
-      case IrOpcode::kJSCreateWithContext:
-      case IrOpcode::kJSCreateBlockContext:
-      case IrOpcode::kJSCreateModuleContext:
-      case IrOpcode::kJSCreateGlobalContext: {
-        // Type is Context, and operand is Internal.
-        Bounds outer = bounds(NodeProperties::GetContextInput(node));
-        // TODO(rossberg): This should really be Is(Internal), but the typer
-        // currently can't do backwards propagation.
-        CHECK(outer.upper->Maybe(Type::Internal()));
-        CHECK(bounds(node).upper->IsContext());
-        break;
+      */
+      break;
+    }
+    case IrOpcode::kEffectPhi: {
+      // EffectPhi input count matches parent control node.
+      CHECK_EQ(0, value_count);
+      CHECK_EQ(1, control_count);
+      Node* control = NodeProperties::GetControlInput(node, 0);
+      CHECK_EQ(effect_count,
+               OperatorProperties::GetControlInputCount(control->op()));
+      CHECK_EQ(input_count, 1 + effect_count);
+      break;
+    }
+    case IrOpcode::kValueEffect:
+      // TODO(rossberg): what are the constraints on these?
+      break;
+    case IrOpcode::kFinish: {
+      // TODO(rossberg): what are the constraints on these?
+      // Type must be subsumed by input type.
+      if (typing == TYPED) {
+        CHECK(bounds(ValueInput(node)).lower->Is(bounds(node).lower));
+        CHECK(bounds(ValueInput(node)).upper->Is(bounds(node).upper));
       }
+      break;
+    }
+    case IrOpcode::kFrameState:
+      // TODO(jarin): what are the constraints on these?
+      break;
+    case IrOpcode::kStateValues:
+      // TODO(jarin): what are the constraints on these?
+      break;
+    case IrOpcode::kCall:
+      // TODO(rossberg): what are the constraints on these?
+      break;
+
+    // JavaScript operators
+    // --------------------
+    case IrOpcode::kJSEqual:
+    case IrOpcode::kJSNotEqual:
+    case IrOpcode::kJSStrictEqual:
+    case IrOpcode::kJSStrictNotEqual:
+    case IrOpcode::kJSLessThan:
+    case IrOpcode::kJSGreaterThan:
+    case IrOpcode::kJSLessThanOrEqual:
+    case IrOpcode::kJSGreaterThanOrEqual:
+    case IrOpcode::kJSUnaryNot:
+      // Type is Boolean.
+      CheckUpperIs(node, Type::Boolean());
+      break;
+
+    case IrOpcode::kJSBitwiseOr:
+    case IrOpcode::kJSBitwiseXor:
+    case IrOpcode::kJSBitwiseAnd:
+    case IrOpcode::kJSShiftLeft:
+    case IrOpcode::kJSShiftRight:
+    case IrOpcode::kJSShiftRightLogical:
+      // Type is 32 bit integral.
+      CheckUpperIs(node, Type::Integral32());
+      break;
+    case IrOpcode::kJSAdd:
+      // Type is Number or String.
+      CheckUpperIs(node, Type::NumberOrString());
+      break;
+    case IrOpcode::kJSSubtract:
+    case IrOpcode::kJSMultiply:
+    case IrOpcode::kJSDivide:
+    case IrOpcode::kJSModulus:
+      // Type is Number.
+      CheckUpperIs(node, Type::Number());
+      break;
+
+    case IrOpcode::kJSToBoolean:
+      // Type is Boolean.
+      CheckUpperIs(node, Type::Boolean());
+      break;
+    case IrOpcode::kJSToNumber:
+      // Type is Number.
+      CheckUpperIs(node, Type::Number());
+      break;
+    case IrOpcode::kJSToString:
+      // Type is String.
+      CheckUpperIs(node, Type::String());
+      break;
+    case IrOpcode::kJSToName:
+      // Type is Name.
+      CheckUpperIs(node, Type::Name());
+      break;
+    case IrOpcode::kJSToObject:
+      // Type is Receiver.
+      CheckUpperIs(node, Type::Receiver());
+      break;
+
+    case IrOpcode::kJSCreate:
+      // Type is Object.
+      CheckUpperIs(node, Type::Object());
+      break;
+    case IrOpcode::kJSLoadProperty:
+    case IrOpcode::kJSLoadNamed:
+      // Type can be anything.
+      CheckUpperIs(node, Type::Any());
+      break;
+    case IrOpcode::kJSStoreProperty:
+    case IrOpcode::kJSStoreNamed:
+      // Type is empty.
+      CheckNotTyped(node);
+      break;
+    case IrOpcode::kJSDeleteProperty:
+    case IrOpcode::kJSHasProperty:
+    case IrOpcode::kJSInstanceOf:
+      // Type is Boolean.
+      CheckUpperIs(node, Type::Boolean());
+      break;
+    case IrOpcode::kJSTypeOf:
+      // Type is String.
+      CheckUpperIs(node, Type::String());
+      break;
+
+    case IrOpcode::kJSLoadContext:
+      // Type can be anything.
+      CheckUpperIs(node, Type::Any());
+      break;
+    case IrOpcode::kJSStoreContext:
+      // Type is empty.
+      CheckNotTyped(node);
+      break;
+    case IrOpcode::kJSCreateFunctionContext:
+    case IrOpcode::kJSCreateCatchContext:
+    case IrOpcode::kJSCreateWithContext:
+    case IrOpcode::kJSCreateBlockContext:
+    case IrOpcode::kJSCreateModuleContext:
+    case IrOpcode::kJSCreateGlobalContext: {
+      // Type is Context, and operand is Internal.
+      Node* context = NodeProperties::GetContextInput(node);
+      // TODO(rossberg): This should really be Is(Internal), but the typer
+      // currently can't do backwards propagation.
+      CheckUpperMaybe(context, Type::Internal());
+      if (typing == TYPED) CHECK(bounds(node).upper->IsContext());
+      break;
+    }
 
-      case IrOpcode::kJSCallConstruct:
-        // Type is Receiver.
-        CHECK(bounds(node).upper->Is(Type::Receiver()));
-        break;
-      case IrOpcode::kJSCallFunction:
-      case IrOpcode::kJSCallRuntime:
-      case IrOpcode::kJSYield:
-      case IrOpcode::kJSDebugger:
-        // Type can be anything.
-        CHECK(bounds(node).upper->Is(Type::Any()));
-        break;
-
-      // Simplified operators
-      // -------------------------------
-      case IrOpcode::kBooleanNot:
-        // Boolean -> Boolean
-        CHECK(bounds(Operand(node)).upper->Is(Type::Boolean()));
-        CHECK(bounds(node).upper->Is(Type::Boolean()));
-        break;
-      case IrOpcode::kBooleanToNumber:
-        // Boolean -> Number
-        CHECK(bounds(Operand(node)).upper->Is(Type::Boolean()));
-        CHECK(bounds(node).upper->Is(Type::Number()));
-        break;
-      case IrOpcode::kNumberEqual:
-      case IrOpcode::kNumberLessThan:
-      case IrOpcode::kNumberLessThanOrEqual:
-        // (Number, Number) -> Boolean
-        CHECK(bounds(Operand(node, 0)).upper->Is(Type::Number()));
-        CHECK(bounds(Operand(node, 1)).upper->Is(Type::Number()));
-        CHECK(bounds(node).upper->Is(Type::Boolean()));
-        break;
-      case IrOpcode::kNumberAdd:
-      case IrOpcode::kNumberSubtract:
-      case IrOpcode::kNumberMultiply:
-      case IrOpcode::kNumberDivide:
-      case IrOpcode::kNumberModulus:
-        // (Number, Number) -> Number
-        CHECK(bounds(Operand(node, 0)).upper->Is(Type::Number()));
-        CHECK(bounds(Operand(node, 1)).upper->Is(Type::Number()));
-        // TODO(rossberg): activate once we retype after opcode changes.
-        // CHECK(bounds(node).upper->Is(Type::Number()));
-        break;
-      case IrOpcode::kNumberToInt32:
-        // Number -> Signed32
-        CHECK(bounds(Operand(node)).upper->Is(Type::Number()));
-        CHECK(bounds(node).upper->Is(Type::Signed32()));
-        break;
-      case IrOpcode::kNumberToUint32:
-        // Number -> Unsigned32
-        CHECK(bounds(Operand(node)).upper->Is(Type::Number()));
-        CHECK(bounds(node).upper->Is(Type::Unsigned32()));
-        break;
-      case IrOpcode::kStringEqual:
-      case IrOpcode::kStringLessThan:
-      case IrOpcode::kStringLessThanOrEqual:
-        // (String, String) -> Boolean
-        CHECK(bounds(Operand(node, 0)).upper->Is(Type::String()));
-        CHECK(bounds(Operand(node, 1)).upper->Is(Type::String()));
-        CHECK(bounds(node).upper->Is(Type::Boolean()));
-        break;
-      case IrOpcode::kStringAdd:
-        // (String, String) -> String
-        CHECK(bounds(Operand(node, 0)).upper->Is(Type::String()));
-        CHECK(bounds(Operand(node, 1)).upper->Is(Type::String()));
-        CHECK(bounds(node).upper->Is(Type::String()));
-        break;
-      case IrOpcode::kReferenceEqual: {
-        // (Unique, Any) -> Boolean  and
-        // (Any, Unique) -> Boolean
-        CHECK(bounds(Operand(node, 0)).upper->Is(Type::Unique()) ||
-              bounds(Operand(node, 1)).upper->Is(Type::Unique()));
-        CHECK(bounds(node).upper->Is(Type::Boolean()));
-        break;
-      }
-      case IrOpcode::kObjectIsSmi:
-        CHECK(bounds(Operand(node)).upper->Is(Type::Any()));
-        CHECK(bounds(node).upper->Is(Type::Boolean()));
-        break;
-      case IrOpcode::kObjectIsNonNegativeSmi:
-        CHECK(bounds(Operand(node)).upper->Is(Type::Any()));
-        CHECK(bounds(node).upper->Is(Type::Boolean()));
-        break;
-
-      case IrOpcode::kChangeTaggedToInt32: {
-        // Signed32 /\ Tagged -> Signed32 /\ UntaggedInt32
-        // TODO(neis): Activate once ChangeRepresentation works in typer.
-        // Type* from = Type::Intersect(Type::Signed32(), Type::Tagged());
-        // Type* to = Type::Intersect(Type::Signed32(), Type::UntaggedInt32());
-        // CHECK(bounds(Operand(node)).upper->Is(from));
-        // CHECK(bounds(node).upper->Is(to));
-        break;
-      }
-      case IrOpcode::kChangeTaggedToUint32: {
-        // Unsigned32 /\ Tagged -> Unsigned32 /\ UntaggedInt32
-        // TODO(neis): Activate once ChangeRepresentation works in typer.
-        // Type* from = Type::Intersect(Type::Unsigned32(), Type::Tagged());
-        // Type* to =Type::Intersect(Type::Unsigned32(), Type::UntaggedInt32());
-        // CHECK(bounds(Operand(node)).upper->Is(from));
-        // CHECK(bounds(node).upper->Is(to));
-        break;
-      }
-      case IrOpcode::kChangeTaggedToFloat64: {
-        // Number /\ Tagged -> Number /\ UntaggedFloat64
-        // TODO(neis): Activate once ChangeRepresentation works in typer.
-        // Type* from = Type::Intersect(Type::Number(), Type::Tagged());
-        // Type* to = Type::Intersect(Type::Number(), Type::UntaggedFloat64());
-        // CHECK(bounds(Operand(node)).upper->Is(from));
-        // CHECK(bounds(node).upper->Is(to));
-        break;
-      }
-      case IrOpcode::kChangeInt32ToTagged: {
-        // Signed32 /\ UntaggedInt32 -> Signed32 /\ Tagged
-        // TODO(neis): Activate once ChangeRepresentation works in typer.
-        // Type* from =Type::Intersect(Type::Signed32(), Type::UntaggedInt32());
-        // Type* to = Type::Intersect(Type::Signed32(), Type::Tagged());
-        // CHECK(bounds(Operand(node)).upper->Is(from));
-        // CHECK(bounds(node).upper->Is(to));
-        break;
-      }
-      case IrOpcode::kChangeUint32ToTagged: {
-        // Unsigned32 /\ UntaggedInt32 -> Unsigned32 /\ Tagged
-        // TODO(neis): Activate once ChangeRepresentation works in typer.
-        // Type* from=Type::Intersect(Type::Unsigned32(),Type::UntaggedInt32());
-        // Type* to = Type::Intersect(Type::Unsigned32(), Type::Tagged());
-        // CHECK(bounds(Operand(node)).upper->Is(from));
-        // CHECK(bounds(node).upper->Is(to));
-        break;
-      }
-      case IrOpcode::kChangeFloat64ToTagged: {
-        // Number /\ UntaggedFloat64 -> Number /\ Tagged
-        // TODO(neis): Activate once ChangeRepresentation works in typer.
-        // Type* from =Type::Intersect(Type::Number(), Type::UntaggedFloat64());
-        // Type* to = Type::Intersect(Type::Number(), Type::Tagged());
-        // CHECK(bounds(Operand(node)).upper->Is(from));
-        // CHECK(bounds(node).upper->Is(to));
-        break;
-      }
-      case IrOpcode::kChangeBoolToBit: {
-        // Boolean /\ TaggedPtr -> Boolean /\ UntaggedInt1
-        // TODO(neis): Activate once ChangeRepresentation works in typer.
-        // Type* from = Type::Intersect(Type::Boolean(), Type::TaggedPtr());
-        // Type* to = Type::Intersect(Type::Boolean(), Type::UntaggedInt1());
-        // CHECK(bounds(Operand(node)).upper->Is(from));
-        // CHECK(bounds(node).upper->Is(to));
-        break;
-      }
-      case IrOpcode::kChangeBitToBool: {
-        // Boolean /\ UntaggedInt1 -> Boolean /\ TaggedPtr
-        // TODO(neis): Activate once ChangeRepresentation works in typer.
-        // Type* from = Type::Intersect(Type::Boolean(), Type::UntaggedInt1());
-        // Type* to = Type::Intersect(Type::Boolean(), Type::TaggedPtr());
-        // CHECK(bounds(Operand(node)).upper->Is(from));
-        // CHECK(bounds(node).upper->Is(to));
-        break;
+    case IrOpcode::kJSCallConstruct:
+      // Type is Receiver.
+      CheckUpperIs(node, Type::Receiver());
+      break;
+    case IrOpcode::kJSCallFunction:
+    case IrOpcode::kJSCallRuntime:
+    case IrOpcode::kJSYield:
+    case IrOpcode::kJSDebugger:
+      // Type can be anything.
+      CheckUpperIs(node, Type::Any());
+      break;
+
+    // Simplified operators
+    // -------------------------------
+    case IrOpcode::kBooleanNot:
+      // Boolean -> Boolean
+      CheckValueInputIs(node, 0, Type::Boolean());
+      CheckUpperIs(node, Type::Boolean());
+      break;
+    case IrOpcode::kBooleanToNumber:
+      // Boolean -> Number
+      CheckValueInputIs(node, 0, Type::Boolean());
+      CheckUpperIs(node, Type::Number());
+      break;
+    case IrOpcode::kNumberEqual:
+    case IrOpcode::kNumberLessThan:
+    case IrOpcode::kNumberLessThanOrEqual:
+      // (Number, Number) -> Boolean
+      CheckValueInputIs(node, 0, Type::Number());
+      CheckValueInputIs(node, 1, Type::Number());
+      CheckUpperIs(node, Type::Boolean());
+      break;
+    case IrOpcode::kNumberAdd:
+    case IrOpcode::kNumberSubtract:
+    case IrOpcode::kNumberMultiply:
+    case IrOpcode::kNumberDivide:
+    case IrOpcode::kNumberModulus:
+      // (Number, Number) -> Number
+      CheckValueInputIs(node, 0, Type::Number());
+      CheckValueInputIs(node, 1, Type::Number());
+      // TODO(rossberg): activate once we retype after opcode changes.
+      // CheckUpperIs(node, Type::Number());
+      break;
+    case IrOpcode::kNumberToInt32:
+      // Number -> Signed32
+      CheckValueInputIs(node, 0, Type::Number());
+      CheckUpperIs(node, Type::Signed32());
+      break;
+    case IrOpcode::kNumberToUint32:
+      // Number -> Unsigned32
+      CheckValueInputIs(node, 0, Type::Number());
+      CheckUpperIs(node, Type::Unsigned32());
+      break;
+    case IrOpcode::kStringEqual:
+    case IrOpcode::kStringLessThan:
+    case IrOpcode::kStringLessThanOrEqual:
+      // (String, String) -> Boolean
+      CheckValueInputIs(node, 0, Type::String());
+      CheckValueInputIs(node, 1, Type::String());
+      CheckUpperIs(node, Type::Boolean());
+      break;
+    case IrOpcode::kStringAdd:
+      // (String, String) -> String
+      CheckValueInputIs(node, 0, Type::String());
+      CheckValueInputIs(node, 1, Type::String());
+      CheckUpperIs(node, Type::String());
+      break;
+    case IrOpcode::kReferenceEqual: {
+      // (Unique, Any) -> Boolean  and
+      // (Any, Unique) -> Boolean
+      if (typing == TYPED) {
+        CHECK(bounds(ValueInput(node, 0)).upper->Is(Type::Unique()) ||
+              bounds(ValueInput(node, 1)).upper->Is(Type::Unique()));
       }
-
-      case IrOpcode::kLoadField:
-        // Object -> fieldtype
-        // TODO(rossberg): activate once machine ops are typed.
-        // CHECK(bounds(Operand(node)).upper->Is(Type::Object()));
-        // CHECK(bounds(node).upper->Is(Field(node).type));
-        break;
-      case IrOpcode::kLoadElement:
-        // Object -> elementtype
-        // TODO(rossberg): activate once machine ops are typed.
-        // CHECK(bounds(Operand(node)).upper->Is(Type::Object()));
-        // CHECK(bounds(node).upper->Is(Element(node).type));
-        break;
-      case IrOpcode::kStoreField:
-        // (Object, fieldtype) -> _|_
-        // TODO(rossberg): activate once machine ops are typed.
-        // CHECK(bounds(Operand(node, 0)).upper->Is(Type::Object()));
-        // CHECK(bounds(Operand(node, 1)).upper->Is(Field(node).type));
-        CHECK(!NodeProperties::IsTyped(node));
-        break;
-      case IrOpcode::kStoreElement:
-        // (Object, elementtype) -> _|_
-        // TODO(rossberg): activate once machine ops are typed.
-        // CHECK(bounds(Operand(node, 0)).upper->Is(Type::Object()));
-        // CHECK(bounds(Operand(node, 1)).upper->Is(Element(node).type));
-        CHECK(!NodeProperties::IsTyped(node));
-        break;
-
-      // Machine operators
-      // -----------------------
-      case IrOpcode::kLoad:
-      case IrOpcode::kStore:
-      case IrOpcode::kWord32And:
-      case IrOpcode::kWord32Or:
-      case IrOpcode::kWord32Xor:
-      case IrOpcode::kWord32Shl:
-      case IrOpcode::kWord32Shr:
-      case IrOpcode::kWord32Sar:
-      case IrOpcode::kWord32Ror:
-      case IrOpcode::kWord32Equal:
-      case IrOpcode::kWord64And:
-      case IrOpcode::kWord64Or:
-      case IrOpcode::kWord64Xor:
-      case IrOpcode::kWord64Shl:
-      case IrOpcode::kWord64Shr:
-      case IrOpcode::kWord64Sar:
-      case IrOpcode::kWord64Ror:
-      case IrOpcode::kWord64Equal:
-      case IrOpcode::kInt32Add:
-      case IrOpcode::kInt32AddWithOverflow:
-      case IrOpcode::kInt32Sub:
-      case IrOpcode::kInt32SubWithOverflow:
-      case IrOpcode::kInt32Mul:
-      case IrOpcode::kInt32MulHigh:
-      case IrOpcode::kInt32Div:
-      case IrOpcode::kInt32Mod:
-      case IrOpcode::kInt32LessThan:
-      case IrOpcode::kInt32LessThanOrEqual:
-      case IrOpcode::kUint32Div:
-      case IrOpcode::kUint32Mod:
-      case IrOpcode::kUint32LessThan:
-      case IrOpcode::kUint32LessThanOrEqual:
-      case IrOpcode::kInt64Add:
-      case IrOpcode::kInt64Sub:
-      case IrOpcode::kInt64Mul:
-      case IrOpcode::kInt64Div:
-      case IrOpcode::kInt64Mod:
-      case IrOpcode::kInt64LessThan:
-      case IrOpcode::kInt64LessThanOrEqual:
-      case IrOpcode::kUint64Div:
-      case IrOpcode::kUint64Mod:
-      case IrOpcode::kUint64LessThan:
-      case IrOpcode::kFloat64Add:
-      case IrOpcode::kFloat64Sub:
-      case IrOpcode::kFloat64Mul:
-      case IrOpcode::kFloat64Div:
-      case IrOpcode::kFloat64Mod:
-      case IrOpcode::kFloat64Sqrt:
-      case IrOpcode::kFloat64Equal:
-      case IrOpcode::kFloat64LessThan:
-      case IrOpcode::kFloat64LessThanOrEqual:
-      case IrOpcode::kTruncateInt64ToInt32:
-      case IrOpcode::kTruncateFloat64ToFloat32:
-      case IrOpcode::kTruncateFloat64ToInt32:
-      case IrOpcode::kChangeInt32ToInt64:
-      case IrOpcode::kChangeUint32ToUint64:
-      case IrOpcode::kChangeInt32ToFloat64:
-      case IrOpcode::kChangeUint32ToFloat64:
-      case IrOpcode::kChangeFloat32ToFloat64:
-      case IrOpcode::kChangeFloat64ToInt32:
-      case IrOpcode::kChangeFloat64ToUint32:
-      case IrOpcode::kLoadStackPointer:
-        // TODO(rossberg): Check.
-        break;
+      CheckUpperIs(node, Type::Boolean());
+      break;
+    }
+    case IrOpcode::kObjectIsSmi:
+      CheckValueInputIs(node, 0, Type::Any());
+      CheckUpperIs(node, Type::Boolean());
+      break;
+    case IrOpcode::kObjectIsNonNegativeSmi:
+      CheckValueInputIs(node, 0, Type::Any());
+      CheckUpperIs(node, Type::Boolean());
+      break;
+
+    case IrOpcode::kChangeTaggedToInt32: {
+      // Signed32 /\ Tagged -> Signed32 /\ UntaggedInt32
+      // TODO(neis): Activate once ChangeRepresentation works in typer.
+      // Type* from = Type::Intersect(Type::Signed32(), Type::Tagged());
+      // Type* to = Type::Intersect(Type::Signed32(), Type::UntaggedInt32());
+      // CheckValueInputIs(node, 0, from));
+      // CheckUpperIs(node, to));
+      break;
+    }
+    case IrOpcode::kChangeTaggedToUint32: {
+      // Unsigned32 /\ Tagged -> Unsigned32 /\ UntaggedInt32
+      // TODO(neis): Activate once ChangeRepresentation works in typer.
+      // Type* from = Type::Intersect(Type::Unsigned32(), Type::Tagged());
+      // Type* to =Type::Intersect(Type::Unsigned32(), Type::UntaggedInt32());
+      // CheckValueInputIs(node, 0, from));
+      // CheckUpperIs(node, to));
+      break;
+    }
+    case IrOpcode::kChangeTaggedToFloat64: {
+      // Number /\ Tagged -> Number /\ UntaggedFloat64
+      // TODO(neis): Activate once ChangeRepresentation works in typer.
+      // Type* from = Type::Intersect(Type::Number(), Type::Tagged());
+      // Type* to = Type::Intersect(Type::Number(), Type::UntaggedFloat64());
+      // CheckValueInputIs(node, 0, from));
+      // CheckUpperIs(node, to));
+      break;
+    }
+    case IrOpcode::kChangeInt32ToTagged: {
+      // Signed32 /\ UntaggedInt32 -> Signed32 /\ Tagged
+      // TODO(neis): Activate once ChangeRepresentation works in typer.
+      // Type* from =Type::Intersect(Type::Signed32(), Type::UntaggedInt32());
+      // Type* to = Type::Intersect(Type::Signed32(), Type::Tagged());
+      // CheckValueInputIs(node, 0, from));
+      // CheckUpperIs(node, to));
+      break;
     }
+    case IrOpcode::kChangeUint32ToTagged: {
+      // Unsigned32 /\ UntaggedInt32 -> Unsigned32 /\ Tagged
+      // TODO(neis): Activate once ChangeRepresentation works in typer.
+      // Type* from=Type::Intersect(Type::Unsigned32(),Type::UntaggedInt32());
+      // Type* to = Type::Intersect(Type::Unsigned32(), Type::Tagged());
+      // CheckValueInputIs(node, 0, from));
+      // CheckUpperIs(node, to));
+      break;
+    }
+    case IrOpcode::kChangeFloat64ToTagged: {
+      // Number /\ UntaggedFloat64 -> Number /\ Tagged
+      // TODO(neis): Activate once ChangeRepresentation works in typer.
+      // Type* from =Type::Intersect(Type::Number(), Type::UntaggedFloat64());
+      // Type* to = Type::Intersect(Type::Number(), Type::Tagged());
+      // CheckValueInputIs(node, 0, from));
+      // CheckUpperIs(node, to));
+      break;
+    }
+    case IrOpcode::kChangeBoolToBit: {
+      // Boolean /\ TaggedPtr -> Boolean /\ UntaggedInt1
+      // TODO(neis): Activate once ChangeRepresentation works in typer.
+      // Type* from = Type::Intersect(Type::Boolean(), Type::TaggedPtr());
+      // Type* to = Type::Intersect(Type::Boolean(), Type::UntaggedInt1());
+      // CheckValueInputIs(node, 0, from));
+      // CheckUpperIs(node, to));
+      break;
+    }
+    case IrOpcode::kChangeBitToBool: {
+      // Boolean /\ UntaggedInt1 -> Boolean /\ TaggedPtr
+      // TODO(neis): Activate once ChangeRepresentation works in typer.
+      // Type* from = Type::Intersect(Type::Boolean(), Type::UntaggedInt1());
+      // Type* to = Type::Intersect(Type::Boolean(), Type::TaggedPtr());
+      // CheckValueInputIs(node, 0, from));
+      // CheckUpperIs(node, to));
+      break;
+    }
+
+    case IrOpcode::kLoadField:
+      // Object -> fieldtype
+      // TODO(rossberg): activate once machine ops are typed.
+      // CheckValueInputIs(node, 0, Type::Object());
+      // CheckUpperIs(node, Field(node).type));
+      break;
+    case IrOpcode::kLoadElement:
+      // Object -> elementtype
+      // TODO(rossberg): activate once machine ops are typed.
+      // CheckValueInputIs(node, 0, Type::Object());
+      // CheckUpperIs(node, Element(node).type));
+      break;
+    case IrOpcode::kStoreField:
+      // (Object, fieldtype) -> _|_
+      // TODO(rossberg): activate once machine ops are typed.
+      // CheckValueInputIs(node, 0, Type::Object());
+      // CheckValueInputIs(node, 1, Field(node).type));
+      CheckNotTyped(node);
+      break;
+    case IrOpcode::kStoreElement:
+      // (Object, elementtype) -> _|_
+      // TODO(rossberg): activate once machine ops are typed.
+      // CheckValueInputIs(node, 0, Type::Object());
+      // CheckValueInputIs(node, 1, Element(node).type));
+      CheckNotTyped(node);
+      break;
+
+    // Machine operators
+    // -----------------------
+    case IrOpcode::kLoad:
+    case IrOpcode::kStore:
+    case IrOpcode::kWord32And:
+    case IrOpcode::kWord32Or:
+    case IrOpcode::kWord32Xor:
+    case IrOpcode::kWord32Shl:
+    case IrOpcode::kWord32Shr:
+    case IrOpcode::kWord32Sar:
+    case IrOpcode::kWord32Ror:
+    case IrOpcode::kWord32Equal:
+    case IrOpcode::kWord64And:
+    case IrOpcode::kWord64Or:
+    case IrOpcode::kWord64Xor:
+    case IrOpcode::kWord64Shl:
+    case IrOpcode::kWord64Shr:
+    case IrOpcode::kWord64Sar:
+    case IrOpcode::kWord64Ror:
+    case IrOpcode::kWord64Equal:
+    case IrOpcode::kInt32Add:
+    case IrOpcode::kInt32AddWithOverflow:
+    case IrOpcode::kInt32Sub:
+    case IrOpcode::kInt32SubWithOverflow:
+    case IrOpcode::kInt32Mul:
+    case IrOpcode::kInt32MulHigh:
+    case IrOpcode::kInt32Div:
+    case IrOpcode::kInt32Mod:
+    case IrOpcode::kInt32LessThan:
+    case IrOpcode::kInt32LessThanOrEqual:
+    case IrOpcode::kUint32Div:
+    case IrOpcode::kUint32Mod:
+    case IrOpcode::kUint32LessThan:
+    case IrOpcode::kUint32LessThanOrEqual:
+    case IrOpcode::kInt64Add:
+    case IrOpcode::kInt64Sub:
+    case IrOpcode::kInt64Mul:
+    case IrOpcode::kInt64Div:
+    case IrOpcode::kInt64Mod:
+    case IrOpcode::kInt64LessThan:
+    case IrOpcode::kInt64LessThanOrEqual:
+    case IrOpcode::kUint64Div:
+    case IrOpcode::kUint64Mod:
+    case IrOpcode::kUint64LessThan:
+    case IrOpcode::kFloat64Add:
+    case IrOpcode::kFloat64Sub:
+    case IrOpcode::kFloat64Mul:
+    case IrOpcode::kFloat64Div:
+    case IrOpcode::kFloat64Mod:
+    case IrOpcode::kFloat64Sqrt:
+    case IrOpcode::kFloat64Equal:
+    case IrOpcode::kFloat64LessThan:
+    case IrOpcode::kFloat64LessThanOrEqual:
+    case IrOpcode::kTruncateInt64ToInt32:
+    case IrOpcode::kTruncateFloat64ToFloat32:
+    case IrOpcode::kTruncateFloat64ToInt32:
+    case IrOpcode::kChangeInt32ToInt64:
+    case IrOpcode::kChangeUint32ToUint64:
+    case IrOpcode::kChangeInt32ToFloat64:
+    case IrOpcode::kChangeUint32ToFloat64:
+    case IrOpcode::kChangeFloat32ToFloat64:
+    case IrOpcode::kChangeFloat64ToInt32:
+    case IrOpcode::kChangeFloat64ToUint32:
+    case IrOpcode::kLoadStackPointer:
+      // TODO(rossberg): Check.
+      break;
   }
 
   return GenericGraphVisit::CONTINUE;