• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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