diff --git a/src/compiler/machine-operator-reducer.cc b/src/compiler/machine-operator-reducer.cc index 5a5c8902dd..193b033bda 100644 --- a/src/compiler/machine-operator-reducer.cc +++ b/src/compiler/machine-operator-reducer.cc @@ -473,6 +473,22 @@ Reduction MachineOperatorReducer::Reduce(Node* node) { if (m.IsChangeFloat32ToFloat64()) return Replace(m.node()->InputAt(0)); break; } + case IrOpcode::kStore: { + Node* const value = node->InputAt(2); + // TODO(turbofan): Extend to 64-bit? + if (value->opcode() == IrOpcode::kWord32And) { + MachineType const rep = static_cast( + StoreRepresentationOf(node->op()).machine_type() & kRepMask); + Uint32BinopMatcher m(value); + if (m.right().HasValue() && + ((rep == kRepWord8 && (m.right().Value() & 0xff) == 0xff) || + (rep == kRepWord16 && (m.right().Value() & 0xffff) == 0xffff))) { + node->ReplaceInput(2, m.left().node()); + return Changed(node); + } + } + break; + } default: break; } diff --git a/src/compiler/machine-operator.cc b/src/compiler/machine-operator.cc index cf10b2f454..f53e4ba7ab 100644 --- a/src/compiler/machine-operator.cc +++ b/src/compiler/machine-operator.cc @@ -46,6 +46,12 @@ std::ostream& operator<<(std::ostream& os, StoreRepresentation rep) { } +StoreRepresentation const& StoreRepresentationOf(Operator const* op) { + DCHECK_EQ(IrOpcode::kStore, op->opcode()); + return OpParameter(op); +} + + #define PURE_OP_LIST(V) \ V(Word32And, Operator::kAssociative | Operator::kCommutative, 2, 1) \ V(Word32Or, Operator::kAssociative | Operator::kCommutative, 2, 1) \ diff --git a/src/compiler/machine-operator.h b/src/compiler/machine-operator.h index 9774f63cfe..58be985d32 100644 --- a/src/compiler/machine-operator.h +++ b/src/compiler/machine-operator.h @@ -49,6 +49,8 @@ size_t hash_value(StoreRepresentation); std::ostream& operator<<(std::ostream&, StoreRepresentation); +StoreRepresentation const& StoreRepresentationOf(Operator const*); + // Interface for building machine-level operators. These operators are // machine-level but machine-independent and thus define a language suitable diff --git a/test/unittests/compiler/change-lowering-unittest.cc b/test/unittests/compiler/change-lowering-unittest.cc index d217f77b2a..5a80b1114f 100644 --- a/test/unittests/compiler/change-lowering-unittest.cc +++ b/test/unittests/compiler/change-lowering-unittest.cc @@ -160,7 +160,8 @@ TARGET_TEST_P(ChangeLoweringCommonTest, ChangeFloat64ToTagged) { IsFinish( AllOf(CaptureEq(&heap_number), IsAllocateHeapNumber(IsValueEffect(val), graph()->start())), - IsStore(kMachFloat64, kNoWriteBarrier, CaptureEq(&heap_number), + IsStore(StoreRepresentation(kMachFloat64, kNoWriteBarrier), + CaptureEq(&heap_number), IsInt32Constant(HeapNumberValueOffset()), val, CaptureEq(&heap_number), graph()->start()))); } @@ -202,13 +203,13 @@ TARGET_TEST_F(ChangeLowering32Test, ChangeInt32ToTagged) { EXPECT_THAT( phi, IsPhi(kMachAnyTagged, - IsFinish( - AllOf(CaptureEq(&heap_number), - IsAllocateHeapNumber(_, CaptureEq(&if_true))), - IsStore(kMachFloat64, kNoWriteBarrier, CaptureEq(&heap_number), - IsInt32Constant(HeapNumberValueOffset()), - IsChangeInt32ToFloat64(val), CaptureEq(&heap_number), - CaptureEq(&if_true))), + IsFinish(AllOf(CaptureEq(&heap_number), + IsAllocateHeapNumber(_, CaptureEq(&if_true))), + IsStore(StoreRepresentation(kMachFloat64, kNoWriteBarrier), + CaptureEq(&heap_number), + IsInt32Constant(HeapNumberValueOffset()), + IsChangeInt32ToFloat64(val), + CaptureEq(&heap_number), CaptureEq(&if_true))), IsProjection( 0, AllOf(CaptureEq(&add), IsInt32AddWithOverflow(val, val))), IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))), @@ -308,13 +309,13 @@ TARGET_TEST_F(ChangeLowering32Test, ChangeUint32ToTagged) { phi, IsPhi( kMachAnyTagged, IsWord32Shl(val, IsInt32Constant(SmiShiftAmount())), - IsFinish( - AllOf(CaptureEq(&heap_number), - IsAllocateHeapNumber(_, CaptureEq(&if_false))), - IsStore(kMachFloat64, kNoWriteBarrier, CaptureEq(&heap_number), - IsInt32Constant(HeapNumberValueOffset()), - IsChangeUint32ToFloat64(val), CaptureEq(&heap_number), - CaptureEq(&if_false))), + IsFinish(AllOf(CaptureEq(&heap_number), + IsAllocateHeapNumber(_, CaptureEq(&if_false))), + IsStore(StoreRepresentation(kMachFloat64, kNoWriteBarrier), + CaptureEq(&heap_number), + IsInt32Constant(HeapNumberValueOffset()), + IsChangeUint32ToFloat64(val), + CaptureEq(&heap_number), CaptureEq(&if_false))), IsMerge( IsIfTrue(AllOf(CaptureEq(&branch), IsBranch(IsUint32LessThanOrEqual( @@ -442,13 +443,13 @@ TARGET_TEST_F(ChangeLowering64Test, ChangeUint32ToTagged) { IsPhi( kMachAnyTagged, IsWord64Shl(IsChangeUint32ToUint64(val), IsInt32Constant(SmiShiftAmount())), - IsFinish( - AllOf(CaptureEq(&heap_number), - IsAllocateHeapNumber(_, CaptureEq(&if_false))), - IsStore(kMachFloat64, kNoWriteBarrier, CaptureEq(&heap_number), - IsInt32Constant(HeapNumberValueOffset()), - IsChangeUint32ToFloat64(val), CaptureEq(&heap_number), - CaptureEq(&if_false))), + IsFinish(AllOf(CaptureEq(&heap_number), + IsAllocateHeapNumber(_, CaptureEq(&if_false))), + IsStore(StoreRepresentation(kMachFloat64, kNoWriteBarrier), + CaptureEq(&heap_number), + IsInt32Constant(HeapNumberValueOffset()), + IsChangeUint32ToFloat64(val), + CaptureEq(&heap_number), CaptureEq(&if_false))), IsMerge( IsIfTrue(AllOf(CaptureEq(&branch), IsBranch(IsUint32LessThanOrEqual( diff --git a/test/unittests/compiler/graph-unittest.cc b/test/unittests/compiler/graph-unittest.cc index 8d935f9086..7c6232e1f6 100644 --- a/test/unittests/compiler/graph-unittest.cc +++ b/test/unittests/compiler/graph-unittest.cc @@ -654,16 +654,14 @@ class IsLoadMatcher FINAL : public NodeMatcher { class IsStoreMatcher FINAL : public NodeMatcher { public: - IsStoreMatcher(const Matcher& type_matcher, - const Matcher write_barrier_matcher, + IsStoreMatcher(const Matcher& rep_matcher, const Matcher& base_matcher, const Matcher& index_matcher, const Matcher& value_matcher, const Matcher& effect_matcher, const Matcher& control_matcher) : NodeMatcher(IrOpcode::kStore), - type_matcher_(type_matcher), - write_barrier_matcher_(write_barrier_matcher), + rep_matcher_(rep_matcher), base_matcher_(base_matcher), index_matcher_(index_matcher), value_matcher_(value_matcher), @@ -672,10 +670,8 @@ class IsStoreMatcher FINAL : public NodeMatcher { virtual void DescribeTo(std::ostream* os) const OVERRIDE { NodeMatcher::DescribeTo(os); - *os << " whose type ("; - type_matcher_.DescribeTo(os); - *os << "), write barrier ("; - write_barrier_matcher_.DescribeTo(os); + *os << " whose rep ("; + rep_matcher_.DescribeTo(os); *os << "), base ("; base_matcher_.DescribeTo(os); *os << "), index ("; @@ -692,12 +688,8 @@ class IsStoreMatcher FINAL : public NodeMatcher { virtual bool MatchAndExplain(Node* node, MatchResultListener* listener) const OVERRIDE { return (NodeMatcher::MatchAndExplain(node, listener) && - PrintMatchAndExplain( - OpParameter(node).machine_type(), "type", - type_matcher_, listener) && - PrintMatchAndExplain( - OpParameter(node).write_barrier_kind(), - "write barrier", write_barrier_matcher_, listener) && + PrintMatchAndExplain(OpParameter(node), "rep", + rep_matcher_, listener) && PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "base", base_matcher_, listener) && PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1), @@ -711,8 +703,7 @@ class IsStoreMatcher FINAL : public NodeMatcher { } private: - const Matcher type_matcher_; - const Matcher write_barrier_matcher_; + const Matcher rep_matcher_; const Matcher base_matcher_; const Matcher index_matcher_; const Matcher value_matcher_; @@ -927,16 +918,15 @@ Matcher IsLoad(const Matcher& rep_matcher, } -Matcher IsStore(const Matcher& type_matcher, - const Matcher& write_barrier_matcher, +Matcher IsStore(const Matcher& rep_matcher, const Matcher& base_matcher, const Matcher& index_matcher, const Matcher& value_matcher, const Matcher& effect_matcher, const Matcher& control_matcher) { - return MakeMatcher(new IsStoreMatcher( - type_matcher, write_barrier_matcher, base_matcher, index_matcher, - value_matcher, effect_matcher, control_matcher)); + return MakeMatcher(new IsStoreMatcher(rep_matcher, base_matcher, + index_matcher, value_matcher, + effect_matcher, control_matcher)); } diff --git a/test/unittests/compiler/graph-unittest.h b/test/unittests/compiler/graph-unittest.h index 41a91f896b..bfed062c71 100644 --- a/test/unittests/compiler/graph-unittest.h +++ b/test/unittests/compiler/graph-unittest.h @@ -41,6 +41,9 @@ class GraphTest : public TestWithContext, public TestWithZone { Node* Float32Constant(volatile float value); Node* Float64Constant(volatile double value); Node* Int32Constant(int32_t value); + Node* Uint32Constant(uint32_t value) { + return Int32Constant(bit_cast(value)); + } Node* Int64Constant(int64_t value); Node* NumberConstant(volatile double value); Node* HeapConstant(const Handle& value); @@ -119,8 +122,7 @@ Matcher IsLoad(const Matcher& rep_matcher, const Matcher& index_matcher, const Matcher& effect_matcher, const Matcher& control_matcher); -Matcher IsStore(const Matcher& type_matcher, - const Matcher& write_barrier_matcher, +Matcher IsStore(const Matcher& rep_matcher, const Matcher& base_matcher, const Matcher& index_matcher, const Matcher& value_matcher, diff --git a/test/unittests/compiler/machine-operator-reducer-unittest.cc b/test/unittests/compiler/machine-operator-reducer-unittest.cc index 4d3df88eb7..3a5eb1af45 100644 --- a/test/unittests/compiler/machine-operator-reducer-unittest.cc +++ b/test/unittests/compiler/machine-operator-reducer-unittest.cc @@ -654,6 +654,54 @@ TEST_F(MachineOperatorReducerTest, Int32SubWithOverflowWithConstant) { } } + +// ----------------------------------------------------------------------------- +// Store + + +TEST_F(MachineOperatorReducerTest, StoreRepWord8WithWord32And) { + const StoreRepresentation rep(kRepWord8, kNoWriteBarrier); + Node* const base = Parameter(0); + Node* const index = Parameter(1); + Node* const value = Parameter(2); + Node* const effect = graph()->start(); + Node* const control = graph()->start(); + TRACED_FOREACH(uint32_t, x, kUint32Values) { + Node* const node = + graph()->NewNode(machine()->Store(rep), base, index, + graph()->NewNode(machine()->Word32And(), value, + Uint32Constant(x | 0xffu)), + effect, control); + + Reduction r = Reduce(node); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), + IsStore(rep, base, index, value, effect, control)); + } +} + + +TEST_F(MachineOperatorReducerTest, StoreRepWord16WithWord32And) { + const StoreRepresentation rep(kRepWord16, kNoWriteBarrier); + Node* const base = Parameter(0); + Node* const index = Parameter(1); + Node* const value = Parameter(2); + Node* const effect = graph()->start(); + Node* const control = graph()->start(); + TRACED_FOREACH(uint32_t, x, kUint32Values) { + Node* const node = + graph()->NewNode(machine()->Store(rep), base, index, + graph()->NewNode(machine()->Word32And(), value, + Uint32Constant(x | 0xffffu)), + effect, control); + + Reduction r = Reduce(node); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), + IsStore(rep, base, index, value, effect, control)); + } +} + } // namespace compiler } // namespace internal } // namespace v8