Line data Source code
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/machine-operator.h"
6 : #include "src/compiler/opcodes.h"
7 : #include "src/compiler/operator.h"
8 : #include "src/compiler/operator-properties.h"
9 : #include "test/unittests/test-utils.h"
10 :
11 : namespace v8 {
12 : namespace internal {
13 : namespace compiler {
14 : namespace machine_operator_unittest {
15 :
16 : #if GTEST_HAS_COMBINE
17 :
18 : template <typename T>
19 800 : class MachineOperatorTestWithParam
20 : : public TestWithZone,
21 : public ::testing::WithParamInterface<
22 : ::testing::tuple<MachineRepresentation, T> > {
23 : protected:
24 : MachineRepresentation representation() const {
25 250 : return ::testing::get<0>(B::GetParam());
26 : }
27 468 : const T& GetParam() const { return ::testing::get<1>(B::GetParam()); }
28 :
29 : private:
30 : typedef ::testing::WithParamInterface<
31 : ::testing::tuple<MachineRepresentation, T> > B;
32 : };
33 :
34 :
35 : const MachineRepresentation kMachineReps[] = {MachineRepresentation::kWord32,
36 : MachineRepresentation::kWord64};
37 :
38 :
39 : const MachineType kMachineTypesForAccess[] = {
40 : MachineType::Float32(), MachineType::Float64(), MachineType::Int8(),
41 : MachineType::Uint8(), MachineType::Int16(), MachineType::Uint16(),
42 : MachineType::Int32(), MachineType::Uint32(), MachineType::Int64(),
43 : MachineType::Uint64(), MachineType::AnyTagged()};
44 :
45 :
46 : const MachineRepresentation kRepresentationsForStore[] = {
47 : MachineRepresentation::kFloat32, MachineRepresentation::kFloat64,
48 : MachineRepresentation::kWord8, MachineRepresentation::kWord16,
49 : MachineRepresentation::kWord32, MachineRepresentation::kWord64,
50 : MachineRepresentation::kTagged};
51 :
52 :
53 : // -----------------------------------------------------------------------------
54 : // Load operator.
55 :
56 :
57 : typedef MachineOperatorTestWithParam<LoadRepresentation>
58 : MachineLoadOperatorTest;
59 :
60 :
61 15874 : TEST_P(MachineLoadOperatorTest, InstancesAreGloballyShared) {
62 22 : MachineOperatorBuilder machine1(zone(), representation());
63 22 : MachineOperatorBuilder machine2(zone(), representation());
64 66 : EXPECT_EQ(machine1.Load(GetParam()), machine2.Load(GetParam()));
65 22 : }
66 :
67 :
68 15874 : TEST_P(MachineLoadOperatorTest, NumberOfInputsAndOutputs) {
69 22 : MachineOperatorBuilder machine(zone(), representation());
70 132 : const Operator* op = machine.Load(GetParam());
71 :
72 44 : EXPECT_EQ(2, op->ValueInputCount());
73 44 : EXPECT_EQ(1, op->EffectInputCount());
74 44 : EXPECT_EQ(1, op->ControlInputCount());
75 44 : EXPECT_EQ(4, OperatorProperties::GetTotalInputCount(op));
76 :
77 44 : EXPECT_EQ(1, op->ValueOutputCount());
78 44 : EXPECT_EQ(1, op->EffectOutputCount());
79 44 : EXPECT_EQ(0, op->ControlOutputCount());
80 22 : }
81 :
82 :
83 15874 : TEST_P(MachineLoadOperatorTest, OpcodeIsCorrect) {
84 22 : MachineOperatorBuilder machine(zone(), representation());
85 44 : EXPECT_EQ(IrOpcode::kLoad, machine.Load(GetParam())->opcode());
86 22 : }
87 :
88 :
89 15874 : TEST_P(MachineLoadOperatorTest, ParameterIsCorrect) {
90 22 : MachineOperatorBuilder machine(zone(), representation());
91 66 : EXPECT_EQ(GetParam(),
92 0 : OpParameter<LoadRepresentation>(machine.Load(GetParam())));
93 22 : }
94 :
95 :
96 297303 : INSTANTIATE_TEST_CASE_P(
97 : MachineOperatorTest, MachineLoadOperatorTest,
98 : ::testing::Combine(::testing::ValuesIn(kMachineReps),
99 : ::testing::ValuesIn(kMachineTypesForAccess)));
100 :
101 :
102 : // -----------------------------------------------------------------------------
103 : // Store operator.
104 :
105 :
106 224 : class MachineStoreOperatorTest
107 : : public MachineOperatorTestWithParam<
108 : ::testing::tuple<MachineRepresentation, WriteBarrierKind> > {
109 : protected:
110 168 : StoreRepresentation GetParam() const {
111 : return StoreRepresentation(
112 : ::testing::get<0>(
113 : MachineOperatorTestWithParam< ::testing::tuple<
114 : MachineRepresentation, WriteBarrierKind> >::GetParam()),
115 : ::testing::get<1>(
116 : MachineOperatorTestWithParam< ::testing::tuple<
117 336 : MachineRepresentation, WriteBarrierKind> >::GetParam()));
118 : }
119 : };
120 :
121 :
122 15898 : TEST_P(MachineStoreOperatorTest, InstancesAreGloballyShared) {
123 28 : MachineOperatorBuilder machine1(zone(), representation());
124 28 : MachineOperatorBuilder machine2(zone(), representation());
125 56 : EXPECT_EQ(machine1.Store(GetParam()), machine2.Store(GetParam()));
126 28 : }
127 :
128 :
129 15898 : TEST_P(MachineStoreOperatorTest, NumberOfInputsAndOutputs) {
130 28 : MachineOperatorBuilder machine(zone(), representation());
131 168 : const Operator* op = machine.Store(GetParam());
132 :
133 56 : EXPECT_EQ(3, op->ValueInputCount());
134 56 : EXPECT_EQ(1, op->EffectInputCount());
135 56 : EXPECT_EQ(1, op->ControlInputCount());
136 56 : EXPECT_EQ(5, OperatorProperties::GetTotalInputCount(op));
137 :
138 56 : EXPECT_EQ(0, op->ValueOutputCount());
139 56 : EXPECT_EQ(1, op->EffectOutputCount());
140 56 : EXPECT_EQ(0, op->ControlOutputCount());
141 28 : }
142 :
143 :
144 15898 : TEST_P(MachineStoreOperatorTest, OpcodeIsCorrect) {
145 28 : MachineOperatorBuilder machine(zone(), representation());
146 56 : EXPECT_EQ(IrOpcode::kStore, machine.Store(GetParam())->opcode());
147 28 : }
148 :
149 :
150 15898 : TEST_P(MachineStoreOperatorTest, ParameterIsCorrect) {
151 28 : MachineOperatorBuilder machine(zone(), representation());
152 56 : EXPECT_EQ(GetParam(),
153 0 : OpParameter<StoreRepresentation>(machine.Store(GetParam())));
154 28 : }
155 :
156 :
157 370971 : INSTANTIATE_TEST_CASE_P(
158 : MachineOperatorTest, MachineStoreOperatorTest,
159 : ::testing::Combine(
160 : ::testing::ValuesIn(kMachineReps),
161 : ::testing::Combine(::testing::ValuesIn(kRepresentationsForStore),
162 : ::testing::Values(kNoWriteBarrier,
163 : kFullWriteBarrier))));
164 : #endif
165 :
166 : // -----------------------------------------------------------------------------
167 : // Pure operators.
168 :
169 : struct PureOperator {
170 : const Operator* (MachineOperatorBuilder::*constructor)();
171 : char const* const constructor_name;
172 : int value_input_count;
173 : int control_input_count;
174 : int value_output_count;
175 : };
176 :
177 :
178 0 : std::ostream& operator<<(std::ostream& os, PureOperator const& pop) {
179 304 : return os << pop.constructor_name;
180 : }
181 :
182 : const PureOperator kPureOperators[] = {
183 : #define PURE(Name, value_input_count, control_input_count, value_output_count) \
184 : { \
185 : &MachineOperatorBuilder::Name, #Name, value_input_count, \
186 : control_input_count, value_output_count \
187 : }
188 : PURE(Word32And, 2, 0, 1), // --
189 : PURE(Word32Or, 2, 0, 1), // --
190 : PURE(Word32Xor, 2, 0, 1), // --
191 : PURE(Word32Shl, 2, 0, 1), // --
192 : PURE(Word32Shr, 2, 0, 1), // --
193 : PURE(Word32Sar, 2, 0, 1), // --
194 : PURE(Word32Ror, 2, 0, 1), // --
195 : PURE(Word32Equal, 2, 0, 1), // --
196 : PURE(Word32Clz, 1, 0, 1), // --
197 : PURE(Word64And, 2, 0, 1), // --
198 : PURE(Word64Or, 2, 0, 1), // --
199 : PURE(Word64Xor, 2, 0, 1), // --
200 : PURE(Word64Shl, 2, 0, 1), // --
201 : PURE(Word64Shr, 2, 0, 1), // --
202 : PURE(Word64Sar, 2, 0, 1), // --
203 : PURE(Word64Ror, 2, 0, 1), // --
204 : PURE(Word64Equal, 2, 0, 1), // --
205 : PURE(Int32Add, 2, 0, 1), // --
206 : PURE(Int32Sub, 2, 0, 1), // --
207 : PURE(Int32Mul, 2, 0, 1), // --
208 : PURE(Int32MulHigh, 2, 0, 1), // --
209 : PURE(Int32Div, 2, 1, 1), // --
210 : PURE(Uint32Div, 2, 1, 1), // --
211 : PURE(Int32Mod, 2, 1, 1), // --
212 : PURE(Uint32Mod, 2, 1, 1), // --
213 : PURE(Int32LessThan, 2, 0, 1), // --
214 : PURE(Int32LessThanOrEqual, 2, 0, 1), // --
215 : PURE(Uint32LessThan, 2, 0, 1), // --
216 : PURE(Uint32LessThanOrEqual, 2, 0, 1), // --
217 : PURE(Int64Add, 2, 0, 1), // --
218 : PURE(Int64Sub, 2, 0, 1), // --
219 : PURE(Int64Mul, 2, 0, 1), // --
220 : PURE(Int64Div, 2, 1, 1), // --
221 : PURE(Uint64Div, 2, 1, 1), // --
222 : PURE(Int64Mod, 2, 1, 1), // --
223 : PURE(Uint64Mod, 2, 1, 1), // --
224 : PURE(Int64LessThan, 2, 0, 1), // --
225 : PURE(Int64LessThanOrEqual, 2, 0, 1), // --
226 : PURE(Uint64LessThan, 2, 0, 1), // --
227 : PURE(Uint64LessThanOrEqual, 2, 0, 1), // --
228 : PURE(ChangeFloat32ToFloat64, 1, 0, 1), // --
229 : PURE(ChangeFloat64ToInt32, 1, 0, 1), // --
230 : PURE(ChangeFloat64ToUint32, 1, 0, 1), // --
231 : PURE(ChangeInt32ToInt64, 1, 0, 1), // --
232 : PURE(ChangeUint32ToFloat64, 1, 0, 1), // --
233 : PURE(ChangeUint32ToUint64, 1, 0, 1), // --
234 : PURE(TruncateFloat64ToFloat32, 1, 0, 1), // --
235 : PURE(TruncateInt64ToInt32, 1, 0, 1), // --
236 : PURE(Float32Abs, 1, 0, 1), // --
237 : PURE(Float32Add, 2, 0, 1), // --
238 : PURE(Float32Sub, 2, 0, 1), // --
239 : PURE(Float32Mul, 2, 0, 1), // --
240 : PURE(Float32Div, 2, 0, 1), // --
241 : PURE(Float32Sqrt, 1, 0, 1), // --
242 : PURE(Float32Equal, 2, 0, 1), // --
243 : PURE(Float32LessThan, 2, 0, 1), // --
244 : PURE(Float32LessThanOrEqual, 2, 0, 1), // --
245 : PURE(Float32Neg, 1, 0, 1), // --
246 : PURE(Float64Abs, 1, 0, 1), // --
247 : PURE(Float64Add, 2, 0, 1), // --
248 : PURE(Float64Sub, 2, 0, 1), // --
249 : PURE(Float64Mul, 2, 0, 1), // --
250 : PURE(Float64Div, 2, 0, 1), // --
251 : PURE(Float64Mod, 2, 0, 1), // --
252 : PURE(Float64Sqrt, 1, 0, 1), // --
253 : PURE(Float64Max, 2, 0, 1), // --
254 : PURE(Float64Min, 2, 0, 1), // --
255 : PURE(Float64Equal, 2, 0, 1), // --
256 : PURE(Float64LessThan, 2, 0, 1), // --
257 : PURE(Float64LessThanOrEqual, 2, 0, 1), // --
258 : PURE(LoadStackPointer, 0, 0, 1), // --
259 : PURE(Float64ExtractLowWord32, 1, 0, 1), // --
260 : PURE(Float64ExtractHighWord32, 1, 0, 1), // --
261 : PURE(Float64InsertLowWord32, 2, 0, 1), // --
262 : PURE(Float64InsertHighWord32, 2, 0, 1), // --
263 : PURE(Float64Neg, 1, 0, 1), // --
264 : #undef PURE
265 : };
266 :
267 :
268 2 : class MachinePureOperatorTest : public TestWithZone {
269 : protected:
270 : MachineRepresentation word_type() {
271 : return MachineType::PointerRepresentation();
272 : }
273 : };
274 :
275 :
276 13159 : TEST_F(MachinePureOperatorTest, PureOperators) {
277 17 : TRACED_FOREACH(MachineRepresentation, machine_rep1, kMachineReps) {
278 2 : MachineOperatorBuilder machine1(zone(), machine_rep1);
279 34 : TRACED_FOREACH(MachineRepresentation, machine_rep2, kMachineReps) {
280 4 : MachineOperatorBuilder machine2(zone(), machine_rep2);
281 2740 : TRACED_FOREACH(PureOperator, pop, kPureOperators) {
282 304 : const Operator* op1 = (machine1.*pop.constructor)();
283 304 : const Operator* op2 = (machine2.*pop.constructor)();
284 304 : EXPECT_EQ(op1, op2);
285 1520 : EXPECT_EQ(pop.value_input_count, op1->ValueInputCount());
286 912 : EXPECT_EQ(pop.control_input_count, op1->ControlInputCount());
287 912 : EXPECT_EQ(pop.value_output_count, op1->ValueOutputCount());
288 304 : }
289 4 : }
290 2 : }
291 1 : }
292 :
293 :
294 : // Optional operators.
295 :
296 : struct OptionalOperatorEntry {
297 : const OptionalOperator (MachineOperatorBuilder::*constructor)();
298 : MachineOperatorBuilder::Flag enabling_flag;
299 : char const* const constructor_name;
300 : int value_input_count;
301 : int control_input_count;
302 : int value_output_count;
303 : };
304 :
305 :
306 0 : std::ostream& operator<<(std::ostream& os, OptionalOperatorEntry const& pop) {
307 3 : return os << pop.constructor_name;
308 : }
309 :
310 : const OptionalOperatorEntry kOptionalOperators[] = {
311 : #define OPTIONAL_ENTRY(Name, value_input_count, control_input_count, \
312 : value_output_count) \
313 : { \
314 : &MachineOperatorBuilder::Name, MachineOperatorBuilder::k##Name, #Name, \
315 : value_input_count, control_input_count, value_output_count \
316 : }
317 : OPTIONAL_ENTRY(Float64RoundDown, 1, 0, 1), // --
318 : OPTIONAL_ENTRY(Float64RoundTruncate, 1, 0, 1), // --
319 : OPTIONAL_ENTRY(Float64RoundTiesAway, 1, 0, 1), // --
320 : #undef OPTIONAL_ENTRY
321 : };
322 :
323 :
324 2 : class MachineOptionalOperatorTest : public TestWithZone {
325 : protected:
326 : MachineRepresentation word_rep() {
327 : return MachineType::PointerRepresentation();
328 : }
329 : };
330 :
331 :
332 13159 : TEST_F(MachineOptionalOperatorTest, OptionalOperators) {
333 28 : TRACED_FOREACH(OptionalOperatorEntry, pop, kOptionalOperators) {
334 54 : TRACED_FOREACH(MachineRepresentation, machine_rep1, kMachineReps) {
335 12 : MachineOperatorBuilder machine1(zone(), machine_rep1, pop.enabling_flag);
336 102 : TRACED_FOREACH(MachineRepresentation, machine_rep2, kMachineReps) {
337 : MachineOperatorBuilder machine2(zone(), machine_rep2,
338 24 : pop.enabling_flag);
339 12 : const Operator* op1 = (machine1.*pop.constructor)().op();
340 12 : const Operator* op2 = (machine2.*pop.constructor)().op();
341 12 : EXPECT_EQ(op1, op2);
342 60 : EXPECT_EQ(pop.value_input_count, op1->ValueInputCount());
343 36 : EXPECT_EQ(pop.control_input_count, op1->ControlInputCount());
344 36 : EXPECT_EQ(pop.value_output_count, op1->ValueOutputCount());
345 :
346 12 : MachineOperatorBuilder machine3(zone(), word_rep());
347 24 : EXPECT_TRUE((machine1.*pop.constructor)().IsSupported());
348 24 : EXPECT_FALSE((machine3.*pop.constructor)().IsSupported());
349 12 : }
350 6 : }
351 3 : }
352 1 : }
353 :
354 :
355 : // -----------------------------------------------------------------------------
356 : // Pseudo operators.
357 :
358 :
359 : typedef TestWithZone MachineOperatorTest;
360 :
361 :
362 13159 : TEST_F(MachineOperatorTest, PseudoOperatorsWhenWordSizeIs32Bit) {
363 1 : MachineOperatorBuilder machine(zone(), MachineRepresentation::kWord32);
364 2 : EXPECT_EQ(machine.Word32And(), machine.WordAnd());
365 2 : EXPECT_EQ(machine.Word32Or(), machine.WordOr());
366 2 : EXPECT_EQ(machine.Word32Xor(), machine.WordXor());
367 2 : EXPECT_EQ(machine.Word32Shl(), machine.WordShl());
368 2 : EXPECT_EQ(machine.Word32Shr(), machine.WordShr());
369 2 : EXPECT_EQ(machine.Word32Sar(), machine.WordSar());
370 2 : EXPECT_EQ(machine.Word32Ror(), machine.WordRor());
371 2 : EXPECT_EQ(machine.Word32Equal(), machine.WordEqual());
372 2 : EXPECT_EQ(machine.Int32Add(), machine.IntAdd());
373 2 : EXPECT_EQ(machine.Int32Sub(), machine.IntSub());
374 2 : EXPECT_EQ(machine.Int32Mul(), machine.IntMul());
375 2 : EXPECT_EQ(machine.Int32Div(), machine.IntDiv());
376 2 : EXPECT_EQ(machine.Uint32Div(), machine.UintDiv());
377 2 : EXPECT_EQ(machine.Int32Mod(), machine.IntMod());
378 2 : EXPECT_EQ(machine.Uint32Mod(), machine.UintMod());
379 2 : EXPECT_EQ(machine.Int32LessThan(), machine.IntLessThan());
380 2 : EXPECT_EQ(machine.Int32LessThanOrEqual(), machine.IntLessThanOrEqual());
381 1 : }
382 :
383 :
384 13159 : TEST_F(MachineOperatorTest, PseudoOperatorsWhenWordSizeIs64Bit) {
385 1 : MachineOperatorBuilder machine(zone(), MachineRepresentation::kWord64);
386 2 : EXPECT_EQ(machine.Word64And(), machine.WordAnd());
387 2 : EXPECT_EQ(machine.Word64Or(), machine.WordOr());
388 2 : EXPECT_EQ(machine.Word64Xor(), machine.WordXor());
389 2 : EXPECT_EQ(machine.Word64Shl(), machine.WordShl());
390 2 : EXPECT_EQ(machine.Word64Shr(), machine.WordShr());
391 2 : EXPECT_EQ(machine.Word64Sar(), machine.WordSar());
392 2 : EXPECT_EQ(machine.Word64Ror(), machine.WordRor());
393 2 : EXPECT_EQ(machine.Word64Equal(), machine.WordEqual());
394 2 : EXPECT_EQ(machine.Int64Add(), machine.IntAdd());
395 2 : EXPECT_EQ(machine.Int64Sub(), machine.IntSub());
396 2 : EXPECT_EQ(machine.Int64Mul(), machine.IntMul());
397 2 : EXPECT_EQ(machine.Int64Div(), machine.IntDiv());
398 2 : EXPECT_EQ(machine.Uint64Div(), machine.UintDiv());
399 2 : EXPECT_EQ(machine.Int64Mod(), machine.IntMod());
400 2 : EXPECT_EQ(machine.Uint64Mod(), machine.UintMod());
401 2 : EXPECT_EQ(machine.Int64LessThan(), machine.IntLessThan());
402 2 : EXPECT_EQ(machine.Int64LessThanOrEqual(), machine.IntLessThanOrEqual());
403 1 : }
404 :
405 : } // namespace machine_operator_unittest
406 : } // namespace compiler
407 : } // namespace internal
408 7893 : } // namespace v8
|