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/compiler/opcodes.h"
6 #include "src/compiler/operator.h"
7 #include "src/compiler/operator-properties.h"
8 #include "src/compiler/simplified-operator.h"
9 #include "src/types-inl.h"
10 #include "test/unittests/test-utils.h"
11
12 namespace v8 {
13 namespace internal {
14 namespace compiler {
15
16 // -----------------------------------------------------------------------------
17 // Pure operators.
18
19
20 namespace {
21
22 struct PureOperator {
23 const Operator* (SimplifiedOperatorBuilder::*constructor)();
24 IrOpcode::Value opcode;
25 Operator::Properties properties;
26 int value_input_count;
27 };
28
29
operator <<(std::ostream & os,const PureOperator & pop)30 std::ostream& operator<<(std::ostream& os, const PureOperator& pop) {
31 return os << IrOpcode::Mnemonic(pop.opcode);
32 }
33
34
35 const PureOperator kPureOperators[] = {
36 #define PURE(Name, properties, input_count) \
37 { \
38 &SimplifiedOperatorBuilder::Name, IrOpcode::k##Name, \
39 Operator::kPure | properties, input_count \
40 }
41 PURE(BooleanNot, Operator::kNoProperties, 1),
42 PURE(BooleanToNumber, Operator::kNoProperties, 1),
43 PURE(NumberEqual, Operator::kCommutative, 2),
44 PURE(NumberLessThan, Operator::kNoProperties, 2),
45 PURE(NumberLessThanOrEqual, Operator::kNoProperties, 2),
46 PURE(NumberAdd, Operator::kCommutative, 2),
47 PURE(NumberSubtract, Operator::kNoProperties, 2),
48 PURE(NumberMultiply, Operator::kCommutative, 2),
49 PURE(NumberDivide, Operator::kNoProperties, 2),
50 PURE(NumberModulus, Operator::kNoProperties, 2),
51 PURE(NumberBitwiseOr, Operator::kCommutative, 2),
52 PURE(NumberBitwiseXor, Operator::kCommutative, 2),
53 PURE(NumberBitwiseAnd, Operator::kCommutative, 2),
54 PURE(NumberShiftLeft, Operator::kNoProperties, 2),
55 PURE(NumberShiftRight, Operator::kNoProperties, 2),
56 PURE(NumberShiftRightLogical, Operator::kNoProperties, 2),
57 PURE(NumberToInt32, Operator::kNoProperties, 1),
58 PURE(NumberToUint32, Operator::kNoProperties, 1),
59 PURE(PlainPrimitiveToNumber, Operator::kNoProperties, 1),
60 PURE(ChangeTaggedToInt32, Operator::kNoProperties, 1),
61 PURE(ChangeTaggedToUint32, Operator::kNoProperties, 1),
62 PURE(ChangeTaggedToFloat64, Operator::kNoProperties, 1),
63 PURE(ChangeInt32ToTagged, Operator::kNoProperties, 1),
64 PURE(ChangeUint32ToTagged, Operator::kNoProperties, 1),
65 PURE(ChangeFloat64ToTagged, Operator::kNoProperties, 1),
66 PURE(ChangeBoolToBit, Operator::kNoProperties, 1),
67 PURE(ChangeBitToBool, Operator::kNoProperties, 1),
68 PURE(ObjectIsSmi, Operator::kNoProperties, 1)
69 #undef PURE
70 };
71
72 } // namespace
73
74
75 class SimplifiedPureOperatorTest
76 : public TestWithZone,
77 public ::testing::WithParamInterface<PureOperator> {};
78
79
TEST_P(SimplifiedPureOperatorTest,InstancesAreGloballyShared)80 TEST_P(SimplifiedPureOperatorTest, InstancesAreGloballyShared) {
81 const PureOperator& pop = GetParam();
82 SimplifiedOperatorBuilder simplified1(zone());
83 SimplifiedOperatorBuilder simplified2(zone());
84 EXPECT_EQ((simplified1.*pop.constructor)(), (simplified2.*pop.constructor)());
85 }
86
87
TEST_P(SimplifiedPureOperatorTest,NumberOfInputsAndOutputs)88 TEST_P(SimplifiedPureOperatorTest, NumberOfInputsAndOutputs) {
89 SimplifiedOperatorBuilder simplified(zone());
90 const PureOperator& pop = GetParam();
91 const Operator* op = (simplified.*pop.constructor)();
92
93 EXPECT_EQ(pop.value_input_count, op->ValueInputCount());
94 EXPECT_EQ(0, op->EffectInputCount());
95 EXPECT_EQ(0, op->ControlInputCount());
96 EXPECT_EQ(pop.value_input_count, OperatorProperties::GetTotalInputCount(op));
97
98 EXPECT_EQ(1, op->ValueOutputCount());
99 EXPECT_EQ(0, op->EffectOutputCount());
100 EXPECT_EQ(0, op->ControlOutputCount());
101 }
102
103
TEST_P(SimplifiedPureOperatorTest,OpcodeIsCorrect)104 TEST_P(SimplifiedPureOperatorTest, OpcodeIsCorrect) {
105 SimplifiedOperatorBuilder simplified(zone());
106 const PureOperator& pop = GetParam();
107 const Operator* op = (simplified.*pop.constructor)();
108 EXPECT_EQ(pop.opcode, op->opcode());
109 }
110
111
TEST_P(SimplifiedPureOperatorTest,Properties)112 TEST_P(SimplifiedPureOperatorTest, Properties) {
113 SimplifiedOperatorBuilder simplified(zone());
114 const PureOperator& pop = GetParam();
115 const Operator* op = (simplified.*pop.constructor)();
116 EXPECT_EQ(pop.properties, op->properties() & pop.properties);
117 }
118
119 INSTANTIATE_TEST_CASE_P(SimplifiedOperatorTest, SimplifiedPureOperatorTest,
120 ::testing::ValuesIn(kPureOperators));
121
122
123 // -----------------------------------------------------------------------------
124 // Buffer access operators.
125
126
127 namespace {
128
129 const ExternalArrayType kExternalArrayTypes[] = {
130 kExternalUint8Array, kExternalInt8Array, kExternalUint16Array,
131 kExternalInt16Array, kExternalUint32Array, kExternalInt32Array,
132 kExternalFloat32Array, kExternalFloat64Array};
133
134 } // namespace
135
136
137 class SimplifiedBufferAccessOperatorTest
138 : public TestWithZone,
139 public ::testing::WithParamInterface<ExternalArrayType> {};
140
141
TEST_P(SimplifiedBufferAccessOperatorTest,InstancesAreGloballyShared)142 TEST_P(SimplifiedBufferAccessOperatorTest, InstancesAreGloballyShared) {
143 BufferAccess const access(GetParam());
144 SimplifiedOperatorBuilder simplified1(zone());
145 SimplifiedOperatorBuilder simplified2(zone());
146 EXPECT_EQ(simplified1.LoadBuffer(access), simplified2.LoadBuffer(access));
147 EXPECT_EQ(simplified1.StoreBuffer(access), simplified2.StoreBuffer(access));
148 }
149
150
TEST_P(SimplifiedBufferAccessOperatorTest,LoadBuffer)151 TEST_P(SimplifiedBufferAccessOperatorTest, LoadBuffer) {
152 SimplifiedOperatorBuilder simplified(zone());
153 BufferAccess const access(GetParam());
154 const Operator* op = simplified.LoadBuffer(access);
155
156 EXPECT_EQ(IrOpcode::kLoadBuffer, op->opcode());
157 EXPECT_EQ(Operator::kNoThrow | Operator::kNoWrite, op->properties());
158 EXPECT_EQ(access, BufferAccessOf(op));
159
160 EXPECT_EQ(3, op->ValueInputCount());
161 EXPECT_EQ(1, op->EffectInputCount());
162 EXPECT_EQ(1, op->ControlInputCount());
163 EXPECT_EQ(5, OperatorProperties::GetTotalInputCount(op));
164
165 EXPECT_EQ(1, op->ValueOutputCount());
166 EXPECT_EQ(1, op->EffectOutputCount());
167 EXPECT_EQ(0, op->ControlOutputCount());
168 }
169
170
TEST_P(SimplifiedBufferAccessOperatorTest,StoreBuffer)171 TEST_P(SimplifiedBufferAccessOperatorTest, StoreBuffer) {
172 SimplifiedOperatorBuilder simplified(zone());
173 BufferAccess const access(GetParam());
174 const Operator* op = simplified.StoreBuffer(access);
175
176 EXPECT_EQ(IrOpcode::kStoreBuffer, op->opcode());
177 EXPECT_EQ(Operator::kNoRead | Operator::kNoThrow, op->properties());
178 EXPECT_EQ(access, BufferAccessOf(op));
179
180 EXPECT_EQ(4, op->ValueInputCount());
181 EXPECT_EQ(1, op->EffectInputCount());
182 EXPECT_EQ(1, op->ControlInputCount());
183 EXPECT_EQ(6, OperatorProperties::GetTotalInputCount(op));
184
185 EXPECT_EQ(0, op->ValueOutputCount());
186 EXPECT_EQ(1, op->EffectOutputCount());
187 EXPECT_EQ(0, op->ControlOutputCount());
188 }
189
190
191 INSTANTIATE_TEST_CASE_P(SimplifiedOperatorTest,
192 SimplifiedBufferAccessOperatorTest,
193 ::testing::ValuesIn(kExternalArrayTypes));
194
195
196 // -----------------------------------------------------------------------------
197 // Element access operators.
198
199
200 namespace {
201
202 const ElementAccess kElementAccesses[] = {
203 {kTaggedBase, FixedArray::kHeaderSize, Type::Any(),
204 MachineType::AnyTagged()},
205 {kUntaggedBase, 0, Type::Any(), MachineType::Int8()},
206 {kUntaggedBase, 0, Type::Any(), MachineType::Int16()},
207 {kUntaggedBase, 0, Type::Any(), MachineType::Int32()},
208 {kUntaggedBase, 0, Type::Any(), MachineType::Uint8()},
209 {kUntaggedBase, 0, Type::Any(), MachineType::Uint16()},
210 {kUntaggedBase, 0, Type::Any(), MachineType::Uint32()},
211 {kUntaggedBase, 0, Type::Signed32(), MachineType::Int8()},
212 {kUntaggedBase, 0, Type::Unsigned32(), MachineType::Uint8()},
213 {kUntaggedBase, 0, Type::Signed32(), MachineType::Int16()},
214 {kUntaggedBase, 0, Type::Unsigned32(), MachineType::Uint16()},
215 {kUntaggedBase, 0, Type::Signed32(), MachineType::Int32()},
216 {kUntaggedBase, 0, Type::Unsigned32(), MachineType::Uint32()},
217 {kUntaggedBase, 0, Type::Number(),
218 MachineType(MachineRepresentation::kFloat32, MachineSemantic::kNone)},
219 {kUntaggedBase, 0, Type::Number(),
220 MachineType(MachineRepresentation::kFloat64, MachineSemantic::kNone)},
221 {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Signed32(),
222 MachineType::Int8()},
223 {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Unsigned32(),
224 MachineType::Uint8()},
225 {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Signed32(),
226 MachineType::Int16()},
227 {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Unsigned32(),
228 MachineType::Uint16()},
229 {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Signed32(),
230 MachineType::Int32()},
231 {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Unsigned32(),
232 MachineType::Uint32()},
233 {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Number(),
234 MachineType(MachineRepresentation::kFloat32, MachineSemantic::kNone)},
235 {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Number(),
236 MachineType(MachineRepresentation::kFloat32, MachineSemantic::kNone)}};
237
238 } // namespace
239
240
241 class SimplifiedElementAccessOperatorTest
242 : public TestWithZone,
243 public ::testing::WithParamInterface<ElementAccess> {};
244
245
TEST_P(SimplifiedElementAccessOperatorTest,LoadElement)246 TEST_P(SimplifiedElementAccessOperatorTest, LoadElement) {
247 SimplifiedOperatorBuilder simplified(zone());
248 const ElementAccess& access = GetParam();
249 const Operator* op = simplified.LoadElement(access);
250
251 EXPECT_EQ(IrOpcode::kLoadElement, op->opcode());
252 EXPECT_EQ(Operator::kNoThrow | Operator::kNoWrite, op->properties());
253 EXPECT_EQ(access, ElementAccessOf(op));
254
255 EXPECT_EQ(2, op->ValueInputCount());
256 EXPECT_EQ(1, op->EffectInputCount());
257 EXPECT_EQ(1, op->ControlInputCount());
258 EXPECT_EQ(4, OperatorProperties::GetTotalInputCount(op));
259
260 EXPECT_EQ(1, op->ValueOutputCount());
261 EXPECT_EQ(1, op->EffectOutputCount());
262 EXPECT_EQ(0, op->ControlOutputCount());
263 }
264
265
TEST_P(SimplifiedElementAccessOperatorTest,StoreElement)266 TEST_P(SimplifiedElementAccessOperatorTest, StoreElement) {
267 SimplifiedOperatorBuilder simplified(zone());
268 const ElementAccess& access = GetParam();
269 const Operator* op = simplified.StoreElement(access);
270
271 EXPECT_EQ(IrOpcode::kStoreElement, op->opcode());
272 EXPECT_EQ(Operator::kNoRead | Operator::kNoThrow, op->properties());
273 EXPECT_EQ(access, ElementAccessOf(op));
274
275 EXPECT_EQ(3, op->ValueInputCount());
276 EXPECT_EQ(1, op->EffectInputCount());
277 EXPECT_EQ(1, op->ControlInputCount());
278 EXPECT_EQ(5, OperatorProperties::GetTotalInputCount(op));
279
280 EXPECT_EQ(0, op->ValueOutputCount());
281 EXPECT_EQ(1, op->EffectOutputCount());
282 EXPECT_EQ(0, op->ControlOutputCount());
283 }
284
285
286 INSTANTIATE_TEST_CASE_P(SimplifiedOperatorTest,
287 SimplifiedElementAccessOperatorTest,
288 ::testing::ValuesIn(kElementAccesses));
289
290 } // namespace compiler
291 } // namespace internal
292 } // namespace v8
293