From 44910725078fd165189361e2adf3939bc7f17264 Mon Sep 17 00:00:00 2001 From: Benedikt Meurer Date: Wed, 19 Sep 2018 14:24:12 +0200 Subject: [PATCH] [turbofan] Fix RedundancyElimination and add more test coverage. Make the RedundancyElimination handle all simplified operators that are listed in the SIMPLIFIED_CHECKED_OP_LIST, and fix a couple of bugs and oversights in the code. This also adds a lot of test coverage for all the cases that we care about in RedundancyElimination (with respect to Check/Checked simplified operators). Bug: v8:8015 Change-Id: I57d29113389841b09abcd013313bf5dd1c67735f Reviewed-on: https://chromium-review.googlesource.com/1233655 Reviewed-by: Sigurd Schneider Commit-Queue: Benedikt Meurer Cr-Commit-Position: refs/heads/master@{#56032} --- src/compiler/redundancy-elimination.cc | 44 +- src/compiler/redundancy-elimination.h | 2 +- src/compiler/simplified-operator.h | 2 +- src/vector-slot-pair.h | 3 +- test/unittests/BUILD.gn | 1 + .../redundancy-elimination-unittest.cc | 643 ++++++++++++++++++ 6 files changed, 675 insertions(+), 20 deletions(-) create mode 100644 test/unittests/compiler/redundancy-elimination-unittest.cc diff --git a/src/compiler/redundancy-elimination.cc b/src/compiler/redundancy-elimination.cc index a9c400f258..17093d87e3 100644 --- a/src/compiler/redundancy-elimination.cc +++ b/src/compiler/redundancy-elimination.cc @@ -32,23 +32,9 @@ Reduction RedundancyElimination::Reduce(Node* node) { case IrOpcode::kCheckSmi: case IrOpcode::kCheckString: case IrOpcode::kCheckSymbol: - case IrOpcode::kCheckedFloat64ToInt32: - case IrOpcode::kCheckedInt32Add: - case IrOpcode::kCheckedInt32Div: - case IrOpcode::kCheckedInt32Mod: - case IrOpcode::kCheckedInt32Mul: - case IrOpcode::kCheckedInt32Sub: - case IrOpcode::kCheckedInt32ToTaggedSigned: - case IrOpcode::kCheckedTaggedSignedToInt32: - case IrOpcode::kCheckedTaggedToFloat64: - case IrOpcode::kCheckedTaggedToInt32: - case IrOpcode::kCheckedTaggedToTaggedPointer: - case IrOpcode::kCheckedTaggedToTaggedSigned: - case IrOpcode::kCheckedTruncateTaggedToWord32: - case IrOpcode::kCheckedUint32Div: - case IrOpcode::kCheckedUint32Mod: - case IrOpcode::kCheckedUint32ToInt32: - case IrOpcode::kCheckedUint32ToTaggedSigned: +#define SIMPLIFIED_CHECKED_OP(Opcode) case IrOpcode::k##Opcode: + SIMPLIFIED_CHECKED_OP_LIST(SIMPLIFIED_CHECKED_OP) +#undef SIMPLIFIED_CHECKED_OP return ReduceCheckNode(node); case IrOpcode::kSpeculativeNumberAdd: case IrOpcode::kSpeculativeNumberSubtract: @@ -140,6 +126,12 @@ bool CheckSubsumes(Node const* a, Node const* b) { if (a->opcode() == IrOpcode::kCheckInternalizedString && b->opcode() == IrOpcode::kCheckString) { // CheckInternalizedString(node) implies CheckString(node) + } else if (a->opcode() == IrOpcode::kCheckSmi && + b->opcode() == IrOpcode::kCheckNumber) { + // CheckSmi(node) implies CheckNumber(node) + } else if (a->opcode() == IrOpcode::kCheckedTaggedSignedToInt32 && + b->opcode() == IrOpcode::kCheckedTaggedToInt32) { + // CheckedTaggedSignedToInt32(node) implies CheckedTaggedToInt32(node) } else if (a->opcode() != b->opcode()) { return false; } else { @@ -150,11 +142,15 @@ bool CheckSubsumes(Node const* a, Node const* b) { case IrOpcode::kCheckNumber: break; case IrOpcode::kCheckedInt32ToTaggedSigned: + case IrOpcode::kCheckedInt64ToInt32: + case IrOpcode::kCheckedInt64ToTaggedSigned: case IrOpcode::kCheckedTaggedSignedToInt32: case IrOpcode::kCheckedTaggedToTaggedPointer: case IrOpcode::kCheckedTaggedToTaggedSigned: case IrOpcode::kCheckedUint32ToInt32: case IrOpcode::kCheckedUint32ToTaggedSigned: + case IrOpcode::kCheckedUint64ToInt32: + case IrOpcode::kCheckedUint64ToTaggedSigned: break; case IrOpcode::kCheckedFloat64ToInt32: case IrOpcode::kCheckedTaggedToInt32: { @@ -167,6 +163,20 @@ bool CheckSubsumes(Node const* a, Node const* b) { } break; } + case IrOpcode::kCheckedTaggedToFloat64: + case IrOpcode::kCheckedTruncateTaggedToWord32: { + CheckTaggedInputParameters const& ap = + CheckTaggedInputParametersOf(a->op()); + CheckTaggedInputParameters const& bp = + CheckTaggedInputParametersOf(b->op()); + // {a} subsumes {b} if the modes are either the same, or {a} checks + // for Number, in which case {b} will be subsumed no matter what. + if (ap.mode() != bp.mode() && + ap.mode() != CheckTaggedInputMode::kNumber) { + return false; + } + break; + } default: DCHECK(!IsCheckedWithFeedback(a->op())); return false; diff --git a/src/compiler/redundancy-elimination.h b/src/compiler/redundancy-elimination.h index 05094a388e..64a373db9f 100644 --- a/src/compiler/redundancy-elimination.h +++ b/src/compiler/redundancy-elimination.h @@ -11,7 +11,7 @@ namespace v8 { namespace internal { namespace compiler { -class RedundancyElimination final : public AdvancedReducer { +class V8_EXPORT_PRIVATE RedundancyElimination final : public AdvancedReducer { public: RedundancyElimination(Editor* editor, Zone* zone); ~RedundancyElimination() final; diff --git a/src/compiler/simplified-operator.h b/src/compiler/simplified-operator.h index e8f7d6d827..df823fb0b0 100644 --- a/src/compiler/simplified-operator.h +++ b/src/compiler/simplified-operator.h @@ -228,7 +228,7 @@ enum class CheckTaggedInputMode : uint8_t { size_t hash_value(CheckTaggedInputMode); -std::ostream& operator<<(std::ostream&, CheckTaggedInputMode); +V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&, CheckTaggedInputMode); class CheckTaggedInputParameters { public: diff --git a/src/vector-slot-pair.h b/src/vector-slot-pair.h index ea6f3b61b1..cb99d06112 100644 --- a/src/vector-slot-pair.h +++ b/src/vector-slot-pair.h @@ -40,7 +40,8 @@ class V8_EXPORT_PRIVATE VectorSlotPair { bool operator==(VectorSlotPair const&, VectorSlotPair const&); bool operator!=(VectorSlotPair const&, VectorSlotPair const&); -std::ostream& operator<<(std::ostream& os, VectorSlotPair const&); +V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, + VectorSlotPair const&); size_t hash_value(VectorSlotPair const&); diff --git a/test/unittests/BUILD.gn b/test/unittests/BUILD.gn index e48d89d7d1..6432622856 100644 --- a/test/unittests/BUILD.gn +++ b/test/unittests/BUILD.gn @@ -131,6 +131,7 @@ v8_source_set("unittests_sources") { "compiler/node-unittest.cc", "compiler/opcodes-unittest.cc", "compiler/persistent-unittest.cc", + "compiler/redundancy-elimination-unittest.cc", "compiler/regalloc/live-range-unittest.cc", "compiler/regalloc/move-optimizer-unittest.cc", "compiler/regalloc/register-allocator-unittest.cc", diff --git a/test/unittests/compiler/redundancy-elimination-unittest.cc b/test/unittests/compiler/redundancy-elimination-unittest.cc new file mode 100644 index 0000000000..28423d652e --- /dev/null +++ b/test/unittests/compiler/redundancy-elimination-unittest.cc @@ -0,0 +1,643 @@ +// 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::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 metadata = FeedbackMetadata::New(isolate(), &spec); + Handle shared = + isolate()->factory()->NewSharedFunctionInfoForBuiltin( + isolate()->factory()->empty_string(), Builtins::kIllegal); + shared->set_raw_outer_scope_info_or_feedback_metadata(*metadata); + Handle feedback_vector = + FeedbackVector::New(isolate(), shared); + 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 const& vector_slot_pairs() const { + return vector_slot_pairs_; + } + SimplifiedOperatorBuilder* simplified() { return &simplified_; } + + private: + NiceMock editor_; + std::vector vector_slot_pairs_; + VectorSlotPair feedback2_; + RedundancyElimination reducer_; + SimplifiedOperatorBuilder simplified_; +}; + +namespace { + +const CheckForMinusZeroMode kCheckForMinusZeroModes[] = { + CheckForMinusZeroMode::kCheckForMinusZero, + CheckForMinusZeroMode::kDontCheckForMinusZero, +}; + +const CheckTaggedInputMode kCheckTaggedInputModes[] = { + CheckTaggedInputMode::kNumber, CheckTaggedInputMode::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); + } + } +} + +// ----------------------------------------------------------------------------- +// 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); + } +} + +// ----------------------------------------------------------------------------- +// 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); + } + } + } +} + +// ----------------------------------------------------------------------------- +// 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); + } + } + } +} + +// ----------------------------------------------------------------------------- +// 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); + } + } +} + +// ----------------------------------------------------------------------------- +// 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); + } + } +} + +// ----------------------------------------------------------------------------- +// 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); + } + } +} + +} // namespace redundancy_elimination_unittest +} // namespace compiler +} // namespace internal +} // namespace v8