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