Home | History | Annotate | Download | only in ia32
      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 
     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 
     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 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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:
    326   AddressingModeUnitTest() : m(NULL) { Reset(); }
    327   ~AddressingModeUnitTest() { delete m; }
    328 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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