text: // Copyright 2018 the V8 project authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #include "src/compiler/redundancy-elimination.h"
  #include "src/compiler/common-operator.h"
  #include "test/unittests/compiler/graph-reducer-unittest.h"
  #include "test/unittests/compiler/graph-unittest.h"
  #include "test/unittests/compiler/node-test-utils.h"
  #include "testing/gmock-support.h"
  
  using testing::_;
  using testing::NiceMock;
  
  namespace v8 {
  namespace internal {
  namespace compiler {
  namespace redundancy_elimination_unittest {
  
  class RedundancyEliminationTest : public GraphTest {
   public:
    explicit RedundancyEliminationTest(int num_parameters = 4)
        : GraphTest(num_parameters),
          reducer_(&editor_, zone()),
          simplified_(zone()) {
      // Initialize the {reducer_} state for the Start node.
      reducer_.Reduce(graph()->start());
  
      // Create a feedback vector with two CALL_IC slots.
      FeedbackVectorSpec spec(zone());
      FeedbackSlot slot1 = spec.AddCallICSlot();
      FeedbackSlot slot2 = spec.AddCallICSlot();
      Handle<FeedbackMetadata> metadata = FeedbackMetadata::New(isolate(), &spec);
      Handle<SharedFunctionInfo> shared =
          isolate()->factory()->NewSharedFunctionInfoForBuiltin(
              isolate()->factory()->empty_string(), Builtins::kIllegal);
      shared->set_raw_outer_scope_info_or_feedback_metadata(*metadata);
      Handle<ClosureFeedbackCellArray> closure_feedback_cell_array =
          ClosureFeedbackCellArray::New(isolate(), shared);
      Handle<FeedbackVector> feedback_vector =
          FeedbackVector::New(isolate(), shared, closure_feedback_cell_array);
      vector_slot_pairs_.push_back(VectorSlotPair());
      vector_slot_pairs_.push_back(
          VectorSlotPair(feedback_vector, slot1, UNINITIALIZED));
      vector_slot_pairs_.push_back(
          VectorSlotPair(feedback_vector, slot2, UNINITIALIZED));
    }
    ~RedundancyEliminationTest() override = default;
  
   protected:
    Reduction Reduce(Node* node) { return reducer_.Reduce(node); }
  
    std::vector<VectorSlotPair> const& vector_slot_pairs() const {
      return vector_slot_pairs_;
    }
    SimplifiedOperatorBuilder* simplified() { return &simplified_; }
  
   private:
    NiceMock<MockAdvancedReducerEditor> editor_;
    std::vector<VectorSlotPair> vector_slot_pairs_;
    VectorSlotPair feedback2_;
    RedundancyElimination reducer_;
    SimplifiedOperatorBuilder simplified_;
  };
  
  namespace {
  
  const CheckForMinusZeroMode kCheckForMinusZeroModes[] = {
      CheckForMinusZeroMode::kCheckForMinusZero,
      CheckForMinusZeroMode::kDontCheckForMinusZero,
  };
  
  const CheckTaggedInputMode kCheckTaggedInputModes[] = {
      CheckTaggedInputMode::kNumber, CheckTaggedInputMode::kNumberOrOddball};
  
  const NumberOperationHint kNumberOperationHints[] = {
      NumberOperationHint::kSignedSmall,
      NumberOperationHint::kSignedSmallInputs,
      NumberOperationHint::kSigned32,
      NumberOperationHint::kNumber,
      NumberOperationHint::kNumberOrOddball,
  };
  
  }  // namespace
  
  // -----------------------------------------------------------------------------
  // CheckBounds
  
  TEST_F(RedundancyEliminationTest, CheckBounds) {
    TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
      TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
        Node* index = Parameter(0);
        Node* length = Parameter(1);
        Node* effect = graph()->start();
        Node* control = graph()->start();
  
        Node* check1 = effect = graph()->NewNode(
            simplified()->CheckBounds(feedback1), index, length, effect, control);
        Reduction r1 = Reduce(check1);
        ASSERT_TRUE(r1.Changed());
        EXPECT_EQ(r1.replacement(), check1);
  
        Node* check2 = effect = graph()->NewNode(
            simplified()->CheckBounds(feedback2), index, length, effect, control);
        Reduction r2 = Reduce(check2);
        ASSERT_TRUE(r2.Changed());
        EXPECT_EQ(r2.replacement(), check1);
      }
    }
  }
  
  // -----------------------------------------------------------------------------
  // CheckNumber
  
  TEST_F(RedundancyEliminationTest, CheckNumberSubsumedByCheckSmi) {
    TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
      TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
        Node* value = Parameter(0);
        Node* effect = graph()->start();
        Node* control = graph()->start();
  
        Node* check1 = effect = graph()->NewNode(
            simplified()->CheckSmi(feedback1), value, effect, control);
        Reduction r1 = Reduce(check1);
        ASSERT_TRUE(r1.Changed());
        EXPECT_EQ(r1.replacement(), check1);
  
        Node* check2 = effect = graph()->NewNode(
            simplified()->CheckNumber(feedback2), value, effect, control);
        Reduction r2 = Reduce(check2);
        ASSERT_TRUE(r2.Changed());
        EXPECT_EQ(r2.replacement(), check1);
      }
    }
  }
  
  // -----------------------------------------------------------------------------
  // CheckReceiver
  
  TEST_F(RedundancyEliminationTest, CheckReceiver) {
    Node* value = Parameter(0);
    Node* effect = graph()->start();
    Node* control = graph()->start();
  
    Node* check1 = effect =
        graph()->NewNode(simplified()->CheckReceiver(), value, effect, control);
    Reduction r1 = Reduce(check1);
    ASSERT_TRUE(r1.Changed());
    EXPECT_EQ(r1.replacement(), check1);
  
    Node* check2 = effect =
        graph()->NewNode(simplified()->CheckReceiver(), value, effect, control);
    Reduction r2 = Reduce(check2);
    ASSERT_TRUE(r2.Changed());
    EXPECT_EQ(r2.replacement(), check1);
  }
  
  // -----------------------------------------------------------------------------
  // CheckReceiverOrNullOrUndefined
  
  TEST_F(RedundancyEliminationTest, CheckReceiverOrNullOrUndefined) {
    Node* value = Parameter(0);
    Node* effect = graph()->start();
    Node* control = graph()->start();
  
    Node* check1 = effect = graph()->NewNode(
        simplified()->CheckReceiverOrNullOrUndefined(), value, effect, control);
    Reduction r1 = Reduce(check1);
    ASSERT_TRUE(r1.Changed());
    EXPECT_EQ(r1.replacement(), check1);
  
    Node* check2 = effect = graph()->NewNode(
        simplified()->CheckReceiverOrNullOrUndefined(), value, effect, control);
    Reduction r2 = Reduce(check2);
    ASSERT_TRUE(r2.Changed());
    EXPECT_EQ(r2.replacement(), check1);
  }
  
  TEST_F(RedundancyEliminationTest,
         CheckReceiverOrNullOrUndefinedSubsumedByCheckReceiver) {
    Node* value = Parameter(0);
    Node* effect = graph()->start();
    Node* control = graph()->start();
  
    Node* check1 = effect =
        graph()->NewNode(simplified()->CheckReceiver(), value, effect, control);
    Reduction r1 = Reduce(check1);
    ASSERT_TRUE(r1.Changed());
    EXPECT_EQ(r1.replacement(), check1);
  
    Node* check2 = effect = graph()->NewNode(
        simplified()->CheckReceiverOrNullOrUndefined(), value, effect, control);
    Reduction r2 = Reduce(check2);
    ASSERT_TRUE(r2.Changed());
    EXPECT_EQ(r2.replacement(), check1);
  }
  
  // -----------------------------------------------------------------------------
  // CheckNonEmptyString
  
  TEST_F(RedundancyEliminationTest,
         CheckNonEmptyStringSubsumedByCheckNonEmptyOneByteString) {
    Node* value = Parameter(0);
    Node* effect = graph()->start();
    Node* control = graph()->start();
  
    Node* check1 = effect = graph()->NewNode(
        simplified()->CheckNonEmptyOneByteString(), value, effect, control);
    Reduction r1 = Reduce(check1);
    ASSERT_TRUE(r1.Changed());
    EXPECT_EQ(r1.replacement(), check1);
  
    Node* check2 = effect = graph()->NewNode(simplified()->CheckNonEmptyString(),
                                             value, effect, control);
    Reduction r2 = Reduce(check2);
    ASSERT_TRUE(r2.Changed());
    EXPECT_EQ(r2.replacement(), check1);
  }
  
  TEST_F(RedundancyEliminationTest,
         CheckNonEmptyStringSubsumedByCheckNonEmptyTwoByteString) {
    Node* value = Parameter(0);
    Node* effect = graph()->start();
    Node* control = graph()->start();
  
    Node* check1 = effect = graph()->NewNode(
        simplified()->CheckNonEmptyTwoByteString(), value, effect, control);
    Reduction r1 = Reduce(check1);
    ASSERT_TRUE(r1.Changed());
    EXPECT_EQ(r1.replacement(), check1);
  
    Node* check2 = effect = graph()->NewNode(simplified()->CheckNonEmptyString(),
                                             value, effect, control);
    Reduction r2 = Reduce(check2);
    ASSERT_TRUE(r2.Changed());
    EXPECT_EQ(r2.replacement(), check1);
  }
  
  // -----------------------------------------------------------------------------
  // CheckString
  
  TEST_F(RedundancyEliminationTest,
         CheckStringSubsumedByCheckInternalizedString) {
    TRACED_FOREACH(VectorSlotPair, feedback, vector_slot_pairs()) {
      Node* value = Parameter(0);
      Node* effect = graph()->start();
      Node* control = graph()->start();
  
      Node* check1 = effect = graph()->NewNode(
          simplified()->CheckInternalizedString(), value, effect, control);
      Reduction r1 = Reduce(check1);
      ASSERT_TRUE(r1.Changed());
      EXPECT_EQ(r1.replacement(), check1);
  
      Node* check2 = effect = graph()->NewNode(
          simplified()->CheckString(feedback), value, effect, control);
      Reduction r2 = Reduce(check2);
      ASSERT_TRUE(r2.Changed());
      EXPECT_EQ(r2.replacement(), check1);
    }
  }
  
  TEST_F(RedundancyEliminationTest, CheckStringSubsumedByCheckNonEmptyString) {
    TRACED_FOREACH(VectorSlotPair, feedback, vector_slot_pairs()) {
      Node* value = Parameter(0);
      Node* effect = graph()->start();
      Node* control = graph()->start();
  
      Node* check1 = effect = graph()->NewNode(
          simplified()->CheckNonEmptyString(), value, effect, control);
      Reduction r1 = Reduce(check1);
      ASSERT_TRUE(r1.Changed());
      EXPECT_EQ(r1.replacement(), check1);
  
      Node* check2 = effect = graph()->NewNode(
          simplified()->CheckString(feedback), value, effect, control);
      Reduction r2 = Reduce(check2);
      ASSERT_TRUE(r2.Changed());
      EXPECT_EQ(r2.replacement(), check1);
    }
  }
  
  TEST_F(RedundancyEliminationTest,
         CheckStringSubsumedByCheckNonEmptyOneByteString) {
    TRACED_FOREACH(VectorSlotPair, feedback, vector_slot_pairs()) {
      Node* value = Parameter(0);
      Node* effect = graph()->start();
      Node* control = graph()->start();
  
      Node* check1 = effect = graph()->NewNode(
          simplified()->CheckNonEmptyOneByteString(), value, effect, control);
      Reduction r1 = Reduce(check1);
      ASSERT_TRUE(r1.Changed());
      EXPECT_EQ(r1.replacement(), check1);
  
      Node* check2 = effect = graph()->NewNode(
          simplified()->CheckString(feedback), value, effect, control);
      Reduction r2 = Reduce(check2);
      ASSERT_TRUE(r2.Changed());
      EXPECT_EQ(r2.replacement(), check1);
    }
  }
  
  TEST_F(RedundancyEliminationTest,
         CheckStringSubsumedByCheckNonEmptyTwoByteString) {
    TRACED_FOREACH(VectorSlotPair, feedback, vector_slot_pairs()) {
      Node* value = Parameter(0);
      Node* effect = graph()->start();
      Node* control = graph()->start();
  
      Node* check1 = effect = graph()->NewNode(
          simplified()->CheckNonEmptyTwoByteString(), value, effect, control);
      Reduction r1 = Reduce(check1);
      ASSERT_TRUE(r1.Changed());
      EXPECT_EQ(r1.replacement(), check1);
  
      Node* check2 = effect = graph()->NewNode(
          simplified()->CheckString(feedback), value, effect, control);
      Reduction r2 = Reduce(check2);
      ASSERT_TRUE(r2.Changed());
      EXPECT_EQ(r2.replacement(), check1);
    }
  }
  
  // -----------------------------------------------------------------------------
  // CheckSymbol
  
  TEST_F(RedundancyEliminationTest, CheckSymbol) {
    Node* value = Parameter(0);
    Node* effect = graph()->start();
    Node* control = graph()->start();
  
    Node* check1 = effect =
        graph()->NewNode(simplified()->CheckSymbol(), value, effect, control);
    Reduction r1 = Reduce(check1);
    ASSERT_TRUE(r1.Changed());
    EXPECT_EQ(r1.replacement(), check1);
  
    Node* check2 = effect =
        graph()->NewNode(simplified()->CheckSymbol(), value, effect, control);
    Reduction r2 = Reduce(check2);
    ASSERT_TRUE(r2.Changed());
    EXPECT_EQ(r2.replacement(), check1);
  }
  
  // -----------------------------------------------------------------------------
  // CheckedFloat64ToInt32
  
  TEST_F(RedundancyEliminationTest, CheckedFloat64ToInt32) {
    TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
      TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
        TRACED_FOREACH(CheckForMinusZeroMode, mode, kCheckForMinusZeroModes) {
          Node* value = Parameter(0);
          Node* effect = graph()->start();
          Node* control = graph()->start();
  
          Node* check1 = effect = graph()->NewNode(
              simplified()->CheckedFloat64ToInt32(mode, feedback1), value, effect,
              control);
          Reduction r1 = Reduce(check1);
          ASSERT_TRUE(r1.Changed());
          EXPECT_EQ(r1.replacement(), check1);
  
          Node* check2 = effect = graph()->NewNode(
              simplified()->CheckedFloat64ToInt32(mode, feedback2), value, effect,
              control);
          Reduction r2 = Reduce(check2);
          ASSERT_TRUE(r2.Changed());
          EXPECT_EQ(r2.replacement(), check1);
        }
      }
    }
  }
  
  // -----------------------------------------------------------------------------
  // CheckedFloat64ToInt64
  
  TEST_F(RedundancyEliminationTest, CheckedFloat64ToInt64) {
    TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
      TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
        TRACED_FOREACH(CheckForMinusZeroMode, mode, kCheckForMinusZeroModes) {
          Node* value = Parameter(0);
          Node* effect = graph()->start();
          Node* control = graph()->start();
  
          Node* check1 = effect = graph()->NewNode(
              simplified()->CheckedFloat64ToInt64(mode, feedback1), value, effect,
              control);
          Reduction r1 = Reduce(check1);
          ASSERT_TRUE(r1.Changed());
          EXPECT_EQ(r1.replacement(), check1);
  
          Node* check2 = effect = graph()->NewNode(
              simplified()->CheckedFloat64ToInt64(mode, feedback2), value, effect,
              control);
          Reduction r2 = Reduce(check2);
          ASSERT_TRUE(r2.Changed());
          EXPECT_EQ(r2.replacement(), check1);
        }
      }
    }
  }
  
  // -----------------------------------------------------------------------------
  // CheckedInt32ToTaggedSigned
  
  TEST_F(RedundancyEliminationTest, CheckedInt32ToTaggedSigned) {
    TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
      TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
        Node* value = Parameter(0);
        Node* effect = graph()->start();
        Node* control = graph()->start();
  
        Node* check1 = effect =
            graph()->NewNode(simplified()->CheckedInt32ToTaggedSigned(feedback1),
                             value, effect, control);
        Reduction r1 = Reduce(check1);
        ASSERT_TRUE(r1.Changed());
        EXPECT_EQ(r1.replacement(), check1);
  
        Node* check2 = effect =
            graph()->NewNode(simplified()->CheckedInt32ToTaggedSigned(feedback2),
                             value, effect, control);
        Reduction r2 = Reduce(check2);
        ASSERT_TRUE(r2.Changed());
        EXPECT_EQ(r2.replacement(), check1);
      }
    }
  }
  
  // -----------------------------------------------------------------------------
  // CheckedInt64ToInt32
  
  TEST_F(RedundancyEliminationTest, CheckedInt64ToInt32) {
    TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
      TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
        Node* value = Parameter(0);
        Node* effect = graph()->start();
        Node* control = graph()->start();
  
        Node* check1 = effect = graph()->NewNode(
            simplified()->CheckedInt64ToInt32(feedback1), value, effect, control);
        Reduction r1 = Reduce(check1);
        ASSERT_TRUE(r1.Changed());
        EXPECT_EQ(r1.replacement(), check1);
  
        Node* check2 = effect = graph()->NewNode(
            simplified()->CheckedInt64ToInt32(feedback2), value, effect, control);
        Reduction r2 = Reduce(check2);
        ASSERT_TRUE(r2.Changed());
        EXPECT_EQ(r2.replacement(), check1);
      }
    }
  }
  
  // -----------------------------------------------------------------------------
  // CheckedInt64ToTaggedSigned
  
  TEST_F(RedundancyEliminationTest, CheckedInt64ToTaggedSigned) {
    TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
      TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
        Node* value = Parameter(0);
        Node* effect = graph()->start();
        Node* control = graph()->start();
  
        Node* check1 = effect =
            graph()->NewNode(simplified()->CheckedInt64ToTaggedSigned(feedback1),
                             value, effect, control);
        Reduction r1 = Reduce(check1);
        ASSERT_TRUE(r1.Changed());
        EXPECT_EQ(r1.replacement(), check1);
  
        Node* check2 = effect =
            graph()->NewNode(simplified()->CheckedInt64ToTaggedSigned(feedback2),
                             value, effect, control);
        Reduction r2 = Reduce(check2);
        ASSERT_TRUE(r2.Changed());
        EXPECT_EQ(r2.replacement(), check1);
      }
    }
  }
  
  // -----------------------------------------------------------------------------
  // CheckedTaggedSignedToInt32
  
  TEST_F(RedundancyEliminationTest, CheckedTaggedSignedToInt32) {
    TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
      TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
        Node* value = Parameter(0);
        Node* effect = graph()->start();
        Node* control = graph()->start();
  
        Node* check1 = effect =
            graph()->NewNode(simplified()->CheckedTaggedSignedToInt32(feedback1),
                             value, effect, control);
        Reduction r1 = Reduce(check1);
        ASSERT_TRUE(r1.Changed());
        EXPECT_EQ(r1.replacement(), check1);
  
        Node* check2 = effect =
            graph()->NewNode(simplified()->CheckedTaggedSignedToInt32(feedback2),
                             value, effect, control);
        Reduction r2 = Reduce(check2);
        ASSERT_TRUE(r2.Changed());
        EXPECT_EQ(r2.replacement(), check1);
      }
    }
  }
  
  // -----------------------------------------------------------------------------
  // CheckedTaggedToFloat64
  
  TEST_F(RedundancyEliminationTest, CheckedTaggedToFloat64) {
    TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
      TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
        TRACED_FOREACH(CheckTaggedInputMode, mode, kCheckTaggedInputModes) {
          Node* value = Parameter(0);
          Node* effect = graph()->start();
          Node* control = graph()->start();
  
          Node* check1 = effect = graph()->NewNode(
              simplified()->CheckedTaggedToFloat64(mode, feedback1), value,
              effect, control);
          Reduction r1 = Reduce(check1);
          ASSERT_TRUE(r1.Changed());
          EXPECT_EQ(r1.replacement(), check1);
  
          Node* check2 = effect = graph()->NewNode(
              simplified()->CheckedTaggedToFloat64(mode, feedback2), value,
              effect, control);
          Reduction r2 = Reduce(check2);
          ASSERT_TRUE(r2.Changed());
          EXPECT_EQ(r2.replacement(), check1);
        }
      }
    }
  }
  
  TEST_F(RedundancyEliminationTest,
         CheckedTaggedToFloat64SubsubmedByCheckedTaggedToFloat64) {
    TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
      TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
        Node* value = Parameter(0);
        Node* effect = graph()->start();
        Node* control = graph()->start();
  
        // If the check passed for CheckTaggedInputMode::kNumber, it'll
        // also pass later for CheckTaggedInputMode::kNumberOrOddball.
        Node* check1 = effect =
            graph()->NewNode(simplified()->CheckedTaggedToFloat64(
                                 CheckTaggedInputMode::kNumber, feedback1),
                             value, effect, control);
        Reduction r1 = Reduce(check1);
        ASSERT_TRUE(r1.Changed());
        EXPECT_EQ(r1.replacement(), check1);
  
        Node* check2 = effect = graph()->NewNode(
            simplified()->CheckedTaggedToFloat64(
                CheckTaggedInputMode::kNumberOrOddball, feedback2),
            value, effect, control);
        Reduction r2 = Reduce(check2);
        ASSERT_TRUE(r2.Changed());
        EXPECT_EQ(r2.replacement(), check1);
      }
    }
  }
  
  // -----------------------------------------------------------------------------
  // CheckedTaggedToInt32
  
  TEST_F(RedundancyEliminationTest, CheckedTaggedToInt32) {
    TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
      TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
        TRACED_FOREACH(CheckForMinusZeroMode, mode, kCheckForMinusZeroModes) {
          Node* value = Parameter(0);
          Node* effect = graph()->start();
          Node* control = graph()->start();
  
          Node* check1 = effect = graph()->NewNode(
              simplified()->CheckedTaggedToInt32(mode, feedback1), value, effect,
              control);
          Reduction r1 = Reduce(check1);
          ASSERT_TRUE(r1.Changed());
          EXPECT_EQ(r1.replacement(), check1);
  
          Node* check2 = effect = graph()->NewNode(
              simplified()->CheckedTaggedToInt32(mode, feedback2), value, effect,
              control);
          Reduction r2 = Reduce(check2);
          ASSERT_TRUE(r2.Changed());
          EXPECT_EQ(r2.replacement(), check1);
        }
      }
    }
  }
  
  TEST_F(RedundancyEliminationTest,
         CheckedTaggedToInt32SubsumedByCheckedTaggedSignedToInt32) {
    TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
      TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
        TRACED_FOREACH(CheckForMinusZeroMode, mode, kCheckForMinusZeroModes) {
          Node* value = Parameter(0);
          Node* effect = graph()->start();
          Node* control = graph()->start();
  
          Node* check1 = effect = graph()->NewNode(
              simplified()->CheckedTaggedSignedToInt32(feedback1), value, effect,
              control);
          Reduction r1 = Reduce(check1);
          ASSERT_TRUE(r1.Changed());
          EXPECT_EQ(r1.replacement(), check1);
  
          Node* check2 = effect = graph()->NewNode(
              simplified()->CheckedTaggedToInt32(mode, feedback2), value, effect,
              control);
          Reduction r2 = Reduce(check2);
          ASSERT_TRUE(r2.Changed());
          EXPECT_EQ(r2.replacement(), check1);
        }
      }
    }
  }
  
  // -----------------------------------------------------------------------------
  // CheckedTaggedToInt64
  
  TEST_F(RedundancyEliminationTest, CheckedTaggedToInt64) {
    TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
      TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
        TRACED_FOREACH(CheckForMinusZeroMode, mode, kCheckForMinusZeroModes) {
          Node* value = Parameter(0);
          Node* effect = graph()->start();
          Node* control = graph()->start();
  
          Node* check1 = effect = graph()->NewNode(
              simplified()->CheckedTaggedToInt64(mode, feedback1), value, effect,
              control);
          Reduction r1 = Reduce(check1);
          ASSERT_TRUE(r1.Changed());
          EXPECT_EQ(r1.replacement(), check1);
  
          Node* check2 = effect = graph()->NewNode(
              simplified()->CheckedTaggedToInt64(mode, feedback2), value, effect,
              control);
          Reduction r2 = Reduce(check2);
          ASSERT_TRUE(r2.Changed());
          EXPECT_EQ(r2.replacement(), check1);
        }
      }
    }
  }
  
  // -----------------------------------------------------------------------------
  // CheckedTaggedToTaggedPointer
  
  TEST_F(RedundancyEliminationTest, CheckedTaggedToTaggedPointer) {
    TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
      TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
        Node* value = Parameter(0);
        Node* effect = graph()->start();
        Node* control = graph()->start();
  
        Node* check1 = effect = graph()->NewNode(
            simplified()->CheckedTaggedToTaggedPointer(feedback1), value, effect,
            control);
        Reduction r1 = Reduce(check1);
        ASSERT_TRUE(r1.Changed());
        EXPECT_EQ(r1.replacement(), check1);
  
        Node* check2 = effect = graph()->NewNode(
            simplified()->CheckedTaggedToTaggedPointer(feedback2), value, effect,
            control);
        Reduction r2 = Reduce(check2);
        ASSERT_TRUE(r2.Changed());
        EXPECT_EQ(r2.replacement(), check1);
      }
    }
  }
  
  // -----------------------------------------------------------------------------
  // CheckedTaggedToTaggedSigned
  
  TEST_F(RedundancyEliminationTest, CheckedTaggedToTaggedSigned) {
    TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
      TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
        Node* value = Parameter(0);
        Node* effect = graph()->start();
        Node* control = graph()->start();
  
        Node* check1 = effect =
            graph()->NewNode(simplified()->CheckedTaggedToTaggedSigned(feedback1),
                             value, effect, control);
        Reduction r1 = Reduce(check1);
        ASSERT_TRUE(r1.Changed());
        EXPECT_EQ(r1.replacement(), check1);
  
        Node* check2 = effect =
            graph()->NewNode(simplified()->CheckedTaggedToTaggedSigned(feedback2),
                             value, effect, control);
        Reduction r2 = Reduce(check2);
        ASSERT_TRUE(r2.Changed());
        EXPECT_EQ(r2.replacement(), check1);
      }
    }
  }
  
  // -----------------------------------------------------------------------------
  // CheckedTruncateTaggedToWord32
  
  TEST_F(RedundancyEliminationTest, CheckedTruncateTaggedToWord32) {
    TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
      TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
        TRACED_FOREACH(CheckTaggedInputMode, mode, kCheckTaggedInputModes) {
          Node* value = Parameter(0);
          Node* effect = graph()->start();
          Node* control = graph()->start();
  
          Node* check1 = effect = graph()->NewNode(
              simplified()->CheckedTruncateTaggedToWord32(mode, feedback1), value,
              effect, control);
          Reduction r1 = Reduce(check1);
          ASSERT_TRUE(r1.Changed());
          EXPECT_EQ(r1.replacement(), check1);
  
          Node* check2 = effect = graph()->NewNode(
              simplified()->CheckedTruncateTaggedToWord32(mode, feedback2), value,
              effect, control);
          Reduction r2 = Reduce(check2);
          ASSERT_TRUE(r2.Changed());
          EXPECT_EQ(r2.replacement(), check1);
        }
      }
    }
  }
  
  TEST_F(RedundancyEliminationTest,
         CheckedTruncateTaggedToWord32SubsumedByCheckedTruncateTaggedToWord32) {
    TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
      TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
        Node* value = Parameter(0);
        Node* effect = graph()->start();
        Node* control = graph()->start();
  
        // If the check passed for CheckTaggedInputMode::kNumber, it'll
        // also pass later for CheckTaggedInputMode::kNumberOrOddball.
        Node* check1 = effect =
            graph()->NewNode(simplified()->CheckedTruncateTaggedToWord32(
                                 CheckTaggedInputMode::kNumber, feedback1),
                             value, effect, control);
        Reduction r1 = Reduce(check1);
        ASSERT_TRUE(r1.Changed());
        EXPECT_EQ(r1.replacement(), check1);
  
        Node* check2 = effect = graph()->NewNode(
            simplified()->CheckedTruncateTaggedToWord32(
                CheckTaggedInputMode::kNumberOrOddball, feedback2),
            value, effect, control);
        Reduction r2 = Reduce(check2);
        ASSERT_TRUE(r2.Changed());
        EXPECT_EQ(r2.replacement(), check1);
      }
    }
  }
  
  // -----------------------------------------------------------------------------
  // CheckedUint32Bounds
  
  TEST_F(RedundancyEliminationTest, CheckedUint32Bounds) {
    TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
      TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
        Node* index = Parameter(0);
        Node* length = Parameter(1);
        Node* effect = graph()->start();
        Node* control = graph()->start();
  
        Node* check1 = effect = graph()->NewNode(
            simplified()->CheckedUint32Bounds(
                feedback1, CheckBoundsParameters::kDeoptOnOutOfBounds),
            index, length, effect, control);
        Reduction r1 = Reduce(check1);
        ASSERT_TRUE(r1.Changed());
        EXPECT_EQ(r1.replacement(), check1);
  
        Node* check2 = effect = graph()->NewNode(
            simplified()->CheckedUint32Bounds(
                feedback2, CheckBoundsParameters::kDeoptOnOutOfBounds),
            index, length, effect, control);
        Reduction r2 = Reduce(check2);
        ASSERT_TRUE(r2.Changed());
        EXPECT_EQ(r2.replacement(), check1);
      }
    }
  }
  
  // -----------------------------------------------------------------------------
  // CheckedUint32ToInt32
  
  TEST_F(RedundancyEliminationTest, CheckedUint32ToInt32) {
    TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
      TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
        Node* value = Parameter(0);
        Node* effect = graph()->start();
        Node* control = graph()->start();
  
        Node* check1 = effect =
            graph()->NewNode(simplified()->CheckedUint32ToInt32(feedback1), value,
                             effect, control);
        Reduction r1 = Reduce(check1);
        ASSERT_TRUE(r1.Changed());
        EXPECT_EQ(r1.replacement(), check1);
  
        Node* check2 = effect =
            graph()->NewNode(simplified()->CheckedUint32ToInt32(feedback2), value,
                             effect, control);
        Reduction r2 = Reduce(check2);
        ASSERT_TRUE(r2.Changed());
        EXPECT_EQ(r2.replacement(), check1);
      }
    }
  }
  
  // -----------------------------------------------------------------------------
  // CheckedUint32ToTaggedSigned
  
  TEST_F(RedundancyEliminationTest, CheckedUint32ToTaggedSigned) {
    TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
      TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
        Node* value = Parameter(0);
        Node* effect = graph()->start();
        Node* control = graph()->start();
  
        Node* check1 = effect =
            graph()->NewNode(simplified()->CheckedUint32ToTaggedSigned(feedback1),
                             value, effect, control);
        Reduction r1 = Reduce(check1);
        ASSERT_TRUE(r1.Changed());
        EXPECT_EQ(r1.replacement(), check1);
  
        Node* check2 = effect =
            graph()->NewNode(simplified()->CheckedUint32ToTaggedSigned(feedback2),
                             value, effect, control);
        Reduction r2 = Reduce(check2);
        ASSERT_TRUE(r2.Changed());
        EXPECT_EQ(r2.replacement(), check1);
      }
    }
  }
  
  // -----------------------------------------------------------------------------
  // CheckedUint64Bounds
  
  TEST_F(RedundancyEliminationTest, CheckedUint64Bounds) {
    TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
      TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
        Node* index = Parameter(0);
        Node* length = Parameter(1);
        Node* effect = graph()->start();
        Node* control = graph()->start();
  
        Node* check1 = effect =
            graph()->NewNode(simplified()->CheckedUint64Bounds(feedback1), index,
                             length, effect, control);
        Reduction r1 = Reduce(check1);
        ASSERT_TRUE(r1.Changed());
        EXPECT_EQ(r1.replacement(), check1);
  
        Node* check2 = effect =
            graph()->NewNode(simplified()->CheckedUint64Bounds(feedback2), index,
                             length, effect, control);
        Reduction r2 = Reduce(check2);
        ASSERT_TRUE(r2.Changed());
        EXPECT_EQ(r2.replacement(), check1);
      }
    }
  }
  
  // -----------------------------------------------------------------------------
  // CheckedUint64ToInt32
  
  TEST_F(RedundancyEliminationTest, CheckedUint64ToInt32) {
    TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
      TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
        Node* value = Parameter(0);
        Node* effect = graph()->start();
        Node* control = graph()->start();
  
        Node* check1 = effect =
            graph()->NewNode(simplified()->CheckedUint64ToInt32(feedback1), value,
                             effect, control);
        Reduction r1 = Reduce(check1);
        ASSERT_TRUE(r1.Changed());
        EXPECT_EQ(r1.replacement(), check1);
  
        Node* check2 = effect =
            graph()->NewNode(simplified()->CheckedUint64ToInt32(feedback2), value,
                             effect, control);
        Reduction r2 = Reduce(check2);
        ASSERT_TRUE(r2.Changed());
        EXPECT_EQ(r2.replacement(), check1);
      }
    }
  }
  
  // -----------------------------------------------------------------------------
  // CheckedUint64ToTaggedSigned
  
  TEST_F(RedundancyEliminationTest, CheckedUint64ToTaggedSigned) {
    TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
      TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
        Node* value = Parameter(0);
        Node* effect = graph()->start();
        Node* control = graph()->start();
  
        Node* check1 = effect =
            graph()->NewNode(simplified()->CheckedUint64ToTaggedSigned(feedback1),
                             value, effect, control);
        Reduction r1 = Reduce(check1);
        ASSERT_TRUE(r1.Changed());
        EXPECT_EQ(r1.replacement(), check1);
  
        Node* check2 = effect =
            graph()->NewNode(simplified()->CheckedUint64ToTaggedSigned(feedback2),
                             value, effect, control);
        Reduction r2 = Reduce(check2);
        ASSERT_TRUE(r2.Changed());
        EXPECT_EQ(r2.replacement(), check1);
      }
    }
  }
  
  // -----------------------------------------------------------------------------
  // SpeculativeNumberEqual
  
  TEST_F(RedundancyEliminationTest,
         SpeculativeNumberEqualWithCheckBoundsBetterType) {
    Typer typer(broker(), Typer::kNoFlags, graph());
    TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
      TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
        Node* lhs = Parameter(Type::Any(), 0);
        Node* rhs = Parameter(Type::Any(), 1);
        Node* length = Parameter(Type::Unsigned31(), 2);
        Node* effect = graph()->start();
        Node* control = graph()->start();
  
        Node* check1 = effect = graph()->NewNode(
            simplified()->CheckBounds(feedback1), lhs, length, effect, control);
        Reduction r1 = Reduce(check1);
        ASSERT_TRUE(r1.Changed());
        EXPECT_EQ(r1.replacement(), check1);
  
        Node* check2 = effect = graph()->NewNode(
            simplified()->CheckBounds(feedback2), rhs, length, effect, control);
        Reduction r2 = Reduce(check2);
        ASSERT_TRUE(r2.Changed());
        EXPECT_EQ(r2.replacement(), check2);
  
        Node* cmp3 = effect =
            graph()->NewNode(simplified()->SpeculativeNumberEqual(
                                 NumberOperationHint::kSignedSmall),
                             lhs, rhs, effect, control);
        Reduction r3 = Reduce(cmp3);
        ASSERT_TRUE(r3.Changed());
        EXPECT_THAT(r3.replacement(),
                    IsSpeculativeNumberEqual(NumberOperationHint::kSignedSmall,
                                             check1, check2, _, _));
      }
    }
  }
  
  TEST_F(RedundancyEliminationTest,
         SpeculativeNumberEqualWithCheckBoundsSameType) {
    Typer typer(broker(), Typer::kNoFlags, graph());
    TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
      TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
        Node* lhs = Parameter(Type::UnsignedSmall(), 0);
        Node* rhs = Parameter(Type::UnsignedSmall(), 1);
        Node* length = Parameter(Type::Unsigned31(), 2);
        Node* effect = graph()->start();
        Node* control = graph()->start();
  
        Node* check1 = effect = graph()->NewNode(
            simplified()->CheckBounds(feedback1), lhs, length, effect, control);
        Reduction r1 = Reduce(check1);
        ASSERT_TRUE(r1.Changed());
        EXPECT_EQ(r1.replacement(), check1);
  
        Node* check2 = effect = graph()->NewNode(
            simplified()->CheckBounds(feedback2), rhs, length, effect, control);
        Reduction r2 = Reduce(check2);
        ASSERT_TRUE(r2.Changed());
        EXPECT_EQ(r2.replacement(), check2);
  
        Node* cmp3 = effect =
            graph()->NewNode(simplified()->SpeculativeNumberEqual(
                                 NumberOperationHint::kSignedSmall),
                             lhs, rhs, effect, control);
        Reduction r3 = Reduce(cmp3);
        ASSERT_TRUE(r3.Changed());
        EXPECT_THAT(r3.replacement(),
                    IsSpeculativeNumberEqual(NumberOperationHint::kSignedSmall,
                                             lhs, rhs, _, _));
      }
    }
  }
  
  // -----------------------------------------------------------------------------
  // SpeculativeNumberLessThan
  
  TEST_F(RedundancyEliminationTest,
         SpeculativeNumberLessThanWithCheckBoundsBetterType) {
    Typer typer(broker(), Typer::kNoFlags, graph());
    TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
      TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
        Node* lhs = Parameter(Type::Any(), 0);
        Node* rhs = Parameter(Type::Any(), 1);
        Node* length = Parameter(Type::Unsigned31(), 2);
        Node* effect = graph()->start();
        Node* control = graph()->start();
  
        Node* check1 = effect = graph()->NewNode(
            simplified()->CheckBounds(feedback1), lhs, length, effect, control);
        Reduction r1 = Reduce(check1);
        ASSERT_TRUE(r1.Changed());
        EXPECT_EQ(r1.replacement(), check1);
  
        Node* check2 = effect = graph()->NewNode(
            simplified()->CheckBounds(feedback2), rhs, length, effect, control);
        Reduction r2 = Reduce(check2);
        ASSERT_TRUE(r2.Changed());
        EXPECT_EQ(r2.replacement(), check2);
  
        Node* cmp3 = effect =
            graph()->NewNode(simplified()->SpeculativeNumberLessThan(
                                 NumberOperationHint::kSignedSmall),
                             lhs, rhs, effect, control);
        Reduction r3 = Reduce(cmp3);
        ASSERT_TRUE(r3.Changed());
        EXPECT_THAT(r3.replacement(),
                    IsSpeculativeNumberLessThan(NumberOperationHint::kSignedSmall,
                                                check1, check2, _, _));
      }
    }
  }
  
  TEST_F(RedundancyEliminationTest,
         SpeculativeNumberLessThanWithCheckBoundsSameType) {
    Typer typer(broker(), Typer::kNoFlags, graph());
    TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
      TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
        Node* lhs = Parameter(Type::UnsignedSmall(), 0);
        Node* rhs = Parameter(Type::UnsignedSmall(), 1);
        Node* length = Parameter(Type::Unsigned31(), 2);
        Node* effect = graph()->start();
        Node* control = graph()->start();
  
        Node* check1 = effect = graph()->NewNode(
            simplified()->CheckBounds(feedback1), lhs, length, effect, control);
        Reduction r1 = Reduce(check1);
        ASSERT_TRUE(r1.Changed());
        EXPECT_EQ(r1.replacement(), check1);
  
        Node* check2 = effect = graph()->NewNode(
            simplified()->CheckBounds(feedback2), rhs, length, effect, control);
        Reduction r2 = Reduce(check2);
        ASSERT_TRUE(r2.Changed());
        EXPECT_EQ(r2.replacement(), check2);
  
        Node* cmp3 = effect =
            graph()->NewNode(simplified()->SpeculativeNumberLessThan(
                                 NumberOperationHint::kSignedSmall),
                             lhs, rhs, effect, control);
        Reduction r3 = Reduce(cmp3);
        ASSERT_TRUE(r3.Changed());
        EXPECT_THAT(r3.replacement(),
                    IsSpeculativeNumberLessThan(NumberOperationHint::kSignedSmall,
                                                lhs, rhs, _, _));
      }
    }
  }
  
  // -----------------------------------------------------------------------------
  // SpeculativeNumberLessThanOrEqual
  
  TEST_F(RedundancyEliminationTest,
         SpeculativeNumberLessThanOrEqualWithCheckBoundsBetterType) {
    Typer typer(broker(), Typer::kNoFlags, graph());
    TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
      TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
        Node* lhs = Parameter(Type::Any(), 0);
        Node* rhs = Parameter(Type::Any(), 1);
        Node* length = Parameter(Type::Unsigned31(), 2);
        Node* effect = graph()->start();
        Node* control = graph()->start();
  
        Node* check1 = effect = graph()->NewNode(
            simplified()->CheckBounds(feedback1), lhs, length, effect, control);
        Reduction r1 = Reduce(check1);
        ASSERT_TRUE(r1.Changed());
        EXPECT_EQ(r1.replacement(), check1);
  
        Node* check2 = effect = graph()->NewNode(
            simplified()->CheckBounds(feedback2), rhs, length, effect, control);
        Reduction r2 = Reduce(check2);
        ASSERT_TRUE(r2.Changed());
        EXPECT_EQ(r2.replacement(), check2);
  
        Node* cmp3 = effect =
            graph()->NewNode(simplified()->SpeculativeNumberLessThanOrEqual(
                                 NumberOperationHint::kSignedSmall),
                             lhs, rhs, effect, control);
        Reduction r3 = Reduce(cmp3);
        ASSERT_TRUE(r3.Changed());
        EXPECT_THAT(r3.replacement(),
                    IsSpeculativeNumberLessThanOrEqual(
                        NumberOperationHint::kSignedSmall, check1, check2, _, _));
      }
    }
  }
  
  TEST_F(RedundancyEliminationTest,
         SpeculativeNumberLessThanOrEqualWithCheckBoundsSameType) {
    Typer typer(broker(), Typer::kNoFlags, graph());
    TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
      TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
        Node* lhs = Parameter(Type::UnsignedSmall(), 0);
        Node* rhs = Parameter(Type::UnsignedSmall(), 1);
        Node* length = Parameter(Type::Unsigned31(), 2);
        Node* effect = graph()->start();
        Node* control = graph()->start();
  
        Node* check1 = effect = graph()->NewNode(
            simplified()->CheckBounds(feedback1), lhs, length, effect, control);
        Reduction r1 = Reduce(check1);
        ASSERT_TRUE(r1.Changed());
        EXPECT_EQ(r1.replacement(), check1);
  
        Node* check2 = effect = graph()->NewNode(
            simplified()->CheckBounds(feedback2), rhs, length, effect, control);
        Reduction r2 = Reduce(check2);
        ASSERT_TRUE(r2.Changed());
        EXPECT_EQ(r2.replacement(), check2);
  
        Node* cmp3 = effect =
            graph()->NewNode(simplified()->SpeculativeNumberLessThanOrEqual(
                                 NumberOperationHint::kSignedSmall),
                             lhs, rhs, effect, control);
        Reduction r3 = Reduce(cmp3);
        ASSERT_TRUE(r3.Changed());
        EXPECT_THAT(r3.replacement(),
                    IsSpeculativeNumberLessThanOrEqual(
                        NumberOperationHint::kSignedSmall, lhs, rhs, _, _));
      }
    }
  }
  
  // -----------------------------------------------------------------------------
  // SpeculativeNumberAdd
  
  TEST_F(RedundancyEliminationTest,
         SpeculativeNumberAddWithCheckBoundsBetterType) {
    Typer typer(broker(), Typer::kNoFlags, graph());
    TRACED_FOREACH(VectorSlotPair, feedback, vector_slot_pairs()) {
      TRACED_FOREACH(NumberOperationHint, hint, kNumberOperationHints) {
        Node* lhs = Parameter(Type::Any(), 0);
        Node* rhs = Parameter(Type::Any(), 1);
        Node* length = Parameter(Type::Unsigned31(), 2);
        Node* effect = graph()->start();
        Node* control = graph()->start();
  
        Node* check1 = effect = graph()->NewNode(
            simplified()->CheckBounds(feedback), lhs, length, effect, control);
        Reduction r1 = Reduce(check1);
        ASSERT_TRUE(r1.Changed());
        EXPECT_EQ(r1.replacement(), check1);
  
        Node* add2 = effect = graph()->NewNode(
            simplified()->SpeculativeNumberAdd(hint), lhs, rhs, effect, control);
        Reduction r2 = Reduce(add2);
        ASSERT_TRUE(r2.Changed());
        EXPECT_THAT(r2.replacement(),
                    IsSpeculativeNumberAdd(hint, check1, rhs, _, _));
      }
    }
  }
  
  TEST_F(RedundancyEliminationTest, SpeculativeNumberAddWithCheckBoundsSameType) {
    Typer typer(broker(), Typer::kNoFlags, graph());
    TRACED_FOREACH(VectorSlotPair, feedback, vector_slot_pairs()) {
      TRACED_FOREACH(NumberOperationHint, hint, kNumberOperationHints) {
        Node* lhs = Parameter(Type::Range(42.0, 42.0, zone()), 0);
        Node* rhs = Parameter(Type::Any(), 0);
        Node* length = Parameter(Type::Unsigned31(), 1);
        Node* effect = graph()->start();
        Node* control = graph()->start();
  
        Node* check1 = effect = graph()->NewNode(
            simplified()->CheckBounds(feedback), lhs, length, effect, control);
        Reduction r1 = Reduce(check1);
        ASSERT_TRUE(r1.Changed());
        EXPECT_EQ(r1.replacement(), check1);
  
        Node* add2 = effect = graph()->NewNode(
            simplified()->SpeculativeNumberAdd(hint), lhs, rhs, effect, control);
        Reduction r2 = Reduce(add2);
        ASSERT_TRUE(r2.Changed());
        EXPECT_THAT(r2.replacement(),
                    IsSpeculativeNumberAdd(hint, lhs, rhs, _, _));
      }
    }
  }
  
  // -----------------------------------------------------------------------------
  // SpeculativeNumberSubtract
  
  TEST_F(RedundancyEliminationTest,
         SpeculativeNumberSubtractWithCheckBoundsBetterType) {
    Typer typer(broker(), Typer::kNoFlags, graph());
    TRACED_FOREACH(VectorSlotPair, feedback, vector_slot_pairs()) {
      TRACED_FOREACH(NumberOperationHint, hint, kNumberOperationHints) {
        Node* lhs = Parameter(Type::Any(), 0);
        Node* rhs = Parameter(Type::Any(), 1);
        Node* length = Parameter(Type::Unsigned31(), 2);
        Node* effect = graph()->start();
        Node* control = graph()->start();
  
        Node* check1 = effect = graph()->NewNode(
            simplified()->CheckBounds(feedback), lhs, length, effect, control);
        Reduction r1 = Reduce(check1);
        ASSERT_TRUE(r1.Changed());
        EXPECT_EQ(r1.replacement(), check1);
  
        Node* subtract2 = effect =
            graph()->NewNode(simplified()->SpeculativeNumberSubtract(hint), lhs,
                             rhs, effect, control);
        Reduction r2 = Reduce(subtract2);
        ASSERT_TRUE(r2.Changed());
        EXPECT_THAT(r2.replacement(),
                    IsSpeculativeNumberSubtract(hint, check1, rhs, _, _));
      }
    }
  }
  
  TEST_F(RedundancyEliminationTest,
         SpeculativeNumberSubtractWithCheckBoundsSameType) {
    Typer typer(broker(), Typer::kNoFlags, graph());
    TRACED_FOREACH(VectorSlotPair, feedback, vector_slot_pairs()) {
      TRACED_FOREACH(NumberOperationHint, hint, kNumberOperationHints) {
        Node* lhs = Parameter(Type::Range(42.0, 42.0, zone()), 0);
        Node* rhs = Parameter(Type::Any(), 0);
        Node* length = Parameter(Type::Unsigned31(), 1);
        Node* effect = graph()->start();
        Node* control = graph()->start();
  
        Node* check1 = effect = graph()->NewNode(
            simplified()->CheckBounds(feedback), lhs, length, effect, control);
        Reduction r1 = Reduce(check1);
        ASSERT_TRUE(r1.Changed());
        EXPECT_EQ(r1.replacement(), check1);
  
        Node* subtract2 = effect =
            graph()->NewNode(simplified()->SpeculativeNumberSubtract(hint), lhs,
                             rhs, effect, control);
        Reduction r2 = Reduce(subtract2);
        ASSERT_TRUE(r2.Changed());
        EXPECT_THAT(r2.replacement(),
                    IsSpeculativeNumberSubtract(hint, lhs, rhs, _, _));
      }
    }
  }
  
  // -----------------------------------------------------------------------------
  // SpeculativeSafeIntegerAdd
  
  TEST_F(RedundancyEliminationTest,
         SpeculativeSafeIntegerAddWithCheckBoundsBetterType) {
    Typer typer(broker(), Typer::kNoFlags, graph());
    TRACED_FOREACH(VectorSlotPair, feedback, vector_slot_pairs()) {
      TRACED_FOREACH(NumberOperationHint, hint, kNumberOperationHints) {
        Node* lhs = Parameter(Type::Any(), 0);
        Node* rhs = Parameter(Type::Any(), 1);
        Node* length = Parameter(Type::Unsigned31(), 2);
        Node* effect = graph()->start();
        Node* control = graph()->start();
  
        Node* check1 = effect = graph()->NewNode(
            simplified()->CheckBounds(feedback), lhs, length, effect, control);
        Reduction r1 = Reduce(check1);
        ASSERT_TRUE(r1.Changed());
        EXPECT_EQ(r1.replacement(), check1);
  
        Node* add2 = effect =
            graph()->NewNode(simplified()->SpeculativeSafeIntegerAdd(hint), lhs,
                             rhs, effect, control);
        Reduction r2 = Reduce(add2);
        ASSERT_TRUE(r2.Changed());
        EXPECT_THAT(r2.replacement(),
                    IsSpeculativeSafeIntegerAdd(hint, check1, rhs, _, _));
      }
    }
  }
  
  TEST_F(RedundancyEliminationTest,
         SpeculativeSafeIntegerAddWithCheckBoundsSameType) {
    Typer typer(broker(), Typer::kNoFlags, graph());
    TRACED_FOREACH(VectorSlotPair, feedback, vector_slot_pairs()) {
      TRACED_FOREACH(NumberOperationHint, hint, kNumberOperationHints) {
        Node* lhs = Parameter(Type::Range(42.0, 42.0, zone()), 0);
        Node* rhs = Parameter(Type::Any(), 0);
        Node* length = Parameter(Type::Unsigned31(), 1);
        Node* effect = graph()->start();
        Node* control = graph()->start();
  
        Node* check1 = effect = graph()->NewNode(
            simplified()->CheckBounds(feedback), lhs, length, effect, control);
        Reduction r1 = Reduce(check1);
        ASSERT_TRUE(r1.Changed());
        EXPECT_EQ(r1.replacement(), check1);
  
        Node* add2 = effect =
            graph()->NewNode(simplified()->SpeculativeSafeIntegerAdd(hint), lhs,
                             rhs, effect, control);
        Reduction r2 = Reduce(add2);
        ASSERT_TRUE(r2.Changed());
        EXPECT_THAT(r2.replacement(),
                    IsSpeculativeSafeIntegerAdd(hint, lhs, rhs, _, _));
      }
    }
  }
  
  // -----------------------------------------------------------------------------
  // SpeculativeSafeIntegerSubtract
  
  TEST_F(RedundancyEliminationTest,
         SpeculativeSafeIntegerSubtractWithCheckBoundsBetterType) {
    Typer typer(broker(), Typer::kNoFlags, graph());
    TRACED_FOREACH(VectorSlotPair, feedback, vector_slot_pairs()) {
      TRACED_FOREACH(NumberOperationHint, hint, kNumberOperationHints) {
        Node* lhs = Parameter(Type::Any(), 0);
        Node* rhs = Parameter(Type::Any(), 1);
        Node* length = Parameter(Type::Unsigned31(), 2);
        Node* effect = graph()->start();
        Node* control = graph()->start();
  
        Node* check1 = effect = graph()->NewNode(
            simplified()->CheckBounds(feedback), lhs, length, effect, control);
        Reduction r1 = Reduce(check1);
        ASSERT_TRUE(r1.Changed());
        EXPECT_EQ(r1.replacement(), check1);
  
        Node* subtract2 = effect =
            graph()->NewNode(simplified()->SpeculativeSafeIntegerSubtract(hint),
                             lhs, rhs, effect, control);
        Reduction r2 = Reduce(subtract2);
        ASSERT_TRUE(r2.Changed());
        EXPECT_THAT(r2.replacement(),
                    IsSpeculativeSafeIntegerSubtract(hint, check1, rhs, _, _));
      }
    }
  }
  
  TEST_F(RedundancyEliminationTest,
         SpeculativeSafeIntegerSubtractWithCheckBoundsSameType) {
    Typer typer(broker(), Typer::kNoFlags, graph());
    TRACED_FOREACH(VectorSlotPair, feedback, vector_slot_pairs()) {
      TRACED_FOREACH(NumberOperationHint, hint, kNumberOperationHints) {
        Node* lhs = Parameter(Type::Range(42.0, 42.0, zone()), 0);
        Node* rhs = Parameter(Type::Any(), 0);
        Node* length = Parameter(Type::Unsigned31(), 1);
        Node* effect = graph()->start();
        Node* control = graph()->start();
  
        Node* check1 = effect = graph()->NewNode(
            simplified()->CheckBounds(feedback), lhs, length, effect, control);
        Reduction r1 = Reduce(check1);
        ASSERT_TRUE(r1.Changed());
        EXPECT_EQ(r1.replacement(), check1);
  
        Node* subtract2 = effect =
            graph()->NewNode(simplified()->SpeculativeSafeIntegerSubtract(hint),
                             lhs, rhs, effect, control);
        Reduction r2 = Reduce(subtract2);
        ASSERT_TRUE(r2.Changed());
        EXPECT_THAT(r2.replacement(),
                    IsSpeculativeSafeIntegerSubtract(hint, lhs, rhs, _, _));
      }
    }
  }
  
  // -----------------------------------------------------------------------------
  // SpeculativeToNumber
  
  TEST_F(RedundancyEliminationTest,
         SpeculativeToNumberWithCheckBoundsBetterType) {
    Typer typer(broker(), Typer::kNoFlags, graph());
    TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
      TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
        TRACED_FOREACH(NumberOperationHint, hint, kNumberOperationHints) {
          Node* index = Parameter(Type::Any(), 0);
          Node* length = Parameter(Type::Unsigned31(), 1);
          Node* effect = graph()->start();
          Node* control = graph()->start();
  
          Node* check1 = effect =
              graph()->NewNode(simplified()->CheckBounds(feedback1), index,
                               length, effect, control);
          Reduction r1 = Reduce(check1);
          ASSERT_TRUE(r1.Changed());
          EXPECT_EQ(r1.replacement(), check1);
  
          Node* to_number2 = effect =
              graph()->NewNode(simplified()->SpeculativeToNumber(hint, feedback2),
                               index, effect, control);
          Reduction r2 = Reduce(to_number2);
          ASSERT_TRUE(r2.Changed());
          EXPECT_THAT(r2.replacement(), IsSpeculativeToNumber(check1));
        }
      }
    }
  }
  
  TEST_F(RedundancyEliminationTest, SpeculativeToNumberWithCheckBoundsSameType) {
    Typer typer(broker(), Typer::kNoFlags, graph());
    TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
      TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
        TRACED_FOREACH(NumberOperationHint, hint, kNumberOperationHints) {
          Node* index = Parameter(Type::Range(42.0, 42.0, zone()), 0);
          Node* length = Parameter(Type::Unsigned31(), 1);
          Node* effect = graph()->start();
          Node* control = graph()->start();
  
          Node* check1 = effect =
              graph()->NewNode(simplified()->CheckBounds(feedback1), index,
                               length, effect, control);
          Reduction r1 = Reduce(check1);
          ASSERT_TRUE(r1.Changed());
          EXPECT_EQ(r1.replacement(), check1);
  
          Node* to_number2 = effect =
              graph()->NewNode(simplified()->SpeculativeToNumber(hint, feedback2),
                               index, effect, control);
          Reduction r2 = Reduce(to_number2);
          ASSERT_TRUE(r2.Changed());
          EXPECT_THAT(r2.replacement(), IsSpeculativeToNumber(index));
        }
      }
    }
  }
  
  }  // namespace redundancy_elimination_unittest
  }  // namespace compiler
  }  // namespace internal
  }  // namespace v8
  