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