V8 Project
instruction-selector-arm64-unittest.cc
Go to the documentation of this file.
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 
8 
9 namespace v8 {
10 namespace internal {
11 namespace compiler {
12 
13 namespace {
14 
16 
17 template <typename T>
18 struct MachInst {
20  const char* constructor_name;
23 };
24 
25 typedef MachInst<Node* (RawMachineAssembler::*)(Node*)> MachInst1;
26 typedef MachInst<Node* (RawMachineAssembler::*)(Node*, Node*)> MachInst2;
27 
28 
29 template <typename T>
30 std::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.
37 Node* 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.
56 static 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", kArm64Eor32, kMachInt32},
62  {&RawMachineAssembler::Word64Xor, "Word64Xor", kArm64Eor, 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.
68 static 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.
89 static 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.
98 static 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.
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.
122  {&RawMachineAssembler::Int32AddWithOverflow, "Int32AddWithOverflow",
123  kArm64Add32, kMachInt32},
124  {&RawMachineAssembler::Int32SubWithOverflow, "Int32SubWithOverflow",
125  kArm64Sub32, kMachInt32}};
126 
127 
128 // ARM64 shift instructions.
129 static 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.
141 static 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.
151 static 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 
162 struct FPCmp {
165 };
166 
167 
168 std::ostream& operator<<(std::ostream& os, const FPCmp& cmp) {
169  return os << cmp.mi;
170 }
171 
172 
173 // ARM64 FP comparison instructions.
174 static const FPCmp kFPCmpInstructions[] = {
175  {{&RawMachineAssembler::Float64Equal, "Float64Equal", kArm64Float64Cmp,
176  kMachFloat64},
178  {{&RawMachineAssembler::Float64LessThan, "Float64LessThan",
179  kArm64Float64Cmp, kMachFloat64},
181  {{&RawMachineAssembler::Float64LessThanOrEqual, "Float64LessThanOrEqual",
182  kArm64Float64Cmp, kMachFloat64},
184 
185 
186 struct Conversion {
187  // The machine_type field in MachInst1 represents the destination type.
190 };
191 
192 
193 std::ostream& operator<<(std::ostream& os, const Conversion& conv) {
194  return os << conv.mi;
195 }
196 
197 
198 // ARM64 type conversion instructions.
200  {{&RawMachineAssembler::ChangeFloat32ToFloat64, "ChangeFloat32ToFloat64",
201  kArm64Float32ToFloat64, kMachFloat64},
202  kMachFloat32},
204  "TruncateFloat64ToFloat32", kArm64Float64ToFloat32, kMachFloat32},
205  kMachFloat64},
206  {{&RawMachineAssembler::ChangeInt32ToInt64, "ChangeInt32ToInt64",
207  kArm64Sxtw, kMachInt64},
208  kMachInt32},
209  {{&RawMachineAssembler::ChangeUint32ToUint64, "ChangeUint32ToUint64",
210  kArm64Mov32, kMachUint64},
211  kMachUint32},
212  {{&RawMachineAssembler::TruncateInt64ToInt32, "TruncateInt64ToInt32",
213  kArm64Mov32, kMachInt32},
214  kMachInt64},
215  {{&RawMachineAssembler::ChangeInt32ToFloat64, "ChangeInt32ToFloat64",
216  kArm64Int32ToFloat64, kMachFloat64},
217  kMachInt32},
218  {{&RawMachineAssembler::ChangeUint32ToFloat64, "ChangeUint32ToFloat64",
219  kArm64Uint32ToFloat64, kMachFloat64},
220  kMachUint32},
221  {{&RawMachineAssembler::ChangeFloat64ToInt32, "ChangeFloat64ToInt32",
222  kArm64Float64ToInt32, kMachInt32},
223  kMachFloat64},
224  {{&RawMachineAssembler::ChangeFloat64ToUint32, "ChangeFloat64ToUint32",
225  kArm64Float64ToUint32, kMachUint32},
226  kMachFloat64}};
227 
228 } // namespace
229 
230 
231 // -----------------------------------------------------------------------------
232 // Logical instructions.
233 
234 
235 typedef InstructionSelectorTestWithParam<MachInst2>
237 
238 
240  const MachInst2 dpi = GetParam();
241  const MachineType type = dpi.machine_type;
242  StreamBuilder m(this, type, type, type);
243  m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)));
244  Stream s = m.Build();
245  ASSERT_EQ(1U, s.size());
246  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
247  EXPECT_EQ(2U, s[0]->InputCount());
248  EXPECT_EQ(1U, s[0]->OutputCount());
249 }
250 
251 
253  const MachInst2 dpi = GetParam();
254  const MachineType type = dpi.machine_type;
255  // TODO(all): Add support for testing 64-bit immediates.
256  if (type == kMachInt32) {
257  // Immediate on the right.
258  TRACED_FOREACH(int32_t, imm, kLogicalImmediates) {
259  StreamBuilder m(this, type, type);
260  m.Return((m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm)));
261  Stream s = m.Build();
262  ASSERT_EQ(1U, s.size());
263  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
264  ASSERT_EQ(2U, s[0]->InputCount());
265  EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
266  EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
267  EXPECT_EQ(1U, s[0]->OutputCount());
268  }
269 
270  // Immediate on the left; all logical ops should commute.
271  TRACED_FOREACH(int32_t, imm, kLogicalImmediates) {
272  StreamBuilder m(this, type, type);
273  m.Return((m.*dpi.constructor)(m.Int32Constant(imm), m.Parameter(0)));
274  Stream s = m.Build();
275  ASSERT_EQ(1U, s.size());
276  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
277  ASSERT_EQ(2U, s[0]->InputCount());
278  EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
279  EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
280  EXPECT_EQ(1U, s[0]->OutputCount());
281  }
282  }
283 }
284 
285 
287  ::testing::ValuesIn(kLogicalInstructions));
288 
289 
290 // -----------------------------------------------------------------------------
291 // Add and Sub instructions.
292 
295 
296 
298  const MachInst2 dpi = GetParam();
299  const MachineType type = dpi.machine_type;
300  StreamBuilder m(this, type, type, type);
301  m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)));
302  Stream s = m.Build();
303  ASSERT_EQ(1U, s.size());
304  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
305  EXPECT_EQ(2U, s[0]->InputCount());
306  EXPECT_EQ(1U, s[0]->OutputCount());
307 }
308 
309 
311  const MachInst2 dpi = GetParam();
312  const MachineType type = dpi.machine_type;
313  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
314  StreamBuilder m(this, type, type);
315  m.Return((m.*dpi.constructor)(m.Parameter(0), BuildConstant(m, type, imm)));
316  Stream s = m.Build();
317  ASSERT_EQ(1U, s.size());
318  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
319  ASSERT_EQ(2U, s[0]->InputCount());
320  EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
321  EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1)));
322  EXPECT_EQ(1U, s[0]->OutputCount());
323  }
324 }
325 
326 
328  const MachInst2 dpi = GetParam();
329  const MachineType type = dpi.machine_type;
330 
331  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
332  StreamBuilder m(this, type, type);
333  m.Return((m.*dpi.constructor)(BuildConstant(m, type, imm), m.Parameter(0)));
334  Stream s = m.Build();
335 
336  // Add can support an immediate on the left by commuting, but Sub can't
337  // commute. We test zero-on-left Sub later.
338  if (strstr(dpi.constructor_name, "Add") != NULL) {
339  ASSERT_EQ(1U, s.size());
340  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
341  ASSERT_EQ(2U, s[0]->InputCount());
342  EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
343  EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1)));
344  EXPECT_EQ(1U, s[0]->OutputCount());
345  }
346  }
347 }
348 
349 
351  ::testing::ValuesIn(kAddSubInstructions));
352 
353 
355  // Subtraction with zero on the left maps to Neg.
356  {
357  // 32-bit subtract.
358  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
359  m.Return(m.Int32Sub(m.Int32Constant(0), m.Parameter(0)));
360  Stream s = m.Build();
361 
362  ASSERT_EQ(1U, s.size());
363  EXPECT_EQ(kArm64Neg32, s[0]->arch_opcode());
364  EXPECT_EQ(1U, s[0]->InputCount());
365  EXPECT_EQ(1U, s[0]->OutputCount());
366  }
367  {
368  // 64-bit subtract.
369  StreamBuilder m(this, kMachInt64, kMachInt64, kMachInt64);
370  m.Return(m.Int64Sub(m.Int64Constant(0), m.Parameter(0)));
371  Stream s = m.Build();
372 
373  ASSERT_EQ(1U, s.size());
374  EXPECT_EQ(kArm64Neg, s[0]->arch_opcode());
375  EXPECT_EQ(1U, s[0]->InputCount());
376  EXPECT_EQ(1U, s[0]->OutputCount());
377  }
378 }
379 
380 
381 // -----------------------------------------------------------------------------
382 // Data processing controlled branches.
383 
384 
385 typedef InstructionSelectorTestWithParam<MachInst2>
387 
388 
389 TEST_P(InstructionSelectorDPFlagSetTest, BranchWithParameters) {
390  const MachInst2 dpi = GetParam();
391  const MachineType type = dpi.machine_type;
392  StreamBuilder m(this, type, type, type);
393  MLabel a, b;
394  m.Branch((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)), &a, &b);
395  m.Bind(&a);
396  m.Return(m.Int32Constant(1));
397  m.Bind(&b);
398  m.Return(m.Int32Constant(0));
399  Stream s = m.Build();
400  ASSERT_EQ(1U, s.size());
401  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
402  EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
403  EXPECT_EQ(kNotEqual, s[0]->flags_condition());
404 }
405 
406 
409  ::testing::ValuesIn(kDPFlagSetInstructions));
410 
411 
412 TEST_F(InstructionSelectorTest, AndBranchWithImmediateOnRight) {
413  TRACED_FOREACH(int32_t, imm, kLogicalImmediates) {
414  StreamBuilder m(this, kMachInt32, kMachInt32);
415  MLabel a, b;
416  m.Branch(m.Word32And(m.Parameter(0), m.Int32Constant(imm)), &a, &b);
417  m.Bind(&a);
418  m.Return(m.Int32Constant(1));
419  m.Bind(&b);
420  m.Return(m.Int32Constant(0));
421  Stream s = m.Build();
422  ASSERT_EQ(1U, s.size());
423  EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode());
424  EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
425  EXPECT_EQ(kNotEqual, s[0]->flags_condition());
426  }
427 }
428 
429 
430 TEST_F(InstructionSelectorTest, AddBranchWithImmediateOnRight) {
431  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
432  StreamBuilder m(this, kMachInt32, kMachInt32);
433  MLabel a, b;
434  m.Branch(m.Int32Add(m.Parameter(0), m.Int32Constant(imm)), &a, &b);
435  m.Bind(&a);
436  m.Return(m.Int32Constant(1));
437  m.Bind(&b);
438  m.Return(m.Int32Constant(0));
439  Stream s = m.Build();
440  ASSERT_EQ(1U, s.size());
441  EXPECT_EQ(kArm64Cmn32, s[0]->arch_opcode());
442  EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
443  EXPECT_EQ(kNotEqual, s[0]->flags_condition());
444  }
445 }
446 
447 
448 TEST_F(InstructionSelectorTest, SubBranchWithImmediateOnRight) {
449  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
450  StreamBuilder m(this, kMachInt32, kMachInt32);
451  MLabel a, b;
452  m.Branch(m.Int32Sub(m.Parameter(0), m.Int32Constant(imm)), &a, &b);
453  m.Bind(&a);
454  m.Return(m.Int32Constant(1));
455  m.Bind(&b);
456  m.Return(m.Int32Constant(0));
457  Stream s = m.Build();
458  ASSERT_EQ(1U, s.size());
459  EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode());
460  EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
461  EXPECT_EQ(kNotEqual, s[0]->flags_condition());
462  }
463 }
464 
465 
466 TEST_F(InstructionSelectorTest, AndBranchWithImmediateOnLeft) {
467  TRACED_FOREACH(int32_t, imm, kLogicalImmediates) {
468  StreamBuilder m(this, kMachInt32, kMachInt32);
469  MLabel a, b;
470  m.Branch(m.Word32And(m.Int32Constant(imm), m.Parameter(0)), &a, &b);
471  m.Bind(&a);
472  m.Return(m.Int32Constant(1));
473  m.Bind(&b);
474  m.Return(m.Int32Constant(0));
475  Stream s = m.Build();
476  ASSERT_EQ(1U, s.size());
477  EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode());
478  ASSERT_LE(1U, s[0]->InputCount());
479  EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
480  EXPECT_EQ(kNotEqual, s[0]->flags_condition());
481  }
482 }
483 
484 
485 TEST_F(InstructionSelectorTest, AddBranchWithImmediateOnLeft) {
486  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
487  StreamBuilder m(this, kMachInt32, kMachInt32);
488  MLabel a, b;
489  m.Branch(m.Int32Add(m.Int32Constant(imm), m.Parameter(0)), &a, &b);
490  m.Bind(&a);
491  m.Return(m.Int32Constant(1));
492  m.Bind(&b);
493  m.Return(m.Int32Constant(0));
494  Stream s = m.Build();
495  ASSERT_EQ(1U, s.size());
496  EXPECT_EQ(kArm64Cmn32, s[0]->arch_opcode());
497  ASSERT_LE(1U, s[0]->InputCount());
498  EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
499  EXPECT_EQ(kNotEqual, s[0]->flags_condition());
500  }
501 }
502 
503 
504 // -----------------------------------------------------------------------------
505 // Add and subtract instructions with overflow.
506 
507 
508 typedef InstructionSelectorTestWithParam<MachInst2>
510 
511 
513  const MachInst2 dpi = GetParam();
514  const MachineType type = dpi.machine_type;
515  StreamBuilder m(this, type, type, type);
516  m.Return(
517  m.Projection(1, (m.*dpi.constructor)(m.Parameter(0), m.Parameter(1))));
518  Stream s = m.Build();
519  ASSERT_EQ(1U, s.size());
520  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
521  EXPECT_EQ(2U, s[0]->InputCount());
522  EXPECT_LE(1U, s[0]->OutputCount());
523  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
524  EXPECT_EQ(kOverflow, s[0]->flags_condition());
525 }
526 
527 
529  const MachInst2 dpi = GetParam();
530  const MachineType type = dpi.machine_type;
531  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
532  StreamBuilder m(this, type, type);
533  m.Return(m.Projection(
534  1, (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm))));
535  Stream s = m.Build();
536  ASSERT_EQ(1U, s.size());
537  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
538  ASSERT_EQ(2U, s[0]->InputCount());
539  EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
540  EXPECT_LE(1U, s[0]->OutputCount());
541  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
542  EXPECT_EQ(kOverflow, s[0]->flags_condition());
543  }
544 }
545 
546 
548  const MachInst2 dpi = GetParam();
549  const MachineType type = dpi.machine_type;
550  StreamBuilder m(this, type, type, type);
551  m.Return(
552  m.Projection(0, (m.*dpi.constructor)(m.Parameter(0), m.Parameter(1))));
553  Stream s = m.Build();
554  ASSERT_EQ(1U, s.size());
555  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
556  EXPECT_EQ(2U, s[0]->InputCount());
557  EXPECT_LE(1U, s[0]->OutputCount());
558  EXPECT_EQ(kFlags_none, s[0]->flags_mode());
559 }
560 
561 
563  const MachInst2 dpi = GetParam();
564  const MachineType type = dpi.machine_type;
565  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
566  StreamBuilder m(this, type, type);
567  m.Return(m.Projection(
568  0, (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm))));
569  Stream s = m.Build();
570  ASSERT_EQ(1U, s.size());
571  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
572  ASSERT_EQ(2U, s[0]->InputCount());
573  EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
574  EXPECT_LE(1U, s[0]->OutputCount());
575  EXPECT_EQ(kFlags_none, s[0]->flags_mode());
576  }
577 }
578 
579 
581  const MachInst2 dpi = GetParam();
582  const MachineType type = dpi.machine_type;
583  StreamBuilder m(this, type, type, type);
584  Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Parameter(1));
585  m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
586  Stream s = m.Build();
587  ASSERT_LE(1U, s.size());
588  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
589  EXPECT_EQ(2U, s[0]->InputCount());
590  EXPECT_EQ(2U, s[0]->OutputCount());
591  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
592  EXPECT_EQ(kOverflow, s[0]->flags_condition());
593 }
594 
595 
596 TEST_P(InstructionSelectorOvfAddSubTest, BothImmediateOnRight) {
597  const MachInst2 dpi = GetParam();
598  const MachineType type = dpi.machine_type;
599  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
600  StreamBuilder m(this, type, type);
601  Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm));
602  m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
603  Stream s = m.Build();
604  ASSERT_LE(1U, s.size());
605  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
606  ASSERT_EQ(2U, s[0]->InputCount());
607  EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
608  EXPECT_EQ(2U, s[0]->OutputCount());
609  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
610  EXPECT_EQ(kOverflow, s[0]->flags_condition());
611  }
612 }
613 
614 
615 TEST_P(InstructionSelectorOvfAddSubTest, BranchWithParameters) {
616  const MachInst2 dpi = GetParam();
617  const MachineType type = dpi.machine_type;
618  StreamBuilder m(this, type, type, type);
619  MLabel a, b;
620  Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Parameter(1));
621  m.Branch(m.Projection(1, n), &a, &b);
622  m.Bind(&a);
623  m.Return(m.Int32Constant(0));
624  m.Bind(&b);
625  m.Return(m.Projection(0, n));
626  Stream s = m.Build();
627  ASSERT_EQ(1U, s.size());
628  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
629  EXPECT_EQ(4U, s[0]->InputCount());
630  EXPECT_EQ(1U, s[0]->OutputCount());
631  EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
632  EXPECT_EQ(kOverflow, s[0]->flags_condition());
633 }
634 
635 
636 TEST_P(InstructionSelectorOvfAddSubTest, BranchWithImmediateOnRight) {
637  const MachInst2 dpi = GetParam();
638  const MachineType type = dpi.machine_type;
639  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
640  StreamBuilder m(this, type, type);
641  MLabel a, b;
642  Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm));
643  m.Branch(m.Projection(1, n), &a, &b);
644  m.Bind(&a);
645  m.Return(m.Int32Constant(0));
646  m.Bind(&b);
647  m.Return(m.Projection(0, n));
648  Stream s = m.Build();
649  ASSERT_EQ(1U, s.size());
650  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
651  ASSERT_EQ(4U, s[0]->InputCount());
652  EXPECT_EQ(1U, s[0]->OutputCount());
653  EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
654  EXPECT_EQ(kOverflow, s[0]->flags_condition());
655  }
656 }
657 
658 
661  ::testing::ValuesIn(kOvfAddSubInstructions));
662 
663 
664 TEST_F(InstructionSelectorTest, OvfFlagAddImmediateOnLeft) {
665  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
666  StreamBuilder m(this, kMachInt32, kMachInt32);
667  m.Return(m.Projection(
668  1, m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0))));
669  Stream s = m.Build();
670 
671  ASSERT_EQ(1U, s.size());
672  EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
673  EXPECT_EQ(2U, s[0]->InputCount());
674  EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
675  EXPECT_LE(1U, s[0]->OutputCount());
676  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
677  EXPECT_EQ(kOverflow, s[0]->flags_condition());
678  }
679 }
680 
681 
682 TEST_F(InstructionSelectorTest, OvfValAddImmediateOnLeft) {
683  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
684  StreamBuilder m(this, kMachInt32, kMachInt32);
685  m.Return(m.Projection(
686  0, m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0))));
687  Stream s = m.Build();
688 
689  ASSERT_EQ(1U, s.size());
690  EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
691  ASSERT_EQ(2U, s[0]->InputCount());
692  EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
693  EXPECT_LE(1U, s[0]->OutputCount());
694  EXPECT_EQ(kFlags_none, s[0]->flags_mode());
695  }
696 }
697 
698 
699 TEST_F(InstructionSelectorTest, OvfBothAddImmediateOnLeft) {
700  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
701  StreamBuilder m(this, kMachInt32, kMachInt32);
702  Node* n = m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0));
703  m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
704  Stream s = m.Build();
705 
706  ASSERT_LE(1U, s.size());
707  EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
708  ASSERT_EQ(2U, s[0]->InputCount());
709  EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
710  EXPECT_EQ(2U, s[0]->OutputCount());
711  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
712  EXPECT_EQ(kOverflow, s[0]->flags_condition());
713  }
714 }
715 
716 
717 TEST_F(InstructionSelectorTest, OvfBranchWithImmediateOnLeft) {
718  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
719  StreamBuilder m(this, kMachInt32, kMachInt32);
720  MLabel a, b;
721  Node* n = m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0));
722  m.Branch(m.Projection(1, n), &a, &b);
723  m.Bind(&a);
724  m.Return(m.Int32Constant(0));
725  m.Bind(&b);
726  m.Return(m.Projection(0, n));
727  Stream s = m.Build();
728 
729  ASSERT_EQ(1U, s.size());
730  EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
731  ASSERT_EQ(4U, s[0]->InputCount());
732  EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
733  EXPECT_EQ(1U, s[0]->OutputCount());
734  EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
735  EXPECT_EQ(kOverflow, s[0]->flags_condition());
736  }
737 }
738 
739 
740 // -----------------------------------------------------------------------------
741 // Shift instructions.
742 
743 
744 typedef InstructionSelectorTestWithParam<MachInst2>
746 
747 
749  const MachInst2 dpi = GetParam();
750  const MachineType type = dpi.machine_type;
751  StreamBuilder m(this, type, type, type);
752  m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)));
753  Stream s = m.Build();
754  ASSERT_EQ(1U, s.size());
755  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
756  EXPECT_EQ(2U, s[0]->InputCount());
757  EXPECT_EQ(1U, s[0]->OutputCount());
758 }
759 
760 
762  const MachInst2 dpi = GetParam();
763  const MachineType type = dpi.machine_type;
764  TRACED_FORRANGE(int32_t, imm, 0, (ElementSizeOf(type) * 8) - 1) {
765  StreamBuilder m(this, type, type);
766  m.Return((m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm)));
767  Stream s = m.Build();
768  ASSERT_EQ(1U, s.size());
769  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
770  EXPECT_EQ(2U, s[0]->InputCount());
771  EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
772  EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
773  EXPECT_EQ(1U, s[0]->OutputCount());
774  }
775 }
776 
777 
779  ::testing::ValuesIn(kShiftInstructions));
780 
781 
782 // -----------------------------------------------------------------------------
783 // Mul and Div instructions.
784 
785 
788 
789 
791  const MachInst2 dpi = GetParam();
792  const MachineType type = dpi.machine_type;
793  StreamBuilder m(this, type, type, type);
794  m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)));
795  Stream s = m.Build();
796  ASSERT_EQ(1U, s.size());
797  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
798  EXPECT_EQ(2U, s[0]->InputCount());
799  EXPECT_EQ(1U, s[0]->OutputCount());
800 }
801 
802 
804  ::testing::ValuesIn(kMulDivInstructions));
805 
806 
807 namespace {
808 
809 struct MulDPInst {
810  const char* mul_constructor_name;
811  Node* (RawMachineAssembler::*mul_constructor)(Node*, Node*);
812  Node* (RawMachineAssembler::*add_constructor)(Node*, Node*);
813  Node* (RawMachineAssembler::*sub_constructor)(Node*, Node*);
818 };
819 
820 
821 std::ostream& operator<<(std::ostream& os, const MulDPInst& inst) {
822  return os << inst.mul_constructor_name;
823 }
824 
825 } // namespace
826 
827 
828 static const MulDPInst kMulDPInstructions[] = {
830  &RawMachineAssembler::Int32Sub, kArm64Madd32, kArm64Msub32, kArm64Mneg32,
831  kMachInt32},
833  &RawMachineAssembler::Int64Sub, kArm64Madd, kArm64Msub, kArm64Mneg,
834  kMachInt64}};
835 
836 
837 typedef InstructionSelectorTestWithParam<MulDPInst>
839 
840 
842  const MulDPInst mdpi = GetParam();
843  const MachineType type = mdpi.machine_type;
844  {
845  StreamBuilder m(this, type, type, type, type);
846  Node* n = (m.*mdpi.mul_constructor)(m.Parameter(1), m.Parameter(2));
847  m.Return((m.*mdpi.add_constructor)(m.Parameter(0), n));
848  Stream s = m.Build();
849  ASSERT_EQ(1U, s.size());
850  EXPECT_EQ(mdpi.add_arch_opcode, s[0]->arch_opcode());
851  EXPECT_EQ(3U, s[0]->InputCount());
852  EXPECT_EQ(1U, s[0]->OutputCount());
853  }
854  {
855  StreamBuilder m(this, type, type, type, type);
856  Node* n = (m.*mdpi.mul_constructor)(m.Parameter(0), m.Parameter(1));
857  m.Return((m.*mdpi.add_constructor)(n, m.Parameter(2)));
858  Stream s = m.Build();
859  ASSERT_EQ(1U, s.size());
860  EXPECT_EQ(mdpi.add_arch_opcode, s[0]->arch_opcode());
861  EXPECT_EQ(3U, s[0]->InputCount());
862  EXPECT_EQ(1U, s[0]->OutputCount());
863  }
864 }
865 
866 
868  const MulDPInst mdpi = GetParam();
869  const MachineType type = mdpi.machine_type;
870  {
871  StreamBuilder m(this, type, type, type, type);
872  Node* n = (m.*mdpi.mul_constructor)(m.Parameter(1), m.Parameter(2));
873  m.Return((m.*mdpi.sub_constructor)(m.Parameter(0), n));
874  Stream s = m.Build();
875  ASSERT_EQ(1U, s.size());
876  EXPECT_EQ(mdpi.sub_arch_opcode, s[0]->arch_opcode());
877  EXPECT_EQ(3U, s[0]->InputCount());
878  EXPECT_EQ(1U, s[0]->OutputCount());
879  }
880 }
881 
882 
884  const MulDPInst mdpi = GetParam();
885  const MachineType type = mdpi.machine_type;
886  {
887  StreamBuilder m(this, type, type, type);
888  Node* n =
889  (m.*mdpi.sub_constructor)(BuildConstant(m, type, 0), m.Parameter(0));
890  m.Return((m.*mdpi.mul_constructor)(n, m.Parameter(1)));
891  Stream s = m.Build();
892  ASSERT_EQ(1U, s.size());
893  EXPECT_EQ(mdpi.neg_arch_opcode, s[0]->arch_opcode());
894  EXPECT_EQ(2U, s[0]->InputCount());
895  EXPECT_EQ(1U, s[0]->OutputCount());
896  }
897  {
898  StreamBuilder m(this, type, type, type);
899  Node* n =
900  (m.*mdpi.sub_constructor)(BuildConstant(m, type, 0), m.Parameter(1));
901  m.Return((m.*mdpi.mul_constructor)(m.Parameter(0), n));
902  Stream s = m.Build();
903  ASSERT_EQ(1U, s.size());
904  EXPECT_EQ(mdpi.neg_arch_opcode, s[0]->arch_opcode());
905  EXPECT_EQ(2U, s[0]->InputCount());
906  EXPECT_EQ(1U, s[0]->OutputCount());
907  }
908 }
909 
910 
913  ::testing::ValuesIn(kMulDPInstructions));
914 
915 
916 // -----------------------------------------------------------------------------
917 // Floating point instructions.
918 
921 
922 
924  const MachInst2 fpa = GetParam();
925  StreamBuilder m(this, fpa.machine_type, fpa.machine_type, fpa.machine_type);
926  m.Return((m.*fpa.constructor)(m.Parameter(0), m.Parameter(1)));
927  Stream s = m.Build();
928  ASSERT_EQ(1U, s.size());
929  EXPECT_EQ(fpa.arch_opcode, s[0]->arch_opcode());
930  EXPECT_EQ(2U, s[0]->InputCount());
931  EXPECT_EQ(1U, s[0]->OutputCount());
932 }
933 
934 
936  ::testing::ValuesIn(kFPArithInstructions));
937 
938 
940 
941 
943  const FPCmp cmp = GetParam();
944  StreamBuilder m(this, kMachInt32, cmp.mi.machine_type, cmp.mi.machine_type);
945  m.Return((m.*cmp.mi.constructor)(m.Parameter(0), m.Parameter(1)));
946  Stream s = m.Build();
947  ASSERT_EQ(1U, s.size());
948  EXPECT_EQ(cmp.mi.arch_opcode, s[0]->arch_opcode());
949  EXPECT_EQ(2U, s[0]->InputCount());
950  EXPECT_EQ(1U, s[0]->OutputCount());
951  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
952  EXPECT_EQ(cmp.cond, s[0]->flags_condition());
953 }
954 
955 
957  ::testing::ValuesIn(kFPCmpInstructions));
958 
959 
960 // -----------------------------------------------------------------------------
961 // Conversions.
962 
965 
966 
968  const Conversion conv = GetParam();
969  StreamBuilder m(this, conv.mi.machine_type, conv.src_machine_type);
970  m.Return((m.*conv.mi.constructor)(m.Parameter(0)));
971  Stream s = m.Build();
972  ASSERT_EQ(1U, s.size());
973  EXPECT_EQ(conv.mi.arch_opcode, s[0]->arch_opcode());
974  EXPECT_EQ(1U, s[0]->InputCount());
975  EXPECT_EQ(1U, s[0]->OutputCount());
976 }
977 
978 
981  ::testing::ValuesIn(kConversionInstructions));
982 
983 
984 // -----------------------------------------------------------------------------
985 // Memory access instructions.
986 
987 
988 namespace {
989 
990 struct MemoryAccess {
994  const int32_t immediates[20];
995 };
996 
997 
998 std::ostream& operator<<(std::ostream& os, const MemoryAccess& memacc) {
999  OStringStream ost;
1000  ost << memacc.type;
1001  return os << ost.c_str();
1002 }
1003 
1004 } // namespace
1005 
1006 
1007 static const MemoryAccess kMemoryAccesses[] = {
1008  {kMachInt8, kArm64Ldrsb, kArm64Strb,
1009  {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 257, 258, 1000, 1001,
1010  2121, 2442, 4093, 4094, 4095}},
1011  {kMachUint8, kArm64Ldrb, kArm64Strb,
1012  {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 257, 258, 1000, 1001,
1013  2121, 2442, 4093, 4094, 4095}},
1014  {kMachInt16, kArm64Ldrsh, kArm64Strh,
1015  {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 258, 260, 4096, 4098,
1016  4100, 4242, 6786, 8188, 8190}},
1017  {kMachUint16, kArm64Ldrh, kArm64Strh,
1018  {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 258, 260, 4096, 4098,
1019  4100, 4242, 6786, 8188, 8190}},
1020  {kMachInt32, kArm64LdrW, kArm64StrW,
1021  {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 260, 4096, 4100, 8192,
1022  8196, 3276, 3280, 16376, 16380}},
1023  {kMachUint32, kArm64LdrW, kArm64StrW,
1024  {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 260, 4096, 4100, 8192,
1025  8196, 3276, 3280, 16376, 16380}},
1026  {kMachInt64, kArm64Ldr, kArm64Str,
1027  {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 264, 4096, 4104, 8192,
1028  8200, 16384, 16392, 32752, 32760}},
1029  {kMachUint64, kArm64Ldr, kArm64Str,
1030  {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 264, 4096, 4104, 8192,
1031  8200, 16384, 16392, 32752, 32760}},
1032  {kMachFloat32, kArm64LdrS, kArm64StrS,
1033  {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 260, 4096, 4100, 8192,
1034  8196, 3276, 3280, 16376, 16380}},
1035  {kMachFloat64, kArm64LdrD, kArm64StrD,
1036  {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 264, 4096, 4104, 8192,
1037  8200, 16384, 16392, 32752, 32760}}};
1038 
1039 
1040 typedef InstructionSelectorTestWithParam<MemoryAccess>
1042 
1043 
1044 TEST_P(InstructionSelectorMemoryAccessTest, LoadWithParameters) {
1045  const MemoryAccess memacc = GetParam();
1046  StreamBuilder m(this, memacc.type, kMachPtr, kMachInt32);
1047  m.Return(m.Load(memacc.type, m.Parameter(0), m.Parameter(1)));
1048  Stream s = m.Build();
1049  ASSERT_EQ(1U, s.size());
1050  EXPECT_EQ(memacc.ldr_opcode, s[0]->arch_opcode());
1051  EXPECT_EQ(kMode_MRR, s[0]->addressing_mode());
1052  EXPECT_EQ(2U, s[0]->InputCount());
1053  EXPECT_EQ(1U, s[0]->OutputCount());
1054 }
1055 
1056 
1057 TEST_P(InstructionSelectorMemoryAccessTest, LoadWithImmediateIndex) {
1058  const MemoryAccess memacc = GetParam();
1059  TRACED_FOREACH(int32_t, index, memacc.immediates) {
1060  StreamBuilder m(this, memacc.type, kMachPtr);
1061  m.Return(m.Load(memacc.type, m.Parameter(0), m.Int32Constant(index)));
1062  Stream s = m.Build();
1063  ASSERT_EQ(1U, s.size());
1064  EXPECT_EQ(memacc.ldr_opcode, s[0]->arch_opcode());
1065  EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
1066  EXPECT_EQ(2U, s[0]->InputCount());
1067  ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
1068  EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
1069  ASSERT_EQ(1U, s[0]->OutputCount());
1070  }
1071 }
1072 
1073 
1074 TEST_P(InstructionSelectorMemoryAccessTest, StoreWithParameters) {
1075  const MemoryAccess memacc = GetParam();
1076  StreamBuilder m(this, kMachInt32, kMachPtr, kMachInt32, memacc.type);
1077  m.Store(memacc.type, m.Parameter(0), m.Parameter(1), m.Parameter(2));
1078  m.Return(m.Int32Constant(0));
1079  Stream s = m.Build();
1080  ASSERT_EQ(1U, s.size());
1081  EXPECT_EQ(memacc.str_opcode, s[0]->arch_opcode());
1082  EXPECT_EQ(kMode_MRR, s[0]->addressing_mode());
1083  EXPECT_EQ(3U, s[0]->InputCount());
1084  EXPECT_EQ(0U, s[0]->OutputCount());
1085 }
1086 
1087 
1088 TEST_P(InstructionSelectorMemoryAccessTest, StoreWithImmediateIndex) {
1089  const MemoryAccess memacc = GetParam();
1090  TRACED_FOREACH(int32_t, index, memacc.immediates) {
1091  StreamBuilder m(this, kMachInt32, kMachPtr, memacc.type);
1092  m.Store(memacc.type, m.Parameter(0), m.Int32Constant(index),
1093  m.Parameter(1));
1094  m.Return(m.Int32Constant(0));
1095  Stream s = m.Build();
1096  ASSERT_EQ(1U, s.size());
1097  EXPECT_EQ(memacc.str_opcode, s[0]->arch_opcode());
1098  EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
1099  ASSERT_EQ(3U, s[0]->InputCount());
1100  ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
1101  EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
1102  EXPECT_EQ(0U, s[0]->OutputCount());
1103  }
1104 }
1105 
1106 
1107 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
1109  ::testing::ValuesIn(kMemoryAccesses));
1110 
1111 
1112 // -----------------------------------------------------------------------------
1113 // Comparison instructions.
1114 
1116  {&RawMachineAssembler::Word32Equal, "Word32Equal", kArm64Cmp32, kMachInt32},
1117  {&RawMachineAssembler::Word64Equal, "Word64Equal", kArm64Cmp, kMachInt64},
1118 };
1119 
1120 
1121 typedef InstructionSelectorTestWithParam<MachInst2>
1123 
1124 
1126  const MachInst2 cmp = GetParam();
1127  const MachineType type = cmp.machine_type;
1128  StreamBuilder m(this, type, type, type);
1129  m.Return((m.*cmp.constructor)(m.Parameter(0), m.Parameter(1)));
1130  Stream s = m.Build();
1131  ASSERT_EQ(1U, s.size());
1132  EXPECT_EQ(cmp.arch_opcode, s[0]->arch_opcode());
1133  EXPECT_EQ(2U, s[0]->InputCount());
1134  EXPECT_EQ(1U, s[0]->OutputCount());
1135  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1136  EXPECT_EQ(kEqual, s[0]->flags_condition());
1137 }
1138 
1139 
1141  const MachInst2 cmp = GetParam();
1142  const MachineType type = cmp.machine_type;
1143  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
1144  // Compare with 0 are turned into tst instruction.
1145  if (imm == 0) continue;
1146  StreamBuilder m(this, type, type);
1147  m.Return((m.*cmp.constructor)(m.Parameter(0), BuildConstant(m, type, imm)));
1148  Stream s = m.Build();
1149  ASSERT_EQ(1U, s.size());
1150  EXPECT_EQ(cmp.arch_opcode, s[0]->arch_opcode());
1151  ASSERT_EQ(2U, s[0]->InputCount());
1152  ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
1153  EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1)));
1154  EXPECT_EQ(1U, s[0]->OutputCount());
1155  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1156  EXPECT_EQ(kEqual, s[0]->flags_condition());
1157  }
1158  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
1159  // Compare with 0 are turned into tst instruction.
1160  if (imm == 0) continue;
1161  StreamBuilder m(this, type, type);
1162  m.Return((m.*cmp.constructor)(BuildConstant(m, type, imm), m.Parameter(0)));
1163  Stream s = m.Build();
1164  ASSERT_EQ(1U, s.size());
1165  EXPECT_EQ(cmp.arch_opcode, s[0]->arch_opcode());
1166  ASSERT_EQ(2U, s[0]->InputCount());
1167  ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
1168  EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1)));
1169  EXPECT_EQ(1U, s[0]->OutputCount());
1170  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1171  EXPECT_EQ(kEqual, s[0]->flags_condition());
1172  }
1173 }
1174 
1177  ::testing::ValuesIn(kComparisonInstructions));
1178 
1179 
1180 TEST_F(InstructionSelectorTest, Word32EqualWithZero) {
1181  {
1182  StreamBuilder m(this, kMachInt32, kMachInt32);
1183  m.Return(m.Word32Equal(m.Parameter(0), m.Int32Constant(0)));
1184  Stream s = m.Build();
1185  ASSERT_EQ(1U, s.size());
1186  EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode());
1187  ASSERT_EQ(2U, s[0]->InputCount());
1188  EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
1189  EXPECT_EQ(1U, s[0]->OutputCount());
1190  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1191  EXPECT_EQ(kEqual, s[0]->flags_condition());
1192  }
1193  {
1194  StreamBuilder m(this, kMachInt32, kMachInt32);
1195  m.Return(m.Word32Equal(m.Int32Constant(0), m.Parameter(0)));
1196  Stream s = m.Build();
1197  ASSERT_EQ(1U, s.size());
1198  EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode());
1199  ASSERT_EQ(2U, s[0]->InputCount());
1200  EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
1201  EXPECT_EQ(1U, s[0]->OutputCount());
1202  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1203  EXPECT_EQ(kEqual, s[0]->flags_condition());
1204  }
1205 }
1206 
1207 
1208 TEST_F(InstructionSelectorTest, Word64EqualWithZero) {
1209  {
1210  StreamBuilder m(this, kMachInt64, kMachInt64);
1211  m.Return(m.Word64Equal(m.Parameter(0), m.Int64Constant(0)));
1212  Stream s = m.Build();
1213  ASSERT_EQ(1U, s.size());
1214  EXPECT_EQ(kArm64Tst, s[0]->arch_opcode());
1215  ASSERT_EQ(2U, s[0]->InputCount());
1216  EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
1217  EXPECT_EQ(1U, s[0]->OutputCount());
1218  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1219  EXPECT_EQ(kEqual, s[0]->flags_condition());
1220  }
1221  {
1222  StreamBuilder m(this, kMachInt64, kMachInt64);
1223  m.Return(m.Word64Equal(m.Int64Constant(0), m.Parameter(0)));
1224  Stream s = m.Build();
1225  ASSERT_EQ(1U, s.size());
1226  EXPECT_EQ(kArm64Tst, s[0]->arch_opcode());
1227  ASSERT_EQ(2U, s[0]->InputCount());
1228  EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
1229  EXPECT_EQ(1U, s[0]->OutputCount());
1230  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1231  EXPECT_EQ(kEqual, s[0]->flags_condition());
1232  }
1233 }
1234 
1235 
1236 // -----------------------------------------------------------------------------
1237 // Miscellaneous
1238 
1239 
1240 static const MachInst2 kLogicalWithNotRHSs[] = {
1241  {&RawMachineAssembler::Word32And, "Word32And", kArm64Bic32, kMachInt32},
1242  {&RawMachineAssembler::Word64And, "Word64And", kArm64Bic, kMachInt64},
1243  {&RawMachineAssembler::Word32Or, "Word32Or", kArm64Orn32, kMachInt32},
1244  {&RawMachineAssembler::Word64Or, "Word64Or", kArm64Orn, kMachInt64},
1245  {&RawMachineAssembler::Word32Xor, "Word32Xor", kArm64Eon32, kMachInt32},
1246  {&RawMachineAssembler::Word64Xor, "Word64Xor", kArm64Eon, kMachInt64}};
1247 
1248 
1249 typedef InstructionSelectorTestWithParam<MachInst2>
1251 
1252 
1254  const MachInst2 inst = GetParam();
1255  const MachineType type = inst.machine_type;
1256  // Test cases where RHS is Xor(x, -1).
1257  {
1258  StreamBuilder m(this, type, type, type);
1259  if (type == kMachInt32) {
1260  m.Return((m.*inst.constructor)(
1261  m.Parameter(0), m.Word32Xor(m.Parameter(1), m.Int32Constant(-1))));
1262  } else {
1263  ASSERT_EQ(kMachInt64, type);
1264  m.Return((m.*inst.constructor)(
1265  m.Parameter(0), m.Word64Xor(m.Parameter(1), m.Int64Constant(-1))));
1266  }
1267  Stream s = m.Build();
1268  ASSERT_EQ(1U, s.size());
1269  EXPECT_EQ(inst.arch_opcode, s[0]->arch_opcode());
1270  EXPECT_EQ(2U, s[0]->InputCount());
1271  EXPECT_EQ(1U, s[0]->OutputCount());
1272  }
1273  {
1274  StreamBuilder m(this, type, type, type);
1275  if (type == kMachInt32) {
1276  m.Return((m.*inst.constructor)(
1277  m.Word32Xor(m.Parameter(0), m.Int32Constant(-1)), m.Parameter(1)));
1278  } else {
1279  ASSERT_EQ(kMachInt64, type);
1280  m.Return((m.*inst.constructor)(
1281  m.Word64Xor(m.Parameter(0), m.Int64Constant(-1)), m.Parameter(1)));
1282  }
1283  Stream s = m.Build();
1284  ASSERT_EQ(1U, s.size());
1285  EXPECT_EQ(inst.arch_opcode, s[0]->arch_opcode());
1286  EXPECT_EQ(2U, s[0]->InputCount());
1287  EXPECT_EQ(1U, s[0]->OutputCount());
1288  }
1289  // Test cases where RHS is Not(x).
1290  {
1291  StreamBuilder m(this, type, type, type);
1292  if (type == kMachInt32) {
1293  m.Return(
1294  (m.*inst.constructor)(m.Parameter(0), m.Word32Not(m.Parameter(1))));
1295  } else {
1296  ASSERT_EQ(kMachInt64, type);
1297  m.Return(
1298  (m.*inst.constructor)(m.Parameter(0), m.Word64Not(m.Parameter(1))));
1299  }
1300  Stream s = m.Build();
1301  ASSERT_EQ(1U, s.size());
1302  EXPECT_EQ(inst.arch_opcode, s[0]->arch_opcode());
1303  EXPECT_EQ(2U, s[0]->InputCount());
1304  EXPECT_EQ(1U, s[0]->OutputCount());
1305  }
1306  {
1307  StreamBuilder m(this, type, type, type);
1308  if (type == kMachInt32) {
1309  m.Return(
1310  (m.*inst.constructor)(m.Word32Not(m.Parameter(0)), m.Parameter(1)));
1311  } else {
1312  ASSERT_EQ(kMachInt64, type);
1313  m.Return(
1314  (m.*inst.constructor)(m.Word64Not(m.Parameter(0)), m.Parameter(1)));
1315  }
1316  Stream s = m.Build();
1317  ASSERT_EQ(1U, s.size());
1318  EXPECT_EQ(inst.arch_opcode, s[0]->arch_opcode());
1319  EXPECT_EQ(2U, s[0]->InputCount());
1320  EXPECT_EQ(1U, s[0]->OutputCount());
1321  }
1322 }
1323 
1324 
1327  ::testing::ValuesIn(kLogicalWithNotRHSs));
1328 
1329 
1330 TEST_F(InstructionSelectorTest, Word32NotWithParameter) {
1331  StreamBuilder m(this, kMachInt32, kMachInt32);
1332  m.Return(m.Word32Not(m.Parameter(0)));
1333  Stream s = m.Build();
1334  ASSERT_EQ(1U, s.size());
1335  EXPECT_EQ(kArm64Not32, s[0]->arch_opcode());
1336  EXPECT_EQ(1U, s[0]->InputCount());
1337  EXPECT_EQ(1U, s[0]->OutputCount());
1338 }
1339 
1340 
1341 TEST_F(InstructionSelectorTest, Word64NotWithParameter) {
1342  StreamBuilder m(this, kMachInt64, kMachInt64);
1343  m.Return(m.Word64Not(m.Parameter(0)));
1344  Stream s = m.Build();
1345  ASSERT_EQ(1U, s.size());
1346  EXPECT_EQ(kArm64Not, s[0]->arch_opcode());
1347  EXPECT_EQ(1U, s[0]->InputCount());
1348  EXPECT_EQ(1U, s[0]->OutputCount());
1349 }
1350 
1351 
1352 TEST_F(InstructionSelectorTest, Word32XorMinusOneWithParameter) {
1353  {
1354  StreamBuilder m(this, kMachInt32, kMachInt32);
1355  m.Return(m.Word32Xor(m.Parameter(0), m.Int32Constant(-1)));
1356  Stream s = m.Build();
1357  ASSERT_EQ(1U, s.size());
1358  EXPECT_EQ(kArm64Not32, s[0]->arch_opcode());
1359  EXPECT_EQ(1U, s[0]->InputCount());
1360  EXPECT_EQ(1U, s[0]->OutputCount());
1361  }
1362  {
1363  StreamBuilder m(this, kMachInt32, kMachInt32);
1364  m.Return(m.Word32Xor(m.Int32Constant(-1), m.Parameter(0)));
1365  Stream s = m.Build();
1366  ASSERT_EQ(1U, s.size());
1367  EXPECT_EQ(kArm64Not32, s[0]->arch_opcode());
1368  EXPECT_EQ(1U, s[0]->InputCount());
1369  EXPECT_EQ(1U, s[0]->OutputCount());
1370  }
1371 }
1372 
1373 
1374 TEST_F(InstructionSelectorTest, Word64XorMinusOneWithParameter) {
1375  {
1376  StreamBuilder m(this, kMachInt64, kMachInt64);
1377  m.Return(m.Word64Xor(m.Parameter(0), m.Int64Constant(-1)));
1378  Stream s = m.Build();
1379  ASSERT_EQ(1U, s.size());
1380  EXPECT_EQ(kArm64Not, s[0]->arch_opcode());
1381  EXPECT_EQ(1U, s[0]->InputCount());
1382  EXPECT_EQ(1U, s[0]->OutputCount());
1383  }
1384  {
1385  StreamBuilder m(this, kMachInt64, kMachInt64);
1386  m.Return(m.Word64Xor(m.Int64Constant(-1), m.Parameter(0)));
1387  Stream s = m.Build();
1388  ASSERT_EQ(1U, s.size());
1389  EXPECT_EQ(kArm64Not, s[0]->arch_opcode());
1390  EXPECT_EQ(1U, s[0]->InputCount());
1391  EXPECT_EQ(1U, s[0]->OutputCount());
1392  }
1393 }
1394 
1395 } // namespace compiler
1396 } // namespace internal
1397 } // namespace v8
const char * c_str() const
Definition: ostreams.h:84
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be NULL
#define UNIMPLEMENTED()
Definition: logging.h:28
int int32_t
Definition: unicode.cc:24
Node * BuildConstant(InstructionSelectorTest::StreamBuilder &m, MachineType type, int64_t value)
InstructionSelectorTestWithParam< Shift > InstructionSelectorShiftTest
InstructionSelectorTestWithParam< FPCmp > InstructionSelectorFPCmpTest
std::ostream & operator<<(std::ostream &os, const MachineType &type)
InstructionSelectorTestWithParam< MachInst2 > InstructionSelectorLogicalWithNotRHSTest
InstructionSelectorTestWithParam< MachInst2 > InstructionSelectorDPFlagSetTest
InstructionSelectorTestWithParam< MachInst2 > InstructionSelectorComparisonTest
InstructionSelectorTestWithParam< MachInst2 > InstructionSelectorMulDivTest
static const MemoryAccess kMemoryAccesses[]
InstructionSelectorTestWithParam< MachInst2 > InstructionSelectorFPArithTest
TEST_P(InstructionSelectorDPITest, Parameters)
InstructionSelectorTestWithParam< MachInst2 > InstructionSelectorLogicalTest
InstructionSelectorTestWithParam< MemoryAccess > InstructionSelectorMemoryAccessTest
INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorDPITest, ::testing::ValuesIn(kDPIs))
InstructionSelectorTestWithParam< MulDPInst > InstructionSelectorIntDPWithIntMulTest
InstructionSelectorTestWithParam< Conversion > InstructionSelectorConversionTest
TEST_F(InstructionSelectorTest, ChangeFloat32ToFloat64WithParameter)
InstructionSelectorTestWithParam< MachInst2 > InstructionSelectorOvfAddSubTest
int ElementSizeOf(MachineType machine_type)
Definition: machine-type.h:83
InstructionSelectorTestWithParam< MachInst2 > InstructionSelectorAddSubTest
static const MachInst2 kComparisonInstructions[]
Debugger support for the V8 JavaScript engine.
Definition: accessors.cc:20
#define T(name, string, precedence)
Definition: token.cc:25