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 <list>
6
7#include "src/compiler/instruction-selector-unittest.h"
8
9namespace v8 {
10namespace internal {
11namespace compiler {
12
13namespace {
14
15typedef RawMachineAssembler::Label MLabel;
16
17template <typename T>
18struct MachInst {
19  T constructor;
20  const char* constructor_name;
21  ArchOpcode arch_opcode;
22  MachineType machine_type;
23};
24
25typedef MachInst<Node* (RawMachineAssembler::*)(Node*)> MachInst1;
26typedef MachInst<Node* (RawMachineAssembler::*)(Node*, Node*)> MachInst2;
27
28
29template <typename T>
30std::ostream& operator<<(std::ostream& os, const MachInst<T>& mi) {
31  return os << mi.constructor_name;
32}
33
34
35// Helper to build Int32Constant or Int64Constant depending on the given
36// machine type.
37Node* BuildConstant(InstructionSelectorTest::StreamBuilder& m, MachineType type,
38                    int64_t value) {
39  switch (type) {
40    case kMachInt32:
41      return m.Int32Constant(value);
42      break;
43
44    case kMachInt64:
45      return m.Int64Constant(value);
46      break;
47
48    default:
49      UNIMPLEMENTED();
50  }
51  return NULL;
52}
53
54
55// ARM64 logical instructions.
56static const MachInst2 kLogicalInstructions[] = {
57    {&RawMachineAssembler::Word32And, "Word32And", kArm64And32, kMachInt32},
58    {&RawMachineAssembler::Word64And, "Word64And", kArm64And, kMachInt64},
59    {&RawMachineAssembler::Word32Or, "Word32Or", kArm64Or32, kMachInt32},
60    {&RawMachineAssembler::Word64Or, "Word64Or", kArm64Or, kMachInt64},
61    {&RawMachineAssembler::Word32Xor, "Word32Xor", kArm64Xor32, kMachInt32},
62    {&RawMachineAssembler::Word64Xor, "Word64Xor", kArm64Xor, kMachInt64}};
63
64
65// ARM64 logical immediates: contiguous set bits, rotated about a power of two
66// sized block. The block is then duplicated across the word. Below is a random
67// subset of the 32-bit immediates.
68static const uint32_t kLogicalImmediates[] = {
69    0x00000002, 0x00000003, 0x00000070, 0x00000080, 0x00000100, 0x000001c0,
70    0x00000300, 0x000007e0, 0x00003ffc, 0x00007fc0, 0x0003c000, 0x0003f000,
71    0x0003ffc0, 0x0003fff8, 0x0007ff00, 0x0007ffe0, 0x000e0000, 0x001e0000,
72    0x001ffffc, 0x003f0000, 0x003f8000, 0x00780000, 0x007fc000, 0x00ff0000,
73    0x01800000, 0x01800180, 0x01f801f8, 0x03fe0000, 0x03ffffc0, 0x03fffffc,
74    0x06000000, 0x07fc0000, 0x07ffc000, 0x07ffffc0, 0x07ffffe0, 0x0ffe0ffe,
75    0x0ffff800, 0x0ffffff0, 0x0fffffff, 0x18001800, 0x1f001f00, 0x1f801f80,
76    0x30303030, 0x3ff03ff0, 0x3ff83ff8, 0x3fff0000, 0x3fff8000, 0x3fffffc0,
77    0x70007000, 0x7f7f7f7f, 0x7fc00000, 0x7fffffc0, 0x8000001f, 0x800001ff,
78    0x81818181, 0x9fff9fff, 0xc00007ff, 0xc0ffffff, 0xdddddddd, 0xe00001ff,
79    0xe00003ff, 0xe007ffff, 0xefffefff, 0xf000003f, 0xf001f001, 0xf3fff3ff,
80    0xf800001f, 0xf80fffff, 0xf87ff87f, 0xfbfbfbfb, 0xfc00001f, 0xfc0000ff,
81    0xfc0001ff, 0xfc03fc03, 0xfe0001ff, 0xff000001, 0xff03ff03, 0xff800000,
82    0xff800fff, 0xff801fff, 0xff87ffff, 0xffc0003f, 0xffc007ff, 0xffcfffcf,
83    0xffe00003, 0xffe1ffff, 0xfff0001f, 0xfff07fff, 0xfff80007, 0xfff87fff,
84    0xfffc00ff, 0xfffe07ff, 0xffff00ff, 0xffffc001, 0xfffff007, 0xfffff3ff,
85    0xfffff807, 0xfffff9ff, 0xfffffc0f, 0xfffffeff};
86
87
88// ARM64 arithmetic instructions.
89static const MachInst2 kAddSubInstructions[] = {
90    {&RawMachineAssembler::Int32Add, "Int32Add", kArm64Add32, kMachInt32},
91    {&RawMachineAssembler::Int64Add, "Int64Add", kArm64Add, kMachInt64},
92    {&RawMachineAssembler::Int32Sub, "Int32Sub", kArm64Sub32, kMachInt32},
93    {&RawMachineAssembler::Int64Sub, "Int64Sub", kArm64Sub, kMachInt64}};
94
95
96// ARM64 Add/Sub immediates: 12-bit immediate optionally shifted by 12.
97// Below is a combination of a random subset and some edge values.
98static const int32_t kAddSubImmediates[] = {
99    0,        1,        69,       493,      599,      701,      719,
100    768,      818,      842,      945,      1246,     1286,     1429,
101    1669,     2171,     2179,     2182,     2254,     2334,     2338,
102    2343,     2396,     2449,     2610,     2732,     2855,     2876,
103    2944,     3377,     3458,     3475,     3476,     3540,     3574,
104    3601,     3813,     3871,     3917,     4095,     4096,     16384,
105    364544,   462848,   970752,   1523712,  1863680,  2363392,  3219456,
106    3280896,  4247552,  4526080,  4575232,  4960256,  5505024,  5894144,
107    6004736,  6193152,  6385664,  6795264,  7114752,  7233536,  7348224,
108    7499776,  7573504,  7729152,  8634368,  8937472,  9465856,  10354688,
109    10682368, 11059200, 11460608, 13168640, 13176832, 14336000, 15028224,
110    15597568, 15892480, 16773120};
111
112
113// ARM64 flag setting data processing instructions.
114static const MachInst2 kDPFlagSetInstructions[] = {
115    {&RawMachineAssembler::Word32And, "Word32And", kArm64Tst32, kMachInt32},
116    {&RawMachineAssembler::Int32Add, "Int32Add", kArm64Cmn32, kMachInt32},
117    {&RawMachineAssembler::Int32Sub, "Int32Sub", kArm64Cmp32, kMachInt32}};
118
119
120// ARM64 arithmetic with overflow instructions.
121static const MachInst2 kOvfAddSubInstructions[] = {
122    {&RawMachineAssembler::Int32AddWithOverflow, "Int32AddWithOverflow",
123     kArm64Add32, kMachInt32},
124    {&RawMachineAssembler::Int32SubWithOverflow, "Int32SubWithOverflow",
125     kArm64Sub32, kMachInt32}};
126
127
128// ARM64 shift instructions.
129static const MachInst2 kShiftInstructions[] = {
130    {&RawMachineAssembler::Word32Shl, "Word32Shl", kArm64Shl32, kMachInt32},
131    {&RawMachineAssembler::Word64Shl, "Word64Shl", kArm64Shl, kMachInt64},
132    {&RawMachineAssembler::Word32Shr, "Word32Shr", kArm64Shr32, kMachInt32},
133    {&RawMachineAssembler::Word64Shr, "Word64Shr", kArm64Shr, kMachInt64},
134    {&RawMachineAssembler::Word32Sar, "Word32Sar", kArm64Sar32, kMachInt32},
135    {&RawMachineAssembler::Word64Sar, "Word64Sar", kArm64Sar, kMachInt64},
136    {&RawMachineAssembler::Word32Ror, "Word32Ror", kArm64Ror32, kMachInt32},
137    {&RawMachineAssembler::Word64Ror, "Word64Ror", kArm64Ror, kMachInt64}};
138
139
140// ARM64 Mul/Div instructions.
141static const MachInst2 kMulDivInstructions[] = {
142    {&RawMachineAssembler::Int32Mul, "Int32Mul", kArm64Mul32, kMachInt32},
143    {&RawMachineAssembler::Int64Mul, "Int64Mul", kArm64Mul, kMachInt64},
144    {&RawMachineAssembler::Int32Div, "Int32Div", kArm64Idiv32, kMachInt32},
145    {&RawMachineAssembler::Int64Div, "Int64Div", kArm64Idiv, kMachInt64},
146    {&RawMachineAssembler::Int32UDiv, "Int32UDiv", kArm64Udiv32, kMachInt32},
147    {&RawMachineAssembler::Int64UDiv, "Int64UDiv", kArm64Udiv, kMachInt64}};
148
149
150// ARM64 FP arithmetic instructions.
151static const MachInst2 kFPArithInstructions[] = {
152    {&RawMachineAssembler::Float64Add, "Float64Add", kArm64Float64Add,
153     kMachFloat64},
154    {&RawMachineAssembler::Float64Sub, "Float64Sub", kArm64Float64Sub,
155     kMachFloat64},
156    {&RawMachineAssembler::Float64Mul, "Float64Mul", kArm64Float64Mul,
157     kMachFloat64},
158    {&RawMachineAssembler::Float64Div, "Float64Div", kArm64Float64Div,
159     kMachFloat64}};
160
161
162struct FPCmp {
163  MachInst2 mi;
164  FlagsCondition cond;
165};
166
167
168std::ostream& operator<<(std::ostream& os, const FPCmp& cmp) {
169  return os << cmp.mi;
170}
171
172
173// ARM64 FP comparison instructions.
174static const FPCmp kFPCmpInstructions[] = {
175    {{&RawMachineAssembler::Float64Equal, "Float64Equal", kArm64Float64Cmp,
176      kMachFloat64},
177     kUnorderedEqual},
178    {{&RawMachineAssembler::Float64LessThan, "Float64LessThan",
179      kArm64Float64Cmp, kMachFloat64},
180     kUnorderedLessThan},
181    {{&RawMachineAssembler::Float64LessThanOrEqual, "Float64LessThanOrEqual",
182      kArm64Float64Cmp, kMachFloat64},
183     kUnorderedLessThanOrEqual}};
184
185
186struct Conversion {
187  // The machine_type field in MachInst1 represents the destination type.
188  MachInst1 mi;
189  MachineType src_machine_type;
190};
191
192
193std::ostream& operator<<(std::ostream& os, const Conversion& conv) {
194  return os << conv.mi;
195}
196
197
198// ARM64 type conversion instructions.
199static const Conversion kConversionInstructions[] = {
200    {{&RawMachineAssembler::ChangeInt32ToInt64, "ChangeInt32ToInt64",
201      kArm64Sxtw, kMachInt64},
202     kMachInt32},
203    {{&RawMachineAssembler::ChangeUint32ToUint64, "ChangeUint32ToUint64",
204      kArm64Mov32, kMachUint64},
205     kMachUint32},
206    {{&RawMachineAssembler::TruncateInt64ToInt32, "TruncateInt64ToInt32",
207      kArm64Mov32, kMachInt32},
208     kMachInt64},
209    {{&RawMachineAssembler::ChangeInt32ToFloat64, "ChangeInt32ToFloat64",
210      kArm64Int32ToFloat64, kMachFloat64},
211     kMachInt32},
212    {{&RawMachineAssembler::ChangeUint32ToFloat64, "ChangeUint32ToFloat64",
213      kArm64Uint32ToFloat64, kMachFloat64},
214     kMachUint32},
215    {{&RawMachineAssembler::ChangeFloat64ToInt32, "ChangeFloat64ToInt32",
216      kArm64Float64ToInt32, kMachInt32},
217     kMachFloat64},
218    {{&RawMachineAssembler::ChangeFloat64ToUint32, "ChangeFloat64ToUint32",
219      kArm64Float64ToUint32, kMachUint32},
220     kMachFloat64}};
221
222}  // namespace
223
224
225// -----------------------------------------------------------------------------
226// Logical instructions.
227
228
229typedef InstructionSelectorTestWithParam<MachInst2>
230    InstructionSelectorLogicalTest;
231
232
233TEST_P(InstructionSelectorLogicalTest, Parameter) {
234  const MachInst2 dpi = GetParam();
235  const MachineType type = dpi.machine_type;
236  StreamBuilder m(this, type, type, type);
237  m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)));
238  Stream s = m.Build();
239  ASSERT_EQ(1U, s.size());
240  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
241  EXPECT_EQ(2U, s[0]->InputCount());
242  EXPECT_EQ(1U, s[0]->OutputCount());
243}
244
245
246TEST_P(InstructionSelectorLogicalTest, Immediate) {
247  const MachInst2 dpi = GetParam();
248  const MachineType type = dpi.machine_type;
249  // TODO(all): Add support for testing 64-bit immediates.
250  if (type == kMachInt32) {
251    // Immediate on the right.
252    TRACED_FOREACH(int32_t, imm, kLogicalImmediates) {
253      StreamBuilder m(this, type, type);
254      m.Return((m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm)));
255      Stream s = m.Build();
256      ASSERT_EQ(1U, s.size());
257      EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
258      ASSERT_EQ(2U, s[0]->InputCount());
259      EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
260      EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
261      EXPECT_EQ(1U, s[0]->OutputCount());
262    }
263
264    // Immediate on the left; all logical ops should commute.
265    TRACED_FOREACH(int32_t, imm, kLogicalImmediates) {
266      StreamBuilder m(this, type, type);
267      m.Return((m.*dpi.constructor)(m.Int32Constant(imm), m.Parameter(0)));
268      Stream s = m.Build();
269      ASSERT_EQ(1U, s.size());
270      EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
271      ASSERT_EQ(2U, s[0]->InputCount());
272      EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
273      EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
274      EXPECT_EQ(1U, s[0]->OutputCount());
275    }
276  }
277}
278
279
280INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorLogicalTest,
281                        ::testing::ValuesIn(kLogicalInstructions));
282
283
284// -----------------------------------------------------------------------------
285// Add and Sub instructions.
286
287typedef InstructionSelectorTestWithParam<MachInst2>
288    InstructionSelectorAddSubTest;
289
290
291TEST_P(InstructionSelectorAddSubTest, Parameter) {
292  const MachInst2 dpi = GetParam();
293  const MachineType type = dpi.machine_type;
294  StreamBuilder m(this, type, type, type);
295  m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)));
296  Stream s = m.Build();
297  ASSERT_EQ(1U, s.size());
298  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
299  EXPECT_EQ(2U, s[0]->InputCount());
300  EXPECT_EQ(1U, s[0]->OutputCount());
301}
302
303
304TEST_P(InstructionSelectorAddSubTest, ImmediateOnRight) {
305  const MachInst2 dpi = GetParam();
306  const MachineType type = dpi.machine_type;
307  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
308    StreamBuilder m(this, type, type);
309    m.Return((m.*dpi.constructor)(m.Parameter(0), BuildConstant(m, type, imm)));
310    Stream s = m.Build();
311    ASSERT_EQ(1U, s.size());
312    EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
313    ASSERT_EQ(2U, s[0]->InputCount());
314    EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
315    EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1)));
316    EXPECT_EQ(1U, s[0]->OutputCount());
317  }
318}
319
320
321TEST_P(InstructionSelectorAddSubTest, ImmediateOnLeft) {
322  const MachInst2 dpi = GetParam();
323  const MachineType type = dpi.machine_type;
324
325  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
326    StreamBuilder m(this, type, type);
327    m.Return((m.*dpi.constructor)(BuildConstant(m, type, imm), m.Parameter(0)));
328    Stream s = m.Build();
329
330    // Add can support an immediate on the left by commuting, but Sub can't
331    // commute. We test zero-on-left Sub later.
332    if (strstr(dpi.constructor_name, "Add") != NULL) {
333      ASSERT_EQ(1U, s.size());
334      EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
335      ASSERT_EQ(2U, s[0]->InputCount());
336      EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
337      EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1)));
338      EXPECT_EQ(1U, s[0]->OutputCount());
339    }
340  }
341}
342
343
344INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorAddSubTest,
345                        ::testing::ValuesIn(kAddSubInstructions));
346
347
348TEST_F(InstructionSelectorTest, SubZeroOnLeft) {
349  // Subtraction with zero on the left maps to Neg.
350  {
351    // 32-bit subtract.
352    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
353    m.Return(m.Int32Sub(m.Int32Constant(0), m.Parameter(0)));
354    Stream s = m.Build();
355
356    ASSERT_EQ(1U, s.size());
357    EXPECT_EQ(kArm64Neg32, s[0]->arch_opcode());
358    EXPECT_EQ(1U, s[0]->InputCount());
359    EXPECT_EQ(1U, s[0]->OutputCount());
360  }
361  {
362    // 64-bit subtract.
363    StreamBuilder m(this, kMachInt64, kMachInt64, kMachInt64);
364    m.Return(m.Int64Sub(m.Int64Constant(0), m.Parameter(0)));
365    Stream s = m.Build();
366
367    ASSERT_EQ(1U, s.size());
368    EXPECT_EQ(kArm64Neg, s[0]->arch_opcode());
369    EXPECT_EQ(1U, s[0]->InputCount());
370    EXPECT_EQ(1U, s[0]->OutputCount());
371  }
372}
373
374
375// -----------------------------------------------------------------------------
376// Data processing controlled branches.
377
378
379typedef InstructionSelectorTestWithParam<MachInst2>
380    InstructionSelectorDPFlagSetTest;
381
382
383TEST_P(InstructionSelectorDPFlagSetTest, BranchWithParameters) {
384  const MachInst2 dpi = GetParam();
385  const MachineType type = dpi.machine_type;
386  StreamBuilder m(this, type, type, type);
387  MLabel a, b;
388  m.Branch((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)), &a, &b);
389  m.Bind(&a);
390  m.Return(m.Int32Constant(1));
391  m.Bind(&b);
392  m.Return(m.Int32Constant(0));
393  Stream s = m.Build();
394  ASSERT_EQ(1U, s.size());
395  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
396  EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
397  EXPECT_EQ(kNotEqual, s[0]->flags_condition());
398}
399
400
401INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
402                        InstructionSelectorDPFlagSetTest,
403                        ::testing::ValuesIn(kDPFlagSetInstructions));
404
405
406TEST_F(InstructionSelectorTest, AndBranchWithImmediateOnRight) {
407  TRACED_FOREACH(int32_t, imm, kLogicalImmediates) {
408    StreamBuilder m(this, kMachInt32, kMachInt32);
409    MLabel a, b;
410    m.Branch(m.Word32And(m.Parameter(0), m.Int32Constant(imm)), &a, &b);
411    m.Bind(&a);
412    m.Return(m.Int32Constant(1));
413    m.Bind(&b);
414    m.Return(m.Int32Constant(0));
415    Stream s = m.Build();
416    ASSERT_EQ(1U, s.size());
417    EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode());
418    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
419    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
420  }
421}
422
423
424TEST_F(InstructionSelectorTest, AddBranchWithImmediateOnRight) {
425  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
426    StreamBuilder m(this, kMachInt32, kMachInt32);
427    MLabel a, b;
428    m.Branch(m.Int32Add(m.Parameter(0), m.Int32Constant(imm)), &a, &b);
429    m.Bind(&a);
430    m.Return(m.Int32Constant(1));
431    m.Bind(&b);
432    m.Return(m.Int32Constant(0));
433    Stream s = m.Build();
434    ASSERT_EQ(1U, s.size());
435    EXPECT_EQ(kArm64Cmn32, s[0]->arch_opcode());
436    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
437    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
438  }
439}
440
441
442TEST_F(InstructionSelectorTest, SubBranchWithImmediateOnRight) {
443  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
444    StreamBuilder m(this, kMachInt32, kMachInt32);
445    MLabel a, b;
446    m.Branch(m.Int32Sub(m.Parameter(0), m.Int32Constant(imm)), &a, &b);
447    m.Bind(&a);
448    m.Return(m.Int32Constant(1));
449    m.Bind(&b);
450    m.Return(m.Int32Constant(0));
451    Stream s = m.Build();
452    ASSERT_EQ(1U, s.size());
453    EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode());
454    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
455    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
456  }
457}
458
459
460TEST_F(InstructionSelectorTest, AndBranchWithImmediateOnLeft) {
461  TRACED_FOREACH(int32_t, imm, kLogicalImmediates) {
462    StreamBuilder m(this, kMachInt32, kMachInt32);
463    MLabel a, b;
464    m.Branch(m.Word32And(m.Int32Constant(imm), m.Parameter(0)), &a, &b);
465    m.Bind(&a);
466    m.Return(m.Int32Constant(1));
467    m.Bind(&b);
468    m.Return(m.Int32Constant(0));
469    Stream s = m.Build();
470    ASSERT_EQ(1U, s.size());
471    EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode());
472    ASSERT_LE(1U, s[0]->InputCount());
473    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
474    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
475  }
476}
477
478
479TEST_F(InstructionSelectorTest, AddBranchWithImmediateOnLeft) {
480  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
481    StreamBuilder m(this, kMachInt32, kMachInt32);
482    MLabel a, b;
483    m.Branch(m.Int32Add(m.Int32Constant(imm), m.Parameter(0)), &a, &b);
484    m.Bind(&a);
485    m.Return(m.Int32Constant(1));
486    m.Bind(&b);
487    m.Return(m.Int32Constant(0));
488    Stream s = m.Build();
489    ASSERT_EQ(1U, s.size());
490    EXPECT_EQ(kArm64Cmn32, s[0]->arch_opcode());
491    ASSERT_LE(1U, s[0]->InputCount());
492    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
493    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
494  }
495}
496
497
498// -----------------------------------------------------------------------------
499// Add and subtract instructions with overflow.
500
501
502typedef InstructionSelectorTestWithParam<MachInst2>
503    InstructionSelectorOvfAddSubTest;
504
505
506TEST_P(InstructionSelectorOvfAddSubTest, OvfParameter) {
507  const MachInst2 dpi = GetParam();
508  const MachineType type = dpi.machine_type;
509  StreamBuilder m(this, type, type, type);
510  m.Return(
511      m.Projection(1, (m.*dpi.constructor)(m.Parameter(0), m.Parameter(1))));
512  Stream s = m.Build();
513  ASSERT_EQ(1U, s.size());
514  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
515  EXPECT_EQ(2U, s[0]->InputCount());
516  EXPECT_LE(1U, s[0]->OutputCount());
517  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
518  EXPECT_EQ(kOverflow, s[0]->flags_condition());
519}
520
521
522TEST_P(InstructionSelectorOvfAddSubTest, OvfImmediateOnRight) {
523  const MachInst2 dpi = GetParam();
524  const MachineType type = dpi.machine_type;
525  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
526    StreamBuilder m(this, type, type);
527    m.Return(m.Projection(
528        1, (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm))));
529    Stream s = m.Build();
530    ASSERT_EQ(1U, s.size());
531    EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
532    ASSERT_EQ(2U, s[0]->InputCount());
533    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
534    EXPECT_LE(1U, s[0]->OutputCount());
535    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
536    EXPECT_EQ(kOverflow, s[0]->flags_condition());
537  }
538}
539
540
541TEST_P(InstructionSelectorOvfAddSubTest, ValParameter) {
542  const MachInst2 dpi = GetParam();
543  const MachineType type = dpi.machine_type;
544  StreamBuilder m(this, type, type, type);
545  m.Return(
546      m.Projection(0, (m.*dpi.constructor)(m.Parameter(0), m.Parameter(1))));
547  Stream s = m.Build();
548  ASSERT_EQ(1U, s.size());
549  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
550  EXPECT_EQ(2U, s[0]->InputCount());
551  EXPECT_LE(1U, s[0]->OutputCount());
552  EXPECT_EQ(kFlags_none, s[0]->flags_mode());
553}
554
555
556TEST_P(InstructionSelectorOvfAddSubTest, ValImmediateOnRight) {
557  const MachInst2 dpi = GetParam();
558  const MachineType type = dpi.machine_type;
559  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
560    StreamBuilder m(this, type, type);
561    m.Return(m.Projection(
562        0, (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm))));
563    Stream s = m.Build();
564    ASSERT_EQ(1U, s.size());
565    EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
566    ASSERT_EQ(2U, s[0]->InputCount());
567    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
568    EXPECT_LE(1U, s[0]->OutputCount());
569    EXPECT_EQ(kFlags_none, s[0]->flags_mode());
570  }
571}
572
573
574TEST_P(InstructionSelectorOvfAddSubTest, BothParameter) {
575  const MachInst2 dpi = GetParam();
576  const MachineType type = dpi.machine_type;
577  StreamBuilder m(this, type, type, type);
578  Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Parameter(1));
579  m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
580  Stream s = m.Build();
581  ASSERT_LE(1U, s.size());
582  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
583  EXPECT_EQ(2U, s[0]->InputCount());
584  EXPECT_EQ(2U, s[0]->OutputCount());
585  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
586  EXPECT_EQ(kOverflow, s[0]->flags_condition());
587}
588
589
590TEST_P(InstructionSelectorOvfAddSubTest, BothImmediateOnRight) {
591  const MachInst2 dpi = GetParam();
592  const MachineType type = dpi.machine_type;
593  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
594    StreamBuilder m(this, type, type);
595    Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm));
596    m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
597    Stream s = m.Build();
598    ASSERT_LE(1U, s.size());
599    EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
600    ASSERT_EQ(2U, s[0]->InputCount());
601    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
602    EXPECT_EQ(2U, s[0]->OutputCount());
603    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
604    EXPECT_EQ(kOverflow, s[0]->flags_condition());
605  }
606}
607
608
609TEST_P(InstructionSelectorOvfAddSubTest, BranchWithParameters) {
610  const MachInst2 dpi = GetParam();
611  const MachineType type = dpi.machine_type;
612  StreamBuilder m(this, type, type, type);
613  MLabel a, b;
614  Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Parameter(1));
615  m.Branch(m.Projection(1, n), &a, &b);
616  m.Bind(&a);
617  m.Return(m.Int32Constant(0));
618  m.Bind(&b);
619  m.Return(m.Projection(0, n));
620  Stream s = m.Build();
621  ASSERT_EQ(1U, s.size());
622  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
623  EXPECT_EQ(4U, s[0]->InputCount());
624  EXPECT_EQ(1U, s[0]->OutputCount());
625  EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
626  EXPECT_EQ(kOverflow, s[0]->flags_condition());
627}
628
629
630TEST_P(InstructionSelectorOvfAddSubTest, BranchWithImmediateOnRight) {
631  const MachInst2 dpi = GetParam();
632  const MachineType type = dpi.machine_type;
633  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
634    StreamBuilder m(this, type, type);
635    MLabel a, b;
636    Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm));
637    m.Branch(m.Projection(1, n), &a, &b);
638    m.Bind(&a);
639    m.Return(m.Int32Constant(0));
640    m.Bind(&b);
641    m.Return(m.Projection(0, n));
642    Stream s = m.Build();
643    ASSERT_EQ(1U, s.size());
644    EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
645    ASSERT_EQ(4U, s[0]->InputCount());
646    EXPECT_EQ(1U, s[0]->OutputCount());
647    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
648    EXPECT_EQ(kOverflow, s[0]->flags_condition());
649  }
650}
651
652
653INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
654                        InstructionSelectorOvfAddSubTest,
655                        ::testing::ValuesIn(kOvfAddSubInstructions));
656
657
658TEST_F(InstructionSelectorTest, OvfFlagAddImmediateOnLeft) {
659  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
660    StreamBuilder m(this, kMachInt32, kMachInt32);
661    m.Return(m.Projection(
662        1, m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0))));
663    Stream s = m.Build();
664
665    ASSERT_EQ(1U, s.size());
666    EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
667    EXPECT_EQ(2U, s[0]->InputCount());
668    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
669    EXPECT_LE(1U, s[0]->OutputCount());
670    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
671    EXPECT_EQ(kOverflow, s[0]->flags_condition());
672  }
673}
674
675
676TEST_F(InstructionSelectorTest, OvfValAddImmediateOnLeft) {
677  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
678    StreamBuilder m(this, kMachInt32, kMachInt32);
679    m.Return(m.Projection(
680        0, m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0))));
681    Stream s = m.Build();
682
683    ASSERT_EQ(1U, s.size());
684    EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
685    ASSERT_EQ(2U, s[0]->InputCount());
686    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
687    EXPECT_LE(1U, s[0]->OutputCount());
688    EXPECT_EQ(kFlags_none, s[0]->flags_mode());
689  }
690}
691
692
693TEST_F(InstructionSelectorTest, OvfBothAddImmediateOnLeft) {
694  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
695    StreamBuilder m(this, kMachInt32, kMachInt32);
696    Node* n = m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0));
697    m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
698    Stream s = m.Build();
699
700    ASSERT_LE(1U, s.size());
701    EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
702    ASSERT_EQ(2U, s[0]->InputCount());
703    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
704    EXPECT_EQ(2U, s[0]->OutputCount());
705    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
706    EXPECT_EQ(kOverflow, s[0]->flags_condition());
707  }
708}
709
710
711TEST_F(InstructionSelectorTest, OvfBranchWithImmediateOnLeft) {
712  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
713    StreamBuilder m(this, kMachInt32, kMachInt32);
714    MLabel a, b;
715    Node* n = m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0));
716    m.Branch(m.Projection(1, n), &a, &b);
717    m.Bind(&a);
718    m.Return(m.Int32Constant(0));
719    m.Bind(&b);
720    m.Return(m.Projection(0, n));
721    Stream s = m.Build();
722
723    ASSERT_EQ(1U, s.size());
724    EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
725    ASSERT_EQ(4U, s[0]->InputCount());
726    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
727    EXPECT_EQ(1U, s[0]->OutputCount());
728    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
729    EXPECT_EQ(kOverflow, s[0]->flags_condition());
730  }
731}
732
733
734// -----------------------------------------------------------------------------
735// Shift instructions.
736
737
738typedef InstructionSelectorTestWithParam<MachInst2>
739    InstructionSelectorShiftTest;
740
741
742TEST_P(InstructionSelectorShiftTest, Parameter) {
743  const MachInst2 dpi = GetParam();
744  const MachineType type = dpi.machine_type;
745  StreamBuilder m(this, type, type, type);
746  m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)));
747  Stream s = m.Build();
748  ASSERT_EQ(1U, s.size());
749  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
750  EXPECT_EQ(2U, s[0]->InputCount());
751  EXPECT_EQ(1U, s[0]->OutputCount());
752}
753
754
755TEST_P(InstructionSelectorShiftTest, Immediate) {
756  const MachInst2 dpi = GetParam();
757  const MachineType type = dpi.machine_type;
758  TRACED_FORRANGE(int32_t, imm, 0, (ElementSizeOf(type) * 8) - 1) {
759    StreamBuilder m(this, type, type);
760    m.Return((m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm)));
761    Stream s = m.Build();
762    ASSERT_EQ(1U, s.size());
763    EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
764    EXPECT_EQ(2U, s[0]->InputCount());
765    EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
766    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
767    EXPECT_EQ(1U, s[0]->OutputCount());
768  }
769}
770
771
772INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorShiftTest,
773                        ::testing::ValuesIn(kShiftInstructions));
774
775
776// -----------------------------------------------------------------------------
777// Mul and Div instructions.
778
779
780typedef InstructionSelectorTestWithParam<MachInst2>
781    InstructionSelectorMulDivTest;
782
783
784TEST_P(InstructionSelectorMulDivTest, Parameter) {
785  const MachInst2 dpi = GetParam();
786  const MachineType type = dpi.machine_type;
787  StreamBuilder m(this, type, type, type);
788  m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)));
789  Stream s = m.Build();
790  ASSERT_EQ(1U, s.size());
791  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
792  EXPECT_EQ(2U, s[0]->InputCount());
793  EXPECT_EQ(1U, s[0]->OutputCount());
794}
795
796INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorMulDivTest,
797                        ::testing::ValuesIn(kMulDivInstructions));
798
799
800// -----------------------------------------------------------------------------
801// Floating point instructions.
802
803typedef InstructionSelectorTestWithParam<MachInst2>
804    InstructionSelectorFPArithTest;
805
806
807TEST_P(InstructionSelectorFPArithTest, Parameter) {
808  const MachInst2 fpa = GetParam();
809  StreamBuilder m(this, fpa.machine_type, fpa.machine_type, fpa.machine_type);
810  m.Return((m.*fpa.constructor)(m.Parameter(0), m.Parameter(1)));
811  Stream s = m.Build();
812  ASSERT_EQ(1U, s.size());
813  EXPECT_EQ(fpa.arch_opcode, s[0]->arch_opcode());
814  EXPECT_EQ(2U, s[0]->InputCount());
815  EXPECT_EQ(1U, s[0]->OutputCount());
816}
817
818
819INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorFPArithTest,
820                        ::testing::ValuesIn(kFPArithInstructions));
821
822
823typedef InstructionSelectorTestWithParam<FPCmp> InstructionSelectorFPCmpTest;
824
825
826TEST_P(InstructionSelectorFPCmpTest, Parameter) {
827  const FPCmp cmp = GetParam();
828  StreamBuilder m(this, kMachInt32, cmp.mi.machine_type, cmp.mi.machine_type);
829  m.Return((m.*cmp.mi.constructor)(m.Parameter(0), m.Parameter(1)));
830  Stream s = m.Build();
831  ASSERT_EQ(1U, s.size());
832  EXPECT_EQ(cmp.mi.arch_opcode, s[0]->arch_opcode());
833  EXPECT_EQ(2U, s[0]->InputCount());
834  EXPECT_EQ(1U, s[0]->OutputCount());
835  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
836  EXPECT_EQ(cmp.cond, s[0]->flags_condition());
837}
838
839
840INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorFPCmpTest,
841                        ::testing::ValuesIn(kFPCmpInstructions));
842
843
844// -----------------------------------------------------------------------------
845// Conversions.
846
847typedef InstructionSelectorTestWithParam<Conversion>
848    InstructionSelectorConversionTest;
849
850
851TEST_P(InstructionSelectorConversionTest, Parameter) {
852  const Conversion conv = GetParam();
853  StreamBuilder m(this, conv.mi.machine_type, conv.src_machine_type);
854  m.Return((m.*conv.mi.constructor)(m.Parameter(0)));
855  Stream s = m.Build();
856  ASSERT_EQ(1U, s.size());
857  EXPECT_EQ(conv.mi.arch_opcode, s[0]->arch_opcode());
858  EXPECT_EQ(1U, s[0]->InputCount());
859  EXPECT_EQ(1U, s[0]->OutputCount());
860}
861
862
863INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
864                        InstructionSelectorConversionTest,
865                        ::testing::ValuesIn(kConversionInstructions));
866
867
868// -----------------------------------------------------------------------------
869// Memory access instructions.
870
871
872namespace {
873
874struct MemoryAccess {
875  MachineType type;
876  ArchOpcode ldr_opcode;
877  ArchOpcode str_opcode;
878  const int32_t immediates[20];
879};
880
881
882std::ostream& operator<<(std::ostream& os, const MemoryAccess& memacc) {
883  OStringStream ost;
884  ost << memacc.type;
885  return os << ost.c_str();
886}
887
888}  // namespace
889
890
891static const MemoryAccess kMemoryAccesses[] = {
892    {kMachInt8, kArm64Ldrsb, kArm64Strb,
893     {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 257, 258, 1000, 1001,
894      2121, 2442, 4093, 4094, 4095}},
895    {kMachUint8, kArm64Ldrb, kArm64Strb,
896     {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 257, 258, 1000, 1001,
897      2121, 2442, 4093, 4094, 4095}},
898    {kMachInt16, kArm64Ldrsh, kArm64Strh,
899     {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 258, 260, 4096, 4098,
900      4100, 4242, 6786, 8188, 8190}},
901    {kMachUint16, kArm64Ldrh, kArm64Strh,
902     {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 258, 260, 4096, 4098,
903      4100, 4242, 6786, 8188, 8190}},
904    {kMachInt32, kArm64LdrW, kArm64StrW,
905     {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 260, 4096, 4100, 8192,
906      8196, 3276, 3280, 16376, 16380}},
907    {kMachUint32, kArm64LdrW, kArm64StrW,
908     {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 260, 4096, 4100, 8192,
909      8196, 3276, 3280, 16376, 16380}},
910    {kMachInt64, kArm64Ldr, kArm64Str,
911     {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 264, 4096, 4104, 8192,
912      8200, 16384, 16392, 32752, 32760}},
913    {kMachUint64, kArm64Ldr, kArm64Str,
914     {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 264, 4096, 4104, 8192,
915      8200, 16384, 16392, 32752, 32760}},
916    {kMachFloat32, kArm64LdrS, kArm64StrS,
917     {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 260, 4096, 4100, 8192,
918      8196, 3276, 3280, 16376, 16380}},
919    {kMachFloat64, kArm64LdrD, kArm64StrD,
920     {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 264, 4096, 4104, 8192,
921      8200, 16384, 16392, 32752, 32760}}};
922
923
924typedef InstructionSelectorTestWithParam<MemoryAccess>
925    InstructionSelectorMemoryAccessTest;
926
927
928TEST_P(InstructionSelectorMemoryAccessTest, LoadWithParameters) {
929  const MemoryAccess memacc = GetParam();
930  StreamBuilder m(this, memacc.type, kMachPtr, kMachInt32);
931  m.Return(m.Load(memacc.type, m.Parameter(0), m.Parameter(1)));
932  Stream s = m.Build();
933  ASSERT_EQ(1U, s.size());
934  EXPECT_EQ(memacc.ldr_opcode, s[0]->arch_opcode());
935  EXPECT_EQ(kMode_MRR, s[0]->addressing_mode());
936  EXPECT_EQ(2U, s[0]->InputCount());
937  EXPECT_EQ(1U, s[0]->OutputCount());
938}
939
940
941TEST_P(InstructionSelectorMemoryAccessTest, LoadWithImmediateIndex) {
942  const MemoryAccess memacc = GetParam();
943  TRACED_FOREACH(int32_t, index, memacc.immediates) {
944    StreamBuilder m(this, memacc.type, kMachPtr);
945    m.Return(m.Load(memacc.type, m.Parameter(0), m.Int32Constant(index)));
946    Stream s = m.Build();
947    ASSERT_EQ(1U, s.size());
948    EXPECT_EQ(memacc.ldr_opcode, s[0]->arch_opcode());
949    EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
950    EXPECT_EQ(2U, s[0]->InputCount());
951    ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
952    EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
953    ASSERT_EQ(1U, s[0]->OutputCount());
954  }
955}
956
957
958TEST_P(InstructionSelectorMemoryAccessTest, StoreWithParameters) {
959  const MemoryAccess memacc = GetParam();
960  StreamBuilder m(this, kMachInt32, kMachPtr, kMachInt32, memacc.type);
961  m.Store(memacc.type, m.Parameter(0), m.Parameter(1), m.Parameter(2));
962  m.Return(m.Int32Constant(0));
963  Stream s = m.Build();
964  ASSERT_EQ(1U, s.size());
965  EXPECT_EQ(memacc.str_opcode, s[0]->arch_opcode());
966  EXPECT_EQ(kMode_MRR, s[0]->addressing_mode());
967  EXPECT_EQ(3U, s[0]->InputCount());
968  EXPECT_EQ(0U, s[0]->OutputCount());
969}
970
971
972TEST_P(InstructionSelectorMemoryAccessTest, StoreWithImmediateIndex) {
973  const MemoryAccess memacc = GetParam();
974  TRACED_FOREACH(int32_t, index, memacc.immediates) {
975    StreamBuilder m(this, kMachInt32, kMachPtr, memacc.type);
976    m.Store(memacc.type, m.Parameter(0), m.Int32Constant(index),
977            m.Parameter(1));
978    m.Return(m.Int32Constant(0));
979    Stream s = m.Build();
980    ASSERT_EQ(1U, s.size());
981    EXPECT_EQ(memacc.str_opcode, s[0]->arch_opcode());
982    EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
983    ASSERT_EQ(3U, s[0]->InputCount());
984    ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
985    EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
986    EXPECT_EQ(0U, s[0]->OutputCount());
987  }
988}
989
990
991INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
992                        InstructionSelectorMemoryAccessTest,
993                        ::testing::ValuesIn(kMemoryAccesses));
994
995
996// -----------------------------------------------------------------------------
997// Comparison instructions.
998
999static const MachInst2 kComparisonInstructions[] = {
1000    {&RawMachineAssembler::Word32Equal, "Word32Equal", kArm64Cmp32, kMachInt32},
1001    {&RawMachineAssembler::Word64Equal, "Word64Equal", kArm64Cmp, kMachInt64},
1002};
1003
1004
1005typedef InstructionSelectorTestWithParam<MachInst2>
1006    InstructionSelectorComparisonTest;
1007
1008
1009TEST_P(InstructionSelectorComparisonTest, WithParameters) {
1010  const MachInst2 cmp = GetParam();
1011  const MachineType type = cmp.machine_type;
1012  StreamBuilder m(this, type, type, type);
1013  m.Return((m.*cmp.constructor)(m.Parameter(0), m.Parameter(1)));
1014  Stream s = m.Build();
1015  ASSERT_EQ(1U, s.size());
1016  EXPECT_EQ(cmp.arch_opcode, s[0]->arch_opcode());
1017  EXPECT_EQ(2U, s[0]->InputCount());
1018  EXPECT_EQ(1U, s[0]->OutputCount());
1019  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1020  EXPECT_EQ(kEqual, s[0]->flags_condition());
1021}
1022
1023
1024TEST_P(InstructionSelectorComparisonTest, WithImmediate) {
1025  const MachInst2 cmp = GetParam();
1026  const MachineType type = cmp.machine_type;
1027  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
1028    // Compare with 0 are turned into tst instruction.
1029    if (imm == 0) continue;
1030    StreamBuilder m(this, type, type);
1031    m.Return((m.*cmp.constructor)(m.Parameter(0), BuildConstant(m, type, imm)));
1032    Stream s = m.Build();
1033    ASSERT_EQ(1U, s.size());
1034    EXPECT_EQ(cmp.arch_opcode, s[0]->arch_opcode());
1035    ASSERT_EQ(2U, s[0]->InputCount());
1036    ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
1037    EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1)));
1038    EXPECT_EQ(1U, s[0]->OutputCount());
1039    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1040    EXPECT_EQ(kEqual, s[0]->flags_condition());
1041  }
1042  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
1043    // Compare with 0 are turned into tst instruction.
1044    if (imm == 0) continue;
1045    StreamBuilder m(this, type, type);
1046    m.Return((m.*cmp.constructor)(m.Parameter(0), BuildConstant(m, type, imm)));
1047    Stream s = m.Build();
1048    ASSERT_EQ(1U, s.size());
1049    EXPECT_EQ(cmp.arch_opcode, s[0]->arch_opcode());
1050    ASSERT_EQ(2U, s[0]->InputCount());
1051    ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
1052    EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1)));
1053    EXPECT_EQ(1U, s[0]->OutputCount());
1054    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1055    EXPECT_EQ(kEqual, s[0]->flags_condition());
1056  }
1057}
1058
1059INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
1060                        InstructionSelectorComparisonTest,
1061                        ::testing::ValuesIn(kComparisonInstructions));
1062
1063
1064TEST_F(InstructionSelectorTest, Word32EqualWithZero) {
1065  {
1066    StreamBuilder m(this, kMachInt32, kMachInt32);
1067    m.Return(m.Word32Equal(m.Parameter(0), m.Int32Constant(0)));
1068    Stream s = m.Build();
1069    ASSERT_EQ(1U, s.size());
1070    EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode());
1071    ASSERT_EQ(2U, s[0]->InputCount());
1072    EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
1073    EXPECT_EQ(1U, s[0]->OutputCount());
1074    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1075    EXPECT_EQ(kEqual, s[0]->flags_condition());
1076  }
1077  {
1078    StreamBuilder m(this, kMachInt32, kMachInt32);
1079    m.Return(m.Word32Equal(m.Int32Constant(0), m.Parameter(0)));
1080    Stream s = m.Build();
1081    ASSERT_EQ(1U, s.size());
1082    EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode());
1083    ASSERT_EQ(2U, s[0]->InputCount());
1084    EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
1085    EXPECT_EQ(1U, s[0]->OutputCount());
1086    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1087    EXPECT_EQ(kEqual, s[0]->flags_condition());
1088  }
1089}
1090
1091
1092TEST_F(InstructionSelectorTest, Word64EqualWithZero) {
1093  {
1094    StreamBuilder m(this, kMachInt64, kMachInt64);
1095    m.Return(m.Word64Equal(m.Parameter(0), m.Int64Constant(0)));
1096    Stream s = m.Build();
1097    ASSERT_EQ(1U, s.size());
1098    EXPECT_EQ(kArm64Tst, s[0]->arch_opcode());
1099    ASSERT_EQ(2U, s[0]->InputCount());
1100    EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
1101    EXPECT_EQ(1U, s[0]->OutputCount());
1102    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1103    EXPECT_EQ(kEqual, s[0]->flags_condition());
1104  }
1105  {
1106    StreamBuilder m(this, kMachInt64, kMachInt64);
1107    m.Return(m.Word64Equal(m.Int64Constant(0), m.Parameter(0)));
1108    Stream s = m.Build();
1109    ASSERT_EQ(1U, s.size());
1110    EXPECT_EQ(kArm64Tst, s[0]->arch_opcode());
1111    ASSERT_EQ(2U, s[0]->InputCount());
1112    EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
1113    EXPECT_EQ(1U, s[0]->OutputCount());
1114    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1115    EXPECT_EQ(kEqual, s[0]->flags_condition());
1116  }
1117}
1118
1119}  // namespace compiler
1120}  // namespace internal
1121}  // namespace v8
1122