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
15 #if GTEST_HAS_COMBINE
16
17 template <typename T>
18 class MachineOperatorTestWithParam
19 : public TestWithZone,
20 public ::testing::WithParamInterface<
21 ::testing::tuple<MachineRepresentation, T> > {
22 protected:
representation() const23 MachineRepresentation representation() const {
24 return ::testing::get<0>(B::GetParam());
25 }
GetParam() const26 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
34 namespace {
35
36 const MachineRepresentation kMachineReps[] = {MachineRepresentation::kWord32,
37 MachineRepresentation::kWord64};
38
39
40 const 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
47 const 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
60 typedef MachineOperatorTestWithParam<LoadRepresentation>
61 MachineLoadOperatorTest;
62
63
TEST_P(MachineLoadOperatorTest,InstancesAreGloballyShared)64 TEST_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
TEST_P(MachineLoadOperatorTest,NumberOfInputsAndOutputs)71 TEST_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
TEST_P(MachineLoadOperatorTest,OpcodeIsCorrect)86 TEST_P(MachineLoadOperatorTest, OpcodeIsCorrect) {
87 MachineOperatorBuilder machine(zone(), representation());
88 EXPECT_EQ(IrOpcode::kLoad, machine.Load(GetParam())->opcode());
89 }
90
91
TEST_P(MachineLoadOperatorTest,ParameterIsCorrect)92 TEST_P(MachineLoadOperatorTest, ParameterIsCorrect) {
93 MachineOperatorBuilder machine(zone(), representation());
94 EXPECT_EQ(GetParam(),
95 OpParameter<LoadRepresentation>(machine.Load(GetParam())));
96 }
97
98
99 INSTANTIATE_TEST_CASE_P(
100 MachineOperatorTest, MachineLoadOperatorTest,
101 ::testing::Combine(::testing::ValuesIn(kMachineReps),
102 ::testing::ValuesIn(kMachineTypesForAccess)));
103
104
105 // -----------------------------------------------------------------------------
106 // Store operator.
107
108
109 class MachineStoreOperatorTest
110 : public MachineOperatorTestWithParam<
111 ::testing::tuple<MachineRepresentation, WriteBarrierKind> > {
112 protected:
GetParam() const113 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
TEST_P(MachineStoreOperatorTest,InstancesAreGloballyShared)125 TEST_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
TEST_P(MachineStoreOperatorTest,NumberOfInputsAndOutputs)132 TEST_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
TEST_P(MachineStoreOperatorTest,OpcodeIsCorrect)147 TEST_P(MachineStoreOperatorTest, OpcodeIsCorrect) {
148 MachineOperatorBuilder machine(zone(), representation());
149 EXPECT_EQ(IrOpcode::kStore, machine.Store(GetParam())->opcode());
150 }
151
152
TEST_P(MachineStoreOperatorTest,ParameterIsCorrect)153 TEST_P(MachineStoreOperatorTest, ParameterIsCorrect) {
154 MachineOperatorBuilder machine(zone(), representation());
155 EXPECT_EQ(GetParam(),
156 OpParameter<StoreRepresentation>(machine.Store(GetParam())));
157 }
158
159
160 INSTANTIATE_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
172 namespace {
173
174 struct 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
operator <<(std::ostream & os,PureOperator const & pop)183 std::ostream& operator<<(std::ostream& os, PureOperator const& pop) {
184 return os << pop.constructor_name;
185 }
186
187 const 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(Int32AddWithOverflow, 2, 0, 2), // --
212 PURE(Int32Sub, 2, 0, 1), // --
213 PURE(Int32SubWithOverflow, 2, 0, 2), // --
214 PURE(Int32Mul, 2, 0, 1), // --
215 PURE(Int32MulHigh, 2, 0, 1), // --
216 PURE(Int32Div, 2, 1, 1), // --
217 PURE(Uint32Div, 2, 1, 1), // --
218 PURE(Int32Mod, 2, 1, 1), // --
219 PURE(Uint32Mod, 2, 1, 1), // --
220 PURE(Int32LessThan, 2, 0, 1), // --
221 PURE(Int32LessThanOrEqual, 2, 0, 1), // --
222 PURE(Uint32LessThan, 2, 0, 1), // --
223 PURE(Uint32LessThanOrEqual, 2, 0, 1), // --
224 PURE(Int64Add, 2, 0, 1), // --
225 PURE(Int64Sub, 2, 0, 1), // --
226 PURE(Int64Mul, 2, 0, 1), // --
227 PURE(Int64Div, 2, 1, 1), // --
228 PURE(Uint64Div, 2, 1, 1), // --
229 PURE(Int64Mod, 2, 1, 1), // --
230 PURE(Uint64Mod, 2, 1, 1), // --
231 PURE(Int64LessThan, 2, 0, 1), // --
232 PURE(Int64LessThanOrEqual, 2, 0, 1), // --
233 PURE(Uint64LessThan, 2, 0, 1), // --
234 PURE(Uint64LessThanOrEqual, 2, 0, 1), // --
235 PURE(ChangeFloat32ToFloat64, 1, 0, 1), // --
236 PURE(ChangeFloat64ToInt32, 1, 0, 1), // --
237 PURE(ChangeFloat64ToUint32, 1, 0, 1), // --
238 PURE(ChangeInt32ToInt64, 1, 0, 1), // --
239 PURE(ChangeUint32ToFloat64, 1, 0, 1), // --
240 PURE(ChangeUint32ToUint64, 1, 0, 1), // --
241 PURE(TruncateFloat64ToFloat32, 1, 0, 1), // --
242 PURE(TruncateInt64ToInt32, 1, 0, 1), // --
243 PURE(Float32Abs, 1, 0, 1), // --
244 PURE(Float32Add, 2, 0, 1), // --
245 PURE(Float32Sub, 2, 0, 1), // --
246 PURE(Float32Mul, 2, 0, 1), // --
247 PURE(Float32Div, 2, 0, 1), // --
248 PURE(Float32Sqrt, 1, 0, 1), // --
249 PURE(Float32Equal, 2, 0, 1), // --
250 PURE(Float32LessThan, 2, 0, 1), // --
251 PURE(Float32LessThanOrEqual, 2, 0, 1), // --
252 PURE(Float64Abs, 1, 0, 1), // --
253 PURE(Float64Add, 2, 0, 1), // --
254 PURE(Float64Sub, 2, 0, 1), // --
255 PURE(Float64Mul, 2, 0, 1), // --
256 PURE(Float64Div, 2, 0, 1), // --
257 PURE(Float64Mod, 2, 0, 1), // --
258 PURE(Float64Sqrt, 1, 0, 1), // --
259 PURE(Float64Equal, 2, 0, 1), // --
260 PURE(Float64LessThan, 2, 0, 1), // --
261 PURE(Float64LessThanOrEqual, 2, 0, 1), // --
262 PURE(LoadStackPointer, 0, 0, 1), // --
263 PURE(Float64ExtractLowWord32, 1, 0, 1), // --
264 PURE(Float64ExtractHighWord32, 1, 0, 1), // --
265 PURE(Float64InsertLowWord32, 2, 0, 1), // --
266 PURE(Float64InsertHighWord32, 2, 0, 1), // --
267 #undef PURE
268 };
269
270 } // namespace
271
272 class MachinePureOperatorTest : public TestWithZone {
273 protected:
word_type()274 MachineRepresentation word_type() {
275 return MachineType::PointerRepresentation();
276 }
277 };
278
279
TEST_F(MachinePureOperatorTest,PureOperators)280 TEST_F(MachinePureOperatorTest, PureOperators) {
281 TRACED_FOREACH(MachineRepresentation, machine_rep1, kMachineReps) {
282 MachineOperatorBuilder machine1(zone(), machine_rep1);
283 TRACED_FOREACH(MachineRepresentation, machine_rep2, kMachineReps) {
284 MachineOperatorBuilder machine2(zone(), machine_rep2);
285 TRACED_FOREACH(PureOperator, pop, kPureOperators) {
286 const Operator* op1 = (machine1.*pop.constructor)();
287 const Operator* op2 = (machine2.*pop.constructor)();
288 EXPECT_EQ(op1, op2);
289 EXPECT_EQ(pop.value_input_count, op1->ValueInputCount());
290 EXPECT_EQ(pop.control_input_count, op1->ControlInputCount());
291 EXPECT_EQ(pop.value_output_count, op1->ValueOutputCount());
292 }
293 }
294 }
295 }
296
297
298 // Optional operators.
299
300 namespace {
301
302 struct OptionalOperatorEntry {
303 const OptionalOperator (MachineOperatorBuilder::*constructor)();
304 MachineOperatorBuilder::Flag enabling_flag;
305 char const* const constructor_name;
306 int value_input_count;
307 int control_input_count;
308 int value_output_count;
309 };
310
311
operator <<(std::ostream & os,OptionalOperatorEntry const & pop)312 std::ostream& operator<<(std::ostream& os, OptionalOperatorEntry const& pop) {
313 return os << pop.constructor_name;
314 }
315
316 const OptionalOperatorEntry kOptionalOperators[] = {
317 #define OPTIONAL_ENTRY(Name, value_input_count, control_input_count, \
318 value_output_count) \
319 { \
320 &MachineOperatorBuilder::Name, MachineOperatorBuilder::k##Name, #Name, \
321 value_input_count, control_input_count, value_output_count \
322 }
323 OPTIONAL_ENTRY(Float32Max, 2, 0, 1), // --
324 OPTIONAL_ENTRY(Float32Min, 2, 0, 1), // --
325 OPTIONAL_ENTRY(Float64Max, 2, 0, 1), // --
326 OPTIONAL_ENTRY(Float64Min, 2, 0, 1), // --
327 OPTIONAL_ENTRY(Float64RoundDown, 1, 0, 1), // --
328 OPTIONAL_ENTRY(Float64RoundTruncate, 1, 0, 1), // --
329 OPTIONAL_ENTRY(Float64RoundTiesAway, 1, 0, 1), // --
330 #undef OPTIONAL_ENTRY
331 };
332 } // namespace
333
334
335 class MachineOptionalOperatorTest : public TestWithZone {
336 protected:
word_rep()337 MachineRepresentation word_rep() {
338 return MachineType::PointerRepresentation();
339 }
340 };
341
342
TEST_F(MachineOptionalOperatorTest,OptionalOperators)343 TEST_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
370 namespace {
371
372 typedef TestWithZone MachineOperatorTest;
373
374 } // namespace
375
376
TEST_F(MachineOperatorTest,PseudoOperatorsWhenWordSizeIs32Bit)377 TEST_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
TEST_F(MachineOperatorTest,PseudoOperatorsWhenWordSizeIs64Bit)399 TEST_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