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 "test/unittests/compiler/instruction-selector-unittest.h"
6
7 namespace v8 {
8 namespace internal {
9 namespace compiler {
10
11 namespace {
12
13 // Immediates (random subset).
14 const int32_t kImmediates[] = {kMinInt, -42, -1, 0, 1, 2,
15 3, 4, 5, 6, 7, 8,
16 16, 42, 0xff, 0xffff, 0x0f0f0f0f, kMaxInt};
17
18 } // namespace
19
20
TEST_F(InstructionSelectorTest,Int32AddWithParameter)21 TEST_F(InstructionSelectorTest, Int32AddWithParameter) {
22 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
23 MachineType::Int32());
24 m.Return(m.Int32Add(m.Parameter(0), m.Parameter(1)));
25 Stream s = m.Build();
26 ASSERT_EQ(1U, s.size());
27 EXPECT_EQ(kIA32Lea, s[0]->arch_opcode());
28 }
29
30
TEST_F(InstructionSelectorTest,Int32AddWithImmediate)31 TEST_F(InstructionSelectorTest, Int32AddWithImmediate) {
32 TRACED_FOREACH(int32_t, imm, kImmediates) {
33 {
34 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
35 m.Return(m.Int32Add(m.Parameter(0), m.Int32Constant(imm)));
36 Stream s = m.Build();
37 ASSERT_EQ(1U, s.size());
38 EXPECT_EQ(kIA32Lea, s[0]->arch_opcode());
39 if (imm == 0) {
40 ASSERT_EQ(1U, s[0]->InputCount());
41 } else {
42 ASSERT_EQ(2U, s[0]->InputCount());
43 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
44 }
45 }
46 {
47 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
48 m.Return(m.Int32Add(m.Int32Constant(imm), m.Parameter(0)));
49 Stream s = m.Build();
50 ASSERT_EQ(1U, s.size());
51 EXPECT_EQ(kIA32Lea, s[0]->arch_opcode());
52 if (imm == 0) {
53 ASSERT_EQ(1U, s[0]->InputCount());
54 } else {
55 ASSERT_EQ(2U, s[0]->InputCount());
56 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
57 }
58 }
59 }
60 }
61
62
TEST_F(InstructionSelectorTest,Int32SubWithParameter)63 TEST_F(InstructionSelectorTest, Int32SubWithParameter) {
64 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
65 MachineType::Int32());
66 m.Return(m.Int32Sub(m.Parameter(0), m.Parameter(1)));
67 Stream s = m.Build();
68 ASSERT_EQ(1U, s.size());
69 EXPECT_EQ(kIA32Sub, s[0]->arch_opcode());
70 EXPECT_EQ(1U, s[0]->OutputCount());
71 }
72
73
TEST_F(InstructionSelectorTest,Int32SubWithImmediate)74 TEST_F(InstructionSelectorTest, Int32SubWithImmediate) {
75 TRACED_FOREACH(int32_t, imm, kImmediates) {
76 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
77 m.Return(m.Int32Sub(m.Parameter(0), m.Int32Constant(imm)));
78 Stream s = m.Build();
79 ASSERT_EQ(1U, s.size());
80 EXPECT_EQ(kIA32Sub, s[0]->arch_opcode());
81 ASSERT_EQ(2U, s[0]->InputCount());
82 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
83 }
84 }
85
86
87 // -----------------------------------------------------------------------------
88 // Conversions.
89
90
TEST_F(InstructionSelectorTest,ChangeFloat32ToFloat64WithParameter)91 TEST_F(InstructionSelectorTest, ChangeFloat32ToFloat64WithParameter) {
92 StreamBuilder m(this, MachineType::Float32(), MachineType::Float64());
93 m.Return(m.ChangeFloat32ToFloat64(m.Parameter(0)));
94 Stream s = m.Build();
95 ASSERT_EQ(1U, s.size());
96 EXPECT_EQ(kSSEFloat32ToFloat64, s[0]->arch_opcode());
97 EXPECT_EQ(1U, s[0]->InputCount());
98 EXPECT_EQ(1U, s[0]->OutputCount());
99 }
100
101
TEST_F(InstructionSelectorTest,TruncateFloat64ToFloat32WithParameter)102 TEST_F(InstructionSelectorTest, TruncateFloat64ToFloat32WithParameter) {
103 StreamBuilder m(this, MachineType::Float64(), MachineType::Float32());
104 m.Return(m.TruncateFloat64ToFloat32(m.Parameter(0)));
105 Stream s = m.Build();
106 ASSERT_EQ(1U, s.size());
107 EXPECT_EQ(kSSEFloat64ToFloat32, s[0]->arch_opcode());
108 EXPECT_EQ(1U, s[0]->InputCount());
109 EXPECT_EQ(1U, s[0]->OutputCount());
110 }
111
112
113 // -----------------------------------------------------------------------------
114 // Better left operand for commutative binops
115
116
TEST_F(InstructionSelectorTest,BetterLeftOperandTestAddBinop)117 TEST_F(InstructionSelectorTest, BetterLeftOperandTestAddBinop) {
118 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
119 MachineType::Int32());
120 Node* param1 = m.Parameter(0);
121 Node* param2 = m.Parameter(1);
122 Node* add = m.Int32Add(param1, param2);
123 m.Return(m.Int32Add(add, param1));
124 Stream s = m.Build();
125 ASSERT_EQ(2U, s.size());
126 EXPECT_EQ(kIA32Lea, s[0]->arch_opcode());
127 ASSERT_EQ(2U, s[0]->InputCount());
128 ASSERT_TRUE(s[0]->InputAt(0)->IsUnallocated());
129 EXPECT_EQ(s.ToVreg(param1), s.ToVreg(s[0]->InputAt(0)));
130 EXPECT_EQ(s.ToVreg(param2), s.ToVreg(s[0]->InputAt(1)));
131 ASSERT_EQ(2U, s[1]->InputCount());
132 EXPECT_EQ(s.ToVreg(param1), s.ToVreg(s[0]->InputAt(0)));
133 }
134
135
TEST_F(InstructionSelectorTest,BetterLeftOperandTestMulBinop)136 TEST_F(InstructionSelectorTest, BetterLeftOperandTestMulBinop) {
137 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
138 MachineType::Int32());
139 Node* param1 = m.Parameter(0);
140 Node* param2 = m.Parameter(1);
141 Node* mul = m.Int32Mul(param1, param2);
142 m.Return(m.Int32Mul(mul, param1));
143 Stream s = m.Build();
144 ASSERT_EQ(2U, s.size());
145 EXPECT_EQ(kIA32Imul, s[0]->arch_opcode());
146 ASSERT_EQ(2U, s[0]->InputCount());
147 ASSERT_TRUE(s[0]->InputAt(0)->IsUnallocated());
148 EXPECT_EQ(s.ToVreg(param2), s.ToVreg(s[0]->InputAt(0)));
149 EXPECT_EQ(s.ToVreg(param1), s.ToVreg(s[0]->InputAt(1)));
150 }
151
152
153 // -----------------------------------------------------------------------------
154 // Conversions.
155
156
TEST_F(InstructionSelectorTest,ChangeUint32ToFloat64WithParameter)157 TEST_F(InstructionSelectorTest, ChangeUint32ToFloat64WithParameter) {
158 StreamBuilder m(this, MachineType::Float64(), MachineType::Uint32());
159 m.Return(m.ChangeUint32ToFloat64(m.Parameter(0)));
160 Stream s = m.Build();
161 ASSERT_EQ(1U, s.size());
162 EXPECT_EQ(kSSEUint32ToFloat64, s[0]->arch_opcode());
163 }
164
165
166 // -----------------------------------------------------------------------------
167 // Loads and stores
168
169
170 namespace {
171
172 struct MemoryAccess {
173 MachineType type;
174 ArchOpcode load_opcode;
175 ArchOpcode store_opcode;
176 };
177
178
operator <<(std::ostream & os,const MemoryAccess & memacc)179 std::ostream& operator<<(std::ostream& os, const MemoryAccess& memacc) {
180 return os << memacc.type;
181 }
182
183
184 static const MemoryAccess kMemoryAccesses[] = {
185 {MachineType::Int8(), kIA32Movsxbl, kIA32Movb},
186 {MachineType::Uint8(), kIA32Movzxbl, kIA32Movb},
187 {MachineType::Int16(), kIA32Movsxwl, kIA32Movw},
188 {MachineType::Uint16(), kIA32Movzxwl, kIA32Movw},
189 {MachineType::Int32(), kIA32Movl, kIA32Movl},
190 {MachineType::Uint32(), kIA32Movl, kIA32Movl},
191 {MachineType::Float32(), kIA32Movss, kIA32Movss},
192 {MachineType::Float64(), kIA32Movsd, kIA32Movsd}};
193
194 } // namespace
195
196
197 typedef InstructionSelectorTestWithParam<MemoryAccess>
198 InstructionSelectorMemoryAccessTest;
199
200
TEST_P(InstructionSelectorMemoryAccessTest,LoadWithParameters)201 TEST_P(InstructionSelectorMemoryAccessTest, LoadWithParameters) {
202 const MemoryAccess memacc = GetParam();
203 StreamBuilder m(this, memacc.type, MachineType::Pointer(),
204 MachineType::Int32());
205 m.Return(m.Load(memacc.type, m.Parameter(0), m.Parameter(1)));
206 Stream s = m.Build();
207 ASSERT_EQ(1U, s.size());
208 EXPECT_EQ(memacc.load_opcode, s[0]->arch_opcode());
209 EXPECT_EQ(2U, s[0]->InputCount());
210 EXPECT_EQ(1U, s[0]->OutputCount());
211 }
212
213
TEST_P(InstructionSelectorMemoryAccessTest,LoadWithImmediateBase)214 TEST_P(InstructionSelectorMemoryAccessTest, LoadWithImmediateBase) {
215 const MemoryAccess memacc = GetParam();
216 TRACED_FOREACH(int32_t, base, kImmediates) {
217 StreamBuilder m(this, memacc.type, MachineType::Pointer());
218 m.Return(m.Load(memacc.type, m.Int32Constant(base), m.Parameter(0)));
219 Stream s = m.Build();
220 ASSERT_EQ(1U, s.size());
221 EXPECT_EQ(memacc.load_opcode, s[0]->arch_opcode());
222 if (base == 0) {
223 ASSERT_EQ(1U, s[0]->InputCount());
224 } else {
225 ASSERT_EQ(2U, s[0]->InputCount());
226 ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
227 EXPECT_EQ(base, s.ToInt32(s[0]->InputAt(1)));
228 }
229 EXPECT_EQ(1U, s[0]->OutputCount());
230 }
231 }
232
233
TEST_P(InstructionSelectorMemoryAccessTest,LoadWithImmediateIndex)234 TEST_P(InstructionSelectorMemoryAccessTest, LoadWithImmediateIndex) {
235 const MemoryAccess memacc = GetParam();
236 TRACED_FOREACH(int32_t, index, kImmediates) {
237 StreamBuilder m(this, memacc.type, MachineType::Pointer());
238 m.Return(m.Load(memacc.type, m.Parameter(0), m.Int32Constant(index)));
239 Stream s = m.Build();
240 ASSERT_EQ(1U, s.size());
241 EXPECT_EQ(memacc.load_opcode, s[0]->arch_opcode());
242 if (index == 0) {
243 ASSERT_EQ(1U, s[0]->InputCount());
244 } else {
245 ASSERT_EQ(2U, s[0]->InputCount());
246 ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
247 EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
248 }
249 EXPECT_EQ(1U, s[0]->OutputCount());
250 }
251 }
252
253
TEST_P(InstructionSelectorMemoryAccessTest,StoreWithParameters)254 TEST_P(InstructionSelectorMemoryAccessTest, StoreWithParameters) {
255 const MemoryAccess memacc = GetParam();
256 StreamBuilder m(this, MachineType::Int32(), MachineType::Pointer(),
257 MachineType::Int32(), memacc.type);
258 m.Store(memacc.type.representation(), m.Parameter(0), m.Parameter(1),
259 m.Parameter(2), kNoWriteBarrier);
260 m.Return(m.Int32Constant(0));
261 Stream s = m.Build();
262 ASSERT_EQ(1U, s.size());
263 EXPECT_EQ(memacc.store_opcode, s[0]->arch_opcode());
264 EXPECT_EQ(3U, s[0]->InputCount());
265 EXPECT_EQ(0U, s[0]->OutputCount());
266 }
267
268
TEST_P(InstructionSelectorMemoryAccessTest,StoreWithImmediateBase)269 TEST_P(InstructionSelectorMemoryAccessTest, StoreWithImmediateBase) {
270 const MemoryAccess memacc = GetParam();
271 TRACED_FOREACH(int32_t, base, kImmediates) {
272 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
273 memacc.type);
274 m.Store(memacc.type.representation(), m.Int32Constant(base), m.Parameter(0),
275 m.Parameter(1), kNoWriteBarrier);
276 m.Return(m.Int32Constant(0));
277 Stream s = m.Build();
278 ASSERT_EQ(1U, s.size());
279 EXPECT_EQ(memacc.store_opcode, s[0]->arch_opcode());
280 if (base == 0) {
281 ASSERT_EQ(2U, s[0]->InputCount());
282 } else {
283 ASSERT_EQ(3U, s[0]->InputCount());
284 ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
285 EXPECT_EQ(base, s.ToInt32(s[0]->InputAt(1)));
286 }
287 EXPECT_EQ(0U, s[0]->OutputCount());
288 }
289 }
290
291
TEST_P(InstructionSelectorMemoryAccessTest,StoreWithImmediateIndex)292 TEST_P(InstructionSelectorMemoryAccessTest, StoreWithImmediateIndex) {
293 const MemoryAccess memacc = GetParam();
294 TRACED_FOREACH(int32_t, index, kImmediates) {
295 StreamBuilder m(this, MachineType::Int32(), MachineType::Pointer(),
296 memacc.type);
297 m.Store(memacc.type.representation(), m.Parameter(0),
298 m.Int32Constant(index), m.Parameter(1), kNoWriteBarrier);
299 m.Return(m.Int32Constant(0));
300 Stream s = m.Build();
301 ASSERT_EQ(1U, s.size());
302 EXPECT_EQ(memacc.store_opcode, s[0]->arch_opcode());
303 if (index == 0) {
304 ASSERT_EQ(2U, s[0]->InputCount());
305 } else {
306 ASSERT_EQ(3U, s[0]->InputCount());
307 ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
308 EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
309 }
310 EXPECT_EQ(0U, s[0]->OutputCount());
311 }
312 }
313
314
315 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
316 InstructionSelectorMemoryAccessTest,
317 ::testing::ValuesIn(kMemoryAccesses));
318
319
320 // -----------------------------------------------------------------------------
321 // AddressingMode for loads and stores.
322
323
324 class AddressingModeUnitTest : public InstructionSelectorTest {
325 public:
AddressingModeUnitTest()326 AddressingModeUnitTest() : m(NULL) { Reset(); }
~AddressingModeUnitTest()327 ~AddressingModeUnitTest() { delete m; }
328
Run(Node * base,Node * load_index,Node * store_index,AddressingMode mode)329 void Run(Node* base, Node* load_index, Node* store_index,
330 AddressingMode mode) {
331 Node* load = m->Load(MachineType::Int32(), base, load_index);
332 m->Store(MachineRepresentation::kWord32, base, store_index, load,
333 kNoWriteBarrier);
334 m->Return(m->Int32Constant(0));
335 Stream s = m->Build();
336 ASSERT_EQ(2U, s.size());
337 EXPECT_EQ(mode, s[0]->addressing_mode());
338 EXPECT_EQ(mode, s[1]->addressing_mode());
339 }
340
341 Node* zero;
342 Node* null_ptr;
343 Node* non_zero;
344 Node* base_reg; // opaque value to generate base as register
345 Node* index_reg; // opaque value to generate index as register
346 Node* scales[4];
347 StreamBuilder* m;
348
Reset()349 void Reset() {
350 delete m;
351 m = new StreamBuilder(this, MachineType::Int32(), MachineType::Int32(),
352 MachineType::Int32());
353 zero = m->Int32Constant(0);
354 null_ptr = m->Int32Constant(0);
355 non_zero = m->Int32Constant(127);
356 base_reg = m->Parameter(0);
357 index_reg = m->Parameter(0);
358
359 scales[0] = m->Int32Constant(1);
360 scales[1] = m->Int32Constant(2);
361 scales[2] = m->Int32Constant(4);
362 scales[3] = m->Int32Constant(8);
363 }
364 };
365
366
TEST_F(AddressingModeUnitTest,AddressingMode_MR)367 TEST_F(AddressingModeUnitTest, AddressingMode_MR) {
368 Node* base = base_reg;
369 Node* index = zero;
370 Run(base, index, index, kMode_MR);
371 }
372
373
TEST_F(AddressingModeUnitTest,AddressingMode_MRI)374 TEST_F(AddressingModeUnitTest, AddressingMode_MRI) {
375 Node* base = base_reg;
376 Node* index = non_zero;
377 Run(base, index, index, kMode_MRI);
378 }
379
380
TEST_F(AddressingModeUnitTest,AddressingMode_MR1)381 TEST_F(AddressingModeUnitTest, AddressingMode_MR1) {
382 Node* base = base_reg;
383 Node* index = index_reg;
384 Run(base, index, index, kMode_MR1);
385 }
386
387
TEST_F(AddressingModeUnitTest,AddressingMode_MRN)388 TEST_F(AddressingModeUnitTest, AddressingMode_MRN) {
389 AddressingMode expected[] = {kMode_MR1, kMode_MR2, kMode_MR4, kMode_MR8};
390 for (size_t i = 0; i < arraysize(scales); ++i) {
391 Reset();
392 Node* base = base_reg;
393 Node* load_index = m->Int32Mul(index_reg, scales[i]);
394 Node* store_index = m->Int32Mul(index_reg, scales[i]);
395 Run(base, load_index, store_index, expected[i]);
396 }
397 }
398
399
TEST_F(AddressingModeUnitTest,AddressingMode_MR1I)400 TEST_F(AddressingModeUnitTest, AddressingMode_MR1I) {
401 Node* base = base_reg;
402 Node* load_index = m->Int32Add(index_reg, non_zero);
403 Node* store_index = m->Int32Add(index_reg, non_zero);
404 Run(base, load_index, store_index, kMode_MR1I);
405 }
406
407
TEST_F(AddressingModeUnitTest,AddressingMode_MRNI)408 TEST_F(AddressingModeUnitTest, AddressingMode_MRNI) {
409 AddressingMode expected[] = {kMode_MR1I, kMode_MR2I, kMode_MR4I, kMode_MR8I};
410 for (size_t i = 0; i < arraysize(scales); ++i) {
411 Reset();
412 Node* base = base_reg;
413 Node* load_index = m->Int32Add(m->Int32Mul(index_reg, scales[i]), non_zero);
414 Node* store_index =
415 m->Int32Add(m->Int32Mul(index_reg, scales[i]), non_zero);
416 Run(base, load_index, store_index, expected[i]);
417 }
418 }
419
420
TEST_F(AddressingModeUnitTest,AddressingMode_M1ToMR)421 TEST_F(AddressingModeUnitTest, AddressingMode_M1ToMR) {
422 Node* base = null_ptr;
423 Node* index = index_reg;
424 // M1 maps to MR
425 Run(base, index, index, kMode_MR);
426 }
427
428
TEST_F(AddressingModeUnitTest,AddressingMode_MN)429 TEST_F(AddressingModeUnitTest, AddressingMode_MN) {
430 AddressingMode expected[] = {kMode_MR, kMode_M2, kMode_M4, kMode_M8};
431 for (size_t i = 0; i < arraysize(scales); ++i) {
432 Reset();
433 Node* base = null_ptr;
434 Node* load_index = m->Int32Mul(index_reg, scales[i]);
435 Node* store_index = m->Int32Mul(index_reg, scales[i]);
436 Run(base, load_index, store_index, expected[i]);
437 }
438 }
439
440
TEST_F(AddressingModeUnitTest,AddressingMode_M1IToMRI)441 TEST_F(AddressingModeUnitTest, AddressingMode_M1IToMRI) {
442 Node* base = null_ptr;
443 Node* load_index = m->Int32Add(index_reg, non_zero);
444 Node* store_index = m->Int32Add(index_reg, non_zero);
445 // M1I maps to MRI
446 Run(base, load_index, store_index, kMode_MRI);
447 }
448
449
TEST_F(AddressingModeUnitTest,AddressingMode_MNI)450 TEST_F(AddressingModeUnitTest, AddressingMode_MNI) {
451 AddressingMode expected[] = {kMode_MRI, kMode_M2I, kMode_M4I, kMode_M8I};
452 for (size_t i = 0; i < arraysize(scales); ++i) {
453 Reset();
454 Node* base = null_ptr;
455 Node* load_index = m->Int32Add(m->Int32Mul(index_reg, scales[i]), non_zero);
456 Node* store_index =
457 m->Int32Add(m->Int32Mul(index_reg, scales[i]), non_zero);
458 Run(base, load_index, store_index, expected[i]);
459 }
460 }
461
462
TEST_F(AddressingModeUnitTest,AddressingMode_MI)463 TEST_F(AddressingModeUnitTest, AddressingMode_MI) {
464 Node* bases[] = {null_ptr, non_zero};
465 Node* indices[] = {zero, non_zero};
466 for (size_t i = 0; i < arraysize(bases); ++i) {
467 for (size_t j = 0; j < arraysize(indices); ++j) {
468 Reset();
469 Node* base = bases[i];
470 Node* index = indices[j];
471 Run(base, index, index, kMode_MI);
472 }
473 }
474 }
475
476
477 // -----------------------------------------------------------------------------
478 // Multiplication.
479
480
481 namespace {
482
483 struct MultParam {
484 int value;
485 bool lea_expected;
486 AddressingMode addressing_mode;
487 };
488
489
operator <<(std::ostream & os,const MultParam & m)490 std::ostream& operator<<(std::ostream& os, const MultParam& m) {
491 return os << m.value << "." << m.lea_expected << "." << m.addressing_mode;
492 }
493
494
495 const MultParam kMultParams[] = {{-1, false, kMode_None},
496 {0, false, kMode_None},
497 {1, true, kMode_MR},
498 {2, true, kMode_M2},
499 {3, true, kMode_MR2},
500 {4, true, kMode_M4},
501 {5, true, kMode_MR4},
502 {6, false, kMode_None},
503 {7, false, kMode_None},
504 {8, true, kMode_M8},
505 {9, true, kMode_MR8},
506 {10, false, kMode_None},
507 {11, false, kMode_None}};
508
509 } // namespace
510
511
512 typedef InstructionSelectorTestWithParam<MultParam> InstructionSelectorMultTest;
513
514
InputCountForLea(AddressingMode mode)515 static unsigned InputCountForLea(AddressingMode mode) {
516 switch (mode) {
517 case kMode_MR1I:
518 case kMode_MR2I:
519 case kMode_MR4I:
520 case kMode_MR8I:
521 return 3U;
522 case kMode_M1I:
523 case kMode_M2I:
524 case kMode_M4I:
525 case kMode_M8I:
526 return 2U;
527 case kMode_MR1:
528 case kMode_MR2:
529 case kMode_MR4:
530 case kMode_MR8:
531 case kMode_MRI:
532 return 2U;
533 case kMode_M1:
534 case kMode_M2:
535 case kMode_M4:
536 case kMode_M8:
537 case kMode_MI:
538 case kMode_MR:
539 return 1U;
540 default:
541 UNREACHABLE();
542 return 0U;
543 }
544 }
545
546
AddressingModeForAddMult(int32_t imm,const MultParam & m)547 static AddressingMode AddressingModeForAddMult(int32_t imm,
548 const MultParam& m) {
549 if (imm == 0) return m.addressing_mode;
550 switch (m.addressing_mode) {
551 case kMode_MR1:
552 return kMode_MR1I;
553 case kMode_MR2:
554 return kMode_MR2I;
555 case kMode_MR4:
556 return kMode_MR4I;
557 case kMode_MR8:
558 return kMode_MR8I;
559 case kMode_M1:
560 return kMode_M1I;
561 case kMode_M2:
562 return kMode_M2I;
563 case kMode_M4:
564 return kMode_M4I;
565 case kMode_M8:
566 return kMode_M8I;
567 case kMode_MR:
568 return kMode_MRI;
569 default:
570 UNREACHABLE();
571 return kMode_None;
572 }
573 }
574
575
TEST_P(InstructionSelectorMultTest,Mult32)576 TEST_P(InstructionSelectorMultTest, Mult32) {
577 const MultParam m_param = GetParam();
578 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
579 Node* param = m.Parameter(0);
580 Node* mult = m.Int32Mul(param, m.Int32Constant(m_param.value));
581 m.Return(mult);
582 Stream s = m.Build();
583 ASSERT_EQ(1U, s.size());
584 EXPECT_EQ(m_param.addressing_mode, s[0]->addressing_mode());
585 if (m_param.lea_expected) {
586 EXPECT_EQ(kIA32Lea, s[0]->arch_opcode());
587 ASSERT_EQ(InputCountForLea(s[0]->addressing_mode()), s[0]->InputCount());
588 } else {
589 EXPECT_EQ(kIA32Imul, s[0]->arch_opcode());
590 ASSERT_EQ(2U, s[0]->InputCount());
591 }
592 EXPECT_EQ(s.ToVreg(param), s.ToVreg(s[0]->InputAt(0)));
593 }
594
595
TEST_P(InstructionSelectorMultTest,MultAdd32)596 TEST_P(InstructionSelectorMultTest, MultAdd32) {
597 TRACED_FOREACH(int32_t, imm, kImmediates) {
598 const MultParam m_param = GetParam();
599 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
600 Node* param = m.Parameter(0);
601 Node* mult = m.Int32Add(m.Int32Mul(param, m.Int32Constant(m_param.value)),
602 m.Int32Constant(imm));
603 m.Return(mult);
604 Stream s = m.Build();
605 if (m_param.lea_expected) {
606 ASSERT_EQ(1U, s.size());
607 EXPECT_EQ(kIA32Lea, s[0]->arch_opcode());
608 EXPECT_EQ(AddressingModeForAddMult(imm, m_param),
609 s[0]->addressing_mode());
610 unsigned input_count = InputCountForLea(s[0]->addressing_mode());
611 ASSERT_EQ(input_count, s[0]->InputCount());
612 if (imm != 0) {
613 ASSERT_EQ(InstructionOperand::IMMEDIATE,
614 s[0]->InputAt(input_count - 1)->kind());
615 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(input_count - 1)));
616 }
617 } else {
618 ASSERT_EQ(2U, s.size());
619 EXPECT_EQ(kIA32Imul, s[0]->arch_opcode());
620 EXPECT_EQ(kIA32Lea, s[1]->arch_opcode());
621 }
622 }
623 }
624
625
626 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorMultTest,
627 ::testing::ValuesIn(kMultParams));
628
629
TEST_F(InstructionSelectorTest,Int32MulHigh)630 TEST_F(InstructionSelectorTest, Int32MulHigh) {
631 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
632 MachineType::Int32());
633 Node* const p0 = m.Parameter(0);
634 Node* const p1 = m.Parameter(1);
635 Node* const n = m.Int32MulHigh(p0, p1);
636 m.Return(n);
637 Stream s = m.Build();
638 ASSERT_EQ(1U, s.size());
639 EXPECT_EQ(kIA32ImulHigh, s[0]->arch_opcode());
640 ASSERT_EQ(2U, s[0]->InputCount());
641 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
642 EXPECT_TRUE(s.IsFixed(s[0]->InputAt(0), eax));
643 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
644 EXPECT_TRUE(!s.IsUsedAtStart(s[0]->InputAt(1)));
645 ASSERT_EQ(1U, s[0]->OutputCount());
646 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
647 EXPECT_TRUE(s.IsFixed(s[0]->OutputAt(0), edx));
648 }
649
650
651 // -----------------------------------------------------------------------------
652 // Floating point operations.
653
654
TEST_F(InstructionSelectorTest,Float32Abs)655 TEST_F(InstructionSelectorTest, Float32Abs) {
656 {
657 StreamBuilder m(this, MachineType::Float32(), MachineType::Float32());
658 Node* const p0 = m.Parameter(0);
659 Node* const n = m.Float32Abs(p0);
660 m.Return(n);
661 Stream s = m.Build();
662 ASSERT_EQ(1U, s.size());
663 EXPECT_EQ(kSSEFloat32Abs, s[0]->arch_opcode());
664 ASSERT_EQ(1U, s[0]->InputCount());
665 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
666 ASSERT_EQ(1U, s[0]->OutputCount());
667 EXPECT_TRUE(s.IsSameAsFirst(s[0]->Output()));
668 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
669 EXPECT_EQ(kFlags_none, s[0]->flags_mode());
670 }
671 {
672 StreamBuilder m(this, MachineType::Float32(), MachineType::Float32());
673 Node* const p0 = m.Parameter(0);
674 Node* const n = m.Float32Abs(p0);
675 m.Return(n);
676 Stream s = m.Build(AVX);
677 ASSERT_EQ(1U, s.size());
678 EXPECT_EQ(kAVXFloat32Abs, s[0]->arch_opcode());
679 ASSERT_EQ(1U, s[0]->InputCount());
680 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
681 ASSERT_EQ(1U, s[0]->OutputCount());
682 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
683 EXPECT_EQ(kFlags_none, s[0]->flags_mode());
684 }
685 }
686
687
TEST_F(InstructionSelectorTest,Float64Abs)688 TEST_F(InstructionSelectorTest, Float64Abs) {
689 {
690 StreamBuilder m(this, MachineType::Float64(), MachineType::Float64());
691 Node* const p0 = m.Parameter(0);
692 Node* const n = m.Float64Abs(p0);
693 m.Return(n);
694 Stream s = m.Build();
695 ASSERT_EQ(1U, s.size());
696 EXPECT_EQ(kSSEFloat64Abs, s[0]->arch_opcode());
697 ASSERT_EQ(1U, s[0]->InputCount());
698 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
699 ASSERT_EQ(1U, s[0]->OutputCount());
700 EXPECT_TRUE(s.IsSameAsFirst(s[0]->Output()));
701 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
702 EXPECT_EQ(kFlags_none, s[0]->flags_mode());
703 }
704 {
705 StreamBuilder m(this, MachineType::Float64(), MachineType::Float64());
706 Node* const p0 = m.Parameter(0);
707 Node* const n = m.Float64Abs(p0);
708 m.Return(n);
709 Stream s = m.Build(AVX);
710 ASSERT_EQ(1U, s.size());
711 EXPECT_EQ(kAVXFloat64Abs, s[0]->arch_opcode());
712 ASSERT_EQ(1U, s[0]->InputCount());
713 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
714 ASSERT_EQ(1U, s[0]->OutputCount());
715 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
716 EXPECT_EQ(kFlags_none, s[0]->flags_mode());
717 }
718 }
719
720
TEST_F(InstructionSelectorTest,Float64BinopArithmetic)721 TEST_F(InstructionSelectorTest, Float64BinopArithmetic) {
722 {
723 StreamBuilder m(this, MachineType::Float64(), MachineType::Float64(),
724 MachineType::Float64());
725 Node* add = m.Float64Add(m.Parameter(0), m.Parameter(1));
726 Node* mul = m.Float64Mul(add, m.Parameter(1));
727 Node* sub = m.Float64Sub(mul, add);
728 Node* ret = m.Float64Div(mul, sub);
729 m.Return(ret);
730 Stream s = m.Build(AVX);
731 ASSERT_EQ(4U, s.size());
732 EXPECT_EQ(kAVXFloat64Add, s[0]->arch_opcode());
733 EXPECT_EQ(kAVXFloat64Mul, s[1]->arch_opcode());
734 EXPECT_EQ(kAVXFloat64Sub, s[2]->arch_opcode());
735 EXPECT_EQ(kAVXFloat64Div, s[3]->arch_opcode());
736 }
737 {
738 StreamBuilder m(this, MachineType::Float64(), MachineType::Float64(),
739 MachineType::Float64());
740 Node* add = m.Float64Add(m.Parameter(0), m.Parameter(1));
741 Node* mul = m.Float64Mul(add, m.Parameter(1));
742 Node* sub = m.Float64Sub(mul, add);
743 Node* ret = m.Float64Div(mul, sub);
744 m.Return(ret);
745 Stream s = m.Build();
746 ASSERT_EQ(4U, s.size());
747 EXPECT_EQ(kSSEFloat64Add, s[0]->arch_opcode());
748 EXPECT_EQ(kSSEFloat64Mul, s[1]->arch_opcode());
749 EXPECT_EQ(kSSEFloat64Sub, s[2]->arch_opcode());
750 EXPECT_EQ(kSSEFloat64Div, s[3]->arch_opcode());
751 }
752 }
753
754
TEST_F(InstructionSelectorTest,Float32SubWithMinusZeroAndParameter)755 TEST_F(InstructionSelectorTest, Float32SubWithMinusZeroAndParameter) {
756 {
757 StreamBuilder m(this, MachineType::Float32(), MachineType::Float32());
758 Node* const p0 = m.Parameter(0);
759 Node* const n = m.Float32Sub(m.Float32Constant(-0.0f), p0);
760 m.Return(n);
761 Stream s = m.Build();
762 ASSERT_EQ(1U, s.size());
763 EXPECT_EQ(kSSEFloat32Neg, s[0]->arch_opcode());
764 ASSERT_EQ(1U, s[0]->InputCount());
765 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
766 ASSERT_EQ(1U, s[0]->OutputCount());
767 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
768 EXPECT_EQ(kFlags_none, s[0]->flags_mode());
769 }
770 {
771 StreamBuilder m(this, MachineType::Float32(), MachineType::Float32());
772 Node* const p0 = m.Parameter(0);
773 Node* const n = m.Float32Sub(m.Float32Constant(-0.0f), p0);
774 m.Return(n);
775 Stream s = m.Build(AVX);
776 ASSERT_EQ(1U, s.size());
777 EXPECT_EQ(kAVXFloat32Neg, s[0]->arch_opcode());
778 ASSERT_EQ(1U, s[0]->InputCount());
779 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
780 ASSERT_EQ(1U, s[0]->OutputCount());
781 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
782 EXPECT_EQ(kFlags_none, s[0]->flags_mode());
783 }
784 }
785
786
TEST_F(InstructionSelectorTest,Float64SubWithMinusZeroAndParameter)787 TEST_F(InstructionSelectorTest, Float64SubWithMinusZeroAndParameter) {
788 {
789 StreamBuilder m(this, MachineType::Float64(), MachineType::Float64());
790 Node* const p0 = m.Parameter(0);
791 Node* const n = m.Float64Sub(m.Float64Constant(-0.0), p0);
792 m.Return(n);
793 Stream s = m.Build();
794 ASSERT_EQ(1U, s.size());
795 EXPECT_EQ(kSSEFloat64Neg, s[0]->arch_opcode());
796 ASSERT_EQ(1U, s[0]->InputCount());
797 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
798 ASSERT_EQ(1U, s[0]->OutputCount());
799 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
800 EXPECT_EQ(kFlags_none, s[0]->flags_mode());
801 }
802 {
803 StreamBuilder m(this, MachineType::Float64(), MachineType::Float64());
804 Node* const p0 = m.Parameter(0);
805 Node* const n = m.Float64Sub(m.Float64Constant(-0.0), p0);
806 m.Return(n);
807 Stream s = m.Build(AVX);
808 ASSERT_EQ(1U, s.size());
809 EXPECT_EQ(kAVXFloat64Neg, s[0]->arch_opcode());
810 ASSERT_EQ(1U, s[0]->InputCount());
811 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
812 ASSERT_EQ(1U, s[0]->OutputCount());
813 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
814 EXPECT_EQ(kFlags_none, s[0]->flags_mode());
815 }
816 }
817
818
819 // -----------------------------------------------------------------------------
820 // Miscellaneous.
821
822
TEST_F(InstructionSelectorTest,Uint32LessThanWithLoadAndLoadStackPointer)823 TEST_F(InstructionSelectorTest, Uint32LessThanWithLoadAndLoadStackPointer) {
824 StreamBuilder m(this, MachineType::Bool());
825 Node* const sl = m.Load(
826 MachineType::Pointer(),
827 m.ExternalConstant(ExternalReference::address_of_stack_limit(isolate())));
828 Node* const sp = m.LoadStackPointer();
829 Node* const n = m.Uint32LessThan(sl, sp);
830 m.Return(n);
831 Stream s = m.Build();
832 ASSERT_EQ(1U, s.size());
833 EXPECT_EQ(kIA32StackCheck, s[0]->arch_opcode());
834 ASSERT_EQ(0U, s[0]->InputCount());
835 ASSERT_EQ(1U, s[0]->OutputCount());
836 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
837 EXPECT_EQ(kFlags_set, s[0]->flags_mode());
838 EXPECT_EQ(kUnsignedGreaterThan, s[0]->flags_condition());
839 }
840
841
TEST_F(InstructionSelectorTest,Word32Clz)842 TEST_F(InstructionSelectorTest, Word32Clz) {
843 StreamBuilder m(this, MachineType::Uint32(), MachineType::Uint32());
844 Node* const p0 = m.Parameter(0);
845 Node* const n = m.Word32Clz(p0);
846 m.Return(n);
847 Stream s = m.Build();
848 ASSERT_EQ(1U, s.size());
849 EXPECT_EQ(kIA32Lzcnt, s[0]->arch_opcode());
850 ASSERT_EQ(1U, s[0]->InputCount());
851 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
852 ASSERT_EQ(1U, s[0]->OutputCount());
853 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
854 }
855
856 } // namespace compiler
857 } // namespace internal
858 } // namespace v8
859