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