| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 the V8 project authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "src/code-stubs.h" | |
| 6 #include "src/compiler/change-lowering.h" | |
| 7 #include "src/compiler/js-graph.h" | |
| 8 #include "src/compiler/linkage.h" | |
| 9 #include "src/compiler/node-properties.h" | |
| 10 #include "src/compiler/simplified-operator.h" | |
| 11 #include "test/unittests/compiler/compiler-test-utils.h" | |
| 12 #include "test/unittests/compiler/graph-unittest.h" | |
| 13 #include "test/unittests/compiler/node-test-utils.h" | |
| 14 #include "testing/gmock-support.h" | |
| 15 | |
| 16 using testing::_; | |
| 17 using testing::AllOf; | |
| 18 using testing::BitEq; | |
| 19 using testing::Capture; | |
| 20 using testing::CaptureEq; | |
| 21 | |
| 22 namespace v8 { | |
| 23 namespace internal { | |
| 24 namespace compiler { | |
| 25 | |
| 26 class ChangeLoweringTest : public TypedGraphTest { | |
| 27 public: | |
| 28 ChangeLoweringTest() : simplified_(zone()) {} | |
| 29 | |
| 30 virtual MachineRepresentation WordRepresentation() const = 0; | |
| 31 | |
| 32 protected: | |
| 33 bool Is32() const { | |
| 34 return WordRepresentation() == MachineRepresentation::kWord32; | |
| 35 } | |
| 36 bool Is64() const { | |
| 37 return WordRepresentation() == MachineRepresentation::kWord64; | |
| 38 } | |
| 39 | |
| 40 Reduction Reduce(Node* node) { | |
| 41 GraphReducer graph_reducer(zone(), graph()); | |
| 42 MachineOperatorBuilder machine(zone(), WordRepresentation()); | |
| 43 JSOperatorBuilder javascript(zone()); | |
| 44 JSGraph jsgraph(isolate(), graph(), common(), &javascript, nullptr, | |
| 45 &machine); | |
| 46 ChangeLowering reducer(&graph_reducer, &jsgraph); | |
| 47 return reducer.Reduce(node); | |
| 48 } | |
| 49 | |
| 50 SimplifiedOperatorBuilder* simplified() { return &simplified_; } | |
| 51 | |
| 52 Matcher<Node*> IsAllocateHeapNumber(const Matcher<Node*>& effect_matcher, | |
| 53 const Matcher<Node*>& control_matcher) { | |
| 54 return IsCall( | |
| 55 _, IsHeapConstant(AllocateHeapNumberStub(isolate()).GetCode()), | |
| 56 IsNumberConstant(BitEq(0.0)), effect_matcher, control_matcher); | |
| 57 } | |
| 58 Matcher<Node*> IsChangeInt32ToSmi(const Matcher<Node*>& value_matcher) { | |
| 59 return Is64() ? IsWord64Shl(IsChangeInt32ToInt64(value_matcher), | |
| 60 IsSmiShiftBitsConstant()) | |
| 61 : IsWord32Shl(value_matcher, IsSmiShiftBitsConstant()); | |
| 62 } | |
| 63 Matcher<Node*> IsChangeSmiToInt32(const Matcher<Node*>& value_matcher) { | |
| 64 return Is64() ? IsTruncateInt64ToInt32( | |
| 65 IsWord64Sar(value_matcher, IsSmiShiftBitsConstant())) | |
| 66 : IsWord32Sar(value_matcher, IsSmiShiftBitsConstant()); | |
| 67 } | |
| 68 Matcher<Node*> IsChangeUint32ToSmi(const Matcher<Node*>& value_matcher) { | |
| 69 return Is64() ? IsWord64Shl(IsChangeUint32ToUint64(value_matcher), | |
| 70 IsSmiShiftBitsConstant()) | |
| 71 : IsWord32Shl(value_matcher, IsSmiShiftBitsConstant()); | |
| 72 } | |
| 73 Matcher<Node*> IsLoadHeapNumber(const Matcher<Node*>& value_matcher, | |
| 74 const Matcher<Node*>& control_matcher) { | |
| 75 return IsLoad(MachineType::Float64(), value_matcher, | |
| 76 IsIntPtrConstant(HeapNumber::kValueOffset - kHeapObjectTag), | |
| 77 graph()->start(), control_matcher); | |
| 78 } | |
| 79 Matcher<Node*> IsIntPtrConstant(int value) { | |
| 80 return Is32() ? IsInt32Constant(value) : IsInt64Constant(value); | |
| 81 } | |
| 82 Matcher<Node*> IsSmiShiftBitsConstant() { | |
| 83 return IsIntPtrConstant(kSmiShiftSize + kSmiTagSize); | |
| 84 } | |
| 85 Matcher<Node*> IsWordEqual(const Matcher<Node*>& lhs_matcher, | |
| 86 const Matcher<Node*>& rhs_matcher) { | |
| 87 return Is32() ? IsWord32Equal(lhs_matcher, rhs_matcher) | |
| 88 : IsWord64Equal(lhs_matcher, rhs_matcher); | |
| 89 } | |
| 90 | |
| 91 private: | |
| 92 SimplifiedOperatorBuilder simplified_; | |
| 93 }; | |
| 94 | |
| 95 | |
| 96 // ----------------------------------------------------------------------------- | |
| 97 // Common. | |
| 98 | |
| 99 | |
| 100 class ChangeLoweringCommonTest | |
| 101 : public ChangeLoweringTest, | |
| 102 public ::testing::WithParamInterface<MachineRepresentation> { | |
| 103 public: | |
| 104 ~ChangeLoweringCommonTest() override {} | |
| 105 | |
| 106 MachineRepresentation WordRepresentation() const final { return GetParam(); } | |
| 107 }; | |
| 108 | |
| 109 TARGET_TEST_P(ChangeLoweringCommonTest, StoreFieldSmi) { | |
| 110 FieldAccess access = { | |
| 111 kTaggedBase, FixedArrayBase::kHeaderSize, Handle<Name>::null(), | |
| 112 Type::Any(), MachineType::AnyTagged(), kNoWriteBarrier}; | |
| 113 Node* p0 = Parameter(Type::TaggedPointer()); | |
| 114 Node* p1 = Parameter(Type::TaggedSigned()); | |
| 115 Node* store = graph()->NewNode(simplified()->StoreField(access), p0, p1, | |
| 116 graph()->start(), graph()->start()); | |
| 117 Reduction r = Reduce(store); | |
| 118 | |
| 119 ASSERT_TRUE(r.Changed()); | |
| 120 EXPECT_THAT(r.replacement(), | |
| 121 IsStore(StoreRepresentation(MachineRepresentation::kTagged, | |
| 122 kNoWriteBarrier), | |
| 123 p0, IsIntPtrConstant(access.offset - access.tag()), p1, | |
| 124 graph()->start(), graph()->start())); | |
| 125 } | |
| 126 | |
| 127 | |
| 128 TARGET_TEST_P(ChangeLoweringCommonTest, StoreFieldTagged) { | |
| 129 FieldAccess access = { | |
| 130 kTaggedBase, FixedArrayBase::kHeaderSize, Handle<Name>::null(), | |
| 131 Type::Any(), MachineType::AnyTagged(), kFullWriteBarrier}; | |
| 132 Node* p0 = Parameter(Type::TaggedPointer()); | |
| 133 Node* p1 = Parameter(Type::Tagged()); | |
| 134 Node* store = graph()->NewNode(simplified()->StoreField(access), p0, p1, | |
| 135 graph()->start(), graph()->start()); | |
| 136 Reduction r = Reduce(store); | |
| 137 | |
| 138 ASSERT_TRUE(r.Changed()); | |
| 139 EXPECT_THAT(r.replacement(), | |
| 140 IsStore(StoreRepresentation(MachineRepresentation::kTagged, | |
| 141 kFullWriteBarrier), | |
| 142 p0, IsIntPtrConstant(access.offset - access.tag()), p1, | |
| 143 graph()->start(), graph()->start())); | |
| 144 } | |
| 145 | |
| 146 | |
| 147 TARGET_TEST_P(ChangeLoweringCommonTest, LoadField) { | |
| 148 FieldAccess access = { | |
| 149 kTaggedBase, FixedArrayBase::kHeaderSize, Handle<Name>::null(), | |
| 150 Type::Any(), MachineType::AnyTagged(), kNoWriteBarrier}; | |
| 151 Node* p0 = Parameter(Type::TaggedPointer()); | |
| 152 Node* load = graph()->NewNode(simplified()->LoadField(access), p0, | |
| 153 graph()->start(), graph()->start()); | |
| 154 Reduction r = Reduce(load); | |
| 155 | |
| 156 ASSERT_TRUE(r.Changed()); | |
| 157 Matcher<Node*> index_match = IsIntPtrConstant(access.offset - access.tag()); | |
| 158 EXPECT_THAT(r.replacement(), | |
| 159 IsLoad(MachineType::AnyTagged(), p0, | |
| 160 IsIntPtrConstant(access.offset - access.tag()), | |
| 161 graph()->start(), graph()->start())); | |
| 162 } | |
| 163 | |
| 164 | |
| 165 TARGET_TEST_P(ChangeLoweringCommonTest, StoreElementTagged) { | |
| 166 ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(), | |
| 167 MachineType::AnyTagged(), kFullWriteBarrier}; | |
| 168 Node* p0 = Parameter(Type::TaggedPointer()); | |
| 169 Node* p1 = Parameter(Type::Signed32()); | |
| 170 Node* p2 = Parameter(Type::Tagged()); | |
| 171 Node* store = graph()->NewNode(simplified()->StoreElement(access), p0, p1, p2, | |
| 172 graph()->start(), graph()->start()); | |
| 173 Reduction r = Reduce(store); | |
| 174 | |
| 175 const int element_size_shift = | |
| 176 ElementSizeLog2Of(access.machine_type.representation()); | |
| 177 ASSERT_TRUE(r.Changed()); | |
| 178 Matcher<Node*> index_match = | |
| 179 IsInt32Add(IsWord32Shl(p1, IsInt32Constant(element_size_shift)), | |
| 180 IsInt32Constant(access.header_size - access.tag())); | |
| 181 if (!Is32()) { | |
| 182 index_match = IsChangeUint32ToUint64(index_match); | |
| 183 } | |
| 184 | |
| 185 EXPECT_THAT(r.replacement(), | |
| 186 IsStore(StoreRepresentation(MachineRepresentation::kTagged, | |
| 187 kFullWriteBarrier), | |
| 188 p0, index_match, p2, graph()->start(), graph()->start())); | |
| 189 } | |
| 190 | |
| 191 | |
| 192 TARGET_TEST_P(ChangeLoweringCommonTest, StoreElementUint8) { | |
| 193 ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, | |
| 194 Type::Signed32(), MachineType::Uint8(), | |
| 195 kNoWriteBarrier}; | |
| 196 Node* p0 = Parameter(Type::TaggedPointer()); | |
| 197 Node* p1 = Parameter(Type::Signed32()); | |
| 198 Node* p2 = Parameter(Type::Signed32()); | |
| 199 Node* store = graph()->NewNode(simplified()->StoreElement(access), p0, p1, p2, | |
| 200 graph()->start(), graph()->start()); | |
| 201 Reduction r = Reduce(store); | |
| 202 | |
| 203 ASSERT_TRUE(r.Changed()); | |
| 204 Matcher<Node*> index_match = | |
| 205 IsInt32Add(p1, IsInt32Constant(access.header_size - access.tag())); | |
| 206 if (!Is32()) { | |
| 207 index_match = IsChangeUint32ToUint64(index_match); | |
| 208 } | |
| 209 | |
| 210 EXPECT_THAT(r.replacement(), | |
| 211 IsStore(StoreRepresentation(MachineRepresentation::kWord8, | |
| 212 kNoWriteBarrier), | |
| 213 p0, index_match, p2, graph()->start(), graph()->start())); | |
| 214 } | |
| 215 | |
| 216 | |
| 217 TARGET_TEST_P(ChangeLoweringCommonTest, LoadElementTagged) { | |
| 218 ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(), | |
| 219 MachineType::AnyTagged(), kNoWriteBarrier}; | |
| 220 Node* p0 = Parameter(Type::TaggedPointer()); | |
| 221 Node* p1 = Parameter(Type::Signed32()); | |
| 222 Node* load = graph()->NewNode(simplified()->LoadElement(access), p0, p1, | |
| 223 graph()->start(), graph()->start()); | |
| 224 Reduction r = Reduce(load); | |
| 225 | |
| 226 const int element_size_shift = | |
| 227 ElementSizeLog2Of(access.machine_type.representation()); | |
| 228 ASSERT_TRUE(r.Changed()); | |
| 229 Matcher<Node*> index_match = | |
| 230 IsInt32Add(IsWord32Shl(p1, IsInt32Constant(element_size_shift)), | |
| 231 IsInt32Constant(access.header_size - access.tag())); | |
| 232 if (!Is32()) { | |
| 233 index_match = IsChangeUint32ToUint64(index_match); | |
| 234 } | |
| 235 | |
| 236 EXPECT_THAT(r.replacement(), IsLoad(MachineType::AnyTagged(), p0, index_match, | |
| 237 graph()->start(), graph()->start())); | |
| 238 } | |
| 239 | |
| 240 | |
| 241 TARGET_TEST_P(ChangeLoweringCommonTest, LoadElementInt8) { | |
| 242 ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, | |
| 243 Type::Signed32(), MachineType::Int8(), | |
| 244 kNoWriteBarrier}; | |
| 245 Node* p0 = Parameter(Type::TaggedPointer()); | |
| 246 Node* p1 = Parameter(Type::Signed32()); | |
| 247 Node* load = graph()->NewNode(simplified()->LoadElement(access), p0, p1, | |
| 248 graph()->start(), graph()->start()); | |
| 249 Reduction r = Reduce(load); | |
| 250 | |
| 251 ASSERT_TRUE(r.Changed()); | |
| 252 Matcher<Node*> index_match = | |
| 253 IsInt32Add(p1, IsInt32Constant(access.header_size - access.tag())); | |
| 254 if (!Is32()) { | |
| 255 index_match = IsChangeUint32ToUint64(index_match); | |
| 256 } | |
| 257 | |
| 258 EXPECT_THAT(r.replacement(), IsLoad(MachineType::Int8(), p0, index_match, | |
| 259 graph()->start(), graph()->start())); | |
| 260 } | |
| 261 | |
| 262 | |
| 263 TARGET_TEST_P(ChangeLoweringCommonTest, Allocate) { | |
| 264 Node* p0 = Parameter(Type::Signed32()); | |
| 265 Node* alloc = graph()->NewNode(simplified()->Allocate(TENURED), p0, | |
| 266 graph()->start(), graph()->start()); | |
| 267 Reduction r = Reduce(alloc); | |
| 268 | |
| 269 // Only check that we lowered, but do not specify the exact form since | |
| 270 // this is subject to change. | |
| 271 ASSERT_TRUE(r.Changed()); | |
| 272 } | |
| 273 | |
| 274 } // namespace compiler | |
| 275 } // namespace internal | |
| 276 } // namespace v8 | |
| OLD | NEW |