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 "src/common/globals.h"
6 #include "src/objects/objects-inl.h"
7 #include "test/unittests/compiler/backend/instruction-selector-unittest.h"
8 
9 namespace v8 {
10 namespace internal {
11 namespace compiler {
12 
13 namespace {
14 
15 template <typename T>
16 struct MachInst {
17   T constructor;
18   const char* constructor_name;
19   ArchOpcode arch_opcode;
20   MachineType machine_type;
21 };
22 
23 using MachInst1 = MachInst<Node* (RawMachineAssembler::*)(Node*)>;
24 using MachInst2 = MachInst<Node* (RawMachineAssembler::*)(Node*, Node*)>;
25 
26 template <typename T>
operator <<(std::ostream & os,const MachInst<T> & mi)27 std::ostream& operator<<(std::ostream& os, const MachInst<T>& mi) {
28   return os << mi.constructor_name;
29 }
30 
31 struct Shift {
32   MachInst2 mi;
33   AddressingMode mode;
34 };
35 
operator <<(std::ostream & os,const Shift & shift)36 std::ostream& operator<<(std::ostream& os, const Shift& shift) {
37   return os << shift.mi;
38 }
39 
40 // Helper to build Int32Constant or Int64Constant depending on the given
41 // machine type.
BuildConstant(InstructionSelectorTest::StreamBuilder * m,MachineType type,int64_t value)42 Node* BuildConstant(InstructionSelectorTest::StreamBuilder* m, MachineType type,
43                     int64_t value) {
44   switch (type.representation()) {
45     case MachineRepresentation::kWord32:
46       return m->Int32Constant(static_cast<int32_t>(value));
47 
48     case MachineRepresentation::kWord64:
49       return m->Int64Constant(value);
50 
51     default:
52       UNIMPLEMENTED();
53   }
54   return NULL;
55 }
56 
57 // ARM64 logical instructions.
58 const MachInst2 kLogicalInstructions[] = {
59     {&RawMachineAssembler::Word32And, "Word32And", kArm64And32,
60      MachineType::Int32()},
61     {&RawMachineAssembler::Word64And, "Word64And", kArm64And,
62      MachineType::Int64()},
63     {&RawMachineAssembler::Word32Or, "Word32Or", kArm64Or32,
64      MachineType::Int32()},
65     {&RawMachineAssembler::Word64Or, "Word64Or", kArm64Or,
66      MachineType::Int64()},
67     {&RawMachineAssembler::Word32Xor, "Word32Xor", kArm64Eor32,
68      MachineType::Int32()},
69     {&RawMachineAssembler::Word64Xor, "Word64Xor", kArm64Eor,
70      MachineType::Int64()}};
71 
72 // ARM64 logical immediates: contiguous set bits, rotated about a power of two
73 // sized block. The block is then duplicated across the word. Below is a random
74 // subset of the 32-bit immediates.
75 const uint32_t kLogical32Immediates[] = {
76     0x00000002, 0x00000003, 0x00000070, 0x00000080, 0x00000100, 0x000001C0,
77     0x00000300, 0x000007E0, 0x00003FFC, 0x00007FC0, 0x0003C000, 0x0003F000,
78     0x0003FFC0, 0x0003FFF8, 0x0007FF00, 0x0007FFE0, 0x000E0000, 0x001E0000,
79     0x001FFFFC, 0x003F0000, 0x003F8000, 0x00780000, 0x007FC000, 0x00FF0000,
80     0x01800000, 0x01800180, 0x01F801F8, 0x03FE0000, 0x03FFFFC0, 0x03FFFFFC,
81     0x06000000, 0x07FC0000, 0x07FFC000, 0x07FFFFC0, 0x07FFFFE0, 0x0FFE0FFE,
82     0x0FFFF800, 0x0FFFFFF0, 0x0FFFFFFF, 0x18001800, 0x1F001F00, 0x1F801F80,
83     0x30303030, 0x3FF03FF0, 0x3FF83FF8, 0x3FFF0000, 0x3FFF8000, 0x3FFFFFC0,
84     0x70007000, 0x7F7F7F7F, 0x7FC00000, 0x7FFFFFC0, 0x8000001F, 0x800001FF,
85     0x81818181, 0x9FFF9FFF, 0xC00007FF, 0xC0FFFFFF, 0xDDDDDDDD, 0xE00001FF,
86     0xE00003FF, 0xE007FFFF, 0xEFFFEFFF, 0xF000003F, 0xF001F001, 0xF3FFF3FF,
87     0xF800001F, 0xF80FFFFF, 0xF87FF87F, 0xFBFBFBFB, 0xFC00001F, 0xFC0000FF,
88     0xFC0001FF, 0xFC03FC03, 0xFE0001FF, 0xFF000001, 0xFF03FF03, 0xFF800000,
89     0xFF800FFF, 0xFF801FFF, 0xFF87FFFF, 0xFFC0003F, 0xFFC007FF, 0xFFCFFFCF,
90     0xFFE00003, 0xFFE1FFFF, 0xFFF0001F, 0xFFF07FFF, 0xFFF80007, 0xFFF87FFF,
91     0xFFFC00FF, 0xFFFE07FF, 0xFFFF00FF, 0xFFFFC001, 0xFFFFF007, 0xFFFFF3FF,
92     0xFFFFF807, 0xFFFFF9FF, 0xFFFFFC0F, 0xFFFFFEFF};
93 
94 // Random subset of 64-bit logical immediates.
95 const uint64_t kLogical64Immediates[] = {
96     0x0000000000000001, 0x0000000000000002, 0x0000000000000003,
97     0x0000000000000070, 0x0000000000000080, 0x0000000000000100,
98     0x00000000000001C0, 0x0000000000000300, 0x0000000000000600,
99     0x00000000000007E0, 0x0000000000003FFC, 0x0000000000007FC0,
100     0x0000000600000000, 0x0000003FFFFFFFFC, 0x000000F000000000,
101     0x000001F800000000, 0x0003FC0000000000, 0x0003FC000003FC00,
102     0x0003FFFFFFC00000, 0x0003FFFFFFFFFFC0, 0x0006000000060000,
103     0x003FFFFFFFFC0000, 0x0180018001800180, 0x01F801F801F801F8,
104     0x0600000000000000, 0x1000000010000000, 0x1000100010001000,
105     0x1010101010101010, 0x1111111111111111, 0x1F001F001F001F00,
106     0x1F1F1F1F1F1F1F1F, 0x1FFFFFFFFFFFFFFE, 0x3FFC3FFC3FFC3FFC,
107     0x5555555555555555, 0x7F7F7F7F7F7F7F7F, 0x8000000000000000,
108     0x8000001F8000001F, 0x8181818181818181, 0x9999999999999999,
109     0x9FFF9FFF9FFF9FFF, 0xAAAAAAAAAAAAAAAA, 0xDDDDDDDDDDDDDDDD,
110     0xE0000000000001FF, 0xF800000000000000, 0xF8000000000001FF,
111     0xF807F807F807F807, 0xFEFEFEFEFEFEFEFE, 0xFFFEFFFEFFFEFFFE,
112     0xFFFFF807FFFFF807, 0xFFFFF9FFFFFFF9FF, 0xFFFFFC0FFFFFFC0F,
113     0xFFFFFC0FFFFFFFFF, 0xFFFFFEFFFFFFFEFF, 0xFFFFFEFFFFFFFFFF,
114     0xFFFFFF8000000000, 0xFFFFFFFEFFFFFFFE, 0xFFFFFFFFEFFFFFFF,
115     0xFFFFFFFFF9FFFFFF, 0xFFFFFFFFFF800000, 0xFFFFFFFFFFFFC0FF,
116     0xFFFFFFFFFFFFFFFE};
117 
118 // ARM64 arithmetic instructions.
119 struct AddSub {
120   MachInst2 mi;
121   ArchOpcode negate_arch_opcode;
122 };
123 
operator <<(std::ostream & os,const AddSub & op)124 std::ostream& operator<<(std::ostream& os, const AddSub& op) {
125   return os << op.mi;
126 }
127 
128 const AddSub kAddSubInstructions[] = {
129     {{&RawMachineAssembler::Int32Add, "Int32Add", kArm64Add32,
130       MachineType::Int32()},
131      kArm64Sub32},
132     {{&RawMachineAssembler::Int64Add, "Int64Add", kArm64Add,
133       MachineType::Int64()},
134      kArm64Sub},
135     {{&RawMachineAssembler::Int32Sub, "Int32Sub", kArm64Sub32,
136       MachineType::Int32()},
137      kArm64Add32},
138     {{&RawMachineAssembler::Int64Sub, "Int64Sub", kArm64Sub,
139       MachineType::Int64()},
140      kArm64Add}};
141 
142 // ARM64 Add/Sub immediates: 12-bit immediate optionally shifted by 12.
143 // Below is a combination of a random subset and some edge values.
144 const int32_t kAddSubImmediates[] = {
145     0,        1,        69,       493,      599,      701,      719,
146     768,      818,      842,      945,      1246,     1286,     1429,
147     1669,     2171,     2179,     2182,     2254,     2334,     2338,
148     2343,     2396,     2449,     2610,     2732,     2855,     2876,
149     2944,     3377,     3458,     3475,     3476,     3540,     3574,
150     3601,     3813,     3871,     3917,     4095,     4096,     16384,
151     364544,   462848,   970752,   1523712,  1863680,  2363392,  3219456,
152     3280896,  4247552,  4526080,  4575232,  4960256,  5505024,  5894144,
153     6004736,  6193152,  6385664,  6795264,  7114752,  7233536,  7348224,
154     7499776,  7573504,  7729152,  8634368,  8937472,  9465856,  10354688,
155     10682368, 11059200, 11460608, 13168640, 13176832, 14336000, 15028224,
156     15597568, 15892480, 16773120};
157 
158 // ARM64 flag setting data processing instructions.
159 const MachInst2 kDPFlagSetInstructions[] = {
160     {&RawMachineAssembler::Word32And, "Word32And", kArm64Tst32,
161      MachineType::Int32()},
162     {&RawMachineAssembler::Int32Add, "Int32Add", kArm64Cmn32,
163      MachineType::Int32()},
164     {&RawMachineAssembler::Int32Sub, "Int32Sub", kArm64Cmp32,
165      MachineType::Int32()},
166     {&RawMachineAssembler::Word64And, "Word64And", kArm64Tst,
167      MachineType::Int64()}};
168 
169 // ARM64 arithmetic with overflow instructions.
170 const MachInst2 kOvfAddSubInstructions[] = {
171     {&RawMachineAssembler::Int32AddWithOverflow, "Int32AddWithOverflow",
172      kArm64Add32, MachineType::Int32()},
173     {&RawMachineAssembler::Int32SubWithOverflow, "Int32SubWithOverflow",
174      kArm64Sub32, MachineType::Int32()},
175     {&RawMachineAssembler::Int64AddWithOverflow, "Int64AddWithOverflow",
176      kArm64Add, MachineType::Int64()},
177     {&RawMachineAssembler::Int64SubWithOverflow, "Int64SubWithOverflow",
178      kArm64Sub, MachineType::Int64()}};
179 
180 // ARM64 shift instructions.
181 const Shift kShiftInstructions[] = {
182     {{&RawMachineAssembler::Word32Shl, "Word32Shl", kArm64Lsl32,
183       MachineType::Int32()},
184      kMode_Operand2_R_LSL_I},
185     {{&RawMachineAssembler::Word64Shl, "Word64Shl", kArm64Lsl,
186       MachineType::Int64()},
187      kMode_Operand2_R_LSL_I},
188     {{&RawMachineAssembler::Word32Shr, "Word32Shr", kArm64Lsr32,
189       MachineType::Int32()},
190      kMode_Operand2_R_LSR_I},
191     {{&RawMachineAssembler::Word64Shr, "Word64Shr", kArm64Lsr,
192       MachineType::Int64()},
193      kMode_Operand2_R_LSR_I},
194     {{&RawMachineAssembler::Word32Sar, "Word32Sar", kArm64Asr32,
195       MachineType::Int32()},
196      kMode_Operand2_R_ASR_I},
197     {{&RawMachineAssembler::Word64Sar, "Word64Sar", kArm64Asr,
198       MachineType::Int64()},
199      kMode_Operand2_R_ASR_I},
200     {{&RawMachineAssembler::Word32Ror, "Word32Ror", kArm64Ror32,
201       MachineType::Int32()},
202      kMode_Operand2_R_ROR_I},
203     {{&RawMachineAssembler::Word64Ror, "Word64Ror", kArm64Ror,
204       MachineType::Int64()},
205      kMode_Operand2_R_ROR_I}};
206 
207 // ARM64 Mul/Div instructions.
208 const MachInst2 kMulDivInstructions[] = {
209     {&RawMachineAssembler::Int32Mul, "Int32Mul", kArm64Mul32,
210      MachineType::Int32()},
211     {&RawMachineAssembler::Int64Mul, "Int64Mul", kArm64Mul,
212      MachineType::Int64()},
213     {&RawMachineAssembler::Int32Div, "Int32Div", kArm64Idiv32,
214      MachineType::Int32()},
215     {&RawMachineAssembler::Int64Div, "Int64Div", kArm64Idiv,
216      MachineType::Int64()},
217     {&RawMachineAssembler::Uint32Div, "Uint32Div", kArm64Udiv32,
218      MachineType::Int32()},
219     {&RawMachineAssembler::Uint64Div, "Uint64Div", kArm64Udiv,
220      MachineType::Int64()}};
221 
222 // ARM64 FP arithmetic instructions.
223 const MachInst2 kFPArithInstructions[] = {
224     {&RawMachineAssembler::Float64Add, "Float64Add", kArm64Float64Add,
225      MachineType::Float64()},
226     {&RawMachineAssembler::Float64Sub, "Float64Sub", kArm64Float64Sub,
227      MachineType::Float64()},
228     {&RawMachineAssembler::Float64Mul, "Float64Mul", kArm64Float64Mul,
229      MachineType::Float64()},
230     {&RawMachineAssembler::Float64Div, "Float64Div", kArm64Float64Div,
231      MachineType::Float64()}};
232 
233 struct FPCmp {
234   MachInst2 mi;
235   FlagsCondition cond;
236   FlagsCondition commuted_cond;
237 };
238 
operator <<(std::ostream & os,const FPCmp & cmp)239 std::ostream& operator<<(std::ostream& os, const FPCmp& cmp) {
240   return os << cmp.mi;
241 }
242 
243 // ARM64 FP comparison instructions.
244 const FPCmp kFPCmpInstructions[] = {
245     {{&RawMachineAssembler::Float64Equal, "Float64Equal", kArm64Float64Cmp,
246       MachineType::Float64()},
247      kEqual,
248      kEqual},
249     {{&RawMachineAssembler::Float64LessThan, "Float64LessThan",
250       kArm64Float64Cmp, MachineType::Float64()},
251      kFloatLessThan,
252      kFloatGreaterThan},
253     {{&RawMachineAssembler::Float64LessThanOrEqual, "Float64LessThanOrEqual",
254       kArm64Float64Cmp, MachineType::Float64()},
255      kFloatLessThanOrEqual,
256      kFloatGreaterThanOrEqual},
257     {{&RawMachineAssembler::Float32Equal, "Float32Equal", kArm64Float32Cmp,
258       MachineType::Float32()},
259      kEqual,
260      kEqual},
261     {{&RawMachineAssembler::Float32LessThan, "Float32LessThan",
262       kArm64Float32Cmp, MachineType::Float32()},
263      kFloatLessThan,
264      kFloatGreaterThan},
265     {{&RawMachineAssembler::Float32LessThanOrEqual, "Float32LessThanOrEqual",
266       kArm64Float32Cmp, MachineType::Float32()},
267      kFloatLessThanOrEqual,
268      kFloatGreaterThanOrEqual}};
269 
270 struct Conversion {
271   // The machine_type field in MachInst1 represents the destination type.
272   MachInst1 mi;
273   MachineType src_machine_type;
274 };
275 
operator <<(std::ostream & os,const Conversion & conv)276 std::ostream& operator<<(std::ostream& os, const Conversion& conv) {
277   return os << conv.mi;
278 }
279 
280 // ARM64 type conversion instructions.
281 const Conversion kConversionInstructions[] = {
282     {{&RawMachineAssembler::ChangeFloat32ToFloat64, "ChangeFloat32ToFloat64",
283       kArm64Float32ToFloat64, MachineType::Float64()},
284      MachineType::Float32()},
285     {{&RawMachineAssembler::TruncateFloat64ToFloat32,
286       "TruncateFloat64ToFloat32", kArm64Float64ToFloat32,
287       MachineType::Float32()},
288      MachineType::Float64()},
289     {{&RawMachineAssembler::ChangeInt32ToInt64, "ChangeInt32ToInt64",
290       kArm64Sxtw, MachineType::Int64()},
291      MachineType::Int32()},
292     {{&RawMachineAssembler::ChangeUint32ToUint64, "ChangeUint32ToUint64",
293       kArm64Mov32, MachineType::Uint64()},
294      MachineType::Uint32()},
295     {{&RawMachineAssembler::TruncateInt64ToInt32, "TruncateInt64ToInt32",
296       kArchNop, MachineType::Int32()},
297      MachineType::Int64()},
298     {{&RawMachineAssembler::ChangeInt32ToFloat64, "ChangeInt32ToFloat64",
299       kArm64Int32ToFloat64, MachineType::Float64()},
300      MachineType::Int32()},
301     {{&RawMachineAssembler::ChangeUint32ToFloat64, "ChangeUint32ToFloat64",
302       kArm64Uint32ToFloat64, MachineType::Float64()},
303      MachineType::Uint32()},
304     {{&RawMachineAssembler::ChangeFloat64ToInt32, "ChangeFloat64ToInt32",
305       kArm64Float64ToInt32, MachineType::Int32()},
306      MachineType::Float64()},
307     {{&RawMachineAssembler::ChangeFloat64ToUint32, "ChangeFloat64ToUint32",
308       kArm64Float64ToUint32, MachineType::Uint32()},
309      MachineType::Float64()}};
310 
311 // ARM64 instructions that clear the top 32 bits of the destination.
312 const MachInst2 kCanElideChangeUint32ToUint64[] = {
313     {&RawMachineAssembler::Word32And, "Word32And", kArm64And32,
314      MachineType::Uint32()},
315     {&RawMachineAssembler::Word32Or, "Word32Or", kArm64Or32,
316      MachineType::Uint32()},
317     {&RawMachineAssembler::Word32Xor, "Word32Xor", kArm64Eor32,
318      MachineType::Uint32()},
319     {&RawMachineAssembler::Word32Shl, "Word32Shl", kArm64Lsl32,
320      MachineType::Uint32()},
321     {&RawMachineAssembler::Word32Shr, "Word32Shr", kArm64Lsr32,
322      MachineType::Uint32()},
323     {&RawMachineAssembler::Word32Sar, "Word32Sar", kArm64Asr32,
324      MachineType::Uint32()},
325     {&RawMachineAssembler::Word32Ror, "Word32Ror", kArm64Ror32,
326      MachineType::Uint32()},
327     {&RawMachineAssembler::Word32Equal, "Word32Equal", kArm64Cmp32,
328      MachineType::Uint32()},
329     {&RawMachineAssembler::Int32Add, "Int32Add", kArm64Add32,
330      MachineType::Int32()},
331     {&RawMachineAssembler::Int32AddWithOverflow, "Int32AddWithOverflow",
332      kArm64Add32, MachineType::Int32()},
333     {&RawMachineAssembler::Int32Sub, "Int32Sub", kArm64Sub32,
334      MachineType::Int32()},
335     {&RawMachineAssembler::Int32SubWithOverflow, "Int32SubWithOverflow",
336      kArm64Sub32, MachineType::Int32()},
337     {&RawMachineAssembler::Int32Mul, "Int32Mul", kArm64Mul32,
338      MachineType::Int32()},
339     {&RawMachineAssembler::Int32Div, "Int32Div", kArm64Idiv32,
340      MachineType::Int32()},
341     {&RawMachineAssembler::Int32Mod, "Int32Mod", kArm64Imod32,
342      MachineType::Int32()},
343     {&RawMachineAssembler::Int32LessThan, "Int32LessThan", kArm64Cmp32,
344      MachineType::Int32()},
345     {&RawMachineAssembler::Int32LessThanOrEqual, "Int32LessThanOrEqual",
346      kArm64Cmp32, MachineType::Int32()},
347     {&RawMachineAssembler::Uint32Div, "Uint32Div", kArm64Udiv32,
348      MachineType::Uint32()},
349     {&RawMachineAssembler::Uint32LessThan, "Uint32LessThan", kArm64Cmp32,
350      MachineType::Uint32()},
351     {&RawMachineAssembler::Uint32LessThanOrEqual, "Uint32LessThanOrEqual",
352      kArm64Cmp32, MachineType::Uint32()},
353     {&RawMachineAssembler::Uint32Mod, "Uint32Mod", kArm64Umod32,
354      MachineType::Uint32()},
355 };
356 
357 // -----------------------------------------------------------------------------
358 // Logical instructions.
359 
360 using InstructionSelectorLogicalTest =
361     InstructionSelectorTestWithParam<MachInst2>;
362 
TEST_P(InstructionSelectorLogicalTest,Parameter)363 TEST_P(InstructionSelectorLogicalTest, Parameter) {
364   const MachInst2 dpi = GetParam();
365   const MachineType type = dpi.machine_type;
366   StreamBuilder m(this, type, type, type);
367   m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)));
368   Stream s = m.Build();
369   ASSERT_EQ(1U, s.size());
370   EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
371   EXPECT_EQ(2U, s[0]->InputCount());
372   EXPECT_EQ(1U, s[0]->OutputCount());
373 }
374 
TEST_P(InstructionSelectorLogicalTest,Immediate)375 TEST_P(InstructionSelectorLogicalTest, Immediate) {
376   const MachInst2 dpi = GetParam();
377   const MachineType type = dpi.machine_type;
378   if (type == MachineType::Int32()) {
379     // Immediate on the right.
380     TRACED_FOREACH(int32_t, imm, kLogical32Immediates) {
381       StreamBuilder m(this, type, type);
382       m.Return((m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm)));
383       Stream s = m.Build();
384       ASSERT_EQ(1U, s.size());
385       EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
386       ASSERT_EQ(2U, s[0]->InputCount());
387       EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
388       EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
389       EXPECT_EQ(1U, s[0]->OutputCount());
390     }
391 
392     // Immediate on the left; all logical ops should commute.
393     TRACED_FOREACH(int32_t, imm, kLogical32Immediates) {
394       StreamBuilder m(this, type, type);
395       m.Return((m.*dpi.constructor)(m.Int32Constant(imm), m.Parameter(0)));
396       Stream s = m.Build();
397       ASSERT_EQ(1U, s.size());
398       EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
399       ASSERT_EQ(2U, s[0]->InputCount());
400       EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
401       EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
402       EXPECT_EQ(1U, s[0]->OutputCount());
403     }
404   } else if (type == MachineType::Int64()) {
405     // Immediate on the right.
406     TRACED_FOREACH(int64_t, imm, kLogical64Immediates) {
407       StreamBuilder m(this, type, type);
408       m.Return((m.*dpi.constructor)(m.Parameter(0), m.Int64Constant(imm)));
409       Stream s = m.Build();
410       ASSERT_EQ(1U, s.size());
411       EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
412       ASSERT_EQ(2U, s[0]->InputCount());
413       EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
414       EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1)));
415       EXPECT_EQ(1U, s[0]->OutputCount());
416     }
417 
418     // Immediate on the left; all logical ops should commute.
419     TRACED_FOREACH(int64_t, imm, kLogical64Immediates) {
420       StreamBuilder m(this, type, type);
421       m.Return((m.*dpi.constructor)(m.Int64Constant(imm), m.Parameter(0)));
422       Stream s = m.Build();
423       ASSERT_EQ(1U, s.size());
424       EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
425       ASSERT_EQ(2U, s[0]->InputCount());
426       EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
427       EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1)));
428       EXPECT_EQ(1U, s[0]->OutputCount());
429     }
430   }
431 }
432 
TEST_P(InstructionSelectorLogicalTest,ShiftByImmediate)433 TEST_P(InstructionSelectorLogicalTest, ShiftByImmediate) {
434   const MachInst2 dpi = GetParam();
435   const MachineType type = dpi.machine_type;
436   TRACED_FOREACH(Shift, shift, kShiftInstructions) {
437     // Only test 64-bit shifted operands with 64-bit instructions.
438     if (shift.mi.machine_type != type) continue;
439 
440     TRACED_FORRANGE(int, imm, 0, ((type == MachineType::Int32()) ? 31 : 63)) {
441       StreamBuilder m(this, type, type, type);
442       m.Return((m.*dpi.constructor)(
443           m.Parameter(0), (m.*shift.mi.constructor)(
444                               m.Parameter(1), BuildConstant(&m, type, imm))));
445       Stream s = m.Build();
446       ASSERT_EQ(1U, s.size());
447       EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
448       EXPECT_EQ(shift.mode, s[0]->addressing_mode());
449       EXPECT_EQ(3U, s[0]->InputCount());
450       EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(2)));
451       EXPECT_EQ(1U, s[0]->OutputCount());
452     }
453 
454     TRACED_FORRANGE(int, imm, 0, ((type == MachineType::Int32()) ? 31 : 63)) {
455       StreamBuilder m(this, type, type, type);
456       m.Return((m.*dpi.constructor)(
457           (m.*shift.mi.constructor)(m.Parameter(1),
458                                     BuildConstant(&m, type, imm)),
459           m.Parameter(0)));
460       Stream s = m.Build();
461       ASSERT_EQ(1U, s.size());
462       EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
463       EXPECT_EQ(shift.mode, s[0]->addressing_mode());
464       EXPECT_EQ(3U, s[0]->InputCount());
465       EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(2)));
466       EXPECT_EQ(1U, s[0]->OutputCount());
467     }
468   }
469 }
470 
471 INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest,
472                          InstructionSelectorLogicalTest,
473                          ::testing::ValuesIn(kLogicalInstructions));
474 
475 // -----------------------------------------------------------------------------
476 // Add and Sub instructions.
477 
478 using InstructionSelectorAddSubTest = InstructionSelectorTestWithParam<AddSub>;
479 
TEST_P(InstructionSelectorAddSubTest,Parameter)480 TEST_P(InstructionSelectorAddSubTest, Parameter) {
481   const AddSub dpi = GetParam();
482   const MachineType type = dpi.mi.machine_type;
483   StreamBuilder m(this, type, type, type);
484   m.Return((m.*dpi.mi.constructor)(m.Parameter(0), m.Parameter(1)));
485   Stream s = m.Build();
486   ASSERT_EQ(1U, s.size());
487   EXPECT_EQ(dpi.mi.arch_opcode, s[0]->arch_opcode());
488   EXPECT_EQ(2U, s[0]->InputCount());
489   EXPECT_EQ(1U, s[0]->OutputCount());
490 }
491 
TEST_P(InstructionSelectorAddSubTest,ImmediateOnRight)492 TEST_P(InstructionSelectorAddSubTest, ImmediateOnRight) {
493   const AddSub dpi = GetParam();
494   const MachineType type = dpi.mi.machine_type;
495   TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
496     StreamBuilder m(this, type, type);
497     m.Return(
498         (m.*dpi.mi.constructor)(m.Parameter(0), BuildConstant(&m, type, imm)));
499     Stream s = m.Build();
500     ASSERT_EQ(1U, s.size());
501     EXPECT_EQ(dpi.mi.arch_opcode, s[0]->arch_opcode());
502     ASSERT_EQ(2U, s[0]->InputCount());
503     EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
504     EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1)));
505     EXPECT_EQ(1U, s[0]->OutputCount());
506   }
507 }
508 
TEST_P(InstructionSelectorAddSubTest,NegImmediateOnRight)509 TEST_P(InstructionSelectorAddSubTest, NegImmediateOnRight) {
510   const AddSub dpi = GetParam();
511   const MachineType type = dpi.mi.machine_type;
512   TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
513     if (imm == 0) continue;
514     StreamBuilder m(this, type, type);
515     m.Return(
516         (m.*dpi.mi.constructor)(m.Parameter(0), BuildConstant(&m, type, -imm)));
517     Stream s = m.Build();
518     ASSERT_EQ(1U, s.size());
519     EXPECT_EQ(dpi.negate_arch_opcode, s[0]->arch_opcode());
520     ASSERT_EQ(2U, s[0]->InputCount());
521     ASSERT_TRUE(s[0]->InputAt(1)->IsImmediate());
522     EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
523     EXPECT_EQ(1U, s[0]->OutputCount());
524   }
525 }
526 
TEST_P(InstructionSelectorAddSubTest,ShiftByImmediateOnRight)527 TEST_P(InstructionSelectorAddSubTest, ShiftByImmediateOnRight) {
528   const AddSub dpi = GetParam();
529   const MachineType type = dpi.mi.machine_type;
530   TRACED_FOREACH(Shift, shift, kShiftInstructions) {
531     // Only test 64-bit shifted operands with 64-bit instructions.
532     if (shift.mi.machine_type != type) continue;
533 
534     if ((shift.mi.arch_opcode == kArm64Ror32) ||
535         (shift.mi.arch_opcode == kArm64Ror)) {
536       // Not supported by add/sub instructions.
537       continue;
538     }
539 
540     TRACED_FORRANGE(int, imm, 0, ((type == MachineType::Int32()) ? 31 : 63)) {
541       StreamBuilder m(this, type, type, type);
542       m.Return((m.*dpi.mi.constructor)(
543           m.Parameter(0), (m.*shift.mi.constructor)(
544                               m.Parameter(1), BuildConstant(&m, type, imm))));
545       Stream s = m.Build();
546       ASSERT_EQ(1U, s.size());
547       EXPECT_EQ(dpi.mi.arch_opcode, s[0]->arch_opcode());
548       EXPECT_EQ(shift.mode, s[0]->addressing_mode());
549       EXPECT_EQ(3U, s[0]->InputCount());
550       EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(2)));
551       EXPECT_EQ(1U, s[0]->OutputCount());
552     }
553   }
554 }
555 
TEST_P(InstructionSelectorAddSubTest,UnsignedExtendByte)556 TEST_P(InstructionSelectorAddSubTest, UnsignedExtendByte) {
557   const AddSub dpi = GetParam();
558   const MachineType type = dpi.mi.machine_type;
559   StreamBuilder m(this, type, type, type);
560   m.Return((m.*dpi.mi.constructor)(
561       m.Parameter(0), m.Word32And(m.Parameter(1), m.Int32Constant(0xFF))));
562   Stream s = m.Build();
563   ASSERT_EQ(1U, s.size());
564   EXPECT_EQ(dpi.mi.arch_opcode, s[0]->arch_opcode());
565   EXPECT_EQ(kMode_Operand2_R_UXTB, s[0]->addressing_mode());
566   ASSERT_EQ(2U, s[0]->InputCount());
567   ASSERT_EQ(1U, s[0]->OutputCount());
568 }
569 
TEST_P(InstructionSelectorAddSubTest,UnsignedExtendHalfword)570 TEST_P(InstructionSelectorAddSubTest, UnsignedExtendHalfword) {
571   const AddSub dpi = GetParam();
572   const MachineType type = dpi.mi.machine_type;
573   StreamBuilder m(this, type, type, type);
574   m.Return((m.*dpi.mi.constructor)(
575       m.Parameter(0), m.Word32And(m.Parameter(1), m.Int32Constant(0xFFFF))));
576   Stream s = m.Build();
577   ASSERT_EQ(1U, s.size());
578   EXPECT_EQ(dpi.mi.arch_opcode, s[0]->arch_opcode());
579   EXPECT_EQ(kMode_Operand2_R_UXTH, s[0]->addressing_mode());
580   ASSERT_EQ(2U, s[0]->InputCount());
581   ASSERT_EQ(1U, s[0]->OutputCount());
582 }
583 
TEST_P(InstructionSelectorAddSubTest,SignedExtendByte)584 TEST_P(InstructionSelectorAddSubTest, SignedExtendByte) {
585   const AddSub dpi = GetParam();
586   const MachineType type = dpi.mi.machine_type;
587   StreamBuilder m(this, type, type, type);
588   m.Return((m.*dpi.mi.constructor)(
589       m.Parameter(0),
590       m.Word32Sar(m.Word32Shl(m.Parameter(1), m.Int32Constant(24)),
591                   m.Int32Constant(24))));
592   Stream s = m.Build();
593   ASSERT_EQ(1U, s.size());
594   EXPECT_EQ(dpi.mi.arch_opcode, s[0]->arch_opcode());
595   EXPECT_EQ(kMode_Operand2_R_SXTB, s[0]->addressing_mode());
596   ASSERT_EQ(2U, s[0]->InputCount());
597   ASSERT_EQ(1U, s[0]->OutputCount());
598 }
599 
TEST_P(InstructionSelectorAddSubTest,SignedExtendHalfword)600 TEST_P(InstructionSelectorAddSubTest, SignedExtendHalfword) {
601   const AddSub dpi = GetParam();
602   const MachineType type = dpi.mi.machine_type;
603   StreamBuilder m(this, type, type, type);
604   m.Return((m.*dpi.mi.constructor)(
605       m.Parameter(0),
606       m.Word32Sar(m.Word32Shl(m.Parameter(1), m.Int32Constant(16)),
607                   m.Int32Constant(16))));
608   Stream s = m.Build();
609   ASSERT_EQ(1U, s.size());
610   EXPECT_EQ(dpi.mi.arch_opcode, s[0]->arch_opcode());
611   EXPECT_EQ(kMode_Operand2_R_SXTH, s[0]->addressing_mode());
612   ASSERT_EQ(2U, s[0]->InputCount());
613   ASSERT_EQ(1U, s[0]->OutputCount());
614 }
615 
TEST_P(InstructionSelectorAddSubTest,SignedExtendWord)616 TEST_P(InstructionSelectorAddSubTest, SignedExtendWord) {
617   const AddSub dpi = GetParam();
618   const MachineType type = dpi.mi.machine_type;
619   if (type != MachineType::Int64()) return;
620   StreamBuilder m(this, type, type, type);
621   m.Return((m.*dpi.mi.constructor)(m.Parameter(0),
622                                    m.ChangeInt32ToInt64(m.Parameter(1))));
623   Stream s = m.Build();
624   ASSERT_EQ(1U, s.size());
625   EXPECT_EQ(dpi.mi.arch_opcode, s[0]->arch_opcode());
626   EXPECT_EQ(kMode_Operand2_R_SXTW, s[0]->addressing_mode());
627   ASSERT_EQ(2U, s[0]->InputCount());
628   ASSERT_EQ(1U, s[0]->OutputCount());
629 }
630 
631 INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest, InstructionSelectorAddSubTest,
632                          ::testing::ValuesIn(kAddSubInstructions));
633 
TEST_F(InstructionSelectorTest,AddImmediateOnLeft)634 TEST_F(InstructionSelectorTest, AddImmediateOnLeft) {
635   // 32-bit add.
636   TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
637     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
638     m.Return(m.Int32Add(m.Int32Constant(imm), m.Parameter(0)));
639     Stream s = m.Build();
640     ASSERT_EQ(1U, s.size());
641     EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
642     ASSERT_EQ(2U, s[0]->InputCount());
643     EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
644     EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
645     EXPECT_EQ(1U, s[0]->OutputCount());
646   }
647 
648   // 64-bit add.
649   TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
650     StreamBuilder m(this, MachineType::Int64(), MachineType::Int64());
651     m.Return(m.Int64Add(m.Int64Constant(imm), m.Parameter(0)));
652     Stream s = m.Build();
653     ASSERT_EQ(1U, s.size());
654     EXPECT_EQ(kArm64Add, s[0]->arch_opcode());
655     ASSERT_EQ(2U, s[0]->InputCount());
656     EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
657     EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1)));
658     EXPECT_EQ(1U, s[0]->OutputCount());
659   }
660 }
661 
TEST_F(InstructionSelectorTest,SubZeroOnLeft)662 TEST_F(InstructionSelectorTest, SubZeroOnLeft) {
663   {
664     // 32-bit subtract.
665     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
666                     MachineType::Int32());
667     m.Return(m.Int32Sub(m.Int32Constant(0), m.Parameter(0)));
668     Stream s = m.Build();
669 
670     ASSERT_EQ(1U, s.size());
671     EXPECT_EQ(kArm64Sub32, s[0]->arch_opcode());
672     ASSERT_EQ(2U, s[0]->InputCount());
673     EXPECT_TRUE(s[0]->InputAt(0)->IsImmediate());
674     EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(0)));
675     EXPECT_EQ(1U, s[0]->OutputCount());
676   }
677   {
678     // 64-bit subtract.
679     StreamBuilder m(this, MachineType::Int64(), MachineType::Int64(),
680                     MachineType::Int64());
681     m.Return(m.Int64Sub(m.Int64Constant(0), m.Parameter(0)));
682     Stream s = m.Build();
683 
684     ASSERT_EQ(1U, s.size());
685     EXPECT_EQ(kArm64Sub, s[0]->arch_opcode());
686     ASSERT_EQ(2U, s[0]->InputCount());
687     EXPECT_TRUE(s[0]->InputAt(0)->IsImmediate());
688     EXPECT_EQ(0, s.ToInt64(s[0]->InputAt(0)));
689     EXPECT_EQ(1U, s[0]->OutputCount());
690   }
691 }
692 
TEST_F(InstructionSelectorTest,SubZeroOnLeftWithShift)693 TEST_F(InstructionSelectorTest, SubZeroOnLeftWithShift) {
694   TRACED_FOREACH(Shift, shift, kShiftInstructions) {
695     {
696       // Test 32-bit operations. Ignore ROR shifts, as subtract does not
697       // support them.
698       if ((shift.mi.machine_type != MachineType::Int32()) ||
699           (shift.mi.arch_opcode == kArm64Ror32) ||
700           (shift.mi.arch_opcode == kArm64Ror))
701         continue;
702 
703       TRACED_FORRANGE(int, imm, -32, 63) {
704         StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
705                         MachineType::Int32());
706         m.Return(m.Int32Sub(
707             m.Int32Constant(0),
708             (m.*shift.mi.constructor)(m.Parameter(1), m.Int32Constant(imm))));
709         Stream s = m.Build();
710 
711         ASSERT_EQ(1U, s.size());
712         EXPECT_EQ(kArm64Sub32, s[0]->arch_opcode());
713         ASSERT_EQ(3U, s[0]->InputCount());
714         EXPECT_TRUE(s[0]->InputAt(0)->IsImmediate());
715         EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(0)));
716         EXPECT_EQ(shift.mode, s[0]->addressing_mode());
717         EXPECT_EQ(0x3F & imm, 0x3F & s.ToInt32(s[0]->InputAt(2)));
718         EXPECT_EQ(1U, s[0]->OutputCount());
719       }
720     }
721     {
722       // Test 64-bit operations. Ignore ROR shifts, as subtract does not
723       // support them.
724       if ((shift.mi.machine_type != MachineType::Int64()) ||
725           (shift.mi.arch_opcode == kArm64Ror32) ||
726           (shift.mi.arch_opcode == kArm64Ror))
727         continue;
728 
729       TRACED_FORRANGE(int, imm, -32, 127) {
730         StreamBuilder m(this, MachineType::Int64(), MachineType::Int64(),
731                         MachineType::Int64());
732         m.Return(m.Int64Sub(
733             m.Int64Constant(0),
734             (m.*shift.mi.constructor)(m.Parameter(1), m.Int64Constant(imm))));
735         Stream s = m.Build();
736 
737         ASSERT_EQ(1U, s.size());
738         EXPECT_EQ(kArm64Sub, s[0]->arch_opcode());
739         ASSERT_EQ(3U, s[0]->InputCount());
740         EXPECT_TRUE(s[0]->InputAt(0)->IsImmediate());
741         EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(0)));
742         EXPECT_EQ(shift.mode, s[0]->addressing_mode());
743         EXPECT_EQ(0x3F & imm, 0x3F & s.ToInt32(s[0]->InputAt(2)));
744         EXPECT_EQ(1U, s[0]->OutputCount());
745       }
746     }
747   }
748 }
749 
TEST_F(InstructionSelectorTest,AddNegImmediateOnLeft)750 TEST_F(InstructionSelectorTest, AddNegImmediateOnLeft) {
751   // 32-bit add.
752   TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
753     if (imm == 0) continue;
754     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
755     m.Return(m.Int32Add(m.Int32Constant(-imm), m.Parameter(0)));
756     Stream s = m.Build();
757 
758     ASSERT_EQ(1U, s.size());
759     EXPECT_EQ(kArm64Sub32, s[0]->arch_opcode());
760     ASSERT_EQ(2U, s[0]->InputCount());
761     ASSERT_TRUE(s[0]->InputAt(1)->IsImmediate());
762     EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
763     EXPECT_EQ(1U, s[0]->OutputCount());
764   }
765 
766   // 64-bit add.
767   TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
768     if (imm == 0) continue;
769     StreamBuilder m(this, MachineType::Int64(), MachineType::Int64());
770     m.Return(m.Int64Add(m.Int64Constant(-imm), m.Parameter(0)));
771     Stream s = m.Build();
772 
773     ASSERT_EQ(1U, s.size());
774     EXPECT_EQ(kArm64Sub, s[0]->arch_opcode());
775     ASSERT_EQ(2U, s[0]->InputCount());
776     ASSERT_TRUE(s[0]->InputAt(1)->IsImmediate());
777     EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1)));
778     EXPECT_EQ(1U, s[0]->OutputCount());
779   }
780 }
781 
TEST_F(InstructionSelectorTest,AddShiftByImmediateOnLeft)782 TEST_F(InstructionSelectorTest, AddShiftByImmediateOnLeft) {
783   // 32-bit add.
784   TRACED_FOREACH(Shift, shift, kShiftInstructions) {
785     // Only test relevant shifted operands.
786     if (shift.mi.machine_type != MachineType::Int32()) continue;
787     if (shift.mi.arch_opcode == kArm64Ror32) continue;
788 
789     // The available shift operand range is `0 <= imm < 32`, but we also test
790     // that immediates outside this range are handled properly (modulo-32).
791     TRACED_FORRANGE(int, imm, -32, 63) {
792       StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
793                       MachineType::Int32());
794       m.Return((m.Int32Add)(
795           (m.*shift.mi.constructor)(m.Parameter(1), m.Int32Constant(imm)),
796           m.Parameter(0)));
797       Stream s = m.Build();
798       ASSERT_EQ(1U, s.size());
799       EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
800       EXPECT_EQ(shift.mode, s[0]->addressing_mode());
801       EXPECT_EQ(3U, s[0]->InputCount());
802       EXPECT_EQ(0x3F & imm, 0x3F & s.ToInt64(s[0]->InputAt(2)));
803       EXPECT_EQ(1U, s[0]->OutputCount());
804     }
805   }
806 
807   // 64-bit add.
808   TRACED_FOREACH(Shift, shift, kShiftInstructions) {
809     // Only test relevant shifted operands.
810     if (shift.mi.machine_type != MachineType::Int64()) continue;
811     if (shift.mi.arch_opcode == kArm64Ror) continue;
812 
813     // The available shift operand range is `0 <= imm < 64`, but we also test
814     // that immediates outside this range are handled properly (modulo-64).
815     TRACED_FORRANGE(int, imm, -64, 127) {
816       StreamBuilder m(this, MachineType::Int64(), MachineType::Int64(),
817                       MachineType::Int64());
818       m.Return((m.Int64Add)(
819           (m.*shift.mi.constructor)(m.Parameter(1), m.Int64Constant(imm)),
820           m.Parameter(0)));
821       Stream s = m.Build();
822       ASSERT_EQ(1U, s.size());
823       EXPECT_EQ(kArm64Add, s[0]->arch_opcode());
824       EXPECT_EQ(shift.mode, s[0]->addressing_mode());
825       EXPECT_EQ(3U, s[0]->InputCount());
826       EXPECT_EQ(0x3F & imm, 0x3F & s.ToInt64(s[0]->InputAt(2)));
827       EXPECT_EQ(1U, s[0]->OutputCount());
828     }
829   }
830 }
831 
TEST_F(InstructionSelectorTest,AddUnsignedExtendByteOnLeft)832 TEST_F(InstructionSelectorTest, AddUnsignedExtendByteOnLeft) {
833   {
834     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
835                     MachineType::Int32());
836     m.Return(m.Int32Add(m.Word32And(m.Parameter(0), m.Int32Constant(0xFF)),
837                         m.Parameter(1)));
838     Stream s = m.Build();
839     ASSERT_EQ(1U, s.size());
840     EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
841     EXPECT_EQ(kMode_Operand2_R_UXTB, s[0]->addressing_mode());
842     ASSERT_EQ(2U, s[0]->InputCount());
843     ASSERT_EQ(1U, s[0]->OutputCount());
844   }
845   {
846     StreamBuilder m(this, MachineType::Int64(), MachineType::Int32(),
847                     MachineType::Int64());
848     m.Return(m.Int64Add(m.Word32And(m.Parameter(0), m.Int32Constant(0xFF)),
849                         m.Parameter(1)));
850     Stream s = m.Build();
851     ASSERT_EQ(1U, s.size());
852     EXPECT_EQ(kArm64Add, s[0]->arch_opcode());
853     EXPECT_EQ(kMode_Operand2_R_UXTB, s[0]->addressing_mode());
854     ASSERT_EQ(2U, s[0]->InputCount());
855     ASSERT_EQ(1U, s[0]->OutputCount());
856   }
857 }
858 
TEST_F(InstructionSelectorTest,AddUnsignedExtendHalfwordOnLeft)859 TEST_F(InstructionSelectorTest, AddUnsignedExtendHalfwordOnLeft) {
860   {
861     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
862                     MachineType::Int32());
863     m.Return(m.Int32Add(m.Word32And(m.Parameter(0), m.Int32Constant(0xFFFF)),
864                         m.Parameter(1)));
865     Stream s = m.Build();
866     ASSERT_EQ(1U, s.size());
867     EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
868     EXPECT_EQ(kMode_Operand2_R_UXTH, s[0]->addressing_mode());
869     ASSERT_EQ(2U, s[0]->InputCount());
870     ASSERT_EQ(1U, s[0]->OutputCount());
871   }
872   {
873     StreamBuilder m(this, MachineType::Int64(), MachineType::Int32(),
874                     MachineType::Int64());
875     m.Return(m.Int64Add(m.Word32And(m.Parameter(0), m.Int32Constant(0xFFFF)),
876                         m.Parameter(1)));
877     Stream s = m.Build();
878     ASSERT_EQ(1U, s.size());
879     EXPECT_EQ(kArm64Add, s[0]->arch_opcode());
880     EXPECT_EQ(kMode_Operand2_R_UXTH, s[0]->addressing_mode());
881     ASSERT_EQ(2U, s[0]->InputCount());
882     ASSERT_EQ(1U, s[0]->OutputCount());
883   }
884 }
885 
TEST_F(InstructionSelectorTest,AddSignedExtendByteOnLeft)886 TEST_F(InstructionSelectorTest, AddSignedExtendByteOnLeft) {
887   {
888     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
889                     MachineType::Int32());
890     m.Return(
891         m.Int32Add(m.Word32Sar(m.Word32Shl(m.Parameter(0), m.Int32Constant(24)),
892                                m.Int32Constant(24)),
893                    m.Parameter(1)));
894     Stream s = m.Build();
895     ASSERT_EQ(1U, s.size());
896     EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
897     EXPECT_EQ(kMode_Operand2_R_SXTB, s[0]->addressing_mode());
898     ASSERT_EQ(2U, s[0]->InputCount());
899     ASSERT_EQ(1U, s[0]->OutputCount());
900   }
901   {
902     StreamBuilder m(this, MachineType::Int64(), MachineType::Int32(),
903                     MachineType::Int64());
904     m.Return(
905         m.Int64Add(m.Word32Sar(m.Word32Shl(m.Parameter(0), m.Int32Constant(24)),
906                                m.Int32Constant(24)),
907                    m.Parameter(1)));
908     Stream s = m.Build();
909     ASSERT_EQ(1U, s.size());
910     EXPECT_EQ(kArm64Add, s[0]->arch_opcode());
911     EXPECT_EQ(kMode_Operand2_R_SXTB, s[0]->addressing_mode());
912     ASSERT_EQ(2U, s[0]->InputCount());
913     ASSERT_EQ(1U, s[0]->OutputCount());
914   }
915 }
916 
TEST_F(InstructionSelectorTest,AddSignedExtendHalfwordOnLeft)917 TEST_F(InstructionSelectorTest, AddSignedExtendHalfwordOnLeft) {
918   {
919     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
920                     MachineType::Int32());
921     m.Return(
922         m.Int32Add(m.Word32Sar(m.Word32Shl(m.Parameter(0), m.Int32Constant(16)),
923                                m.Int32Constant(16)),
924                    m.Parameter(1)));
925     Stream s = m.Build();
926     ASSERT_EQ(1U, s.size());
927     EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
928     EXPECT_EQ(kMode_Operand2_R_SXTH, s[0]->addressing_mode());
929     ASSERT_EQ(2U, s[0]->InputCount());
930     ASSERT_EQ(1U, s[0]->OutputCount());
931   }
932   {
933     StreamBuilder m(this, MachineType::Int64(), MachineType::Int32(),
934                     MachineType::Int64());
935     m.Return(
936         m.Int64Add(m.Word32Sar(m.Word32Shl(m.Parameter(0), m.Int32Constant(16)),
937                                m.Int32Constant(16)),
938                    m.Parameter(1)));
939     Stream s = m.Build();
940     ASSERT_EQ(1U, s.size());
941     EXPECT_EQ(kArm64Add, s[0]->arch_opcode());
942     EXPECT_EQ(kMode_Operand2_R_SXTH, s[0]->addressing_mode());
943     ASSERT_EQ(2U, s[0]->InputCount());
944     ASSERT_EQ(1U, s[0]->OutputCount());
945   }
946 }
947 
948 enum PairwiseAddSide { LEFT, RIGHT };
949 
operator <<(std::ostream & os,const PairwiseAddSide & side)950 std::ostream& operator<<(std::ostream& os, const PairwiseAddSide& side) {
951   switch (side) {
952     case LEFT:
953       return os << "LEFT";
954     case RIGHT:
955       return os << "RIGHT";
956   }
957 }
958 
959 struct AddWithPairwiseAddSideAndWidth {
960   PairwiseAddSide side;
961   int32_t width;
962   bool isSigned;
963 };
964 
operator <<(std::ostream & os,const AddWithPairwiseAddSideAndWidth & sw)965 std::ostream& operator<<(std::ostream& os,
966                          const AddWithPairwiseAddSideAndWidth& sw) {
967   return os << "{ side: " << sw.side << ", width: " << sw.width
968             << ", isSigned: " << sw.isSigned << " }";
969 }
970 
971 using InstructionSelectorAddWithPairwiseAddTest =
972     InstructionSelectorTestWithParam<AddWithPairwiseAddSideAndWidth>;
973 
TEST_P(InstructionSelectorAddWithPairwiseAddTest,AddWithPairwiseAdd)974 TEST_P(InstructionSelectorAddWithPairwiseAddTest, AddWithPairwiseAdd) {
975   AddWithPairwiseAddSideAndWidth params = GetParam();
976   const MachineType type = MachineType::Simd128();
977   StreamBuilder m(this, type, type, type, type);
978 
979   Node* x = m.Parameter(0);
980   Node* y = m.Parameter(1);
981   const Operator* pairwiseAddOp;
982   if (params.width == 32 && params.isSigned) {
983     pairwiseAddOp = m.machine()->I32x4ExtAddPairwiseI16x8S();
984   } else if (params.width == 16 && params.isSigned) {
985     pairwiseAddOp = m.machine()->I16x8ExtAddPairwiseI8x16S();
986   } else if (params.width == 32 && !params.isSigned) {
987     pairwiseAddOp = m.machine()->I32x4ExtAddPairwiseI16x8U();
988   } else {
989     pairwiseAddOp = m.machine()->I16x8ExtAddPairwiseI8x16U();
990   }
991   Node* pairwiseAdd = m.AddNode(pairwiseAddOp, x);
992   const Operator* addOp =
993       params.width == 32 ? m.machine()->I32x4Add() : m.machine()->I16x8Add();
994   Node* add = params.side == LEFT ? m.AddNode(addOp, pairwiseAdd, y)
995                                   : m.AddNode(addOp, y, pairwiseAdd);
996   m.Return(add);
997   Stream s = m.Build();
998 
999   // Should be fused to Sadalp/Uadalp
1000   ASSERT_EQ(1U, s.size());
1001   EXPECT_EQ(params.isSigned ? kArm64Sadalp : kArm64Uadalp, s[0]->arch_opcode());
1002   EXPECT_EQ(2U, s[0]->InputCount());
1003   EXPECT_EQ(1U, s[0]->OutputCount());
1004 }
1005 
1006 const AddWithPairwiseAddSideAndWidth kAddWithPairAddTestCases[] = {
1007     {LEFT, 16, true},  {RIGHT, 16, true}, {LEFT, 32, true},
1008     {RIGHT, 32, true}, {LEFT, 16, false}, {RIGHT, 16, false},
1009     {LEFT, 32, false}, {RIGHT, 32, false}};
1010 
1011 INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest,
1012                          InstructionSelectorAddWithPairwiseAddTest,
1013                          ::testing::ValuesIn(kAddWithPairAddTestCases));
1014 
1015 // -----------------------------------------------------------------------------
1016 // Data processing controlled branches.
1017 
1018 using InstructionSelectorDPFlagSetTest =
1019     InstructionSelectorTestWithParam<MachInst2>;
1020 
TEST_P(InstructionSelectorDPFlagSetTest,BranchWithParameters)1021 TEST_P(InstructionSelectorDPFlagSetTest, BranchWithParameters) {
1022   const MachInst2 dpi = GetParam();
1023   const MachineType type = dpi.machine_type;
1024   StreamBuilder m(this, type, type, type);
1025   RawMachineLabel a, b;
1026   m.Branch((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)), &a, &b);
1027   m.Bind(&a);
1028   m.Return(m.Int32Constant(1));
1029   m.Bind(&b);
1030   m.Return(m.Int32Constant(0));
1031   Stream s = m.Build();
1032   ASSERT_EQ(1U, s.size());
1033   EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
1034   EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
1035   EXPECT_EQ(kNotEqual, s[0]->flags_condition());
1036 }
1037 
1038 INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest,
1039                          InstructionSelectorDPFlagSetTest,
1040                          ::testing::ValuesIn(kDPFlagSetInstructions));
1041 
TEST_F(InstructionSelectorTest,Word32AndBranchWithImmediateOnRight)1042 TEST_F(InstructionSelectorTest, Word32AndBranchWithImmediateOnRight) {
1043   TRACED_FOREACH(int32_t, imm, kLogical32Immediates) {
1044     // Skip the cases where the instruction selector would use tbz/tbnz.
1045     if (base::bits::CountPopulation(static_cast<uint32_t>(imm)) == 1) continue;
1046 
1047     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
1048     RawMachineLabel a, b;
1049     m.Branch(m.Word32And(m.Parameter(0), m.Int32Constant(imm)), &a, &b);
1050     m.Bind(&a);
1051     m.Return(m.Int32Constant(1));
1052     m.Bind(&b);
1053     m.Return(m.Int32Constant(0));
1054     Stream s = m.Build();
1055     ASSERT_EQ(1U, s.size());
1056     EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode());
1057     EXPECT_EQ(4U, s[0]->InputCount());
1058     EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
1059     EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
1060     EXPECT_EQ(kNotEqual, s[0]->flags_condition());
1061   }
1062 }
1063 
TEST_F(InstructionSelectorTest,Word64AndBranchWithImmediateOnRight)1064 TEST_F(InstructionSelectorTest, Word64AndBranchWithImmediateOnRight) {
1065   TRACED_FOREACH(int64_t, imm, kLogical64Immediates) {
1066     // Skip the cases where the instruction selector would use tbz/tbnz.
1067     if (base::bits::CountPopulation(static_cast<uint64_t>(imm)) == 1) continue;
1068 
1069     StreamBuilder m(this, MachineType::Int64(), MachineType::Int64());
1070     RawMachineLabel a, b;
1071     m.Branch(m.Word64And(m.Parameter(0), m.Int64Constant(imm)), &a, &b);
1072     m.Bind(&a);
1073     m.Return(m.Int32Constant(1));
1074     m.Bind(&b);
1075     m.Return(m.Int32Constant(0));
1076     Stream s = m.Build();
1077     ASSERT_EQ(1U, s.size());
1078     EXPECT_EQ(kArm64Tst, s[0]->arch_opcode());
1079     EXPECT_EQ(4U, s[0]->InputCount());
1080     EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
1081     EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
1082     EXPECT_EQ(kNotEqual, s[0]->flags_condition());
1083   }
1084 }
1085 
TEST_F(InstructionSelectorTest,AddBranchWithImmediateOnRight)1086 TEST_F(InstructionSelectorTest, AddBranchWithImmediateOnRight) {
1087   TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
1088     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
1089     RawMachineLabel a, b;
1090     m.Branch(m.Int32Add(m.Parameter(0), m.Int32Constant(imm)), &a, &b);
1091     m.Bind(&a);
1092     m.Return(m.Int32Constant(1));
1093     m.Bind(&b);
1094     m.Return(m.Int32Constant(0));
1095     Stream s = m.Build();
1096     ASSERT_EQ(1U, s.size());
1097     EXPECT_EQ(kArm64Cmn32, s[0]->arch_opcode());
1098     EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
1099     EXPECT_EQ(kNotEqual, s[0]->flags_condition());
1100   }
1101 }
1102 
TEST_F(InstructionSelectorTest,SubBranchWithImmediateOnRight)1103 TEST_F(InstructionSelectorTest, SubBranchWithImmediateOnRight) {
1104   TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
1105     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
1106     RawMachineLabel a, b;
1107     m.Branch(m.Int32Sub(m.Parameter(0), m.Int32Constant(imm)), &a, &b);
1108     m.Bind(&a);
1109     m.Return(m.Int32Constant(1));
1110     m.Bind(&b);
1111     m.Return(m.Int32Constant(0));
1112     Stream s = m.Build();
1113     ASSERT_EQ(1U, s.size());
1114     EXPECT_EQ((imm == 0) ? kArm64CompareAndBranch32 : kArm64Cmp32,
1115               s[0]->arch_opcode());
1116     EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
1117     EXPECT_EQ(kNotEqual, s[0]->flags_condition());
1118   }
1119 }
1120 
TEST_F(InstructionSelectorTest,Word32AndBranchWithImmediateOnLeft)1121 TEST_F(InstructionSelectorTest, Word32AndBranchWithImmediateOnLeft) {
1122   TRACED_FOREACH(int32_t, imm, kLogical32Immediates) {
1123     // Skip the cases where the instruction selector would use tbz/tbnz.
1124     if (base::bits::CountPopulation(static_cast<uint32_t>(imm)) == 1) continue;
1125 
1126     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
1127     RawMachineLabel a, b;
1128     m.Branch(m.Word32And(m.Int32Constant(imm), m.Parameter(0)), &a, &b);
1129     m.Bind(&a);
1130     m.Return(m.Int32Constant(1));
1131     m.Bind(&b);
1132     m.Return(m.Int32Constant(0));
1133     Stream s = m.Build();
1134     ASSERT_EQ(1U, s.size());
1135     EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode());
1136     EXPECT_EQ(4U, s[0]->InputCount());
1137     EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
1138     ASSERT_LE(1U, s[0]->InputCount());
1139     EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
1140     EXPECT_EQ(kNotEqual, s[0]->flags_condition());
1141   }
1142 }
1143 
TEST_F(InstructionSelectorTest,Word64AndBranchWithImmediateOnLeft)1144 TEST_F(InstructionSelectorTest, Word64AndBranchWithImmediateOnLeft) {
1145   TRACED_FOREACH(int64_t, imm, kLogical64Immediates) {
1146     // Skip the cases where the instruction selector would use tbz/tbnz.
1147     if (base::bits::CountPopulation(static_cast<uint64_t>(imm)) == 1) continue;
1148 
1149     StreamBuilder m(this, MachineType::Int64(), MachineType::Int64());
1150     RawMachineLabel a, b;
1151     m.Branch(m.Word64And(m.Int64Constant(imm), m.Parameter(0)), &a, &b);
1152     m.Bind(&a);
1153     m.Return(m.Int32Constant(1));
1154     m.Bind(&b);
1155     m.Return(m.Int32Constant(0));
1156     Stream s = m.Build();
1157     ASSERT_EQ(1U, s.size());
1158     EXPECT_EQ(kArm64Tst, s[0]->arch_opcode());
1159     EXPECT_EQ(4U, s[0]->InputCount());
1160     EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
1161     ASSERT_LE(1U, s[0]->InputCount());
1162     EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
1163     EXPECT_EQ(kNotEqual, s[0]->flags_condition());
1164   }
1165 }
1166 
TEST_F(InstructionSelectorTest,AddBranchWithImmediateOnLeft)1167 TEST_F(InstructionSelectorTest, AddBranchWithImmediateOnLeft) {
1168   TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
1169     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
1170     RawMachineLabel a, b;
1171     m.Branch(m.Int32Add(m.Int32Constant(imm), m.Parameter(0)), &a, &b);
1172     m.Bind(&a);
1173     m.Return(m.Int32Constant(1));
1174     m.Bind(&b);
1175     m.Return(m.Int32Constant(0));
1176     Stream s = m.Build();
1177     ASSERT_EQ(1U, s.size());
1178     EXPECT_EQ(kArm64Cmn32, s[0]->arch_opcode());
1179     ASSERT_LE(1U, s[0]->InputCount());
1180     EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
1181     EXPECT_EQ(kNotEqual, s[0]->flags_condition());
1182   }
1183 }
1184 
1185 struct TestAndBranch {
1186   MachInst<std::function<Node*(InstructionSelectorTest::StreamBuilder&, Node*,
1187                                uint64_t mask)>>
1188       mi;
1189   FlagsCondition cond;
1190 };
1191 
operator <<(std::ostream & os,const TestAndBranch & tb)1192 std::ostream& operator<<(std::ostream& os, const TestAndBranch& tb) {
1193   return os << tb.mi;
1194 }
1195 
1196 const TestAndBranch kTestAndBranchMatchers32[] = {
1197     // Branch on the result of Word32And directly.
1198     {{[](InstructionSelectorTest::StreamBuilder& m, Node* x, uint32_t mask)
__anone2b855730202() 1199           -> Node* { return m.Word32And(x, m.Int32Constant(mask)); },
1200       "if (x and mask)", kArm64TestAndBranch32, MachineType::Int32()},
1201      kNotEqual},
1202     {{[](InstructionSelectorTest::StreamBuilder& m, Node* x,
__anone2b855730302() 1203          uint32_t mask) -> Node* {
1204         return m.Word32BinaryNot(m.Word32And(x, m.Int32Constant(mask)));
1205       },
1206       "if not (x and mask)", kArm64TestAndBranch32, MachineType::Int32()},
1207      kEqual},
1208     {{[](InstructionSelectorTest::StreamBuilder& m, Node* x, uint32_t mask)
__anone2b855730402() 1209           -> Node* { return m.Word32And(m.Int32Constant(mask), x); },
1210       "if (mask and x)", kArm64TestAndBranch32, MachineType::Int32()},
1211      kNotEqual},
1212     {{[](InstructionSelectorTest::StreamBuilder& m, Node* x,
__anone2b855730502() 1213          uint32_t mask) -> Node* {
1214         return m.Word32BinaryNot(m.Word32And(m.Int32Constant(mask), x));
1215       },
1216       "if not (mask and x)", kArm64TestAndBranch32, MachineType::Int32()},
1217      kEqual},
1218     // Branch on the result of '(x and mask) == mask'. This tests that a bit is
1219     // set rather than cleared which is why conditions are inverted.
1220     {{[](InstructionSelectorTest::StreamBuilder& m, Node* x,
__anone2b855730602() 1221          uint32_t mask) -> Node* {
1222         return m.Word32Equal(m.Word32And(x, m.Int32Constant(mask)),
1223                              m.Int32Constant(mask));
1224       },
1225       "if ((x and mask) == mask)", kArm64TestAndBranch32, MachineType::Int32()},
1226      kNotEqual},
1227     {{[](InstructionSelectorTest::StreamBuilder& m, Node* x,
__anone2b855730702() 1228          uint32_t mask) -> Node* {
1229         return m.Word32BinaryNot(m.Word32Equal(
1230             m.Word32And(x, m.Int32Constant(mask)), m.Int32Constant(mask)));
1231       },
1232       "if ((x and mask) != mask)", kArm64TestAndBranch32, MachineType::Int32()},
1233      kEqual},
1234     {{[](InstructionSelectorTest::StreamBuilder& m, Node* x,
__anone2b855730802() 1235          uint32_t mask) -> Node* {
1236         return m.Word32Equal(m.Int32Constant(mask),
1237                              m.Word32And(x, m.Int32Constant(mask)));
1238       },
1239       "if (mask == (x and mask))", kArm64TestAndBranch32, MachineType::Int32()},
1240      kNotEqual},
1241     {{[](InstructionSelectorTest::StreamBuilder& m, Node* x,
__anone2b855730902() 1242          uint32_t mask) -> Node* {
1243         return m.Word32BinaryNot(m.Word32Equal(
1244             m.Int32Constant(mask), m.Word32And(x, m.Int32Constant(mask))));
1245       },
1246       "if (mask != (x and mask))", kArm64TestAndBranch32, MachineType::Int32()},
1247      kEqual},
1248     // Same as above but swap 'mask' and 'x'.
1249     {{[](InstructionSelectorTest::StreamBuilder& m, Node* x,
__anone2b855730a02() 1250          uint32_t mask) -> Node* {
1251         return m.Word32Equal(m.Word32And(m.Int32Constant(mask), x),
1252                              m.Int32Constant(mask));
1253       },
1254       "if ((mask and x) == mask)", kArm64TestAndBranch32, MachineType::Int32()},
1255      kNotEqual},
1256     {{[](InstructionSelectorTest::StreamBuilder& m, Node* x,
__anone2b855730b02() 1257          uint32_t mask) -> Node* {
1258         return m.Word32BinaryNot(m.Word32Equal(
1259             m.Word32And(m.Int32Constant(mask), x), m.Int32Constant(mask)));
1260       },
1261       "if ((mask and x) != mask)", kArm64TestAndBranch32, MachineType::Int32()},
1262      kEqual},
1263     {{[](InstructionSelectorTest::StreamBuilder& m, Node* x,
__anone2b855730c02() 1264          uint32_t mask) -> Node* {
1265         return m.Word32Equal(m.Int32Constant(mask),
1266                              m.Word32And(m.Int32Constant(mask), x));
1267       },
1268       "if (mask == (mask and x))", kArm64TestAndBranch32, MachineType::Int32()},
1269      kNotEqual},
1270     {{[](InstructionSelectorTest::StreamBuilder& m, Node* x,
__anone2b855730d02() 1271          uint32_t mask) -> Node* {
1272         return m.Word32BinaryNot(m.Word32Equal(
1273             m.Int32Constant(mask), m.Word32And(m.Int32Constant(mask), x)));
1274       },
1275       "if (mask != (mask and x))", kArm64TestAndBranch32, MachineType::Int32()},
1276      kEqual}};
1277 
1278 using InstructionSelectorTestAndBranchTest =
1279     InstructionSelectorTestWithParam<TestAndBranch>;
1280 
TEST_P(InstructionSelectorTestAndBranchTest,TestAndBranch32)1281 TEST_P(InstructionSelectorTestAndBranchTest, TestAndBranch32) {
1282   const TestAndBranch inst = GetParam();
1283   TRACED_FORRANGE(int, bit, 0, 31) {
1284     uint32_t mask = 1 << bit;
1285     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
1286     RawMachineLabel a, b;
1287     m.Branch(inst.mi.constructor(m, m.Parameter(0), mask), &a, &b);
1288     m.Bind(&a);
1289     m.Return(m.Int32Constant(1));
1290     m.Bind(&b);
1291     m.Return(m.Int32Constant(0));
1292     Stream s = m.Build();
1293     ASSERT_EQ(1U, s.size());
1294     EXPECT_EQ(inst.mi.arch_opcode, s[0]->arch_opcode());
1295     EXPECT_EQ(inst.cond, s[0]->flags_condition());
1296     EXPECT_EQ(4U, s[0]->InputCount());
1297     EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
1298     EXPECT_EQ(bit, s.ToInt32(s[0]->InputAt(1)));
1299   }
1300 }
1301 
1302 INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest,
1303                          InstructionSelectorTestAndBranchTest,
1304                          ::testing::ValuesIn(kTestAndBranchMatchers32));
1305 
1306 // TODO(arm64): Add the missing Word32BinaryNot test cases from the 32-bit
1307 // version.
1308 const TestAndBranch kTestAndBranchMatchers64[] = {
1309     // Branch on the result of Word64And directly.
1310     {{[](InstructionSelectorTest::StreamBuilder& m, Node* x, uint64_t mask)
__anone2b855730e02() 1311           -> Node* { return m.Word64And(x, m.Int64Constant(mask)); },
1312       "if (x and mask)", kArm64TestAndBranch, MachineType::Int64()},
1313      kNotEqual},
1314     {{[](InstructionSelectorTest::StreamBuilder& m, Node* x,
__anone2b855730f02() 1315          uint64_t mask) -> Node* {
1316         return m.Word64Equal(m.Word64And(x, m.Int64Constant(mask)),
1317                              m.Int64Constant(0));
1318       },
1319       "if not (x and mask)", kArm64TestAndBranch, MachineType::Int64()},
1320      kEqual},
1321     {{[](InstructionSelectorTest::StreamBuilder& m, Node* x, uint64_t mask)
__anone2b855731002() 1322           -> Node* { return m.Word64And(m.Int64Constant(mask), x); },
1323       "if (mask and x)", kArm64TestAndBranch, MachineType::Int64()},
1324      kNotEqual},
1325     {{[](InstructionSelectorTest::StreamBuilder& m, Node* x,
__anone2b855731102() 1326          uint64_t mask) -> Node* {
1327         return m.Word64Equal(m.Word64And(m.Int64Constant(mask), x),
1328                              m.Int64Constant(0));
1329       },
1330       "if not (mask and x)", kArm64TestAndBranch, MachineType::Int64()},
1331      kEqual},
1332     // Branch on the result of '(x and mask) == mask'. This tests that a bit is
1333     // set rather than cleared which is why conditions are inverted.
1334     {{[](InstructionSelectorTest::StreamBuilder& m, Node* x,
__anone2b855731202() 1335          uint64_t mask) -> Node* {
1336         return m.Word64Equal(m.Word64And(x, m.Int64Constant(mask)),
1337                              m.Int64Constant(mask));
1338       },
1339       "if ((x and mask) == mask)", kArm64TestAndBranch, MachineType::Int64()},
1340      kNotEqual},
1341     {{[](InstructionSelectorTest::StreamBuilder& m, Node* x,
__anone2b855731302() 1342          uint64_t mask) -> Node* {
1343         return m.Word64Equal(m.Int64Constant(mask),
1344                              m.Word64And(x, m.Int64Constant(mask)));
1345       },
1346       "if (mask == (x and mask))", kArm64TestAndBranch, MachineType::Int64()},
1347      kNotEqual},
1348     // Same as above but swap 'mask' and 'x'.
1349     {{[](InstructionSelectorTest::StreamBuilder& m, Node* x,
__anone2b855731402() 1350          uint64_t mask) -> Node* {
1351         return m.Word64Equal(m.Word64And(m.Int64Constant(mask), x),
1352                              m.Int64Constant(mask));
1353       },
1354       "if ((mask and x) == mask)", kArm64TestAndBranch, MachineType::Int64()},
1355      kNotEqual},
1356     {{[](InstructionSelectorTest::StreamBuilder& m, Node* x,
__anone2b855731502() 1357          uint64_t mask) -> Node* {
1358         return m.Word64Equal(m.Int64Constant(mask),
1359                              m.Word64And(m.Int64Constant(mask), x));
1360       },
1361       "if (mask == (mask and x))", kArm64TestAndBranch, MachineType::Int64()},
1362      kNotEqual}};
1363 
1364 using InstructionSelectorTestAndBranchTest64 =
1365     InstructionSelectorTestWithParam<TestAndBranch>;
1366 
TEST_P(InstructionSelectorTestAndBranchTest64,TestAndBranch64)1367 TEST_P(InstructionSelectorTestAndBranchTest64, TestAndBranch64) {
1368   const TestAndBranch inst = GetParam();
1369   TRACED_FORRANGE(int, bit, 0, 63) {
1370     uint64_t mask = uint64_t{1} << bit;
1371     StreamBuilder m(this, MachineType::Int64(), MachineType::Int64());
1372     RawMachineLabel a, b;
1373     m.Branch(inst.mi.constructor(m, m.Parameter(0), mask), &a, &b);
1374     m.Bind(&a);
1375     m.Return(m.Int64Constant(1));
1376     m.Bind(&b);
1377     m.Return(m.Int64Constant(0));
1378     Stream s = m.Build();
1379     ASSERT_EQ(1U, s.size());
1380     EXPECT_EQ(inst.mi.arch_opcode, s[0]->arch_opcode());
1381     EXPECT_EQ(inst.cond, s[0]->flags_condition());
1382     EXPECT_EQ(4U, s[0]->InputCount());
1383     EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
1384     EXPECT_EQ(bit, s.ToInt64(s[0]->InputAt(1)));
1385   }
1386 }
1387 
1388 INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest,
1389                          InstructionSelectorTestAndBranchTest64,
1390                          ::testing::ValuesIn(kTestAndBranchMatchers64));
1391 
TEST_F(InstructionSelectorTest,Word64AndBranchWithOneBitMaskOnRight)1392 TEST_F(InstructionSelectorTest, Word64AndBranchWithOneBitMaskOnRight) {
1393   TRACED_FORRANGE(int, bit, 0, 63) {
1394     uint64_t mask = uint64_t{1} << bit;
1395     StreamBuilder m(this, MachineType::Int64(), MachineType::Int64());
1396     RawMachineLabel a, b;
1397     m.Branch(m.Word64And(m.Parameter(0), m.Int64Constant(mask)), &a, &b);
1398     m.Bind(&a);
1399     m.Return(m.Int32Constant(1));
1400     m.Bind(&b);
1401     m.Return(m.Int32Constant(0));
1402     Stream s = m.Build();
1403     ASSERT_EQ(1U, s.size());
1404     EXPECT_EQ(kArm64TestAndBranch, s[0]->arch_opcode());
1405     EXPECT_EQ(kNotEqual, s[0]->flags_condition());
1406     EXPECT_EQ(4U, s[0]->InputCount());
1407     EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
1408     EXPECT_EQ(bit, s.ToInt64(s[0]->InputAt(1)));
1409   }
1410 }
1411 
TEST_F(InstructionSelectorTest,Word64AndBranchWithOneBitMaskOnLeft)1412 TEST_F(InstructionSelectorTest, Word64AndBranchWithOneBitMaskOnLeft) {
1413   TRACED_FORRANGE(int, bit, 0, 63) {
1414     uint64_t mask = uint64_t{1} << bit;
1415     StreamBuilder m(this, MachineType::Int64(), MachineType::Int64());
1416     RawMachineLabel a, b;
1417     m.Branch(m.Word64And(m.Int64Constant(mask), m.Parameter(0)), &a, &b);
1418     m.Bind(&a);
1419     m.Return(m.Int32Constant(1));
1420     m.Bind(&b);
1421     m.Return(m.Int32Constant(0));
1422     Stream s = m.Build();
1423     ASSERT_EQ(1U, s.size());
1424     EXPECT_EQ(kArm64TestAndBranch, s[0]->arch_opcode());
1425     EXPECT_EQ(kNotEqual, s[0]->flags_condition());
1426     EXPECT_EQ(4U, s[0]->InputCount());
1427     EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
1428     EXPECT_EQ(bit, s.ToInt64(s[0]->InputAt(1)));
1429   }
1430 }
1431 
TEST_F(InstructionSelectorTest,TestAndBranch64EqualWhenCanCoverFalse)1432 TEST_F(InstructionSelectorTest, TestAndBranch64EqualWhenCanCoverFalse) {
1433   TRACED_FORRANGE(int, bit, 0, 63) {
1434     uint64_t mask = uint64_t{1} << bit;
1435     StreamBuilder m(this, MachineType::Int64(), MachineType::Int64());
1436     RawMachineLabel a, b, c;
1437     Node* n = m.Word64And(m.Parameter(0), m.Int64Constant(mask));
1438     m.Branch(m.Word64Equal(n, m.Int64Constant(0)), &a, &b);
1439     m.Bind(&a);
1440     m.Branch(m.Word64Equal(n, m.Int64Constant(3)), &b, &c);
1441     m.Bind(&c);
1442     m.Return(m.Int64Constant(1));
1443     m.Bind(&b);
1444     m.Return(m.Int64Constant(0));
1445 
1446     Stream s = m.Build();
1447     ASSERT_EQ(3U, s.size());
1448     EXPECT_EQ(kArm64And, s[0]->arch_opcode());
1449     EXPECT_EQ(kEqual, s[0]->flags_condition());
1450     EXPECT_EQ(kArm64TestAndBranch, s[1]->arch_opcode());
1451     EXPECT_EQ(kEqual, s[1]->flags_condition());
1452     EXPECT_EQ(kArm64Cmp, s[2]->arch_opcode());
1453     EXPECT_EQ(kEqual, s[2]->flags_condition());
1454     EXPECT_EQ(2U, s[0]->InputCount());
1455   }
1456 }
1457 
TEST_F(InstructionSelectorTest,TestAndBranch64AndWhenCanCoverFalse)1458 TEST_F(InstructionSelectorTest, TestAndBranch64AndWhenCanCoverFalse) {
1459   TRACED_FORRANGE(int, bit, 0, 63) {
1460     uint64_t mask = uint64_t{1} << bit;
1461     StreamBuilder m(this, MachineType::Int64(), MachineType::Int64());
1462     RawMachineLabel a, b, c;
1463     m.Branch(m.Word64And(m.Parameter(0), m.Int64Constant(mask)), &a, &b);
1464     m.Bind(&a);
1465     m.Return(m.Int64Constant(1));
1466     m.Bind(&b);
1467     m.Return(m.Int64Constant(0));
1468 
1469     Stream s = m.Build();
1470     ASSERT_EQ(1U, s.size());
1471     EXPECT_EQ(kArm64TestAndBranch, s[0]->arch_opcode());
1472     EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
1473     EXPECT_EQ(4U, s[0]->InputCount());
1474   }
1475 }
1476 
TEST_F(InstructionSelectorTest,TestAndBranch32AndWhenCanCoverFalse)1477 TEST_F(InstructionSelectorTest, TestAndBranch32AndWhenCanCoverFalse) {
1478   TRACED_FORRANGE(int, bit, 0, 31) {
1479     uint32_t mask = uint32_t{1} << bit;
1480     StreamBuilder m(this, MachineType::Int64(), MachineType::Int64());
1481     RawMachineLabel a, b, c;
1482     m.Branch(m.Word32And(m.Parameter(0), m.Int32Constant(mask)), &a, &b);
1483     m.Bind(&a);
1484     m.Return(m.Int32Constant(1));
1485     m.Bind(&b);
1486     m.Return(m.Int32Constant(0));
1487 
1488     Stream s = m.Build();
1489     ASSERT_EQ(1U, s.size());
1490     EXPECT_EQ(kArm64TestAndBranch32, s[0]->arch_opcode());
1491     EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
1492     EXPECT_EQ(4U, s[0]->InputCount());
1493   }
1494 }
1495 
TEST_F(InstructionSelectorTest,Word32EqualZeroAndBranchWithOneBitMask)1496 TEST_F(InstructionSelectorTest, Word32EqualZeroAndBranchWithOneBitMask) {
1497   TRACED_FORRANGE(int, bit, 0, 31) {
1498     uint32_t mask = 1 << bit;
1499     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
1500     RawMachineLabel a, b;
1501     m.Branch(m.Word32Equal(m.Word32And(m.Int32Constant(mask), m.Parameter(0)),
1502                            m.Int32Constant(0)),
1503              &a, &b);
1504     m.Bind(&a);
1505     m.Return(m.Int32Constant(1));
1506     m.Bind(&b);
1507     m.Return(m.Int32Constant(0));
1508     Stream s = m.Build();
1509     ASSERT_EQ(1U, s.size());
1510     EXPECT_EQ(kArm64TestAndBranch32, s[0]->arch_opcode());
1511     EXPECT_EQ(kEqual, s[0]->flags_condition());
1512     EXPECT_EQ(4U, s[0]->InputCount());
1513     EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
1514     EXPECT_EQ(bit, s.ToInt32(s[0]->InputAt(1)));
1515   }
1516 
1517   TRACED_FORRANGE(int, bit, 0, 31) {
1518     uint32_t mask = 1 << bit;
1519     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
1520     RawMachineLabel a, b;
1521     m.Branch(
1522         m.Word32NotEqual(m.Word32And(m.Int32Constant(mask), m.Parameter(0)),
1523                          m.Int32Constant(0)),
1524         &a, &b);
1525     m.Bind(&a);
1526     m.Return(m.Int32Constant(1));
1527     m.Bind(&b);
1528     m.Return(m.Int32Constant(0));
1529     Stream s = m.Build();
1530     ASSERT_EQ(1U, s.size());
1531     EXPECT_EQ(kArm64TestAndBranch32, s[0]->arch_opcode());
1532     EXPECT_EQ(kNotEqual, s[0]->flags_condition());
1533     EXPECT_EQ(4U, s[0]->InputCount());
1534     EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
1535     EXPECT_EQ(bit, s.ToInt32(s[0]->InputAt(1)));
1536   }
1537 }
1538 
TEST_F(InstructionSelectorTest,Word64EqualZeroAndBranchWithOneBitMask)1539 TEST_F(InstructionSelectorTest, Word64EqualZeroAndBranchWithOneBitMask) {
1540   TRACED_FORRANGE(int, bit, 0, 63) {
1541     uint64_t mask = uint64_t{1} << bit;
1542     StreamBuilder m(this, MachineType::Int64(), MachineType::Int64());
1543     RawMachineLabel a, b;
1544     m.Branch(m.Word64Equal(m.Word64And(m.Int64Constant(mask), m.Parameter(0)),
1545                            m.Int64Constant(0)),
1546              &a, &b);
1547     m.Bind(&a);
1548     m.Return(m.Int64Constant(1));
1549     m.Bind(&b);
1550     m.Return(m.Int64Constant(0));
1551     Stream s = m.Build();
1552     ASSERT_EQ(1U, s.size());
1553     EXPECT_EQ(kArm64TestAndBranch, s[0]->arch_opcode());
1554     EXPECT_EQ(kEqual, s[0]->flags_condition());
1555     EXPECT_EQ(4U, s[0]->InputCount());
1556     EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
1557     EXPECT_EQ(bit, s.ToInt64(s[0]->InputAt(1)));
1558   }
1559 
1560   TRACED_FORRANGE(int, bit, 0, 63) {
1561     uint64_t mask = uint64_t{1} << bit;
1562     StreamBuilder m(this, MachineType::Int64(), MachineType::Int64());
1563     RawMachineLabel a, b;
1564     m.Branch(
1565         m.Word64NotEqual(m.Word64And(m.Int64Constant(mask), m.Parameter(0)),
1566                          m.Int64Constant(0)),
1567         &a, &b);
1568     m.Bind(&a);
1569     m.Return(m.Int64Constant(1));
1570     m.Bind(&b);
1571     m.Return(m.Int64Constant(0));
1572     Stream s = m.Build();
1573     ASSERT_EQ(1U, s.size());
1574     EXPECT_EQ(kArm64TestAndBranch, s[0]->arch_opcode());
1575     EXPECT_EQ(kNotEqual, s[0]->flags_condition());
1576     EXPECT_EQ(4U, s[0]->InputCount());
1577     EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
1578     EXPECT_EQ(bit, s.ToInt64(s[0]->InputAt(1)));
1579   }
1580 }
1581 
TEST_F(InstructionSelectorTest,CompareAgainstZeroAndBranch)1582 TEST_F(InstructionSelectorTest, CompareAgainstZeroAndBranch) {
1583   {
1584     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
1585     RawMachineLabel a, b;
1586     Node* p0 = m.Parameter(0);
1587     m.Branch(p0, &a, &b);
1588     m.Bind(&a);
1589     m.Return(m.Int32Constant(1));
1590     m.Bind(&b);
1591     m.Return(m.Int32Constant(0));
1592     Stream s = m.Build();
1593     ASSERT_EQ(1U, s.size());
1594     EXPECT_EQ(kArm64CompareAndBranch32, s[0]->arch_opcode());
1595     EXPECT_EQ(kNotEqual, s[0]->flags_condition());
1596     EXPECT_EQ(3U, s[0]->InputCount());
1597     EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1598   }
1599 
1600   {
1601     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
1602     RawMachineLabel a, b;
1603     Node* p0 = m.Parameter(0);
1604     m.Branch(m.Word32BinaryNot(p0), &a, &b);
1605     m.Bind(&a);
1606     m.Return(m.Int32Constant(1));
1607     m.Bind(&b);
1608     m.Return(m.Int32Constant(0));
1609     Stream s = m.Build();
1610     ASSERT_EQ(1U, s.size());
1611     EXPECT_EQ(kArm64CompareAndBranch32, s[0]->arch_opcode());
1612     EXPECT_EQ(kEqual, s[0]->flags_condition());
1613     EXPECT_EQ(3U, s[0]->InputCount());
1614     EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1615   }
1616 }
1617 
TEST_F(InstructionSelectorTest,EqualZeroAndBranch)1618 TEST_F(InstructionSelectorTest, EqualZeroAndBranch) {
1619   {
1620     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
1621     RawMachineLabel a, b;
1622     Node* p0 = m.Parameter(0);
1623     m.Branch(m.Word32Equal(p0, m.Int32Constant(0)), &a, &b);
1624     m.Bind(&a);
1625     m.Return(m.Int32Constant(1));
1626     m.Bind(&b);
1627     m.Return(m.Int32Constant(0));
1628     Stream s = m.Build();
1629     ASSERT_EQ(1U, s.size());
1630     EXPECT_EQ(kArm64CompareAndBranch32, s[0]->arch_opcode());
1631     EXPECT_EQ(kEqual, s[0]->flags_condition());
1632     EXPECT_EQ(3U, s[0]->InputCount());
1633     EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1634   }
1635 
1636   {
1637     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
1638     RawMachineLabel a, b;
1639     Node* p0 = m.Parameter(0);
1640     m.Branch(m.Word32NotEqual(p0, m.Int32Constant(0)), &a, &b);
1641     m.Bind(&a);
1642     m.Return(m.Int32Constant(1));
1643     m.Bind(&b);
1644     m.Return(m.Int32Constant(0));
1645     Stream s = m.Build();
1646     ASSERT_EQ(1U, s.size());
1647     EXPECT_EQ(kArm64CompareAndBranch32, s[0]->arch_opcode());
1648     EXPECT_EQ(kNotEqual, s[0]->flags_condition());
1649     EXPECT_EQ(3U, s[0]->InputCount());
1650     EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1651   }
1652 
1653   {
1654     StreamBuilder m(this, MachineType::Int64(), MachineType::Int64());
1655     RawMachineLabel a, b;
1656     Node* p0 = m.Parameter(0);
1657     m.Branch(m.Word64Equal(p0, m.Int64Constant(0)), &a, &b);
1658     m.Bind(&a);
1659     m.Return(m.Int64Constant(1));
1660     m.Bind(&b);
1661     m.Return(m.Int64Constant(0));
1662     Stream s = m.Build();
1663     ASSERT_EQ(1U, s.size());
1664     EXPECT_EQ(kArm64CompareAndBranch, s[0]->arch_opcode());
1665     EXPECT_EQ(kEqual, s[0]->flags_condition());
1666     EXPECT_EQ(3U, s[0]->InputCount());
1667     EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1668   }
1669 
1670   {
1671     StreamBuilder m(this, MachineType::Int64(), MachineType::Int64());
1672     RawMachineLabel a, b;
1673     Node* p0 = m.Parameter(0);
1674     m.Branch(m.Word64NotEqual(p0, m.Int64Constant(0)), &a, &b);
1675     m.Bind(&a);
1676     m.Return(m.Int64Constant(1));
1677     m.Bind(&b);
1678     m.Return(m.Int64Constant(0));
1679     Stream s = m.Build();
1680     ASSERT_EQ(1U, s.size());
1681     EXPECT_EQ(kArm64CompareAndBranch, s[0]->arch_opcode());
1682     EXPECT_EQ(kNotEqual, s[0]->flags_condition());
1683     EXPECT_EQ(3U, s[0]->InputCount());
1684     EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1685   }
1686 }
1687 
1688 // -----------------------------------------------------------------------------
1689 // Add and subtract instructions with overflow.
1690 
1691 using InstructionSelectorOvfAddSubTest =
1692     InstructionSelectorTestWithParam<MachInst2>;
1693 
TEST_P(InstructionSelectorOvfAddSubTest,OvfParameter)1694 TEST_P(InstructionSelectorOvfAddSubTest, OvfParameter) {
1695   const MachInst2 dpi = GetParam();
1696   const MachineType type = dpi.machine_type;
1697   StreamBuilder m(this, type, type, type);
1698   m.Return(
1699       m.Projection(1, (m.*dpi.constructor)(m.Parameter(0), m.Parameter(1))));
1700   Stream s = m.Build();
1701   ASSERT_EQ(1U, s.size());
1702   EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
1703   EXPECT_EQ(2U, s[0]->InputCount());
1704   EXPECT_LE(1U, s[0]->OutputCount());
1705   EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1706   EXPECT_EQ(kOverflow, s[0]->flags_condition());
1707 }
1708 
TEST_P(InstructionSelectorOvfAddSubTest,OvfImmediateOnRight)1709 TEST_P(InstructionSelectorOvfAddSubTest, OvfImmediateOnRight) {
1710   const MachInst2 dpi = GetParam();
1711   const MachineType type = dpi.machine_type;
1712   TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
1713     StreamBuilder m(this, type, type);
1714     m.Return(m.Projection(
1715         1, (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm))));
1716     Stream s = m.Build();
1717     ASSERT_EQ(1U, s.size());
1718     EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
1719     ASSERT_EQ(2U, s[0]->InputCount());
1720     EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
1721     EXPECT_LE(1U, s[0]->OutputCount());
1722     EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1723     EXPECT_EQ(kOverflow, s[0]->flags_condition());
1724   }
1725 }
1726 
TEST_P(InstructionSelectorOvfAddSubTest,ValParameter)1727 TEST_P(InstructionSelectorOvfAddSubTest, ValParameter) {
1728   const MachInst2 dpi = GetParam();
1729   const MachineType type = dpi.machine_type;
1730   StreamBuilder m(this, type, type, type);
1731   m.Return(
1732       m.Projection(0, (m.*dpi.constructor)(m.Parameter(0), m.Parameter(1))));
1733   Stream s = m.Build();
1734   ASSERT_EQ(1U, s.size());
1735   EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
1736   EXPECT_EQ(2U, s[0]->InputCount());
1737   EXPECT_LE(1U, s[0]->OutputCount());
1738   EXPECT_EQ(kFlags_none, s[0]->flags_mode());
1739 }
1740 
TEST_P(InstructionSelectorOvfAddSubTest,ValImmediateOnRight)1741 TEST_P(InstructionSelectorOvfAddSubTest, ValImmediateOnRight) {
1742   const MachInst2 dpi = GetParam();
1743   const MachineType type = dpi.machine_type;
1744   TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
1745     StreamBuilder m(this, type, type);
1746     m.Return(m.Projection(
1747         0, (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm))));
1748     Stream s = m.Build();
1749     ASSERT_EQ(1U, s.size());
1750     EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
1751     ASSERT_EQ(2U, s[0]->InputCount());
1752     EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
1753     EXPECT_LE(1U, s[0]->OutputCount());
1754     EXPECT_EQ(kFlags_none, s[0]->flags_mode());
1755   }
1756 }
1757 
TEST_P(InstructionSelectorOvfAddSubTest,BothParameter)1758 TEST_P(InstructionSelectorOvfAddSubTest, BothParameter) {
1759   const MachInst2 dpi = GetParam();
1760   const MachineType type = dpi.machine_type;
1761   StreamBuilder m(this, type, type, type);
1762   Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Parameter(1));
1763   m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
1764   Stream s = m.Build();
1765   ASSERT_LE(1U, s.size());
1766   EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
1767   EXPECT_EQ(2U, s[0]->InputCount());
1768   EXPECT_EQ(2U, s[0]->OutputCount());
1769   EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1770   EXPECT_EQ(kOverflow, s[0]->flags_condition());
1771 }
1772 
TEST_P(InstructionSelectorOvfAddSubTest,BothImmediateOnRight)1773 TEST_P(InstructionSelectorOvfAddSubTest, BothImmediateOnRight) {
1774   const MachInst2 dpi = GetParam();
1775   const MachineType type = dpi.machine_type;
1776   TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
1777     StreamBuilder m(this, type, type);
1778     Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm));
1779     m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
1780     Stream s = m.Build();
1781     ASSERT_LE(1U, s.size());
1782     EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
1783     ASSERT_EQ(2U, s[0]->InputCount());
1784     EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
1785     EXPECT_EQ(2U, s[0]->OutputCount());
1786     EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1787     EXPECT_EQ(kOverflow, s[0]->flags_condition());
1788   }
1789 }
1790 
TEST_P(InstructionSelectorOvfAddSubTest,BranchWithParameters)1791 TEST_P(InstructionSelectorOvfAddSubTest, BranchWithParameters) {
1792   const MachInst2 dpi = GetParam();
1793   const MachineType type = dpi.machine_type;
1794   StreamBuilder m(this, type, type, type);
1795   RawMachineLabel a, b;
1796   Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Parameter(1));
1797   m.Branch(m.Projection(1, n), &a, &b);
1798   m.Bind(&a);
1799   m.Return(m.Int32Constant(0));
1800   m.Bind(&b);
1801   m.Return(m.Projection(0, n));
1802   Stream s = m.Build();
1803   ASSERT_EQ(1U, s.size());
1804   EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
1805   EXPECT_EQ(4U, s[0]->InputCount());
1806   EXPECT_EQ(1U, s[0]->OutputCount());
1807   EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
1808   EXPECT_EQ(kOverflow, s[0]->flags_condition());
1809 }
1810 
TEST_P(InstructionSelectorOvfAddSubTest,BranchWithImmediateOnRight)1811 TEST_P(InstructionSelectorOvfAddSubTest, BranchWithImmediateOnRight) {
1812   const MachInst2 dpi = GetParam();
1813   const MachineType type = dpi.machine_type;
1814   TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
1815     StreamBuilder m(this, type, type);
1816     RawMachineLabel a, b;
1817     Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm));
1818     m.Branch(m.Projection(1, n), &a, &b);
1819     m.Bind(&a);
1820     m.Return(m.Int32Constant(0));
1821     m.Bind(&b);
1822     m.Return(m.Projection(0, n));
1823     Stream s = m.Build();
1824     ASSERT_EQ(1U, s.size());
1825     EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
1826     ASSERT_EQ(4U, s[0]->InputCount());
1827     EXPECT_EQ(1U, s[0]->OutputCount());
1828     EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
1829     EXPECT_EQ(kOverflow, s[0]->flags_condition());
1830   }
1831 }
1832 
TEST_P(InstructionSelectorOvfAddSubTest,RORShift)1833 TEST_P(InstructionSelectorOvfAddSubTest, RORShift) {
1834   // ADD and SUB do not support ROR shifts, make sure we do not try
1835   // to merge them into the ADD/SUB instruction.
1836   const MachInst2 dpi = GetParam();
1837   const MachineType type = dpi.machine_type;
1838   auto rotate = &RawMachineAssembler::Word64Ror;
1839   ArchOpcode rotate_opcode = kArm64Ror;
1840   if (type == MachineType::Int32()) {
1841     rotate = &RawMachineAssembler::Word32Ror;
1842     rotate_opcode = kArm64Ror32;
1843   }
1844   TRACED_FORRANGE(int32_t, imm, -32, 63) {
1845     StreamBuilder m(this, type, type, type);
1846     Node* const p0 = m.Parameter(0);
1847     Node* const p1 = m.Parameter(1);
1848     Node* r = (m.*rotate)(p1, m.Int32Constant(imm));
1849     m.Return((m.*dpi.constructor)(p0, r));
1850     Stream s = m.Build();
1851     ASSERT_EQ(2U, s.size());
1852     EXPECT_EQ(rotate_opcode, s[0]->arch_opcode());
1853     EXPECT_EQ(dpi.arch_opcode, s[1]->arch_opcode());
1854   }
1855 }
1856 
1857 INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest,
1858                          InstructionSelectorOvfAddSubTest,
1859                          ::testing::ValuesIn(kOvfAddSubInstructions));
1860 
TEST_F(InstructionSelectorTest,OvfFlagAddImmediateOnLeft)1861 TEST_F(InstructionSelectorTest, OvfFlagAddImmediateOnLeft) {
1862   TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
1863     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
1864     m.Return(m.Projection(
1865         1, m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0))));
1866     Stream s = m.Build();
1867 
1868     ASSERT_EQ(1U, s.size());
1869     EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
1870     EXPECT_EQ(2U, s[0]->InputCount());
1871     EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
1872     EXPECT_LE(1U, s[0]->OutputCount());
1873     EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1874     EXPECT_EQ(kOverflow, s[0]->flags_condition());
1875   }
1876 }
1877 
TEST_F(InstructionSelectorTest,OvfValAddImmediateOnLeft)1878 TEST_F(InstructionSelectorTest, OvfValAddImmediateOnLeft) {
1879   TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
1880     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
1881     m.Return(m.Projection(
1882         0, m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0))));
1883     Stream s = m.Build();
1884 
1885     ASSERT_EQ(1U, s.size());
1886     EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
1887     ASSERT_EQ(2U, s[0]->InputCount());
1888     EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
1889     EXPECT_LE(1U, s[0]->OutputCount());
1890     EXPECT_EQ(kFlags_none, s[0]->flags_mode());
1891   }
1892 }
1893 
TEST_F(InstructionSelectorTest,OvfBothAddImmediateOnLeft)1894 TEST_F(InstructionSelectorTest, OvfBothAddImmediateOnLeft) {
1895   TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
1896     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
1897     Node* n = m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0));
1898     m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
1899     Stream s = m.Build();
1900 
1901     ASSERT_LE(1U, s.size());
1902     EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
1903     ASSERT_EQ(2U, s[0]->InputCount());
1904     EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
1905     EXPECT_EQ(2U, s[0]->OutputCount());
1906     EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1907     EXPECT_EQ(kOverflow, s[0]->flags_condition());
1908   }
1909 }
1910 
TEST_F(InstructionSelectorTest,OvfBranchWithImmediateOnLeft)1911 TEST_F(InstructionSelectorTest, OvfBranchWithImmediateOnLeft) {
1912   TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
1913     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
1914     RawMachineLabel a, b;
1915     Node* n = m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0));
1916     m.Branch(m.Projection(1, n), &a, &b);
1917     m.Bind(&a);
1918     m.Return(m.Int32Constant(0));
1919     m.Bind(&b);
1920     m.Return(m.Projection(0, n));
1921     Stream s = m.Build();
1922 
1923     ASSERT_EQ(1U, s.size());
1924     EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
1925     ASSERT_EQ(4U, s[0]->InputCount());
1926     EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
1927     EXPECT_EQ(1U, s[0]->OutputCount());
1928     EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
1929     EXPECT_EQ(kOverflow, s[0]->flags_condition());
1930   }
1931 }
1932 
1933 // -----------------------------------------------------------------------------
1934 // Shift instructions.
1935 
1936 using InstructionSelectorShiftTest = InstructionSelectorTestWithParam<Shift>;
1937 
TEST_P(InstructionSelectorShiftTest,Parameter)1938 TEST_P(InstructionSelectorShiftTest, Parameter) {
1939   const Shift shift = GetParam();
1940   const MachineType type = shift.mi.machine_type;
1941   StreamBuilder m(this, type, type, type);
1942   m.Return((m.*shift.mi.constructor)(m.Parameter(0), m.Parameter(1)));
1943   Stream s = m.Build();
1944   ASSERT_EQ(1U, s.size());
1945   EXPECT_EQ(shift.mi.arch_opcode, s[0]->arch_opcode());
1946   EXPECT_EQ(2U, s[0]->InputCount());
1947   EXPECT_EQ(1U, s[0]->OutputCount());
1948 }
1949 
TEST_P(InstructionSelectorShiftTest,Immediate)1950 TEST_P(InstructionSelectorShiftTest, Immediate) {
1951   const Shift shift = GetParam();
1952   const MachineType type = shift.mi.machine_type;
1953   TRACED_FORRANGE(int32_t, imm, 0,
1954                   ((1 << ElementSizeLog2Of(type.representation())) * 8) - 1) {
1955     StreamBuilder m(this, type, type);
1956     m.Return((m.*shift.mi.constructor)(m.Parameter(0), m.Int32Constant(imm)));
1957     Stream s = m.Build();
1958     ASSERT_EQ(1U, s.size());
1959     EXPECT_EQ(shift.mi.arch_opcode, s[0]->arch_opcode());
1960     EXPECT_EQ(2U, s[0]->InputCount());
1961     EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
1962     EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
1963     EXPECT_EQ(1U, s[0]->OutputCount());
1964   }
1965 }
1966 
1967 INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest, InstructionSelectorShiftTest,
1968                          ::testing::ValuesIn(kShiftInstructions));
1969 
TEST_F(InstructionSelectorTest,Word64ShlWithChangeInt32ToInt64)1970 TEST_F(InstructionSelectorTest, Word64ShlWithChangeInt32ToInt64) {
1971   TRACED_FORRANGE(int64_t, x, 32, 63) {
1972     StreamBuilder m(this, MachineType::Int64(), MachineType::Int32());
1973     Node* const p0 = m.Parameter(0);
1974     Node* const n = m.Word64Shl(m.ChangeInt32ToInt64(p0), m.Int64Constant(x));
1975     m.Return(n);
1976     Stream s = m.Build();
1977     ASSERT_EQ(1U, s.size());
1978     EXPECT_EQ(kArm64Lsl, s[0]->arch_opcode());
1979     ASSERT_EQ(2U, s[0]->InputCount());
1980     EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1981     EXPECT_EQ(x, s.ToInt64(s[0]->InputAt(1)));
1982     ASSERT_EQ(1U, s[0]->OutputCount());
1983     EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
1984   }
1985 }
1986 
TEST_F(InstructionSelectorTest,Word64ShlWithChangeUint32ToUint64)1987 TEST_F(InstructionSelectorTest, Word64ShlWithChangeUint32ToUint64) {
1988   TRACED_FORRANGE(int64_t, x, 32, 63) {
1989     StreamBuilder m(this, MachineType::Int64(), MachineType::Uint32());
1990     Node* const p0 = m.Parameter(0);
1991     Node* const n = m.Word64Shl(m.ChangeUint32ToUint64(p0), m.Int64Constant(x));
1992     m.Return(n);
1993     Stream s = m.Build();
1994     ASSERT_EQ(1U, s.size());
1995     EXPECT_EQ(kArm64Lsl, s[0]->arch_opcode());
1996     ASSERT_EQ(2U, s[0]->InputCount());
1997     EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1998     EXPECT_EQ(x, s.ToInt64(s[0]->InputAt(1)));
1999     ASSERT_EQ(1U, s[0]->OutputCount());
2000     EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
2001   }
2002 }
2003 
TEST_F(InstructionSelectorTest,TruncateInt64ToInt32WithWord64Sar)2004 TEST_F(InstructionSelectorTest, TruncateInt64ToInt32WithWord64Sar) {
2005   StreamBuilder m(this, MachineType::Int32(), MachineType::Int64());
2006   Node* const p = m.Parameter(0);
2007   Node* const t = m.TruncateInt64ToInt32(m.Word64Sar(p, m.Int64Constant(32)));
2008   m.Return(t);
2009   Stream s = m.Build();
2010   ASSERT_EQ(1U, s.size());
2011   EXPECT_EQ(kArm64Asr, s[0]->arch_opcode());
2012   ASSERT_EQ(2U, s[0]->InputCount());
2013   EXPECT_EQ(s.ToVreg(p), s.ToVreg(s[0]->InputAt(0)));
2014   EXPECT_EQ(32, s.ToInt64(s[0]->InputAt(1)));
2015   ASSERT_EQ(1U, s[0]->OutputCount());
2016 }
2017 
TEST_F(InstructionSelectorTest,TruncateInt64ToInt32WithWord64Shr)2018 TEST_F(InstructionSelectorTest, TruncateInt64ToInt32WithWord64Shr) {
2019   TRACED_FORRANGE(int64_t, x, 32, 63) {
2020     StreamBuilder m(this, MachineType::Int32(), MachineType::Int64());
2021     Node* const p = m.Parameter(0);
2022     Node* const t = m.TruncateInt64ToInt32(m.Word64Shr(p, m.Int64Constant(x)));
2023     m.Return(t);
2024     Stream s = m.Build();
2025     ASSERT_EQ(1U, s.size());
2026     EXPECT_EQ(kArm64Lsr, s[0]->arch_opcode());
2027     ASSERT_EQ(2U, s[0]->InputCount());
2028     EXPECT_EQ(s.ToVreg(p), s.ToVreg(s[0]->InputAt(0)));
2029     EXPECT_EQ(x, s.ToInt64(s[0]->InputAt(1)));
2030     ASSERT_EQ(1U, s[0]->OutputCount());
2031   }
2032 }
2033 
2034 // -----------------------------------------------------------------------------
2035 // Mul and Div instructions.
2036 
2037 using InstructionSelectorMulDivTest =
2038     InstructionSelectorTestWithParam<MachInst2>;
2039 
TEST_P(InstructionSelectorMulDivTest,Parameter)2040 TEST_P(InstructionSelectorMulDivTest, Parameter) {
2041   const MachInst2 dpi = GetParam();
2042   const MachineType type = dpi.machine_type;
2043   StreamBuilder m(this, type, type, type);
2044   m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)));
2045   Stream s = m.Build();
2046   ASSERT_EQ(1U, s.size());
2047   EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
2048   EXPECT_EQ(2U, s[0]->InputCount());
2049   EXPECT_EQ(1U, s[0]->OutputCount());
2050 }
2051 
2052 INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest, InstructionSelectorMulDivTest,
2053                          ::testing::ValuesIn(kMulDivInstructions));
2054 
2055 namespace {
2056 
2057 struct MulDPInst {
2058   const char* mul_constructor_name;
2059   Node* (RawMachineAssembler::*mul_constructor)(Node*, Node*);
2060   Node* (RawMachineAssembler::*add_constructor)(Node*, Node*);
2061   Node* (RawMachineAssembler::*sub_constructor)(Node*, Node*);
2062   ArchOpcode multiply_add_arch_opcode;
2063   ArchOpcode multiply_sub_arch_opcode;
2064   ArchOpcode multiply_neg_arch_opcode;
2065   MachineType machine_type;
2066 };
2067 
operator <<(std::ostream & os,const MulDPInst & inst)2068 std::ostream& operator<<(std::ostream& os, const MulDPInst& inst) {
2069   return os << inst.mul_constructor_name;
2070 }
2071 
2072 }  // namespace
2073 
2074 static const MulDPInst kMulDPInstructions[] = {
2075     {"Int32Mul", &RawMachineAssembler::Int32Mul, &RawMachineAssembler::Int32Add,
2076      &RawMachineAssembler::Int32Sub, kArm64Madd32, kArm64Msub32, kArm64Mneg32,
2077      MachineType::Int32()},
2078     {"Int64Mul", &RawMachineAssembler::Int64Mul, &RawMachineAssembler::Int64Add,
2079      &RawMachineAssembler::Int64Sub, kArm64Madd, kArm64Msub, kArm64Mneg,
2080      MachineType::Int64()}};
2081 
2082 using InstructionSelectorIntDPWithIntMulTest =
2083     InstructionSelectorTestWithParam<MulDPInst>;
2084 
TEST_P(InstructionSelectorIntDPWithIntMulTest,AddWithMul)2085 TEST_P(InstructionSelectorIntDPWithIntMulTest, AddWithMul) {
2086   const MulDPInst mdpi = GetParam();
2087   const MachineType type = mdpi.machine_type;
2088   {
2089     StreamBuilder m(this, type, type, type, type);
2090     Node* n = (m.*mdpi.mul_constructor)(m.Parameter(1), m.Parameter(2));
2091     m.Return((m.*mdpi.add_constructor)(m.Parameter(0), n));
2092     Stream s = m.Build();
2093     ASSERT_EQ(1U, s.size());
2094     EXPECT_EQ(mdpi.multiply_add_arch_opcode, s[0]->arch_opcode());
2095     EXPECT_EQ(3U, s[0]->InputCount());
2096     EXPECT_EQ(1U, s[0]->OutputCount());
2097   }
2098   {
2099     StreamBuilder m(this, type, type, type, type);
2100     Node* n = (m.*mdpi.mul_constructor)(m.Parameter(0), m.Parameter(1));
2101     m.Return((m.*mdpi.add_constructor)(n, m.Parameter(2)));
2102     Stream s = m.Build();
2103     ASSERT_EQ(1U, s.size());
2104     EXPECT_EQ(mdpi.multiply_add_arch_opcode, s[0]->arch_opcode());
2105     EXPECT_EQ(3U, s[0]->InputCount());
2106     EXPECT_EQ(1U, s[0]->OutputCount());
2107   }
2108 }
2109 
TEST_P(InstructionSelectorIntDPWithIntMulTest,SubWithMul)2110 TEST_P(InstructionSelectorIntDPWithIntMulTest, SubWithMul) {
2111   const MulDPInst mdpi = GetParam();
2112   const MachineType type = mdpi.machine_type;
2113   {
2114     StreamBuilder m(this, type, type, type, type);
2115     Node* n = (m.*mdpi.mul_constructor)(m.Parameter(1), m.Parameter(2));
2116     m.Return((m.*mdpi.sub_constructor)(m.Parameter(0), n));
2117     Stream s = m.Build();
2118     ASSERT_EQ(1U, s.size());
2119     EXPECT_EQ(mdpi.multiply_sub_arch_opcode, s[0]->arch_opcode());
2120     EXPECT_EQ(3U, s[0]->InputCount());
2121     EXPECT_EQ(1U, s[0]->OutputCount());
2122   }
2123 }
2124 
TEST_P(InstructionSelectorIntDPWithIntMulTest,NegativeMul)2125 TEST_P(InstructionSelectorIntDPWithIntMulTest, NegativeMul) {
2126   const MulDPInst mdpi = GetParam();
2127   const MachineType type = mdpi.machine_type;
2128   {
2129     StreamBuilder m(this, type, type, type);
2130     Node* n =
2131         (m.*mdpi.sub_constructor)(BuildConstant(&m, type, 0), m.Parameter(0));
2132     m.Return((m.*mdpi.mul_constructor)(n, m.Parameter(1)));
2133     Stream s = m.Build();
2134     ASSERT_EQ(1U, s.size());
2135     EXPECT_EQ(mdpi.multiply_neg_arch_opcode, s[0]->arch_opcode());
2136     EXPECT_EQ(2U, s[0]->InputCount());
2137     EXPECT_EQ(1U, s[0]->OutputCount());
2138   }
2139   {
2140     StreamBuilder m(this, type, type, type);
2141     Node* n =
2142         (m.*mdpi.sub_constructor)(BuildConstant(&m, type, 0), m.Parameter(1));
2143     m.Return((m.*mdpi.mul_constructor)(m.Parameter(0), n));
2144     Stream s = m.Build();
2145     ASSERT_EQ(1U, s.size());
2146     EXPECT_EQ(mdpi.multiply_neg_arch_opcode, s[0]->arch_opcode());
2147     EXPECT_EQ(2U, s[0]->InputCount());
2148     EXPECT_EQ(1U, s[0]->OutputCount());
2149   }
2150 }
2151 
2152 INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest,
2153                          InstructionSelectorIntDPWithIntMulTest,
2154                          ::testing::ValuesIn(kMulDPInstructions));
2155 
2156 namespace {
2157 
2158 struct SIMDMulDPInst {
2159   const char* mul_constructor_name;
2160   const Operator* (MachineOperatorBuilder::*mul_operator)(void);
2161   const Operator* (MachineOperatorBuilder::*add_operator)(void);
2162   const Operator* (MachineOperatorBuilder::*sub_operator)(void);
2163   ArchOpcode multiply_add_arch_opcode;
2164   ArchOpcode multiply_sub_arch_opcode;
2165   MachineType machine_type;
2166   const int lane_size;
2167 };
2168 
operator <<(std::ostream & os,const SIMDMulDPInst & inst)2169 std::ostream& operator<<(std::ostream& os, const SIMDMulDPInst& inst) {
2170   return os << inst.mul_constructor_name;
2171 }
2172 
2173 }  // namespace
2174 
2175 static const SIMDMulDPInst kSIMDMulDPInstructions[] = {
2176     {"I32x4Mul", &MachineOperatorBuilder::I32x4Mul,
2177      &MachineOperatorBuilder::I32x4Add, &MachineOperatorBuilder::I32x4Sub,
2178      kArm64Mla, kArm64Mls, MachineType::Simd128(), 32},
2179     {"I16x8Mul", &MachineOperatorBuilder::I16x8Mul,
2180      &MachineOperatorBuilder::I16x8Add, &MachineOperatorBuilder::I16x8Sub,
2181      kArm64Mla, kArm64Mls, MachineType::Simd128(), 16}};
2182 
2183 using InstructionSelectorSIMDDPWithSIMDMulTest =
2184     InstructionSelectorTestWithParam<SIMDMulDPInst>;
2185 
TEST_P(InstructionSelectorSIMDDPWithSIMDMulTest,AddWithMul)2186 TEST_P(InstructionSelectorSIMDDPWithSIMDMulTest, AddWithMul) {
2187   const SIMDMulDPInst mdpi = GetParam();
2188   const MachineType type = mdpi.machine_type;
2189   {
2190     StreamBuilder m(this, type, type, type, type);
2191     Node* n = m.AddNode((m.machine()->*mdpi.mul_operator)(), m.Parameter(1),
2192                         m.Parameter(2));
2193     m.Return(m.AddNode((m.machine()->*mdpi.add_operator)(), m.Parameter(0), n));
2194     Stream s = m.Build();
2195     ASSERT_EQ(1U, s.size());
2196     EXPECT_EQ(mdpi.multiply_add_arch_opcode, s[0]->arch_opcode());
2197     EXPECT_EQ(mdpi.lane_size, LaneSizeField::decode(s[0]->opcode()));
2198     EXPECT_EQ(3U, s[0]->InputCount());
2199     EXPECT_EQ(1U, s[0]->OutputCount());
2200   }
2201   {
2202     StreamBuilder m(this, type, type, type, type);
2203     Node* n = m.AddNode((m.machine()->*mdpi.mul_operator)(), m.Parameter(0),
2204                         m.Parameter(1));
2205     m.Return(m.AddNode((m.machine()->*mdpi.add_operator)(), n, m.Parameter(2)));
2206     Stream s = m.Build();
2207     ASSERT_EQ(1U, s.size());
2208     EXPECT_EQ(mdpi.multiply_add_arch_opcode, s[0]->arch_opcode());
2209     EXPECT_EQ(mdpi.lane_size, LaneSizeField::decode(s[0]->opcode()));
2210     EXPECT_EQ(3U, s[0]->InputCount());
2211     EXPECT_EQ(1U, s[0]->OutputCount());
2212   }
2213 }
2214 
TEST_P(InstructionSelectorSIMDDPWithSIMDMulTest,SubWithMul)2215 TEST_P(InstructionSelectorSIMDDPWithSIMDMulTest, SubWithMul) {
2216   const SIMDMulDPInst mdpi = GetParam();
2217   const MachineType type = mdpi.machine_type;
2218   {
2219     StreamBuilder m(this, type, type, type, type);
2220     Node* n = m.AddNode((m.machine()->*mdpi.mul_operator)(), m.Parameter(1),
2221                         m.Parameter(2));
2222     m.Return(m.AddNode((m.machine()->*mdpi.sub_operator)(), m.Parameter(0), n));
2223     Stream s = m.Build();
2224     ASSERT_EQ(1U, s.size());
2225     EXPECT_EQ(mdpi.multiply_sub_arch_opcode, s[0]->arch_opcode());
2226     EXPECT_EQ(mdpi.lane_size, LaneSizeField::decode(s[0]->opcode()));
2227     EXPECT_EQ(3U, s[0]->InputCount());
2228     EXPECT_EQ(1U, s[0]->OutputCount());
2229   }
2230 }
2231 
2232 INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest,
2233                          InstructionSelectorSIMDDPWithSIMDMulTest,
2234                          ::testing::ValuesIn(kSIMDMulDPInstructions));
2235 
2236 namespace {
2237 
2238 struct SIMDShrAddInst {
2239   const char* shradd_constructor_name;
2240   const Operator* (MachineOperatorBuilder::*shr_s_operator)();
2241   const Operator* (MachineOperatorBuilder::*shr_u_operator)();
2242   const Operator* (MachineOperatorBuilder::*add_operator)();
2243   const int laneSize;
2244 };
2245 
operator <<(std::ostream & os,const SIMDShrAddInst & inst)2246 std::ostream& operator<<(std::ostream& os, const SIMDShrAddInst& inst) {
2247   return os << inst.shradd_constructor_name;
2248 }
2249 
2250 }  // namespace
2251 
2252 static const SIMDShrAddInst kSIMDShrAddInstructions[] = {
2253     {"I64x2ShrAdd", &MachineOperatorBuilder::I64x2ShrS,
2254      &MachineOperatorBuilder::I64x2ShrU, &MachineOperatorBuilder::I64x2Add, 64},
2255     {"I32x4ShrAdd", &MachineOperatorBuilder::I32x4ShrS,
2256      &MachineOperatorBuilder::I32x4ShrU, &MachineOperatorBuilder::I32x4Add, 32},
2257     {"I16x8ShrAdd", &MachineOperatorBuilder::I16x8ShrS,
2258      &MachineOperatorBuilder::I16x8ShrU, &MachineOperatorBuilder::I16x8Add, 16},
2259     {"I8x16ShrAdd", &MachineOperatorBuilder::I8x16ShrS,
2260      &MachineOperatorBuilder::I8x16ShrU, &MachineOperatorBuilder::I8x16Add, 8}};
2261 
2262 using InstructionSelectorSIMDShrAddTest =
2263     InstructionSelectorTestWithParam<SIMDShrAddInst>;
2264 
TEST_P(InstructionSelectorSIMDShrAddTest,ShrAddS)2265 TEST_P(InstructionSelectorSIMDShrAddTest, ShrAddS) {
2266   const SIMDShrAddInst param = GetParam();
2267   const MachineType type = MachineType::Simd128();
2268   {
2269     StreamBuilder m(this, type, type, type);
2270     Node* n = m.AddNode((m.machine()->*param.shr_s_operator)(), m.Parameter(1),
2271                         m.Int32Constant(1));
2272     m.Return(
2273         m.AddNode((m.machine()->*param.add_operator)(), m.Parameter(0), n));
2274     Stream s = m.Build();
2275     ASSERT_EQ(1U, s.size());
2276     EXPECT_EQ(kArm64Ssra, s[0]->arch_opcode());
2277     EXPECT_EQ(3U, s[0]->InputCount());
2278     EXPECT_EQ(param.laneSize, LaneSizeField::decode(s[0]->opcode()));
2279     EXPECT_EQ(1U, s[0]->OutputCount());
2280   }
2281   {
2282     StreamBuilder m(this, type, type, type);
2283     Node* n = m.AddNode((m.machine()->*param.shr_s_operator)(), m.Parameter(0),
2284                         m.Int32Constant(1));
2285     m.Return(
2286         m.AddNode((m.machine()->*param.add_operator)(), n, m.Parameter(1)));
2287     Stream s = m.Build();
2288     ASSERT_EQ(1U, s.size());
2289     EXPECT_EQ(kArm64Ssra, s[0]->arch_opcode());
2290     EXPECT_EQ(3U, s[0]->InputCount());
2291     EXPECT_EQ(param.laneSize, LaneSizeField::decode(s[0]->opcode()));
2292     EXPECT_EQ(1U, s[0]->OutputCount());
2293   }
2294 }
2295 
TEST_P(InstructionSelectorSIMDShrAddTest,ShrAddU)2296 TEST_P(InstructionSelectorSIMDShrAddTest, ShrAddU) {
2297   const SIMDShrAddInst param = GetParam();
2298   const MachineType type = MachineType::Simd128();
2299   {
2300     StreamBuilder m(this, type, type, type);
2301     Node* n = m.AddNode((m.machine()->*param.shr_u_operator)(), m.Parameter(1),
2302                         m.Int32Constant(1));
2303     m.Return(
2304         m.AddNode((m.machine()->*param.add_operator)(), m.Parameter(0), n));
2305     Stream s = m.Build();
2306     ASSERT_EQ(1U, s.size());
2307     EXPECT_EQ(kArm64Usra, s[0]->arch_opcode());
2308     EXPECT_EQ(3U, s[0]->InputCount());
2309     EXPECT_EQ(param.laneSize, LaneSizeField::decode(s[0]->opcode()));
2310     EXPECT_EQ(1U, s[0]->OutputCount());
2311   }
2312   {
2313     StreamBuilder m(this, type, type, type);
2314     Node* n = m.AddNode((m.machine()->*param.shr_u_operator)(), m.Parameter(0),
2315                         m.Int32Constant(1));
2316     m.Return(
2317         m.AddNode((m.machine()->*param.add_operator)(), n, m.Parameter(1)));
2318     Stream s = m.Build();
2319     ASSERT_EQ(1U, s.size());
2320     EXPECT_EQ(kArm64Usra, s[0]->arch_opcode());
2321     EXPECT_EQ(3U, s[0]->InputCount());
2322     EXPECT_EQ(param.laneSize, LaneSizeField::decode(s[0]->opcode()));
2323     EXPECT_EQ(1U, s[0]->OutputCount());
2324   }
2325 }
2326 
2327 INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest,
2328                          InstructionSelectorSIMDShrAddTest,
2329                          ::testing::ValuesIn(kSIMDShrAddInstructions));
2330 
2331 namespace {
2332 struct SIMDAddExtMulInst {
2333   const char* mul_constructor_name;
2334   const Operator* (MachineOperatorBuilder::*mul_operator)();
2335   const Operator* (MachineOperatorBuilder::*add_operator)();
2336   ArchOpcode multiply_add_arch_opcode;
2337   MachineType machine_type;
2338   int lane_size;
2339 };
2340 }  // namespace
2341 
2342 static const SIMDAddExtMulInst kSimdAddExtMulInstructions[] = {
2343     {"I16x8ExtMulLowI8x16S", &MachineOperatorBuilder::I16x8ExtMulLowI8x16S,
2344      &MachineOperatorBuilder::I16x8Add, kArm64Smlal, MachineType::Simd128(),
2345      16},
2346     {"I16x8ExtMulHighI8x16S", &MachineOperatorBuilder::I16x8ExtMulHighI8x16S,
2347      &MachineOperatorBuilder::I16x8Add, kArm64Smlal2, MachineType::Simd128(),
2348      16},
2349     {"I16x8ExtMulLowI8x16U", &MachineOperatorBuilder::I16x8ExtMulLowI8x16U,
2350      &MachineOperatorBuilder::I16x8Add, kArm64Umlal, MachineType::Simd128(),
2351      16},
2352     {"I16x8ExtMulHighI8x16U", &MachineOperatorBuilder::I16x8ExtMulHighI8x16U,
2353      &MachineOperatorBuilder::I16x8Add, kArm64Umlal2, MachineType::Simd128(),
2354      16},
2355     {"I32x4ExtMulLowI16x8S", &MachineOperatorBuilder::I32x4ExtMulLowI16x8S,
2356      &MachineOperatorBuilder::I32x4Add, kArm64Smlal, MachineType::Simd128(),
2357      32},
2358     {"I32x4ExtMulHighI16x8S", &MachineOperatorBuilder::I32x4ExtMulHighI16x8S,
2359      &MachineOperatorBuilder::I32x4Add, kArm64Smlal2, MachineType::Simd128(),
2360      32},
2361     {"I32x4ExtMulLowI16x8U", &MachineOperatorBuilder::I32x4ExtMulLowI16x8U,
2362      &MachineOperatorBuilder::I32x4Add, kArm64Umlal, MachineType::Simd128(),
2363      32},
2364     {"I32x4ExtMulHighI16x8U", &MachineOperatorBuilder::I32x4ExtMulHighI16x8U,
2365      &MachineOperatorBuilder::I32x4Add, kArm64Umlal2, MachineType::Simd128(),
2366      32}};
2367 
2368 using InstructionSelectorSIMDAddExtMulTest =
2369     InstructionSelectorTestWithParam<SIMDAddExtMulInst>;
2370 
2371 // TODO(zhin): This can be merged with InstructionSelectorSIMDDPWithSIMDMulTest
2372 // once sub+extmul matching is implemented.
TEST_P(InstructionSelectorSIMDAddExtMulTest,AddExtMul)2373 TEST_P(InstructionSelectorSIMDAddExtMulTest, AddExtMul) {
2374   const SIMDAddExtMulInst mdpi = GetParam();
2375   const MachineType type = mdpi.machine_type;
2376   {
2377     // Test Add(x, ExtMul(y, z)).
2378     StreamBuilder m(this, type, type, type, type);
2379     Node* n = m.AddNode((m.machine()->*mdpi.mul_operator)(), m.Parameter(1),
2380                         m.Parameter(2));
2381     m.Return(m.AddNode((m.machine()->*mdpi.add_operator)(), m.Parameter(0), n));
2382     Stream s = m.Build();
2383     ASSERT_EQ(1U, s.size());
2384     EXPECT_EQ(mdpi.multiply_add_arch_opcode, s[0]->arch_opcode());
2385     EXPECT_EQ(mdpi.lane_size, LaneSizeField::decode(s[0]->opcode()));
2386     EXPECT_EQ(3U, s[0]->InputCount());
2387     EXPECT_EQ(1U, s[0]->OutputCount());
2388   }
2389   {
2390     // Test Add(ExtMul(y, z), x), making sure it's commutative.
2391     StreamBuilder m(this, type, type, type, type);
2392     Node* n = m.AddNode((m.machine()->*mdpi.mul_operator)(), m.Parameter(0),
2393                         m.Parameter(1));
2394     m.Return(m.AddNode((m.machine()->*mdpi.add_operator)(), n, m.Parameter(2)));
2395     Stream s = m.Build();
2396     ASSERT_EQ(1U, s.size());
2397     EXPECT_EQ(mdpi.multiply_add_arch_opcode, s[0]->arch_opcode());
2398     EXPECT_EQ(mdpi.lane_size, LaneSizeField::decode(s[0]->opcode()));
2399     EXPECT_EQ(3U, s[0]->InputCount());
2400     EXPECT_EQ(1U, s[0]->OutputCount());
2401   }
2402 }
2403 
2404 INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest,
2405                          InstructionSelectorSIMDAddExtMulTest,
2406                          ::testing::ValuesIn(kSimdAddExtMulInstructions));
2407 
2408 struct SIMDMulDupInst {
2409   const uint8_t shuffle[16];
2410   int32_t lane;
2411   int shuffle_input_index;
2412 };
2413 
2414 const SIMDMulDupInst kSIMDF32x4MulDuplInstructions[] = {
2415     {
2416         {0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3},
2417         0,
2418         0,
2419     },
2420     {
2421         {4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7},
2422         1,
2423         0,
2424     },
2425     {
2426         {8, 9, 10, 11, 8, 9, 10, 11, 8, 9, 10, 11, 8, 9, 10, 11},
2427         2,
2428         0,
2429     },
2430     {
2431         {12, 13, 14, 15, 12, 13, 14, 15, 12, 13, 14, 15, 12, 13, 14, 15},
2432         3,
2433         0,
2434     },
2435     {
2436         {16, 17, 18, 19, 16, 17, 18, 19, 16, 17, 18, 19, 16, 17, 18, 19},
2437         0,
2438         1,
2439     },
2440     {
2441         {20, 21, 22, 23, 20, 21, 22, 23, 20, 21, 22, 23, 20, 21, 22, 23},
2442         1,
2443         1,
2444     },
2445     {
2446         {24, 25, 26, 27, 24, 25, 26, 27, 24, 25, 26, 27, 24, 25, 26, 27},
2447         2,
2448         1,
2449     },
2450     {
2451         {28, 29, 30, 31, 28, 29, 30, 31, 28, 29, 30, 31, 28, 29, 30, 31},
2452         3,
2453         1,
2454     },
2455 };
2456 
2457 using InstructionSelectorSimdF32x4MulWithDupTest =
2458     InstructionSelectorTestWithParam<SIMDMulDupInst>;
2459 
TEST_P(InstructionSelectorSimdF32x4MulWithDupTest,MulWithDup)2460 TEST_P(InstructionSelectorSimdF32x4MulWithDupTest, MulWithDup) {
2461   const SIMDMulDupInst param = GetParam();
2462   const MachineType type = MachineType::Simd128();
2463   {
2464     StreamBuilder m(this, type, type, type, type);
2465     Node* shuffle = m.AddNode(m.machine()->I8x16Shuffle(param.shuffle),
2466                               m.Parameter(0), m.Parameter(1));
2467     m.Return(m.AddNode(m.machine()->F32x4Mul(), m.Parameter(2), shuffle));
2468     Stream s = m.Build();
2469     ASSERT_EQ(1U, s.size());
2470     EXPECT_EQ(kArm64FMulElement, s[0]->arch_opcode());
2471     EXPECT_EQ(32, LaneSizeField::decode(s[0]->opcode()));
2472     EXPECT_EQ(3U, s[0]->InputCount());
2473     EXPECT_EQ(param.lane, s.ToInt32(s[0]->InputAt(2)));
2474     EXPECT_EQ(1U, s[0]->OutputCount());
2475     EXPECT_EQ(s.ToVreg(m.Parameter(param.shuffle_input_index)),
2476               s.ToVreg(s[0]->InputAt(1)));
2477   }
2478 
2479   // Multiplication operator should be commutative, so test shuffle op as lhs.
2480   {
2481     StreamBuilder m(this, type, type, type, type);
2482     Node* shuffle = m.AddNode(m.machine()->I8x16Shuffle(param.shuffle),
2483                               m.Parameter(0), m.Parameter(1));
2484     m.Return(m.AddNode(m.machine()->F32x4Mul(), shuffle, m.Parameter(2)));
2485     Stream s = m.Build();
2486     ASSERT_EQ(1U, s.size());
2487     EXPECT_EQ(kArm64FMulElement, s[0]->arch_opcode());
2488     EXPECT_EQ(32, LaneSizeField::decode(s[0]->opcode()));
2489     EXPECT_EQ(3U, s[0]->InputCount());
2490     EXPECT_EQ(param.lane, s.ToInt32(s[0]->InputAt(2)));
2491     EXPECT_EQ(1U, s[0]->OutputCount());
2492     EXPECT_EQ(s.ToVreg(m.Parameter(param.shuffle_input_index)),
2493               s.ToVreg(s[0]->InputAt(1)));
2494   }
2495 }
2496 
2497 INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest,
2498                          InstructionSelectorSimdF32x4MulWithDupTest,
2499                          ::testing::ValuesIn(kSIMDF32x4MulDuplInstructions));
2500 
TEST_F(InstructionSelectorTest,SimdF32x4MulWithDupNegativeTest)2501 TEST_F(InstructionSelectorTest, SimdF32x4MulWithDupNegativeTest) {
2502   const MachineType type = MachineType::Simd128();
2503   // Check that optimization does not match when the shuffle is not a f32x4.dup.
2504   const uint8_t mask[kSimd128Size] = {0};
2505   {
2506     StreamBuilder m(this, type, type, type, type);
2507     Node* shuffle = m.AddNode((m.machine()->I8x16Shuffle(mask)), m.Parameter(0),
2508                               m.Parameter(1));
2509     m.Return(m.AddNode(m.machine()->F32x4Mul(), m.Parameter(2), shuffle));
2510     Stream s = m.Build();
2511     ASSERT_EQ(2U, s.size());
2512     // The shuffle is a i8x16.dup of lane 0.
2513     EXPECT_EQ(kArm64S128Dup, s[0]->arch_opcode());
2514     EXPECT_EQ(3U, s[0]->InputCount());
2515     EXPECT_EQ(kArm64FMul, s[1]->arch_opcode());
2516     EXPECT_EQ(32, LaneSizeField::decode(s[1]->opcode()));
2517     EXPECT_EQ(1U, s[0]->OutputCount());
2518     EXPECT_EQ(2U, s[1]->InputCount());
2519     EXPECT_EQ(1U, s[1]->OutputCount());
2520   }
2521 }
2522 
2523 const SIMDMulDupInst kSIMDF64x2MulDuplInstructions[] = {
2524     {
2525         {0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7},
2526         0,
2527         0,
2528     },
2529     {
2530         {8, 9, 10, 11, 12, 13, 14, 15, 8, 9, 10, 11, 12, 13, 14, 15},
2531         1,
2532         0,
2533     },
2534     {
2535         {16, 17, 18, 19, 20, 21, 22, 23, 16, 17, 18, 19, 20, 21, 22, 23},
2536         0,
2537         1,
2538     },
2539     {
2540         {24, 25, 26, 27, 28, 29, 30, 31, 24, 25, 26, 27, 28, 29, 30, 31},
2541         1,
2542         1,
2543     },
2544 };
2545 
2546 using InstructionSelectorSimdF64x2MulWithDupTest =
2547     InstructionSelectorTestWithParam<SIMDMulDupInst>;
2548 
TEST_P(InstructionSelectorSimdF64x2MulWithDupTest,MulWithDup)2549 TEST_P(InstructionSelectorSimdF64x2MulWithDupTest, MulWithDup) {
2550   const SIMDMulDupInst param = GetParam();
2551   const MachineType type = MachineType::Simd128();
2552   {
2553     StreamBuilder m(this, type, type, type, type);
2554     Node* shuffle = m.AddNode(m.machine()->I8x16Shuffle(param.shuffle),
2555                               m.Parameter(0), m.Parameter(1));
2556     m.Return(m.AddNode(m.machine()->F64x2Mul(), m.Parameter(2), shuffle));
2557     Stream s = m.Build();
2558     ASSERT_EQ(1U, s.size());
2559     EXPECT_EQ(kArm64FMulElement, s[0]->arch_opcode());
2560     EXPECT_EQ(64, LaneSizeField::decode(s[0]->opcode()));
2561     EXPECT_EQ(3U, s[0]->InputCount());
2562     EXPECT_EQ(param.lane, s.ToInt32(s[0]->InputAt(2)));
2563     EXPECT_EQ(1U, s[0]->OutputCount());
2564     EXPECT_EQ(s.ToVreg(m.Parameter(param.shuffle_input_index)),
2565               s.ToVreg(s[0]->InputAt(1)));
2566   }
2567 
2568   // Multiplication operator should be commutative, so test shuffle op as lhs.
2569   {
2570     StreamBuilder m(this, type, type, type, type);
2571     Node* shuffle = m.AddNode(m.machine()->I8x16Shuffle(param.shuffle),
2572                               m.Parameter(0), m.Parameter(1));
2573     m.Return(m.AddNode(m.machine()->F64x2Mul(), shuffle, m.Parameter(2)));
2574     Stream s = m.Build();
2575     ASSERT_EQ(1U, s.size());
2576     EXPECT_EQ(kArm64FMulElement, s[0]->arch_opcode());
2577     EXPECT_EQ(64, LaneSizeField::decode(s[0]->opcode()));
2578     EXPECT_EQ(3U, s[0]->InputCount());
2579     EXPECT_EQ(param.lane, s.ToInt32(s[0]->InputAt(2)));
2580     EXPECT_EQ(1U, s[0]->OutputCount());
2581     EXPECT_EQ(s.ToVreg(m.Parameter(param.shuffle_input_index)),
2582               s.ToVreg(s[0]->InputAt(1)));
2583   }
2584 }
2585 
2586 INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest,
2587                          InstructionSelectorSimdF64x2MulWithDupTest,
2588                          ::testing::ValuesIn(kSIMDF64x2MulDuplInstructions));
2589 
TEST_F(InstructionSelectorTest,SimdF64x2MulWithDupNegativeTest)2590 TEST_F(InstructionSelectorTest, SimdF64x2MulWithDupNegativeTest) {
2591   const MachineType type = MachineType::Simd128();
2592   // Check that optimization does not match when the shuffle is not a f64x2.dup.
2593   const uint8_t mask[kSimd128Size] = {0};
2594   {
2595     StreamBuilder m(this, type, type, type, type);
2596     Node* shuffle = m.AddNode((m.machine()->I8x16Shuffle(mask)), m.Parameter(0),
2597                               m.Parameter(1));
2598     m.Return(m.AddNode(m.machine()->F64x2Mul(), m.Parameter(2), shuffle));
2599     Stream s = m.Build();
2600     ASSERT_EQ(2U, s.size());
2601     // The shuffle is a i8x16.dup of lane 0.
2602     EXPECT_EQ(kArm64S128Dup, s[0]->arch_opcode());
2603     EXPECT_EQ(3U, s[0]->InputCount());
2604     EXPECT_EQ(kArm64FMul, s[1]->arch_opcode());
2605     EXPECT_EQ(64, LaneSizeField::decode(s[1]->opcode()));
2606     EXPECT_EQ(1U, s[0]->OutputCount());
2607     EXPECT_EQ(2U, s[1]->InputCount());
2608     EXPECT_EQ(1U, s[1]->OutputCount());
2609   }
2610 }
2611 
TEST_F(InstructionSelectorTest,Int32MulWithImmediate)2612 TEST_F(InstructionSelectorTest, Int32MulWithImmediate) {
2613   // x * (2^k + 1) -> x + (x << k)
2614   TRACED_FORRANGE(int32_t, k, 1, 30) {
2615     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
2616     m.Return(m.Int32Mul(m.Parameter(0), m.Int32Constant((1 << k) + 1)));
2617     Stream s = m.Build();
2618     ASSERT_EQ(1U, s.size());
2619     EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
2620     EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode());
2621     ASSERT_EQ(3U, s[0]->InputCount());
2622     EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
2623     EXPECT_EQ(k, s.ToInt32(s[0]->InputAt(2)));
2624     EXPECT_EQ(1U, s[0]->OutputCount());
2625   }
2626   // (2^k + 1) * x -> x + (x << k)
2627   TRACED_FORRANGE(int32_t, k, 1, 30) {
2628     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
2629     m.Return(m.Int32Mul(m.Int32Constant((1 << k) + 1), m.Parameter(0)));
2630     Stream s = m.Build();
2631     ASSERT_EQ(1U, s.size());
2632     EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
2633     EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode());
2634     ASSERT_EQ(3U, s[0]->InputCount());
2635     EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
2636     EXPECT_EQ(k, s.ToInt32(s[0]->InputAt(2)));
2637     EXPECT_EQ(1U, s[0]->OutputCount());
2638   }
2639   // x * (2^k + 1) + c -> x + (x << k) + c
2640   TRACED_FORRANGE(int32_t, k, 1, 30) {
2641     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
2642                     MachineType::Int32());
2643     m.Return(
2644         m.Int32Add(m.Int32Mul(m.Parameter(0), m.Int32Constant((1 << k) + 1)),
2645                    m.Parameter(1)));
2646     Stream s = m.Build();
2647     ASSERT_EQ(2U, s.size());
2648     EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
2649     EXPECT_EQ(kArm64Add32, s[1]->arch_opcode());
2650     EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode());
2651     ASSERT_EQ(3U, s[0]->InputCount());
2652     EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
2653     EXPECT_EQ(k, s.ToInt32(s[0]->InputAt(2)));
2654     EXPECT_EQ(1U, s[0]->OutputCount());
2655   }
2656   // (2^k + 1) * x + c -> x + (x << k) + c
2657   TRACED_FORRANGE(int32_t, k, 1, 30) {
2658     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
2659                     MachineType::Int32());
2660     m.Return(
2661         m.Int32Add(m.Int32Mul(m.Int32Constant((1 << k) + 1), m.Parameter(0)),
2662                    m.Parameter(1)));
2663     Stream s = m.Build();
2664     ASSERT_EQ(2U, s.size());
2665     EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
2666     EXPECT_EQ(kArm64Add32, s[1]->arch_opcode());
2667     EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode());
2668     ASSERT_EQ(3U, s[0]->InputCount());
2669     EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
2670     EXPECT_EQ(k, s.ToInt32(s[0]->InputAt(2)));
2671     EXPECT_EQ(1U, s[0]->OutputCount());
2672   }
2673   // c + x * (2^k + 1) -> c + x + (x << k)
2674   TRACED_FORRANGE(int32_t, k, 1, 30) {
2675     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
2676                     MachineType::Int32());
2677     m.Return(
2678         m.Int32Add(m.Parameter(0),
2679                    m.Int32Mul(m.Parameter(1), m.Int32Constant((1 << k) + 1))));
2680     Stream s = m.Build();
2681     ASSERT_EQ(2U, s.size());
2682     EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
2683     EXPECT_EQ(kArm64Add32, s[1]->arch_opcode());
2684     EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode());
2685     ASSERT_EQ(3U, s[0]->InputCount());
2686     EXPECT_EQ(s.ToVreg(s[0]->InputAt(1)), s.ToVreg(s[0]->InputAt(1)));
2687     EXPECT_EQ(k, s.ToInt32(s[0]->InputAt(2)));
2688     EXPECT_EQ(1U, s[0]->OutputCount());
2689   }
2690   // c + (2^k + 1) * x -> c + x + (x << k)
2691   TRACED_FORRANGE(int32_t, k, 1, 30) {
2692     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
2693                     MachineType::Int32());
2694     m.Return(
2695         m.Int32Add(m.Parameter(0),
2696                    m.Int32Mul(m.Int32Constant((1 << k) + 1), m.Parameter(1))));
2697     Stream s = m.Build();
2698     ASSERT_EQ(2U, s.size());
2699     EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
2700     EXPECT_EQ(kArm64Add32, s[1]->arch_opcode());
2701     EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode());
2702     ASSERT_EQ(3U, s[0]->InputCount());
2703     EXPECT_EQ(s.ToVreg(s[0]->InputAt(1)), s.ToVreg(s[0]->InputAt(1)));
2704     EXPECT_EQ(k, s.ToInt32(s[0]->InputAt(2)));
2705     EXPECT_EQ(1U, s[0]->OutputCount());
2706   }
2707   // c - x * (2^k + 1) -> c - x + (x << k)
2708   TRACED_FORRANGE(int32_t, k, 1, 30) {
2709     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
2710                     MachineType::Int32());
2711     m.Return(
2712         m.Int32Sub(m.Parameter(0),
2713                    m.Int32Mul(m.Parameter(1), m.Int32Constant((1 << k) + 1))));
2714     Stream s = m.Build();
2715     ASSERT_EQ(2U, s.size());
2716     EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
2717     EXPECT_EQ(kArm64Sub32, s[1]->arch_opcode());
2718     EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode());
2719     ASSERT_EQ(3U, s[0]->InputCount());
2720     EXPECT_EQ(s.ToVreg(s[0]->InputAt(1)), s.ToVreg(s[0]->InputAt(1)));
2721     EXPECT_EQ(k, s.ToInt32(s[0]->InputAt(2)));
2722     EXPECT_EQ(1U, s[0]->OutputCount());
2723   }
2724   // c - (2^k + 1) * x -> c - x + (x << k)
2725   TRACED_FORRANGE(int32_t, k, 1, 30) {
2726     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
2727                     MachineType::Int32());
2728     m.Return(
2729         m.Int32Sub(m.Parameter(0),
2730                    m.Int32Mul(m.Int32Constant((1 << k) + 1), m.Parameter(1))));
2731     Stream s = m.Build();
2732     ASSERT_EQ(2U, s.size());
2733     EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
2734     EXPECT_EQ(kArm64Sub32, s[1]->arch_opcode());
2735     EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode());
2736     ASSERT_EQ(3U, s[0]->InputCount());
2737     EXPECT_EQ(s.ToVreg(s[0]->InputAt(1)), s.ToVreg(s[0]->InputAt(1)));
2738     EXPECT_EQ(k, s.ToInt32(s[0]->InputAt(2)));
2739     EXPECT_EQ(1U, s[0]->OutputCount());
2740   }
2741 }
2742 
TEST_F(InstructionSelectorTest,Int64MulWithImmediate)2743 TEST_F(InstructionSelectorTest, Int64MulWithImmediate) {
2744   // x * (2^k + 1) -> x + (x << k)
2745   TRACED_FORRANGE(int64_t, k, 1, 62) {
2746     StreamBuilder m(this, MachineType::Int64(), MachineType::Int64());
2747     m.Return(
2748         m.Int64Mul(m.Parameter(0), m.Int64Constant((int64_t{1} << k) + 1)));
2749     Stream s = m.Build();
2750     ASSERT_EQ(1U, s.size());
2751     EXPECT_EQ(kArm64Add, s[0]->arch_opcode());
2752     EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode());
2753     ASSERT_EQ(3U, s[0]->InputCount());
2754     EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
2755     EXPECT_EQ(k, s.ToInt64(s[0]->InputAt(2)));
2756     EXPECT_EQ(1U, s[0]->OutputCount());
2757   }
2758   // (2^k + 1) * x -> x + (x << k)
2759   TRACED_FORRANGE(int64_t, k, 1, 62) {
2760     StreamBuilder m(this, MachineType::Int64(), MachineType::Int64());
2761     m.Return(
2762         m.Int64Mul(m.Int64Constant((int64_t{1} << k) + 1), m.Parameter(0)));
2763     Stream s = m.Build();
2764     ASSERT_EQ(1U, s.size());
2765     EXPECT_EQ(kArm64Add, s[0]->arch_opcode());
2766     EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode());
2767     ASSERT_EQ(3U, s[0]->InputCount());
2768     EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
2769     EXPECT_EQ(k, s.ToInt64(s[0]->InputAt(2)));
2770     EXPECT_EQ(1U, s[0]->OutputCount());
2771   }
2772   // x * (2^k + 1) + c -> x + (x << k) + c
2773   TRACED_FORRANGE(int64_t, k, 1, 62) {
2774     StreamBuilder m(this, MachineType::Int64(), MachineType::Int64(),
2775                     MachineType::Int64());
2776     m.Return(m.Int64Add(
2777         m.Int64Mul(m.Parameter(0), m.Int64Constant((int64_t{1} << k) + 1)),
2778         m.Parameter(1)));
2779     Stream s = m.Build();
2780     ASSERT_EQ(2U, s.size());
2781     EXPECT_EQ(kArm64Add, s[0]->arch_opcode());
2782     EXPECT_EQ(kArm64Add, s[1]->arch_opcode());
2783     EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode());
2784     ASSERT_EQ(3U, s[0]->InputCount());
2785     EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
2786     EXPECT_EQ(k, s.ToInt64(s[0]->InputAt(2)));
2787     EXPECT_EQ(1U, s[0]->OutputCount());
2788   }
2789   // (2^k + 1) * x + c -> x + (x << k) + c
2790   TRACED_FORRANGE(int64_t, k, 1, 62) {
2791     StreamBuilder m(this, MachineType::Int64(), MachineType::Int64(),
2792                     MachineType::Int64());
2793     m.Return(m.Int64Add(
2794         m.Int64Mul(m.Int64Constant((int64_t{1} << k) + 1), m.Parameter(0)),
2795         m.Parameter(1)));
2796     Stream s = m.Build();
2797     ASSERT_EQ(2U, s.size());
2798     EXPECT_EQ(kArm64Add, s[0]->arch_opcode());
2799     EXPECT_EQ(kArm64Add, s[1]->arch_opcode());
2800     EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode());
2801     ASSERT_EQ(3U, s[0]->InputCount());
2802     EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
2803     EXPECT_EQ(k, s.ToInt64(s[0]->InputAt(2)));
2804     EXPECT_EQ(1U, s[0]->OutputCount());
2805   }
2806   // c + x * (2^k + 1) -> c + x + (x << k)
2807   TRACED_FORRANGE(int64_t, k, 1, 62) {
2808     StreamBuilder m(this, MachineType::Int64(), MachineType::Int64(),
2809                     MachineType::Int64());
2810     m.Return(m.Int64Add(
2811         m.Parameter(0),
2812         m.Int64Mul(m.Parameter(1), m.Int64Constant((int64_t{1} << k) + 1))));
2813     Stream s = m.Build();
2814     ASSERT_EQ(2U, s.size());
2815     EXPECT_EQ(kArm64Add, s[0]->arch_opcode());
2816     EXPECT_EQ(kArm64Add, s[1]->arch_opcode());
2817     EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode());
2818     ASSERT_EQ(3U, s[0]->InputCount());
2819     EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
2820     EXPECT_EQ(k, s.ToInt64(s[0]->InputAt(2)));
2821     EXPECT_EQ(1U, s[0]->OutputCount());
2822   }
2823   // c + (2^k + 1) * x -> c + x + (x << k)
2824   TRACED_FORRANGE(int64_t, k, 1, 62) {
2825     StreamBuilder m(this, MachineType::Int64(), MachineType::Int64(),
2826                     MachineType::Int64());
2827     m.Return(m.Int64Add(
2828         m.Parameter(0),
2829         m.Int64Mul(m.Int64Constant((int64_t{1} << k) + 1), m.Parameter(1))));
2830     Stream s = m.Build();
2831     ASSERT_EQ(2U, s.size());
2832     EXPECT_EQ(kArm64Add, s[0]->arch_opcode());
2833     EXPECT_EQ(kArm64Add, s[1]->arch_opcode());
2834     EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode());
2835     ASSERT_EQ(3U, s[0]->InputCount());
2836     EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
2837     EXPECT_EQ(k, s.ToInt64(s[0]->InputAt(2)));
2838     EXPECT_EQ(1U, s[0]->OutputCount());
2839   }
2840   // c - x * (2^k + 1) -> c - x + (x << k)
2841   TRACED_FORRANGE(int64_t, k, 1, 62) {
2842     StreamBuilder m(this, MachineType::Int64(), MachineType::Int64(),
2843                     MachineType::Int64());
2844     m.Return(m.Int64Sub(
2845         m.Parameter(0),
2846         m.Int64Mul(m.Parameter(1), m.Int64Constant((int64_t{1} << k) + 1))));
2847     Stream s = m.Build();
2848     ASSERT_EQ(2U, s.size());
2849     EXPECT_EQ(kArm64Add, s[0]->arch_opcode());
2850     EXPECT_EQ(kArm64Sub, s[1]->arch_opcode());
2851     EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode());
2852     ASSERT_EQ(3U, s[0]->InputCount());
2853     EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
2854     EXPECT_EQ(k, s.ToInt64(s[0]->InputAt(2)));
2855     EXPECT_EQ(1U, s[0]->OutputCount());
2856   }
2857   // c - (2^k + 1) * x -> c - x + (x << k)
2858   TRACED_FORRANGE(int64_t, k, 1, 62) {
2859     StreamBuilder m(this, MachineType::Int64(), MachineType::Int64(),
2860                     MachineType::Int64());
2861     m.Return(m.Int64Sub(
2862         m.Parameter(0),
2863         m.Int64Mul(m.Int64Constant((int64_t{1} << k) + 1), m.Parameter(1))));
2864     Stream s = m.Build();
2865     ASSERT_EQ(2U, s.size());
2866     EXPECT_EQ(kArm64Add, s[0]->arch_opcode());
2867     EXPECT_EQ(kArm64Sub, s[1]->arch_opcode());
2868     EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode());
2869     ASSERT_EQ(3U, s[0]->InputCount());
2870     EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
2871     EXPECT_EQ(k, s.ToInt64(s[0]->InputAt(2)));
2872     EXPECT_EQ(1U, s[0]->OutputCount());
2873   }
2874 }
2875 
2876 // -----------------------------------------------------------------------------
2877 // Floating point instructions.
2878 
2879 using InstructionSelectorFPArithTest =
2880     InstructionSelectorTestWithParam<MachInst2>;
2881 
TEST_P(InstructionSelectorFPArithTest,Parameter)2882 TEST_P(InstructionSelectorFPArithTest, Parameter) {
2883   const MachInst2 fpa = GetParam();
2884   StreamBuilder m(this, fpa.machine_type, fpa.machine_type, fpa.machine_type);
2885   m.Return((m.*fpa.constructor)(m.Parameter(0), m.Parameter(1)));
2886   Stream s = m.Build();
2887   ASSERT_EQ(1U, s.size());
2888   EXPECT_EQ(fpa.arch_opcode, s[0]->arch_opcode());
2889   EXPECT_EQ(2U, s[0]->InputCount());
2890   EXPECT_EQ(1U, s[0]->OutputCount());
2891 }
2892 
2893 INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest,
2894                          InstructionSelectorFPArithTest,
2895                          ::testing::ValuesIn(kFPArithInstructions));
2896 
2897 using InstructionSelectorFPCmpTest = InstructionSelectorTestWithParam<FPCmp>;
2898 
TEST_P(InstructionSelectorFPCmpTest,Parameter)2899 TEST_P(InstructionSelectorFPCmpTest, Parameter) {
2900   const FPCmp cmp = GetParam();
2901   StreamBuilder m(this, MachineType::Int32(), cmp.mi.machine_type,
2902                   cmp.mi.machine_type);
2903   m.Return((m.*cmp.mi.constructor)(m.Parameter(0), m.Parameter(1)));
2904   Stream s = m.Build();
2905   ASSERT_EQ(1U, s.size());
2906   EXPECT_EQ(cmp.mi.arch_opcode, s[0]->arch_opcode());
2907   EXPECT_EQ(2U, s[0]->InputCount());
2908   EXPECT_EQ(1U, s[0]->OutputCount());
2909   EXPECT_EQ(kFlags_set, s[0]->flags_mode());
2910   EXPECT_EQ(cmp.cond, s[0]->flags_condition());
2911 }
2912 
TEST_P(InstructionSelectorFPCmpTest,WithImmediateZeroOnRight)2913 TEST_P(InstructionSelectorFPCmpTest, WithImmediateZeroOnRight) {
2914   const FPCmp cmp = GetParam();
2915   StreamBuilder m(this, MachineType::Int32(), cmp.mi.machine_type);
2916   if (cmp.mi.machine_type == MachineType::Float64()) {
2917     m.Return((m.*cmp.mi.constructor)(m.Parameter(0), m.Float64Constant(0.0)));
2918   } else {
2919     m.Return((m.*cmp.mi.constructor)(m.Parameter(0), m.Float32Constant(0.0f)));
2920   }
2921   Stream s = m.Build();
2922   ASSERT_EQ(1U, s.size());
2923   EXPECT_EQ(cmp.mi.arch_opcode, s[0]->arch_opcode());
2924   EXPECT_EQ(2U, s[0]->InputCount());
2925   EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
2926   EXPECT_EQ(1U, s[0]->OutputCount());
2927   EXPECT_EQ(kFlags_set, s[0]->flags_mode());
2928   EXPECT_EQ(cmp.cond, s[0]->flags_condition());
2929 }
2930 
TEST_P(InstructionSelectorFPCmpTest,WithImmediateZeroOnLeft)2931 TEST_P(InstructionSelectorFPCmpTest, WithImmediateZeroOnLeft) {
2932   const FPCmp cmp = GetParam();
2933   StreamBuilder m(this, MachineType::Int32(), cmp.mi.machine_type);
2934   if (cmp.mi.machine_type == MachineType::Float64()) {
2935     m.Return((m.*cmp.mi.constructor)(m.Float64Constant(0.0), m.Parameter(0)));
2936   } else {
2937     m.Return((m.*cmp.mi.constructor)(m.Float32Constant(0.0f), m.Parameter(0)));
2938   }
2939   Stream s = m.Build();
2940   ASSERT_EQ(1U, s.size());
2941   EXPECT_EQ(cmp.mi.arch_opcode, s[0]->arch_opcode());
2942   EXPECT_EQ(2U, s[0]->InputCount());
2943   EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
2944   EXPECT_EQ(1U, s[0]->OutputCount());
2945   EXPECT_EQ(kFlags_set, s[0]->flags_mode());
2946   EXPECT_EQ(cmp.commuted_cond, s[0]->flags_condition());
2947 }
2948 
2949 INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest, InstructionSelectorFPCmpTest,
2950                          ::testing::ValuesIn(kFPCmpInstructions));
2951 
TEST_F(InstructionSelectorTest,Float32SelectWithRegisters)2952 TEST_F(InstructionSelectorTest, Float32SelectWithRegisters) {
2953   StreamBuilder m(this, MachineType::Int32(), MachineType::Float32(),
2954                   MachineType::Float32());
2955   Node* cond = m.Int32Constant(1);
2956   m.Return(m.Float32Select(cond, m.Parameter(0), m.Parameter(1)));
2957   Stream s = m.Build();
2958   EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode());
2959   EXPECT_EQ(4U, s[0]->InputCount());
2960   EXPECT_EQ(1U, s[0]->OutputCount());
2961   EXPECT_EQ(kFlags_select, s[0]->flags_mode());
2962   EXPECT_EQ(kNotEqual, s[0]->flags_condition());
2963 }
2964 
TEST_F(InstructionSelectorTest,Float64SelectWithRegisters)2965 TEST_F(InstructionSelectorTest, Float64SelectWithRegisters) {
2966   StreamBuilder m(this, MachineType::Int32(), MachineType::Float64(),
2967                   MachineType::Float64());
2968   Node* cond = m.Int32Constant(1);
2969   m.Return(m.Float64Select(cond, m.Parameter(0), m.Parameter(1)));
2970   Stream s = m.Build();
2971   EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode());
2972   EXPECT_EQ(4U, s[0]->InputCount());
2973   EXPECT_EQ(1U, s[0]->OutputCount());
2974   EXPECT_EQ(kFlags_select, s[0]->flags_mode());
2975   EXPECT_EQ(kNotEqual, s[0]->flags_condition());
2976 }
2977 
2978 // -----------------------------------------------------------------------------
2979 // Conversions.
2980 
2981 using InstructionSelectorConversionTest =
2982     InstructionSelectorTestWithParam<Conversion>;
2983 
TEST_P(InstructionSelectorConversionTest,Parameter)2984 TEST_P(InstructionSelectorConversionTest, Parameter) {
2985   const Conversion conv = GetParam();
2986   StreamBuilder m(this, conv.mi.machine_type, conv.src_machine_type);
2987   m.Return((m.*conv.mi.constructor)(m.Parameter(0)));
2988   Stream s = m.Build();
2989   if (conv.mi.arch_opcode == kArchNop) {
2990     ASSERT_EQ(0U, s.size());
2991     return;
2992   }
2993   ASSERT_EQ(1U, s.size());
2994   EXPECT_EQ(conv.mi.arch_opcode, s[0]->arch_opcode());
2995   EXPECT_EQ(1U, s[0]->InputCount());
2996   EXPECT_EQ(1U, s[0]->OutputCount());
2997 }
2998 
2999 INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest,
3000                          InstructionSelectorConversionTest,
3001                          ::testing::ValuesIn(kConversionInstructions));
3002 
3003 using InstructionSelectorElidedChangeUint32ToUint64Test =
3004     InstructionSelectorTestWithParam<MachInst2>;
3005 
TEST_P(InstructionSelectorElidedChangeUint32ToUint64Test,Parameter)3006 TEST_P(InstructionSelectorElidedChangeUint32ToUint64Test, Parameter) {
3007   const MachInst2 binop = GetParam();
3008   StreamBuilder m(this, MachineType::Uint64(), binop.machine_type,
3009                   binop.machine_type);
3010   m.Return(m.ChangeUint32ToUint64(
3011       (m.*binop.constructor)(m.Parameter(0), m.Parameter(1))));
3012   Stream s = m.Build();
3013   // Make sure the `ChangeUint32ToUint64` node turned into a no-op.
3014   ASSERT_EQ(1U, s.size());
3015   EXPECT_EQ(binop.arch_opcode, s[0]->arch_opcode());
3016   EXPECT_EQ(2U, s[0]->InputCount());
3017   EXPECT_EQ(1U, s[0]->OutputCount());
3018 }
3019 
3020 INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest,
3021                          InstructionSelectorElidedChangeUint32ToUint64Test,
3022                          ::testing::ValuesIn(kCanElideChangeUint32ToUint64));
3023 
TEST_F(InstructionSelectorTest,ChangeUint32ToUint64AfterLoad)3024 TEST_F(InstructionSelectorTest, ChangeUint32ToUint64AfterLoad) {
3025   // For each case, make sure the `ChangeUint32ToUint64` node turned into a
3026   // no-op.
3027 
3028   // Ldrb
3029   {
3030     StreamBuilder m(this, MachineType::Uint64(), MachineType::Pointer(),
3031                     MachineType::Int32());
3032     m.Return(m.ChangeUint32ToUint64(
3033         m.Load(MachineType::Uint8(), m.Parameter(0), m.Parameter(1))));
3034     Stream s = m.Build();
3035     ASSERT_EQ(1U, s.size());
3036     EXPECT_EQ(kArm64Ldrb, s[0]->arch_opcode());
3037     EXPECT_EQ(kMode_MRR, s[0]->addressing_mode());
3038     EXPECT_EQ(2U, s[0]->InputCount());
3039     EXPECT_EQ(1U, s[0]->OutputCount());
3040   }
3041   // Ldrh
3042   {
3043     StreamBuilder m(this, MachineType::Uint64(), MachineType::Pointer(),
3044                     MachineType::Int32());
3045     m.Return(m.ChangeUint32ToUint64(
3046         m.Load(MachineType::Uint16(), m.Parameter(0), m.Parameter(1))));
3047     Stream s = m.Build();
3048     ASSERT_EQ(1U, s.size());
3049     EXPECT_EQ(kArm64Ldrh, s[0]->arch_opcode());
3050     EXPECT_EQ(kMode_MRR, s[0]->addressing_mode());
3051     EXPECT_EQ(2U, s[0]->InputCount());
3052     EXPECT_EQ(1U, s[0]->OutputCount());
3053   }
3054   // LdrW
3055   {
3056     StreamBuilder m(this, MachineType::Uint64(), MachineType::Pointer(),
3057                     MachineType::Int32());
3058     m.Return(m.ChangeUint32ToUint64(
3059         m.Load(MachineType::Uint32(), m.Parameter(0), m.Parameter(1))));
3060     Stream s = m.Build();
3061     ASSERT_EQ(1U, s.size());
3062     EXPECT_EQ(kArm64LdrW, s[0]->arch_opcode());
3063     EXPECT_EQ(kMode_MRR, s[0]->addressing_mode());
3064     EXPECT_EQ(2U, s[0]->InputCount());
3065     EXPECT_EQ(1U, s[0]->OutputCount());
3066   }
3067 }
3068 
TEST_F(InstructionSelectorTest,ChangeInt32ToInt64AfterLoad)3069 TEST_F(InstructionSelectorTest, ChangeInt32ToInt64AfterLoad) {
3070   // For each case, test that the conversion is merged into the load
3071   // operation.
3072   // ChangeInt32ToInt64(Load_Uint8) -> Ldrb
3073   {
3074     StreamBuilder m(this, MachineType::Int64(), MachineType::Pointer(),
3075                     MachineType::Int32());
3076     m.Return(m.ChangeInt32ToInt64(
3077         m.Load(MachineType::Uint8(), m.Parameter(0), m.Parameter(1))));
3078     Stream s = m.Build();
3079     ASSERT_EQ(1U, s.size());
3080     EXPECT_EQ(kArm64Ldrb, s[0]->arch_opcode());
3081     EXPECT_EQ(kMode_MRR, s[0]->addressing_mode());
3082     EXPECT_EQ(2U, s[0]->InputCount());
3083     EXPECT_EQ(1U, s[0]->OutputCount());
3084   }
3085   // ChangeInt32ToInt64(Load_Int8) -> Ldrsb
3086   {
3087     StreamBuilder m(this, MachineType::Int64(), MachineType::Pointer(),
3088                     MachineType::Int32());
3089     m.Return(m.ChangeInt32ToInt64(
3090         m.Load(MachineType::Int8(), m.Parameter(0), m.Parameter(1))));
3091     Stream s = m.Build();
3092     ASSERT_EQ(1U, s.size());
3093     EXPECT_EQ(kArm64Ldrsb, s[0]->arch_opcode());
3094     EXPECT_EQ(kMode_MRR, s[0]->addressing_mode());
3095     EXPECT_EQ(2U, s[0]->InputCount());
3096     EXPECT_EQ(1U, s[0]->OutputCount());
3097   }
3098   // ChangeInt32ToInt64(Load_Uint16) -> Ldrh
3099   {
3100     StreamBuilder m(this, MachineType::Int64(), MachineType::Pointer(),
3101                     MachineType::Int32());
3102     m.Return(m.ChangeInt32ToInt64(
3103         m.Load(MachineType::Uint16(), m.Parameter(0), m.Parameter(1))));
3104     Stream s = m.Build();
3105     ASSERT_EQ(1U, s.size());
3106     EXPECT_EQ(kArm64Ldrh, s[0]->arch_opcode());
3107     EXPECT_EQ(kMode_MRR, s[0]->addressing_mode());
3108     EXPECT_EQ(2U, s[0]->InputCount());
3109     EXPECT_EQ(1U, s[0]->OutputCount());
3110   }
3111   // ChangeInt32ToInt64(Load_Int16) -> Ldrsh
3112   {
3113     StreamBuilder m(this, MachineType::Int64(), MachineType::Pointer(),
3114                     MachineType::Int32());
3115     m.Return(m.ChangeInt32ToInt64(
3116         m.Load(MachineType::Int16(), m.Parameter(0), m.Parameter(1))));
3117     Stream s = m.Build();
3118     ASSERT_EQ(1U, s.size());
3119     EXPECT_EQ(kArm64Ldrsh, s[0]->arch_opcode());
3120     EXPECT_EQ(kMode_MRR, s[0]->addressing_mode());
3121     EXPECT_EQ(2U, s[0]->InputCount());
3122     EXPECT_EQ(1U, s[0]->OutputCount());
3123   }
3124   // ChangeInt32ToInt64(Load_Uint32) -> Ldrsw
3125   {
3126     StreamBuilder m(this, MachineType::Int64(), MachineType::Pointer(),
3127                     MachineType::Int32());
3128     m.Return(m.ChangeInt32ToInt64(
3129         m.Load(MachineType::Uint32(), m.Parameter(0), m.Parameter(1))));
3130     Stream s = m.Build();
3131     ASSERT_EQ(1U, s.size());
3132     EXPECT_EQ(kArm64Ldrsw, s[0]->arch_opcode());
3133     EXPECT_EQ(kMode_MRR, s[0]->addressing_mode());
3134     EXPECT_EQ(2U, s[0]->InputCount());
3135     EXPECT_EQ(1U, s[0]->OutputCount());
3136   }
3137   // ChangeInt32ToInt64(Load_Int32) -> Ldrsw
3138   {
3139     StreamBuilder m(this, MachineType::Int64(), MachineType::Pointer(),
3140                     MachineType::Int32());
3141     m.Return(m.ChangeInt32ToInt64(
3142         m.Load(MachineType::Int32(), m.Parameter(0), m.Parameter(1))));
3143     Stream s = m.Build();
3144     ASSERT_EQ(1U, s.size());
3145     EXPECT_EQ(kArm64Ldrsw, s[0]->arch_opcode());
3146     EXPECT_EQ(kMode_MRR, s[0]->addressing_mode());
3147     EXPECT_EQ(2U, s[0]->InputCount());
3148     EXPECT_EQ(1U, s[0]->OutputCount());
3149   }
3150 }
3151 
TEST_F(InstructionSelectorTest,ChangeInt32ToInt64WithWord32Sar)3152 TEST_F(InstructionSelectorTest, ChangeInt32ToInt64WithWord32Sar) {
3153   // Test the mod 32 behaviour of Word32Sar by iterating up to 33.
3154   TRACED_FORRANGE(int32_t, imm, 0, 33) {
3155     StreamBuilder m(this, MachineType::Int64(), MachineType::Int32());
3156     m.Return(m.ChangeInt32ToInt64(
3157         m.Word32Sar(m.Parameter(0), m.Int32Constant(imm))));
3158     Stream s = m.Build();
3159     ASSERT_EQ(1U, s.size());
3160     EXPECT_EQ(kArm64Sbfx, s[0]->arch_opcode());
3161     EXPECT_EQ(3U, s[0]->InputCount());
3162     EXPECT_EQ(1U, s[0]->OutputCount());
3163     EXPECT_EQ(imm & 0x1f, s.ToInt32(s[0]->InputAt(1)));
3164     EXPECT_EQ(32 - (imm & 0x1f), s.ToInt32(s[0]->InputAt(2)));
3165   }
3166 }
3167 
3168 // -----------------------------------------------------------------------------
3169 // Memory access instructions.
3170 
3171 namespace {
3172 
3173 struct MemoryAccess {
3174   MachineType type;
3175   ArchOpcode ldr_opcode;
3176   ArchOpcode str_opcode;
3177   const int32_t immediates[20];
3178 };
3179 
operator <<(std::ostream & os,const MemoryAccess & memacc)3180 std::ostream& operator<<(std::ostream& os, const MemoryAccess& memacc) {
3181   return os << memacc.type;
3182 }
3183 
3184 }  // namespace
3185 
3186 static const MemoryAccess kMemoryAccesses[] = {
3187     {MachineType::Int8(),
3188      kArm64LdrsbW,
3189      kArm64Strb,
3190      {-256, -255, -3,  -2,   -1,   0,    1,    2,    3,    255,
3191       256,  257,  258, 1000, 1001, 2121, 2442, 4093, 4094, 4095}},
3192     {MachineType::Uint8(),
3193      kArm64Ldrb,
3194      kArm64Strb,
3195      {-256, -255, -3,  -2,   -1,   0,    1,    2,    3,    255,
3196       256,  257,  258, 1000, 1001, 2121, 2442, 4093, 4094, 4095}},
3197     {MachineType::Int16(),
3198      kArm64LdrshW,
3199      kArm64Strh,
3200      {-256, -255, -3,  -2,   -1,   0,    1,    2,    3,    255,
3201       256,  258,  260, 4096, 4098, 4100, 4242, 6786, 8188, 8190}},
3202     {MachineType::Uint16(),
3203      kArm64Ldrh,
3204      kArm64Strh,
3205      {-256, -255, -3,  -2,   -1,   0,    1,    2,    3,    255,
3206       256,  258,  260, 4096, 4098, 4100, 4242, 6786, 8188, 8190}},
3207     {MachineType::Int32(),
3208      kArm64LdrW,
3209      kArm64StrW,
3210      {-256, -255, -3,   -2,   -1,   0,    1,    2,    3,     255,
3211       256,  260,  4096, 4100, 8192, 8196, 3276, 3280, 16376, 16380}},
3212     {MachineType::Uint32(),
3213      kArm64LdrW,
3214      kArm64StrW,
3215      {-256, -255, -3,   -2,   -1,   0,    1,    2,    3,     255,
3216       256,  260,  4096, 4100, 8192, 8196, 3276, 3280, 16376, 16380}},
3217     {MachineType::Int64(),
3218      kArm64Ldr,
3219      kArm64Str,
3220      {-256, -255, -3,   -2,   -1,   0,    1,     2,     3,     255,
3221       256,  264,  4096, 4104, 8192, 8200, 16384, 16392, 32752, 32760}},
3222     {MachineType::Uint64(),
3223      kArm64Ldr,
3224      kArm64Str,
3225      {-256, -255, -3,   -2,   -1,   0,    1,     2,     3,     255,
3226       256,  264,  4096, 4104, 8192, 8200, 16384, 16392, 32752, 32760}},
3227     {MachineType::Float32(),
3228      kArm64LdrS,
3229      kArm64StrS,
3230      {-256, -255, -3,   -2,   -1,   0,    1,    2,    3,     255,
3231       256,  260,  4096, 4100, 8192, 8196, 3276, 3280, 16376, 16380}},
3232     {MachineType::Float64(),
3233      kArm64LdrD,
3234      kArm64StrD,
3235      {-256, -255, -3,   -2,   -1,   0,    1,     2,     3,     255,
3236       256,  264,  4096, 4104, 8192, 8200, 16384, 16392, 32752, 32760}}};
3237 
3238 using InstructionSelectorMemoryAccessTest =
3239     InstructionSelectorTestWithParam<MemoryAccess>;
3240 
TEST_P(InstructionSelectorMemoryAccessTest,LoadWithParameters)3241 TEST_P(InstructionSelectorMemoryAccessTest, LoadWithParameters) {
3242   const MemoryAccess memacc = GetParam();
3243   StreamBuilder m(this, memacc.type, MachineType::Pointer(),
3244                   MachineType::Int32());
3245   m.Return(m.Load(memacc.type, m.Parameter(0), m.Parameter(1)));
3246   Stream s = m.Build();
3247   ASSERT_EQ(1U, s.size());
3248   EXPECT_EQ(memacc.ldr_opcode, s[0]->arch_opcode());
3249   EXPECT_EQ(kMode_MRR, s[0]->addressing_mode());
3250   EXPECT_EQ(2U, s[0]->InputCount());
3251   EXPECT_EQ(1U, s[0]->OutputCount());
3252 }
3253 
TEST_P(InstructionSelectorMemoryAccessTest,LoadWithImmediateIndex)3254 TEST_P(InstructionSelectorMemoryAccessTest, LoadWithImmediateIndex) {
3255   const MemoryAccess memacc = GetParam();
3256   TRACED_FOREACH(int32_t, index, memacc.immediates) {
3257     StreamBuilder m(this, memacc.type, MachineType::Pointer());
3258     m.Return(m.Load(memacc.type, m.Parameter(0), m.Int32Constant(index)));
3259     Stream s = m.Build();
3260     ASSERT_EQ(1U, s.size());
3261     EXPECT_EQ(memacc.ldr_opcode, s[0]->arch_opcode());
3262     EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
3263     EXPECT_EQ(2U, s[0]->InputCount());
3264     ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
3265     EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
3266     ASSERT_EQ(1U, s[0]->OutputCount());
3267   }
3268 }
3269 
TEST_P(InstructionSelectorMemoryAccessTest,StoreWithParameters)3270 TEST_P(InstructionSelectorMemoryAccessTest, StoreWithParameters) {
3271   const MemoryAccess memacc = GetParam();
3272   StreamBuilder m(this, MachineType::Int32(), MachineType::Pointer(),
3273                   MachineType::Int32(), memacc.type);
3274   m.Store(memacc.type.representation(), m.Parameter(0), m.Parameter(1),
3275           m.Parameter(2), kNoWriteBarrier);
3276   m.Return(m.Int32Constant(0));
3277   Stream s = m.Build();
3278   ASSERT_EQ(1U, s.size());
3279   EXPECT_EQ(memacc.str_opcode, s[0]->arch_opcode());
3280   EXPECT_EQ(kMode_MRR, s[0]->addressing_mode());
3281   EXPECT_EQ(3U, s[0]->InputCount());
3282   EXPECT_EQ(0U, s[0]->OutputCount());
3283 }
3284 
TEST_P(InstructionSelectorMemoryAccessTest,StoreWithImmediateIndex)3285 TEST_P(InstructionSelectorMemoryAccessTest, StoreWithImmediateIndex) {
3286   const MemoryAccess memacc = GetParam();
3287   TRACED_FOREACH(int32_t, index, memacc.immediates) {
3288     StreamBuilder m(this, MachineType::Int32(), MachineType::Pointer(),
3289                     memacc.type);
3290     m.Store(memacc.type.representation(), m.Parameter(0),
3291             m.Int32Constant(index), m.Parameter(1), kNoWriteBarrier);
3292     m.Return(m.Int32Constant(0));
3293     Stream s = m.Build();
3294     ASSERT_EQ(1U, s.size());
3295     EXPECT_EQ(memacc.str_opcode, s[0]->arch_opcode());
3296     EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
3297     ASSERT_EQ(3U, s[0]->InputCount());
3298     ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(2)->kind());
3299     EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(2)));
3300     EXPECT_EQ(0U, s[0]->OutputCount());
3301   }
3302 }
3303 
TEST_P(InstructionSelectorMemoryAccessTest,StoreZero)3304 TEST_P(InstructionSelectorMemoryAccessTest, StoreZero) {
3305   const MemoryAccess memacc = GetParam();
3306   TRACED_FOREACH(int32_t, index, memacc.immediates) {
3307     StreamBuilder m(this, MachineType::Int32(), MachineType::Pointer());
3308     m.Store(memacc.type.representation(), m.Parameter(0),
3309             m.Int32Constant(index), m.Int32Constant(0), kNoWriteBarrier);
3310     m.Return(m.Int32Constant(0));
3311     Stream s = m.Build();
3312     ASSERT_EQ(1U, s.size());
3313     EXPECT_EQ(memacc.str_opcode, s[0]->arch_opcode());
3314     EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
3315     ASSERT_EQ(3U, s[0]->InputCount());
3316     ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(2)->kind());
3317     EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(2)));
3318     ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(0)->kind());
3319     EXPECT_EQ(0, s.ToInt64(s[0]->InputAt(0)));
3320     EXPECT_EQ(0U, s[0]->OutputCount());
3321   }
3322 }
3323 
TEST_P(InstructionSelectorMemoryAccessTest,LoadWithShiftedIndex)3324 TEST_P(InstructionSelectorMemoryAccessTest, LoadWithShiftedIndex) {
3325   const MemoryAccess memacc = GetParam();
3326   TRACED_FORRANGE(int, immediate_shift, 0, 4) {
3327     // 32 bit shift
3328     {
3329       StreamBuilder m(this, memacc.type, MachineType::Pointer(),
3330                       MachineType::Int32());
3331       Node* const index =
3332           m.Word32Shl(m.Parameter(1), m.Int32Constant(immediate_shift));
3333       m.Return(m.Load(memacc.type, m.Parameter(0), index));
3334       Stream s = m.Build();
3335       if (immediate_shift == ElementSizeLog2Of(memacc.type.representation())) {
3336         ASSERT_EQ(1U, s.size());
3337         EXPECT_EQ(memacc.ldr_opcode, s[0]->arch_opcode());
3338         EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode());
3339         EXPECT_EQ(3U, s[0]->InputCount());
3340         EXPECT_EQ(1U, s[0]->OutputCount());
3341       } else {
3342         // Make sure we haven't merged the shift into the load instruction.
3343         ASSERT_NE(1U, s.size());
3344         EXPECT_NE(memacc.ldr_opcode, s[0]->arch_opcode());
3345         EXPECT_NE(kMode_Operand2_R_LSL_I, s[0]->addressing_mode());
3346       }
3347     }
3348     // 64 bit shift
3349     {
3350       StreamBuilder m(this, memacc.type, MachineType::Pointer(),
3351                       MachineType::Int64());
3352       Node* const index =
3353           m.Word64Shl(m.Parameter(1), m.Int64Constant(immediate_shift));
3354       m.Return(m.Load(memacc.type, m.Parameter(0), index));
3355       Stream s = m.Build();
3356       if (immediate_shift == ElementSizeLog2Of(memacc.type.representation())) {
3357         ASSERT_EQ(1U, s.size());
3358         EXPECT_EQ(memacc.ldr_opcode, s[0]->arch_opcode());
3359         EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode());
3360         EXPECT_EQ(3U, s[0]->InputCount());
3361         EXPECT_EQ(1U, s[0]->OutputCount());
3362       } else {
3363         // Make sure we haven't merged the shift into the load instruction.
3364         ASSERT_NE(1U, s.size());
3365         EXPECT_NE(memacc.ldr_opcode, s[0]->arch_opcode());
3366         EXPECT_NE(kMode_Operand2_R_LSL_I, s[0]->addressing_mode());
3367       }
3368     }
3369   }
3370 }
3371 
TEST_P(InstructionSelectorMemoryAccessTest,StoreWithShiftedIndex)3372 TEST_P(InstructionSelectorMemoryAccessTest, StoreWithShiftedIndex) {
3373   const MemoryAccess memacc = GetParam();
3374   TRACED_FORRANGE(int, immediate_shift, 0, 4) {
3375     // 32 bit shift
3376     {
3377       StreamBuilder m(this, MachineType::Int32(), MachineType::Pointer(),
3378                       MachineType::Int32(), memacc.type);
3379       Node* const index =
3380           m.Word32Shl(m.Parameter(1), m.Int32Constant(immediate_shift));
3381       m.Store(memacc.type.representation(), m.Parameter(0), index,
3382               m.Parameter(2), kNoWriteBarrier);
3383       m.Return(m.Int32Constant(0));
3384       Stream s = m.Build();
3385       if (immediate_shift == ElementSizeLog2Of(memacc.type.representation())) {
3386         ASSERT_EQ(1U, s.size());
3387         EXPECT_EQ(memacc.str_opcode, s[0]->arch_opcode());
3388         EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode());
3389         EXPECT_EQ(4U, s[0]->InputCount());
3390         EXPECT_EQ(0U, s[0]->OutputCount());
3391       } else {
3392         // Make sure we haven't merged the shift into the store instruction.
3393         ASSERT_NE(1U, s.size());
3394         EXPECT_NE(memacc.str_opcode, s[0]->arch_opcode());
3395         EXPECT_NE(kMode_Operand2_R_LSL_I, s[0]->addressing_mode());
3396       }
3397     }
3398     // 64 bit shift
3399     {
3400       StreamBuilder m(this, MachineType::Int64(), MachineType::Pointer(),
3401                       MachineType::Int64(), memacc.type);
3402       Node* const index =
3403           m.Word64Shl(m.Parameter(1), m.Int64Constant(immediate_shift));
3404       m.Store(memacc.type.representation(), m.Parameter(0), index,
3405               m.Parameter(2), kNoWriteBarrier);
3406       m.Return(m.Int64Constant(0));
3407       Stream s = m.Build();
3408       if (immediate_shift == ElementSizeLog2Of(memacc.type.representation())) {
3409         ASSERT_EQ(1U, s.size());
3410         EXPECT_EQ(memacc.str_opcode, s[0]->arch_opcode());
3411         EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode());
3412         EXPECT_EQ(4U, s[0]->InputCount());
3413         EXPECT_EQ(0U, s[0]->OutputCount());
3414       } else {
3415         // Make sure we haven't merged the shift into the store instruction.
3416         ASSERT_NE(1U, s.size());
3417         EXPECT_NE(memacc.str_opcode, s[0]->arch_opcode());
3418         EXPECT_NE(kMode_Operand2_R_LSL_I, s[0]->addressing_mode());
3419       }
3420     }
3421   }
3422 }
3423 
3424 INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest,
3425                          InstructionSelectorMemoryAccessTest,
3426                          ::testing::ValuesIn(kMemoryAccesses));
3427 
3428 static const WriteBarrierKind kWriteBarrierKinds[] = {
3429     kMapWriteBarrier, kPointerWriteBarrier, kEphemeronKeyWriteBarrier,
3430     kFullWriteBarrier};
3431 
3432 const int32_t kStoreWithBarrierImmediates[] = {
3433     -256, -255, -3,   -2,   -1,   0,    1,     2,     3,     255,
3434     256,  264,  4096, 4104, 8192, 8200, 16384, 16392, 32752, 32760};
3435 
3436 using InstructionSelectorStoreWithBarrierTest =
3437     InstructionSelectorTestWithParam<WriteBarrierKind>;
3438 
TEST_P(InstructionSelectorStoreWithBarrierTest,StoreWithWriteBarrierParameters)3439 TEST_P(InstructionSelectorStoreWithBarrierTest,
3440        StoreWithWriteBarrierParameters) {
3441   const WriteBarrierKind barrier_kind = GetParam();
3442   StreamBuilder m(this, MachineType::Int32(), MachineType::TaggedPointer(),
3443                   MachineType::Int32(), MachineType::AnyTagged());
3444   m.Store(MachineRepresentation::kTagged, m.Parameter(0), m.Parameter(1),
3445           m.Parameter(2), barrier_kind);
3446   m.Return(m.Int32Constant(0));
3447   Stream s = m.Build(kAllExceptNopInstructions);
3448   // We have two instructions that are not nops: Store and Return.
3449   ASSERT_EQ(2U, s.size());
3450   EXPECT_EQ(kArchStoreWithWriteBarrier, s[0]->arch_opcode());
3451   EXPECT_EQ(kMode_MRR, s[0]->addressing_mode());
3452   EXPECT_EQ(3U, s[0]->InputCount());
3453   EXPECT_EQ(0U, s[0]->OutputCount());
3454 }
3455 
TEST_P(InstructionSelectorStoreWithBarrierTest,StoreWithWriteBarrierImmediate)3456 TEST_P(InstructionSelectorStoreWithBarrierTest,
3457        StoreWithWriteBarrierImmediate) {
3458   const WriteBarrierKind barrier_kind = GetParam();
3459   TRACED_FOREACH(int32_t, index, kStoreWithBarrierImmediates) {
3460     StreamBuilder m(this, MachineType::Int32(), MachineType::TaggedPointer(),
3461                     MachineType::AnyTagged());
3462     m.Store(MachineRepresentation::kTagged, m.Parameter(0),
3463             m.Int32Constant(index), m.Parameter(1), barrier_kind);
3464     m.Return(m.Int32Constant(0));
3465     Stream s = m.Build(kAllExceptNopInstructions);
3466     // We have two instructions that are not nops: Store and Return.
3467     ASSERT_EQ(2U, s.size());
3468     EXPECT_EQ(kArchStoreWithWriteBarrier, s[0]->arch_opcode());
3469     // With compressed pointers, a store with barrier is a 32-bit str which has
3470     // a smaller immediate range.
3471     if (COMPRESS_POINTERS_BOOL && (index > 16380)) {
3472       EXPECT_EQ(kMode_MRR, s[0]->addressing_mode());
3473     } else {
3474       EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
3475     }
3476     EXPECT_EQ(3U, s[0]->InputCount());
3477     EXPECT_EQ(0U, s[0]->OutputCount());
3478   }
3479 }
3480 
3481 INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest,
3482                          InstructionSelectorStoreWithBarrierTest,
3483                          ::testing::ValuesIn(kWriteBarrierKinds));
3484 
3485 // -----------------------------------------------------------------------------
3486 // Comparison instructions.
3487 
3488 static const MachInst2 kComparisonInstructions[] = {
3489     {&RawMachineAssembler::Word32Equal, "Word32Equal", kArm64Cmp32,
3490      MachineType::Int32()},
3491     {&RawMachineAssembler::Word64Equal, "Word64Equal", kArm64Cmp,
3492      MachineType::Int64()},
3493 };
3494 
3495 using InstructionSelectorComparisonTest =
3496     InstructionSelectorTestWithParam<MachInst2>;
3497 
TEST_P(InstructionSelectorComparisonTest,WithParameters)3498 TEST_P(InstructionSelectorComparisonTest, WithParameters) {
3499   const MachInst2 cmp = GetParam();
3500   const MachineType type = cmp.machine_type;
3501   StreamBuilder m(this, type, type, type);
3502   m.Return((m.*cmp.constructor)(m.Parameter(0), m.Parameter(1)));
3503   Stream s = m.Build();
3504   ASSERT_EQ(1U, s.size());
3505   EXPECT_EQ(cmp.arch_opcode, s[0]->arch_opcode());
3506   EXPECT_EQ(2U, s[0]->InputCount());
3507   EXPECT_EQ(1U, s[0]->OutputCount());
3508   EXPECT_EQ(kFlags_set, s[0]->flags_mode());
3509   EXPECT_EQ(kEqual, s[0]->flags_condition());
3510 }
3511 
TEST_P(InstructionSelectorComparisonTest,WithImmediate)3512 TEST_P(InstructionSelectorComparisonTest, WithImmediate) {
3513   const MachInst2 cmp = GetParam();
3514   const MachineType type = cmp.machine_type;
3515   TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
3516     // Compare with 0 are turned into tst instruction.
3517     if (imm == 0) continue;
3518     StreamBuilder m(this, type, type);
3519     m.Return(
3520         (m.*cmp.constructor)(m.Parameter(0), BuildConstant(&m, type, imm)));
3521     Stream s = m.Build();
3522     ASSERT_EQ(1U, s.size());
3523     EXPECT_EQ(cmp.arch_opcode, s[0]->arch_opcode());
3524     ASSERT_EQ(2U, s[0]->InputCount());
3525     ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
3526     EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1)));
3527     EXPECT_EQ(1U, s[0]->OutputCount());
3528     EXPECT_EQ(kFlags_set, s[0]->flags_mode());
3529     EXPECT_EQ(kEqual, s[0]->flags_condition());
3530   }
3531   TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
3532     // Compare with 0 are turned into tst instruction.
3533     if (imm == 0) continue;
3534     StreamBuilder m(this, type, type);
3535     m.Return(
3536         (m.*cmp.constructor)(BuildConstant(&m, type, imm), m.Parameter(0)));
3537     Stream s = m.Build();
3538     ASSERT_EQ(1U, s.size());
3539     EXPECT_EQ(cmp.arch_opcode, s[0]->arch_opcode());
3540     ASSERT_EQ(2U, s[0]->InputCount());
3541     ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
3542     EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1)));
3543     EXPECT_EQ(1U, s[0]->OutputCount());
3544     EXPECT_EQ(kFlags_set, s[0]->flags_mode());
3545     EXPECT_EQ(kEqual, s[0]->flags_condition());
3546   }
3547 }
3548 
3549 INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest,
3550                          InstructionSelectorComparisonTest,
3551                          ::testing::ValuesIn(kComparisonInstructions));
3552 
TEST_F(InstructionSelectorTest,Word32EqualWithZero)3553 TEST_F(InstructionSelectorTest, Word32EqualWithZero) {
3554   {
3555     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
3556     m.Return(m.Word32Equal(m.Parameter(0), m.Int32Constant(0)));
3557     Stream s = m.Build();
3558     ASSERT_EQ(1U, s.size());
3559     EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode());
3560     ASSERT_EQ(2U, s[0]->InputCount());
3561     EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
3562     EXPECT_EQ(1U, s[0]->OutputCount());
3563     EXPECT_EQ(kFlags_set, s[0]->flags_mode());
3564     EXPECT_EQ(kEqual, s[0]->flags_condition());
3565   }
3566   {
3567     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
3568     m.Return(m.Word32Equal(m.Int32Constant(0), m.Parameter(0)));
3569     Stream s = m.Build();
3570     ASSERT_EQ(1U, s.size());
3571     EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode());
3572     ASSERT_EQ(2U, s[0]->InputCount());
3573     EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
3574     EXPECT_EQ(1U, s[0]->OutputCount());
3575     EXPECT_EQ(kFlags_set, s[0]->flags_mode());
3576     EXPECT_EQ(kEqual, s[0]->flags_condition());
3577   }
3578 }
3579 
TEST_F(InstructionSelectorTest,Word64EqualWithZero)3580 TEST_F(InstructionSelectorTest, Word64EqualWithZero) {
3581   {
3582     StreamBuilder m(this, MachineType::Int64(), MachineType::Int64());
3583     m.Return(m.Word64Equal(m.Parameter(0), m.Int64Constant(0)));
3584     Stream s = m.Build();
3585     ASSERT_EQ(1U, s.size());
3586     EXPECT_EQ(kArm64Tst, s[0]->arch_opcode());
3587     ASSERT_EQ(2U, s[0]->InputCount());
3588     EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
3589     EXPECT_EQ(1U, s[0]->OutputCount());
3590     EXPECT_EQ(kFlags_set, s[0]->flags_mode());
3591     EXPECT_EQ(kEqual, s[0]->flags_condition());
3592   }
3593   {
3594     StreamBuilder m(this, MachineType::Int64(), MachineType::Int64());
3595     m.Return(m.Word64Equal(m.Int64Constant(0), m.Parameter(0)));
3596     Stream s = m.Build();
3597     ASSERT_EQ(1U, s.size());
3598     EXPECT_EQ(kArm64Tst, s[0]->arch_opcode());
3599     ASSERT_EQ(2U, s[0]->InputCount());
3600     EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
3601     EXPECT_EQ(1U, s[0]->OutputCount());
3602     EXPECT_EQ(kFlags_set, s[0]->flags_mode());
3603     EXPECT_EQ(kEqual, s[0]->flags_condition());
3604   }
3605 }
3606 
TEST_F(InstructionSelectorTest,Word32EqualWithWord32Shift)3607 TEST_F(InstructionSelectorTest, Word32EqualWithWord32Shift) {
3608   TRACED_FOREACH(Shift, shift, kShiftInstructions) {
3609     // Skip non 32-bit shifts or ror operations.
3610     if (shift.mi.machine_type != MachineType::Int32() ||
3611         shift.mi.arch_opcode == kArm64Ror32) {
3612       continue;
3613     }
3614 
3615     TRACED_FORRANGE(int32_t, imm, -32, 63) {
3616       StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
3617                       MachineType::Int32());
3618       Node* const p0 = m.Parameter(0);
3619       Node* const p1 = m.Parameter(1);
3620       Node* r = (m.*shift.mi.constructor)(p1, m.Int32Constant(imm));
3621       m.Return(m.Word32Equal(p0, r));
3622       Stream s = m.Build();
3623       ASSERT_EQ(1U, s.size());
3624       EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode());
3625       EXPECT_EQ(shift.mode, s[0]->addressing_mode());
3626       ASSERT_EQ(3U, s[0]->InputCount());
3627       EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
3628       EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
3629       EXPECT_EQ(0x3F & imm, 0x3F & s.ToInt32(s[0]->InputAt(2)));
3630       ASSERT_EQ(1U, s[0]->OutputCount());
3631     }
3632     TRACED_FORRANGE(int32_t, imm, -32, 63) {
3633       StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
3634                       MachineType::Int32());
3635       Node* const p0 = m.Parameter(0);
3636       Node* const p1 = m.Parameter(1);
3637       Node* r = (m.*shift.mi.constructor)(p1, m.Int32Constant(imm));
3638       m.Return(m.Word32Equal(r, p0));
3639       Stream s = m.Build();
3640       ASSERT_EQ(1U, s.size());
3641       EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode());
3642       EXPECT_EQ(shift.mode, s[0]->addressing_mode());
3643       ASSERT_EQ(3U, s[0]->InputCount());
3644       EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
3645       EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
3646       EXPECT_EQ(0x3F & imm, 0x3F & s.ToInt32(s[0]->InputAt(2)));
3647       ASSERT_EQ(1U, s[0]->OutputCount());
3648     }
3649   }
3650 }
3651 
TEST_F(InstructionSelectorTest,Word32EqualWithUnsignedExtendByte)3652 TEST_F(InstructionSelectorTest, Word32EqualWithUnsignedExtendByte) {
3653   {
3654     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
3655                     MachineType::Int32());
3656     Node* const p0 = m.Parameter(0);
3657     Node* const p1 = m.Parameter(1);
3658     Node* r = m.Word32And(p1, m.Int32Constant(0xFF));
3659     m.Return(m.Word32Equal(p0, r));
3660     Stream s = m.Build();
3661     ASSERT_EQ(1U, s.size());
3662     EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode());
3663     EXPECT_EQ(kMode_Operand2_R_UXTB, s[0]->addressing_mode());
3664     ASSERT_EQ(2U, s[0]->InputCount());
3665     EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
3666     EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
3667     ASSERT_EQ(1U, s[0]->OutputCount());
3668   }
3669   {
3670     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
3671                     MachineType::Int32());
3672     Node* const p0 = m.Parameter(0);
3673     Node* const p1 = m.Parameter(1);
3674     Node* r = m.Word32And(p1, m.Int32Constant(0xFF));
3675     m.Return(m.Word32Equal(r, p0));
3676     Stream s = m.Build();
3677     ASSERT_EQ(1U, s.size());
3678     EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode());
3679     EXPECT_EQ(kMode_Operand2_R_UXTB, s[0]->addressing_mode());
3680     ASSERT_EQ(2U, s[0]->InputCount());
3681     EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
3682     EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
3683     ASSERT_EQ(1U, s[0]->OutputCount());
3684   }
3685 }
3686 
TEST_F(InstructionSelectorTest,Word32EqualWithUnsignedExtendHalfword)3687 TEST_F(InstructionSelectorTest, Word32EqualWithUnsignedExtendHalfword) {
3688   {
3689     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
3690                     MachineType::Int32());
3691     Node* const p0 = m.Parameter(0);
3692     Node* const p1 = m.Parameter(1);
3693     Node* r = m.Word32And(p1, m.Int32Constant(0xFFFF));
3694     m.Return(m.Word32Equal(p0, r));
3695     Stream s = m.Build();
3696     ASSERT_EQ(1U, s.size());
3697     EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode());
3698     EXPECT_EQ(kMode_Operand2_R_UXTH, s[0]->addressing_mode());
3699     ASSERT_EQ(2U, s[0]->InputCount());
3700     EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
3701     EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
3702     ASSERT_EQ(1U, s[0]->OutputCount());
3703   }
3704   {
3705     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
3706                     MachineType::Int32());
3707     Node* const p0 = m.Parameter(0);
3708     Node* const p1 = m.Parameter(1);
3709     Node* r = m.Word32And(p1, m.Int32Constant(0xFFFF));
3710     m.Return(m.Word32Equal(r, p0));
3711     Stream s = m.Build();
3712     ASSERT_EQ(1U, s.size());
3713     EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode());
3714     EXPECT_EQ(kMode_Operand2_R_UXTH, s[0]->addressing_mode());
3715     ASSERT_EQ(2U, s[0]->InputCount());
3716     EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
3717     EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
3718     ASSERT_EQ(1U, s[0]->OutputCount());
3719   }
3720 }
3721 
TEST_F(InstructionSelectorTest,Word32EqualWithSignedExtendByte)3722 TEST_F(InstructionSelectorTest, Word32EqualWithSignedExtendByte) {
3723   {
3724     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
3725                     MachineType::Int32());
3726     Node* const p0 = m.Parameter(0);
3727     Node* const p1 = m.Parameter(1);
3728     Node* r =
3729         m.Word32Sar(m.Word32Shl(p1, m.Int32Constant(24)), m.Int32Constant(24));
3730     m.Return(m.Word32Equal(p0, r));
3731     Stream s = m.Build();
3732     ASSERT_EQ(1U, s.size());
3733     EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode());
3734     EXPECT_EQ(kMode_Operand2_R_SXTB, s[0]->addressing_mode());
3735     ASSERT_EQ(2U, s[0]->InputCount());
3736     EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
3737     EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
3738     ASSERT_EQ(1U, s[0]->OutputCount());
3739   }
3740   {
3741     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
3742                     MachineType::Int32());
3743     Node* const p0 = m.Parameter(0);
3744     Node* const p1 = m.Parameter(1);
3745     Node* r =
3746         m.Word32Sar(m.Word32Shl(p1, m.Int32Constant(24)), m.Int32Constant(24));
3747     m.Return(m.Word32Equal(r, p0));
3748     Stream s = m.Build();
3749     ASSERT_EQ(1U, s.size());
3750     EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode());
3751     EXPECT_EQ(kMode_Operand2_R_SXTB, s[0]->addressing_mode());
3752     ASSERT_EQ(2U, s[0]->InputCount());
3753     EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
3754     EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
3755     ASSERT_EQ(1U, s[0]->OutputCount());
3756   }
3757 }
3758 
TEST_F(InstructionSelectorTest,Word32EqualWithSignedExtendHalfword)3759 TEST_F(InstructionSelectorTest, Word32EqualWithSignedExtendHalfword) {
3760   {
3761     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
3762                     MachineType::Int32());
3763     Node* const p0 = m.Parameter(0);
3764     Node* const p1 = m.Parameter(1);
3765     Node* r =
3766         m.Word32Sar(m.Word32Shl(p1, m.Int32Constant(16)), m.Int32Constant(16));
3767     m.Return(m.Word32Equal(p0, r));
3768     Stream s = m.Build();
3769     ASSERT_EQ(1U, s.size());
3770     EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode());
3771     EXPECT_EQ(kMode_Operand2_R_SXTH, s[0]->addressing_mode());
3772     ASSERT_EQ(2U, s[0]->InputCount());
3773     EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
3774     EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
3775     ASSERT_EQ(1U, s[0]->OutputCount());
3776   }
3777   {
3778     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
3779                     MachineType::Int32());
3780     Node* const p0 = m.Parameter(0);
3781     Node* const p1 = m.Parameter(1);
3782     Node* r =
3783         m.Word32Sar(m.Word32Shl(p1, m.Int32Constant(16)), m.Int32Constant(16));
3784     m.Return(m.Word32Equal(r, p0));
3785     Stream s = m.Build();
3786     ASSERT_EQ(1U, s.size());
3787     EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode());
3788     EXPECT_EQ(kMode_Operand2_R_SXTH, s[0]->addressing_mode());
3789     ASSERT_EQ(2U, s[0]->InputCount());
3790     EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
3791     EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
3792     ASSERT_EQ(1U, s[0]->OutputCount());
3793   }
3794 }
3795 
TEST_F(InstructionSelectorTest,Word32EqualZeroWithWord32Equal)3796 TEST_F(InstructionSelectorTest, Word32EqualZeroWithWord32Equal) {
3797   {
3798     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
3799                     MachineType::Int32());
3800     Node* const p0 = m.Parameter(0);
3801     Node* const p1 = m.Parameter(1);
3802     m.Return(m.Word32Equal(m.Word32Equal(p0, p1), m.Int32Constant(0)));
3803     Stream s = m.Build();
3804     ASSERT_EQ(1U, s.size());
3805     EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode());
3806     ASSERT_EQ(2U, s[0]->InputCount());
3807     EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
3808     EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
3809     EXPECT_EQ(1U, s[0]->OutputCount());
3810     EXPECT_EQ(kFlags_set, s[0]->flags_mode());
3811     EXPECT_EQ(kNotEqual, s[0]->flags_condition());
3812   }
3813   {
3814     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
3815                     MachineType::Int32());
3816     Node* const p0 = m.Parameter(0);
3817     Node* const p1 = m.Parameter(1);
3818     m.Return(m.Word32Equal(m.Int32Constant(0), m.Word32Equal(p0, p1)));
3819     Stream s = m.Build();
3820     ASSERT_EQ(1U, s.size());
3821     EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode());
3822     ASSERT_EQ(2U, s[0]->InputCount());
3823     EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
3824     EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
3825     EXPECT_EQ(1U, s[0]->OutputCount());
3826     EXPECT_EQ(kFlags_set, s[0]->flags_mode());
3827     EXPECT_EQ(kNotEqual, s[0]->flags_condition());
3828   }
3829 }
3830 
3831 namespace {
3832 
3833 struct IntegerCmp {
3834   MachInst2 mi;
3835   FlagsCondition cond;
3836   FlagsCondition commuted_cond;
3837 };
3838 
operator <<(std::ostream & os,const IntegerCmp & cmp)3839 std::ostream& operator<<(std::ostream& os, const IntegerCmp& cmp) {
3840   return os << cmp.mi;
3841 }
3842 
3843 // ARM64 32-bit integer comparison instructions.
3844 const IntegerCmp kIntegerCmpInstructions[] = {
3845     {{&RawMachineAssembler::Word32Equal, "Word32Equal", kArm64Cmp32,
3846       MachineType::Int32()},
3847      kEqual,
3848      kEqual},
3849     {{&RawMachineAssembler::Int32LessThan, "Int32LessThan", kArm64Cmp32,
3850       MachineType::Int32()},
3851      kSignedLessThan,
3852      kSignedGreaterThan},
3853     {{&RawMachineAssembler::Int32LessThanOrEqual, "Int32LessThanOrEqual",
3854       kArm64Cmp32, MachineType::Int32()},
3855      kSignedLessThanOrEqual,
3856      kSignedGreaterThanOrEqual},
3857     {{&RawMachineAssembler::Uint32LessThan, "Uint32LessThan", kArm64Cmp32,
3858       MachineType::Uint32()},
3859      kUnsignedLessThan,
3860      kUnsignedGreaterThan},
3861     {{&RawMachineAssembler::Uint32LessThanOrEqual, "Uint32LessThanOrEqual",
3862       kArm64Cmp32, MachineType::Uint32()},
3863      kUnsignedLessThanOrEqual,
3864      kUnsignedGreaterThanOrEqual}};
3865 
3866 const IntegerCmp kIntegerCmpEqualityInstructions[] = {
3867     {{&RawMachineAssembler::Word32Equal, "Word32Equal", kArm64Cmp32,
3868       MachineType::Int32()},
3869      kEqual,
3870      kEqual},
3871     {{&RawMachineAssembler::Word32NotEqual, "Word32NotEqual", kArm64Cmp32,
3872       MachineType::Int32()},
3873      kNotEqual,
3874      kNotEqual}};
3875 }  // namespace
3876 
TEST_F(InstructionSelectorTest,Word32CompareNegateWithWord32Shift)3877 TEST_F(InstructionSelectorTest, Word32CompareNegateWithWord32Shift) {
3878   TRACED_FOREACH(IntegerCmp, cmp, kIntegerCmpEqualityInstructions) {
3879     TRACED_FOREACH(Shift, shift, kShiftInstructions) {
3880       // Test 32-bit operations. Ignore ROR shifts, as compare-negate does not
3881       // support them.
3882       if (shift.mi.machine_type != MachineType::Int32() ||
3883           shift.mi.arch_opcode == kArm64Ror32) {
3884         continue;
3885       }
3886 
3887       TRACED_FORRANGE(int32_t, imm, -32, 63) {
3888         StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
3889                         MachineType::Int32());
3890         Node* const p0 = m.Parameter(0);
3891         Node* const p1 = m.Parameter(1);
3892         Node* r = (m.*shift.mi.constructor)(p1, m.Int32Constant(imm));
3893         m.Return(
3894             (m.*cmp.mi.constructor)(p0, m.Int32Sub(m.Int32Constant(0), r)));
3895         Stream s = m.Build();
3896         ASSERT_EQ(1U, s.size());
3897         EXPECT_EQ(kArm64Cmn32, s[0]->arch_opcode());
3898         EXPECT_EQ(3U, s[0]->InputCount());
3899         EXPECT_EQ(shift.mode, s[0]->addressing_mode());
3900         EXPECT_EQ(0x3F & imm, 0x3F & s.ToInt32(s[0]->InputAt(2)));
3901         EXPECT_EQ(1U, s[0]->OutputCount());
3902         EXPECT_EQ(kFlags_set, s[0]->flags_mode());
3903         EXPECT_EQ(cmp.cond, s[0]->flags_condition());
3904       }
3905     }
3906   }
3907 }
3908 
TEST_F(InstructionSelectorTest,CmpWithImmediateOnLeft)3909 TEST_F(InstructionSelectorTest, CmpWithImmediateOnLeft) {
3910   TRACED_FOREACH(IntegerCmp, cmp, kIntegerCmpInstructions) {
3911     TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
3912       // kEqual and kNotEqual trigger the cbz/cbnz optimization, which
3913       // is tested elsewhere.
3914       if (cmp.cond == kEqual || cmp.cond == kNotEqual) continue;
3915       // For signed less than or equal to zero, we generate TBNZ.
3916       if (cmp.cond == kSignedLessThanOrEqual && imm == 0) continue;
3917       StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
3918       Node* const p0 = m.Parameter(0);
3919       m.Return((m.*cmp.mi.constructor)(m.Int32Constant(imm), p0));
3920       Stream s = m.Build();
3921       ASSERT_EQ(1U, s.size());
3922       EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode());
3923       ASSERT_LE(2U, s[0]->InputCount());
3924       EXPECT_EQ(kFlags_set, s[0]->flags_mode());
3925       EXPECT_EQ(cmp.commuted_cond, s[0]->flags_condition());
3926       EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
3927     }
3928   }
3929 }
3930 
TEST_F(InstructionSelectorTest,CmnWithImmediateOnLeft)3931 TEST_F(InstructionSelectorTest, CmnWithImmediateOnLeft) {
3932   TRACED_FOREACH(IntegerCmp, cmp, kIntegerCmpEqualityInstructions) {
3933     TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
3934       // kEqual and kNotEqual trigger the cbz/cbnz optimization, which
3935       // is tested elsewhere.
3936       if (cmp.cond == kEqual || cmp.cond == kNotEqual) continue;
3937       StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
3938       Node* sub = m.Int32Sub(m.Int32Constant(0), m.Parameter(0));
3939       m.Return((m.*cmp.mi.constructor)(m.Int32Constant(imm), sub));
3940       Stream s = m.Build();
3941       ASSERT_EQ(1U, s.size());
3942       EXPECT_EQ(kArm64Cmn32, s[0]->arch_opcode());
3943       ASSERT_LE(2U, s[0]->InputCount());
3944       EXPECT_EQ(kFlags_set, s[0]->flags_mode());
3945       EXPECT_EQ(cmp.cond, s[0]->flags_condition());
3946       EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
3947     }
3948   }
3949 }
3950 
TEST_F(InstructionSelectorTest,CmpSignedExtendByteOnLeft)3951 TEST_F(InstructionSelectorTest, CmpSignedExtendByteOnLeft) {
3952   TRACED_FOREACH(IntegerCmp, cmp, kIntegerCmpInstructions) {
3953     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
3954                     MachineType::Int32());
3955     Node* extend = m.Word32Sar(m.Word32Shl(m.Parameter(0), m.Int32Constant(24)),
3956                                m.Int32Constant(24));
3957     m.Return((m.*cmp.mi.constructor)(extend, m.Parameter(1)));
3958     Stream s = m.Build();
3959     ASSERT_EQ(1U, s.size());
3960     EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode());
3961     EXPECT_EQ(kFlags_set, s[0]->flags_mode());
3962     EXPECT_EQ(cmp.commuted_cond, s[0]->flags_condition());
3963     EXPECT_EQ(kMode_Operand2_R_SXTB, s[0]->addressing_mode());
3964   }
3965 }
3966 
TEST_F(InstructionSelectorTest,CmnSignedExtendByteOnLeft)3967 TEST_F(InstructionSelectorTest, CmnSignedExtendByteOnLeft) {
3968   TRACED_FOREACH(IntegerCmp, cmp, kIntegerCmpEqualityInstructions) {
3969     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
3970                     MachineType::Int32());
3971     Node* sub = m.Int32Sub(m.Int32Constant(0), m.Parameter(0));
3972     Node* extend = m.Word32Sar(m.Word32Shl(m.Parameter(0), m.Int32Constant(24)),
3973                                m.Int32Constant(24));
3974     m.Return((m.*cmp.mi.constructor)(extend, sub));
3975     Stream s = m.Build();
3976     ASSERT_EQ(1U, s.size());
3977     EXPECT_EQ(kArm64Cmn32, s[0]->arch_opcode());
3978     EXPECT_EQ(kFlags_set, s[0]->flags_mode());
3979     EXPECT_EQ(cmp.cond, s[0]->flags_condition());
3980     EXPECT_EQ(kMode_Operand2_R_SXTB, s[0]->addressing_mode());
3981   }
3982 }
3983 
TEST_F(InstructionSelectorTest,CmpShiftByImmediateOnLeft)3984 TEST_F(InstructionSelectorTest, CmpShiftByImmediateOnLeft) {
3985   TRACED_FOREACH(IntegerCmp, cmp, kIntegerCmpInstructions) {
3986     TRACED_FOREACH(Shift, shift, kShiftInstructions) {
3987       // Only test relevant shifted operands.
3988       if (shift.mi.machine_type != MachineType::Int32()) continue;
3989 
3990       // The available shift operand range is `0 <= imm < 32`, but we also test
3991       // that immediates outside this range are handled properly (modulo-32).
3992       TRACED_FORRANGE(int, imm, -32, 63) {
3993         StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
3994                         MachineType::Int32());
3995         m.Return((m.*cmp.mi.constructor)(
3996             (m.*shift.mi.constructor)(m.Parameter(1), m.Int32Constant(imm)),
3997             m.Parameter(0)));
3998         Stream s = m.Build();
3999         // Cmp does not support ROR shifts.
4000         if (shift.mi.arch_opcode == kArm64Ror32) {
4001           ASSERT_EQ(2U, s.size());
4002           continue;
4003         }
4004         ASSERT_EQ(1U, s.size());
4005         EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode());
4006         EXPECT_EQ(shift.mode, s[0]->addressing_mode());
4007         EXPECT_EQ(3U, s[0]->InputCount());
4008         EXPECT_EQ(0x3F & imm, 0x3F & s.ToInt64(s[0]->InputAt(2)));
4009         EXPECT_EQ(1U, s[0]->OutputCount());
4010         EXPECT_EQ(kFlags_set, s[0]->flags_mode());
4011         EXPECT_EQ(cmp.commuted_cond, s[0]->flags_condition());
4012       }
4013     }
4014   }
4015 }
4016 
TEST_F(InstructionSelectorTest,CmnShiftByImmediateOnLeft)4017 TEST_F(InstructionSelectorTest, CmnShiftByImmediateOnLeft) {
4018   TRACED_FOREACH(IntegerCmp, cmp, kIntegerCmpEqualityInstructions) {
4019     TRACED_FOREACH(Shift, shift, kShiftInstructions) {
4020       // Only test relevant shifted operands.
4021       if (shift.mi.machine_type != MachineType::Int32()) continue;
4022 
4023       // The available shift operand range is `0 <= imm < 32`, but we also test
4024       // that immediates outside this range are handled properly (modulo-32).
4025       TRACED_FORRANGE(int, imm, -32, 63) {
4026         StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
4027                         MachineType::Int32());
4028         Node* sub = m.Int32Sub(m.Int32Constant(0), m.Parameter(0));
4029         m.Return((m.*cmp.mi.constructor)(
4030             (m.*shift.mi.constructor)(m.Parameter(1), m.Int32Constant(imm)),
4031             sub));
4032         Stream s = m.Build();
4033         // Cmn does not support ROR shifts.
4034         if (shift.mi.arch_opcode == kArm64Ror32) {
4035           ASSERT_EQ(2U, s.size());
4036           continue;
4037         }
4038         ASSERT_EQ(1U, s.size());
4039         EXPECT_EQ(kArm64Cmn32, s[0]->arch_opcode());
4040         EXPECT_EQ(shift.mode, s[0]->addressing_mode());
4041         EXPECT_EQ(3U, s[0]->InputCount());
4042         EXPECT_EQ(0x3F & imm, 0x3F & s.ToInt64(s[0]->InputAt(2)));
4043         EXPECT_EQ(1U, s[0]->OutputCount());
4044         EXPECT_EQ(kFlags_set, s[0]->flags_mode());
4045         EXPECT_EQ(cmp.cond, s[0]->flags_condition());
4046       }
4047     }
4048   }
4049 }
4050 
4051 // -----------------------------------------------------------------------------
4052 // Flag-setting add and and instructions.
4053 
4054 const IntegerCmp kBinopCmpZeroRightInstructions[] = {
4055     {{&RawMachineAssembler::Word32Equal, "Word32Equal", kArm64Cmp32,
4056       MachineType::Int32()},
4057      kEqual,
4058      kEqual},
4059     {{&RawMachineAssembler::Word32NotEqual, "Word32NotEqual", kArm64Cmp32,
4060       MachineType::Int32()},
4061      kNotEqual,
4062      kNotEqual},
4063     {{&RawMachineAssembler::Int32LessThan, "Int32LessThan", kArm64Cmp32,
4064       MachineType::Int32()},
4065      kNegative,
4066      kNegative},
4067     {{&RawMachineAssembler::Int32GreaterThanOrEqual, "Int32GreaterThanOrEqual",
4068       kArm64Cmp32, MachineType::Int32()},
4069      kPositiveOrZero,
4070      kPositiveOrZero},
4071     {{&RawMachineAssembler::Uint32LessThanOrEqual, "Uint32LessThanOrEqual",
4072       kArm64Cmp32, MachineType::Int32()},
4073      kEqual,
4074      kEqual},
4075     {{&RawMachineAssembler::Uint32GreaterThan, "Uint32GreaterThan", kArm64Cmp32,
4076       MachineType::Int32()},
4077      kNotEqual,
4078      kNotEqual}};
4079 
4080 const IntegerCmp kBinop64CmpZeroRightInstructions[] = {
4081     {{&RawMachineAssembler::Word64Equal, "Word64Equal", kArm64Cmp,
4082       MachineType::Int64()},
4083      kEqual,
4084      kEqual},
4085     {{&RawMachineAssembler::Word64NotEqual, "Word64NotEqual", kArm64Cmp,
4086       MachineType::Int64()},
4087      kNotEqual,
4088      kNotEqual},
4089     {{&RawMachineAssembler::Int64LessThan, "Int64LessThan", kArm64Cmp,
4090       MachineType::Int64()},
4091      kNegative,
4092      kNegative},
4093     {{&RawMachineAssembler::Int64GreaterThanOrEqual, "Int64GreaterThanOrEqual",
4094       kArm64Cmp, MachineType::Int64()},
4095      kPositiveOrZero,
4096      kPositiveOrZero},
4097     {{&RawMachineAssembler::Uint64LessThanOrEqual, "Uint64LessThanOrEqual",
4098       kArm64Cmp, MachineType::Int64()},
4099      kEqual,
4100      kEqual},
4101     {{&RawMachineAssembler::Uint64GreaterThan, "Uint64GreaterThan", kArm64Cmp,
4102       MachineType::Int64()},
4103      kNotEqual,
4104      kNotEqual},
4105 };
4106 
4107 const IntegerCmp kBinopCmpZeroLeftInstructions[] = {
4108     {{&RawMachineAssembler::Word32Equal, "Word32Equal", kArm64Cmp32,
4109       MachineType::Int32()},
4110      kEqual,
4111      kEqual},
4112     {{&RawMachineAssembler::Word32NotEqual, "Word32NotEqual", kArm64Cmp32,
4113       MachineType::Int32()},
4114      kNotEqual,
4115      kNotEqual},
4116     {{&RawMachineAssembler::Int32GreaterThan, "Int32GreaterThan", kArm64Cmp32,
4117       MachineType::Int32()},
4118      kNegative,
4119      kNegative},
4120     {{&RawMachineAssembler::Int32LessThanOrEqual, "Int32LessThanOrEqual",
4121       kArm64Cmp32, MachineType::Int32()},
4122      kPositiveOrZero,
4123      kPositiveOrZero},
4124     {{&RawMachineAssembler::Uint32GreaterThanOrEqual,
4125       "Uint32GreaterThanOrEqual", kArm64Cmp32, MachineType::Int32()},
4126      kEqual,
4127      kEqual},
4128     {{&RawMachineAssembler::Uint32LessThan, "Uint32LessThan", kArm64Cmp32,
4129       MachineType::Int32()},
4130      kNotEqual,
4131      kNotEqual}};
4132 
4133 struct FlagSettingInst {
4134   MachInst2 mi;
4135   ArchOpcode no_output_opcode;
4136 };
4137 
operator <<(std::ostream & os,const FlagSettingInst & inst)4138 std::ostream& operator<<(std::ostream& os, const FlagSettingInst& inst) {
4139   return os << inst.mi.constructor_name;
4140 }
4141 
4142 const FlagSettingInst kFlagSettingInstructions[] = {
4143     {{&RawMachineAssembler::Int32Add, "Int32Add", kArm64Add32,
4144       MachineType::Int32()},
4145      kArm64Cmn32},
4146     {{&RawMachineAssembler::Word32And, "Word32And", kArm64And32,
4147       MachineType::Int32()},
4148      kArm64Tst32}};
4149 
4150 using InstructionSelectorFlagSettingTest =
4151     InstructionSelectorTestWithParam<FlagSettingInst>;
4152 
TEST_P(InstructionSelectorFlagSettingTest,CmpZeroRight)4153 TEST_P(InstructionSelectorFlagSettingTest, CmpZeroRight) {
4154   const FlagSettingInst inst = GetParam();
4155   // Add with single user : a cmp instruction.
4156   TRACED_FOREACH(IntegerCmp, cmp, kBinopCmpZeroRightInstructions) {
4157     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
4158                     MachineType::Int32());
4159     Node* binop = (m.*inst.mi.constructor)(m.Parameter(0), m.Parameter(1));
4160     m.Return((m.*cmp.mi.constructor)(binop, m.Int32Constant(0)));
4161     Stream s = m.Build();
4162     ASSERT_EQ(1U, s.size());
4163     ASSERT_EQ(2U, s[0]->InputCount());
4164     EXPECT_EQ(inst.no_output_opcode, s[0]->arch_opcode());
4165     EXPECT_EQ(s.ToVreg(m.Parameter(0)), s.ToVreg(s[0]->InputAt(0)));
4166     EXPECT_EQ(s.ToVreg(m.Parameter(1)), s.ToVreg(s[0]->InputAt(1)));
4167     EXPECT_EQ(kFlags_set, s[0]->flags_mode());
4168     EXPECT_EQ(cmp.cond, s[0]->flags_condition());
4169   }
4170 }
4171 
TEST_P(InstructionSelectorFlagSettingTest,CmpZeroLeft)4172 TEST_P(InstructionSelectorFlagSettingTest, CmpZeroLeft) {
4173   const FlagSettingInst inst = GetParam();
4174   // Test a cmp with zero on the left-hand side.
4175   TRACED_FOREACH(IntegerCmp, cmp, kBinopCmpZeroLeftInstructions) {
4176     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
4177                     MachineType::Int32());
4178     Node* binop = (m.*inst.mi.constructor)(m.Parameter(0), m.Parameter(1));
4179     m.Return((m.*cmp.mi.constructor)(m.Int32Constant(0), binop));
4180     Stream s = m.Build();
4181     ASSERT_EQ(1U, s.size());
4182     ASSERT_EQ(2U, s[0]->InputCount());
4183     EXPECT_EQ(inst.no_output_opcode, s[0]->arch_opcode());
4184     EXPECT_EQ(s.ToVreg(m.Parameter(0)), s.ToVreg(s[0]->InputAt(0)));
4185     EXPECT_EQ(s.ToVreg(m.Parameter(1)), s.ToVreg(s[0]->InputAt(1)));
4186     EXPECT_EQ(kFlags_set, s[0]->flags_mode());
4187     EXPECT_EQ(cmp.cond, s[0]->flags_condition());
4188   }
4189 }
4190 
TEST_P(InstructionSelectorFlagSettingTest,CmpZeroOnlyUserInBasicBlock)4191 TEST_P(InstructionSelectorFlagSettingTest, CmpZeroOnlyUserInBasicBlock) {
4192   const FlagSettingInst inst = GetParam();
4193   // Binop with additional users, but in a different basic block.
4194   TRACED_FOREACH(IntegerCmp, cmp, kBinopCmpZeroRightInstructions) {
4195     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
4196                     MachineType::Int32());
4197     RawMachineLabel a, b;
4198     Node* binop = (m.*inst.mi.constructor)(m.Parameter(0), m.Parameter(1));
4199     Node* comp = (m.*cmp.mi.constructor)(binop, m.Int32Constant(0));
4200     m.Branch(m.Parameter(0), &a, &b);
4201     m.Bind(&a);
4202     m.Return(binop);
4203     m.Bind(&b);
4204     m.Return(comp);
4205     Stream s = m.Build();
4206     ASSERT_EQ(2U, s.size());  // Flag-setting instruction and branch.
4207     ASSERT_EQ(2U, s[0]->InputCount());
4208     EXPECT_EQ(inst.mi.arch_opcode, s[0]->arch_opcode());
4209     EXPECT_EQ(s.ToVreg(m.Parameter(0)), s.ToVreg(s[0]->InputAt(0)));
4210     EXPECT_EQ(s.ToVreg(m.Parameter(1)), s.ToVreg(s[0]->InputAt(1)));
4211     EXPECT_EQ(kFlags_set, s[0]->flags_mode());
4212     EXPECT_EQ(cmp.cond, s[0]->flags_condition());
4213   }
4214 }
4215 
TEST_P(InstructionSelectorFlagSettingTest,ShiftedOperand)4216 TEST_P(InstructionSelectorFlagSettingTest, ShiftedOperand) {
4217   const FlagSettingInst inst = GetParam();
4218   // Like the test above, but with a shifted input to the binary operator.
4219   TRACED_FOREACH(IntegerCmp, cmp, kBinopCmpZeroRightInstructions) {
4220     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
4221                     MachineType::Int32());
4222     RawMachineLabel a, b;
4223     Node* imm = m.Int32Constant(5);
4224     Node* shift = m.Word32Shl(m.Parameter(1), imm);
4225     Node* binop = (m.*inst.mi.constructor)(m.Parameter(0), shift);
4226     Node* comp = (m.*cmp.mi.constructor)(binop, m.Int32Constant(0));
4227     m.Branch(m.Parameter(0), &a, &b);
4228     m.Bind(&a);
4229     m.Return(binop);
4230     m.Bind(&b);
4231     m.Return(comp);
4232     Stream s = m.Build();
4233     ASSERT_EQ(2U, s.size());  // Flag-setting instruction and branch.
4234     ASSERT_EQ(3U, s[0]->InputCount());
4235     EXPECT_EQ(inst.mi.arch_opcode, s[0]->arch_opcode());
4236     EXPECT_EQ(s.ToVreg(m.Parameter(0)), s.ToVreg(s[0]->InputAt(0)));
4237     EXPECT_EQ(s.ToVreg(m.Parameter(1)), s.ToVreg(s[0]->InputAt(1)));
4238     EXPECT_EQ(5, s.ToInt32(s[0]->InputAt(2)));
4239     EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode());
4240     EXPECT_EQ(kFlags_set, s[0]->flags_mode());
4241     EXPECT_EQ(cmp.cond, s[0]->flags_condition());
4242   }
4243 }
4244 
TEST_P(InstructionSelectorFlagSettingTest,UsersInSameBasicBlock)4245 TEST_P(InstructionSelectorFlagSettingTest, UsersInSameBasicBlock) {
4246   const FlagSettingInst inst = GetParam();
4247   // Binop with additional users, in the same basic block. We need to make sure
4248   // we don't try to optimise this case.
4249   TRACED_FOREACH(IntegerCmp, cmp, kIntegerCmpInstructions) {
4250     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
4251                     MachineType::Int32());
4252     RawMachineLabel a, b;
4253     Node* binop = (m.*inst.mi.constructor)(m.Parameter(0), m.Parameter(1));
4254     Node* mul = m.Int32Mul(m.Parameter(0), binop);
4255     Node* comp = (m.*cmp.mi.constructor)(binop, m.Int32Constant(0));
4256     m.Branch(m.Parameter(0), &a, &b);
4257     m.Bind(&a);
4258     m.Return(mul);
4259     m.Bind(&b);
4260     m.Return(comp);
4261     Stream s = m.Build();
4262     ASSERT_EQ(4U, s.size());  // Includes the compare and branch instruction.
4263     EXPECT_EQ(inst.mi.arch_opcode, s[0]->arch_opcode());
4264     EXPECT_EQ(kFlags_none, s[0]->flags_mode());
4265     EXPECT_EQ(kArm64Mul32, s[1]->arch_opcode());
4266     EXPECT_EQ(kArm64Cmp32, s[2]->arch_opcode());
4267     EXPECT_EQ(kFlags_set, s[2]->flags_mode());
4268     EXPECT_EQ(cmp.cond, s[2]->flags_condition());
4269   }
4270 }
4271 
TEST_P(InstructionSelectorFlagSettingTest,CommuteImmediate)4272 TEST_P(InstructionSelectorFlagSettingTest, CommuteImmediate) {
4273   const FlagSettingInst inst = GetParam();
4274   // Immediate on left hand side of the binary operator.
4275   TRACED_FOREACH(IntegerCmp, cmp, kBinopCmpZeroRightInstructions) {
4276     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
4277     // 3 can be an immediate on both arithmetic and logical instructions.
4278     Node* imm = m.Int32Constant(3);
4279     Node* binop = (m.*inst.mi.constructor)(imm, m.Parameter(0));
4280     Node* comp = (m.*cmp.mi.constructor)(binop, m.Int32Constant(0));
4281     m.Return(comp);
4282     Stream s = m.Build();
4283     ASSERT_EQ(1U, s.size());
4284     ASSERT_EQ(2U, s[0]->InputCount());
4285     EXPECT_EQ(inst.no_output_opcode, s[0]->arch_opcode());
4286     EXPECT_EQ(s.ToVreg(m.Parameter(0)), s.ToVreg(s[0]->InputAt(0)));
4287     EXPECT_EQ(3, s.ToInt32(s[0]->InputAt(1)));
4288     EXPECT_EQ(kFlags_set, s[0]->flags_mode());
4289     EXPECT_EQ(cmp.cond, s[0]->flags_condition());
4290   }
4291 }
4292 
TEST_P(InstructionSelectorFlagSettingTest,CommuteShift)4293 TEST_P(InstructionSelectorFlagSettingTest, CommuteShift) {
4294   const FlagSettingInst inst = GetParam();
4295   // Left-hand side operand shifted by immediate.
4296   TRACED_FOREACH(IntegerCmp, cmp, kBinopCmpZeroRightInstructions) {
4297     TRACED_FOREACH(Shift, shift, kShiftInstructions) {
4298       // Only test relevant shifted operands.
4299       if (shift.mi.machine_type != MachineType::Int32()) continue;
4300 
4301       StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
4302                       MachineType::Int32());
4303       Node* imm = m.Int32Constant(5);
4304       Node* shifted_operand = (m.*shift.mi.constructor)(m.Parameter(0), imm);
4305       Node* binop = (m.*inst.mi.constructor)(shifted_operand, m.Parameter(1));
4306       Node* comp = (m.*cmp.mi.constructor)(binop, m.Int32Constant(0));
4307       m.Return(comp);
4308       Stream s = m.Build();
4309       // Cmn does not support ROR shifts.
4310       if (inst.no_output_opcode == kArm64Cmn32 &&
4311           shift.mi.arch_opcode == kArm64Ror32) {
4312         ASSERT_EQ(2U, s.size());
4313         continue;
4314       }
4315       ASSERT_EQ(1U, s.size());
4316       EXPECT_EQ(inst.no_output_opcode, s[0]->arch_opcode());
4317       EXPECT_EQ(shift.mode, s[0]->addressing_mode());
4318       EXPECT_EQ(3U, s[0]->InputCount());
4319       EXPECT_EQ(5, s.ToInt64(s[0]->InputAt(2)));
4320       EXPECT_EQ(1U, s[0]->OutputCount());
4321       EXPECT_EQ(kFlags_set, s[0]->flags_mode());
4322       EXPECT_EQ(cmp.cond, s[0]->flags_condition());
4323     }
4324   }
4325 }
4326 
4327 INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest,
4328                          InstructionSelectorFlagSettingTest,
4329                          ::testing::ValuesIn(kFlagSettingInstructions));
4330 
TEST_F(InstructionSelectorTest,TstInvalidImmediate)4331 TEST_F(InstructionSelectorTest, TstInvalidImmediate) {
4332   // Make sure we do not generate an invalid immediate for TST.
4333   TRACED_FOREACH(IntegerCmp, cmp, kBinopCmpZeroRightInstructions) {
4334     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
4335     // 5 is not a valid constant for TST.
4336     Node* imm = m.Int32Constant(5);
4337     Node* binop = m.Word32And(imm, m.Parameter(0));
4338     Node* comp = (m.*cmp.mi.constructor)(binop, m.Int32Constant(0));
4339     m.Return(comp);
4340     Stream s = m.Build();
4341     ASSERT_EQ(1U, s.size());
4342     ASSERT_EQ(2U, s[0]->InputCount());
4343     EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode());
4344     EXPECT_NE(InstructionOperand::IMMEDIATE, s[0]->InputAt(0)->kind());
4345     EXPECT_NE(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
4346     EXPECT_EQ(kFlags_set, s[0]->flags_mode());
4347     EXPECT_EQ(cmp.cond, s[0]->flags_condition());
4348   }
4349 }
4350 
TEST_F(InstructionSelectorTest,CommuteAddsExtend)4351 TEST_F(InstructionSelectorTest, CommuteAddsExtend) {
4352   // Extended left-hand side operand.
4353   TRACED_FOREACH(IntegerCmp, cmp, kBinopCmpZeroRightInstructions) {
4354     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
4355                     MachineType::Int32());
4356     Node* extend = m.Word32Sar(m.Word32Shl(m.Parameter(0), m.Int32Constant(24)),
4357                                m.Int32Constant(24));
4358     Node* binop = m.Int32Add(extend, m.Parameter(1));
4359     m.Return((m.*cmp.mi.constructor)(binop, m.Int32Constant(0)));
4360     Stream s = m.Build();
4361     ASSERT_EQ(1U, s.size());
4362     EXPECT_EQ(kArm64Cmn32, s[0]->arch_opcode());
4363     EXPECT_EQ(kFlags_set, s[0]->flags_mode());
4364     EXPECT_EQ(cmp.cond, s[0]->flags_condition());
4365     EXPECT_EQ(kMode_Operand2_R_SXTB, s[0]->addressing_mode());
4366   }
4367 }
4368 
4369 // -----------------------------------------------------------------------------
4370 // Miscellaneous
4371 
4372 static const MachInst2 kLogicalWithNotRHSs[] = {
4373     {&RawMachineAssembler::Word32And, "Word32And", kArm64Bic32,
4374      MachineType::Int32()},
4375     {&RawMachineAssembler::Word64And, "Word64And", kArm64Bic,
4376      MachineType::Int64()},
4377     {&RawMachineAssembler::Word32Or, "Word32Or", kArm64Orn32,
4378      MachineType::Int32()},
4379     {&RawMachineAssembler::Word64Or, "Word64Or", kArm64Orn,
4380      MachineType::Int64()},
4381     {&RawMachineAssembler::Word32Xor, "Word32Xor", kArm64Eon32,
4382      MachineType::Int32()},
4383     {&RawMachineAssembler::Word64Xor, "Word64Xor", kArm64Eon,
4384      MachineType::Int64()}};
4385 
4386 using InstructionSelectorLogicalWithNotRHSTest =
4387     InstructionSelectorTestWithParam<MachInst2>;
4388 
TEST_P(InstructionSelectorLogicalWithNotRHSTest,Parameter)4389 TEST_P(InstructionSelectorLogicalWithNotRHSTest, Parameter) {
4390   const MachInst2 inst = GetParam();
4391   const MachineType type = inst.machine_type;
4392   // Test cases where RHS is Xor(x, -1).
4393   {
4394     StreamBuilder m(this, type, type, type);
4395     if (type == MachineType::Int32()) {
4396       m.Return((m.*inst.constructor)(
4397           m.Parameter(0), m.Word32Xor(m.Parameter(1), m.Int32Constant(-1))));
4398     } else {
4399       ASSERT_EQ(MachineType::Int64(), type);
4400       m.Return((m.*inst.constructor)(
4401           m.Parameter(0), m.Word64Xor(m.Parameter(1), m.Int64Constant(-1))));
4402     }
4403     Stream s = m.Build();
4404     ASSERT_EQ(1U, s.size());
4405     EXPECT_EQ(inst.arch_opcode, s[0]->arch_opcode());
4406     EXPECT_EQ(2U, s[0]->InputCount());
4407     EXPECT_EQ(1U, s[0]->OutputCount());
4408   }
4409   {
4410     StreamBuilder m(this, type, type, type);
4411     if (type == MachineType::Int32()) {
4412       m.Return((m.*inst.constructor)(
4413           m.Word32Xor(m.Parameter(0), m.Int32Constant(-1)), m.Parameter(1)));
4414     } else {
4415       ASSERT_EQ(MachineType::Int64(), type);
4416       m.Return((m.*inst.constructor)(
4417           m.Word64Xor(m.Parameter(0), m.Int64Constant(-1)), m.Parameter(1)));
4418     }
4419     Stream s = m.Build();
4420     ASSERT_EQ(1U, s.size());
4421     EXPECT_EQ(inst.arch_opcode, s[0]->arch_opcode());
4422     EXPECT_EQ(2U, s[0]->InputCount());
4423     EXPECT_EQ(1U, s[0]->OutputCount());
4424   }
4425   // Test cases where RHS is Not(x).
4426   {
4427     StreamBuilder m(this, type, type, type);
4428     if (type == MachineType::Int32()) {
4429       m.Return((m.*inst.constructor)(m.Parameter(0),
4430                                      m.Word32BitwiseNot(m.Parameter(1))));
4431     } else {
4432       ASSERT_EQ(MachineType::Int64(), type);
4433       m.Return(
4434           (m.*inst.constructor)(m.Parameter(0), m.Word64Not(m.Parameter(1))));
4435     }
4436     Stream s = m.Build();
4437     ASSERT_EQ(1U, s.size());
4438     EXPECT_EQ(inst.arch_opcode, s[0]->arch_opcode());
4439     EXPECT_EQ(2U, s[0]->InputCount());
4440     EXPECT_EQ(1U, s[0]->OutputCount());
4441   }
4442   {
4443     StreamBuilder m(this, type, type, type);
4444     if (type == MachineType::Int32()) {
4445       m.Return((m.*inst.constructor)(m.Word32BitwiseNot(m.Parameter(0)),
4446                                      m.Parameter(1)));
4447     } else {
4448       ASSERT_EQ(MachineType::Int64(), type);
4449       m.Return(
4450           (m.*inst.constructor)(m.Word64Not(m.Parameter(0)), m.Parameter(1)));
4451     }
4452     Stream s = m.Build();
4453     ASSERT_EQ(1U, s.size());
4454     EXPECT_EQ(inst.arch_opcode, s[0]->arch_opcode());
4455     EXPECT_EQ(2U, s[0]->InputCount());
4456     EXPECT_EQ(1U, s[0]->OutputCount());
4457   }
4458 }
4459 
4460 INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest,
4461                          InstructionSelectorLogicalWithNotRHSTest,
4462                          ::testing::ValuesIn(kLogicalWithNotRHSs));
4463 
TEST_F(InstructionSelectorTest,Word32BitwiseNotWithParameter)4464 TEST_F(InstructionSelectorTest, Word32BitwiseNotWithParameter) {
4465   StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
4466   m.Return(m.Word32BitwiseNot(m.Parameter(0)));
4467   Stream s = m.Build();
4468   ASSERT_EQ(1U, s.size());
4469   EXPECT_EQ(kArm64Not32, s[0]->arch_opcode());
4470   EXPECT_EQ(1U, s[0]->InputCount());
4471   EXPECT_EQ(1U, s[0]->OutputCount());
4472 }
4473 
TEST_F(InstructionSelectorTest,Word64NotWithParameter)4474 TEST_F(InstructionSelectorTest, Word64NotWithParameter) {
4475   StreamBuilder m(this, MachineType::Int64(), MachineType::Int64());
4476   m.Return(m.Word64Not(m.Parameter(0)));
4477   Stream s = m.Build();
4478   ASSERT_EQ(1U, s.size());
4479   EXPECT_EQ(kArm64Not, s[0]->arch_opcode());
4480   EXPECT_EQ(1U, s[0]->InputCount());
4481   EXPECT_EQ(1U, s[0]->OutputCount());
4482 }
4483 
TEST_F(InstructionSelectorTest,Word32XorMinusOneWithParameter)4484 TEST_F(InstructionSelectorTest, Word32XorMinusOneWithParameter) {
4485   {
4486     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
4487     m.Return(m.Word32Xor(m.Parameter(0), m.Int32Constant(-1)));
4488     Stream s = m.Build();
4489     ASSERT_EQ(1U, s.size());
4490     EXPECT_EQ(kArm64Not32, s[0]->arch_opcode());
4491     EXPECT_EQ(1U, s[0]->InputCount());
4492     EXPECT_EQ(1U, s[0]->OutputCount());
4493   }
4494   {
4495     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
4496     m.Return(m.Word32Xor(m.Int32Constant(-1), m.Parameter(0)));
4497     Stream s = m.Build();
4498     ASSERT_EQ(1U, s.size());
4499     EXPECT_EQ(kArm64Not32, s[0]->arch_opcode());
4500     EXPECT_EQ(1U, s[0]->InputCount());
4501     EXPECT_EQ(1U, s[0]->OutputCount());
4502   }
4503 }
4504 
TEST_F(InstructionSelectorTest,Word64XorMinusOneWithParameter)4505 TEST_F(InstructionSelectorTest, Word64XorMinusOneWithParameter) {
4506   {
4507     StreamBuilder m(this, MachineType::Int64(), MachineType::Int64());
4508     m.Return(m.Word64Xor(m.Parameter(0), m.Int64Constant(-1)));
4509     Stream s = m.Build();
4510     ASSERT_EQ(1U, s.size());
4511     EXPECT_EQ(kArm64Not, s[0]->arch_opcode());
4512     EXPECT_EQ(1U, s[0]->InputCount());
4513     EXPECT_EQ(1U, s[0]->OutputCount());
4514   }
4515   {
4516     StreamBuilder m(this, MachineType::Int64(), MachineType::Int64());
4517     m.Return(m.Word64Xor(m.Int64Constant(-1), m.Parameter(0)));
4518     Stream s = m.Build();
4519     ASSERT_EQ(1U, s.size());
4520     EXPECT_EQ(kArm64Not, s[0]->arch_opcode());
4521     EXPECT_EQ(1U, s[0]->InputCount());
4522     EXPECT_EQ(1U, s[0]->OutputCount());
4523   }
4524 }
4525 
TEST_F(InstructionSelectorTest,Word32ShrWithWord32AndWithImmediate)4526 TEST_F(InstructionSelectorTest, Word32ShrWithWord32AndWithImmediate) {
4527   // The available shift operand range is `0 <= imm < 32`, but we also test
4528   // that immediates outside this range are handled properly (modulo-32).
4529   TRACED_FORRANGE(int32_t, shift, -32, 63) {
4530     int32_t lsb = shift & 0x1F;
4531     TRACED_FORRANGE(int32_t, width, 1, 32 - lsb) {
4532       uint32_t jnk = rng()->NextInt();
4533       jnk = (lsb > 0) ? (jnk >> (32 - lsb)) : 0;
4534       uint32_t msk = ((0xFFFFFFFFu >> (32 - width)) << lsb) | jnk;
4535       StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
4536       m.Return(m.Word32Shr(m.Word32And(m.Parameter(0), m.Int32Constant(msk)),
4537                            m.Int32Constant(shift)));
4538       Stream s = m.Build();
4539       ASSERT_EQ(1U, s.size());
4540       EXPECT_EQ(kArm64Ubfx32, s[0]->arch_opcode());
4541       ASSERT_EQ(3U, s[0]->InputCount());
4542       EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1)));
4543       EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2)));
4544     }
4545   }
4546   TRACED_FORRANGE(int32_t, shift, -32, 63) {
4547     int32_t lsb = shift & 0x1F;
4548     TRACED_FORRANGE(int32_t, width, 1, 32 - lsb) {
4549       uint32_t jnk = rng()->NextInt();
4550       jnk = (lsb > 0) ? (jnk >> (32 - lsb)) : 0;
4551       uint32_t msk = ((0xFFFFFFFFu >> (32 - width)) << lsb) | jnk;
4552       StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
4553       m.Return(m.Word32Shr(m.Word32And(m.Int32Constant(msk), m.Parameter(0)),
4554                            m.Int32Constant(shift)));
4555       Stream s = m.Build();
4556       ASSERT_EQ(1U, s.size());
4557       EXPECT_EQ(kArm64Ubfx32, s[0]->arch_opcode());
4558       ASSERT_EQ(3U, s[0]->InputCount());
4559       EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1)));
4560       EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2)));
4561     }
4562   }
4563 }
4564 
TEST_F(InstructionSelectorTest,Word64ShrWithWord64AndWithImmediate)4565 TEST_F(InstructionSelectorTest, Word64ShrWithWord64AndWithImmediate) {
4566   // The available shift operand range is `0 <= imm < 64`, but we also test
4567   // that immediates outside this range are handled properly (modulo-64).
4568   TRACED_FORRANGE(int32_t, shift, -64, 127) {
4569     int32_t lsb = shift & 0x3F;
4570     TRACED_FORRANGE(int32_t, width, 1, 64 - lsb) {
4571       uint64_t jnk = rng()->NextInt64();
4572       jnk = (lsb > 0) ? (jnk >> (64 - lsb)) : 0;
4573       uint64_t msk =
4574           ((uint64_t{0xFFFFFFFFFFFFFFFF} >> (64 - width)) << lsb) | jnk;
4575       StreamBuilder m(this, MachineType::Int64(), MachineType::Int64());
4576       m.Return(m.Word64Shr(m.Word64And(m.Parameter(0), m.Int64Constant(msk)),
4577                            m.Int64Constant(shift)));
4578       Stream s = m.Build();
4579       ASSERT_EQ(1U, s.size());
4580       EXPECT_EQ(kArm64Ubfx, s[0]->arch_opcode());
4581       ASSERT_EQ(3U, s[0]->InputCount());
4582       EXPECT_EQ(lsb, s.ToInt64(s[0]->InputAt(1)));
4583       EXPECT_EQ(width, s.ToInt64(s[0]->InputAt(2)));
4584     }
4585   }
4586   TRACED_FORRANGE(int32_t, shift, -64, 127) {
4587     int32_t lsb = shift & 0x3F;
4588     TRACED_FORRANGE(int32_t, width, 1, 64 - lsb) {
4589       uint64_t jnk = rng()->NextInt64();
4590       jnk = (lsb > 0) ? (jnk >> (64 - lsb)) : 0;
4591       uint64_t msk =
4592           ((uint64_t{0xFFFFFFFFFFFFFFFF} >> (64 - width)) << lsb) | jnk;
4593       StreamBuilder m(this, MachineType::Int64(), MachineType::Int64());
4594       m.Return(m.Word64Shr(m.Word64And(m.Int64Constant(msk), m.Parameter(0)),
4595                            m.Int64Constant(shift)));
4596       Stream s = m.Build();
4597       ASSERT_EQ(1U, s.size());
4598       EXPECT_EQ(kArm64Ubfx, s[0]->arch_opcode());
4599       ASSERT_EQ(3U, s[0]->InputCount());
4600       EXPECT_EQ(lsb, s.ToInt64(s[0]->InputAt(1)));
4601       EXPECT_EQ(width, s.ToInt64(s[0]->InputAt(2)));
4602     }
4603   }
4604 }
4605 
TEST_F(InstructionSelectorTest,Word32AndWithImmediateWithWord32Shr)4606 TEST_F(InstructionSelectorTest, Word32AndWithImmediateWithWord32Shr) {
4607   // The available shift operand range is `0 <= imm < 32`, but we also test
4608   // that immediates outside this range are handled properly (modulo-32).
4609   TRACED_FORRANGE(int32_t, shift, -32, 63) {
4610     int32_t lsb = shift & 0x1F;
4611     TRACED_FORRANGE(int32_t, width, 1, 31) {
4612       uint32_t msk = (1u << width) - 1;
4613       StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
4614       m.Return(m.Word32And(m.Word32Shr(m.Parameter(0), m.Int32Constant(shift)),
4615                            m.Int32Constant(msk)));
4616       Stream s = m.Build();
4617       ASSERT_EQ(1U, s.size());
4618       EXPECT_EQ(kArm64Ubfx32, s[0]->arch_opcode());
4619       ASSERT_EQ(3U, s[0]->InputCount());
4620       EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1)));
4621       int32_t actual_width = (lsb + width > 32) ? (32 - lsb) : width;
4622       EXPECT_EQ(actual_width, s.ToInt32(s[0]->InputAt(2)));
4623     }
4624   }
4625   TRACED_FORRANGE(int32_t, shift, -32, 63) {
4626     int32_t lsb = shift & 0x1F;
4627     TRACED_FORRANGE(int32_t, width, 1, 31) {
4628       uint32_t msk = (1u << width) - 1;
4629       StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
4630       m.Return(
4631           m.Word32And(m.Int32Constant(msk),
4632                       m.Word32Shr(m.Parameter(0), m.Int32Constant(shift))));
4633       Stream s = m.Build();
4634       ASSERT_EQ(1U, s.size());
4635       EXPECT_EQ(kArm64Ubfx32, s[0]->arch_opcode());
4636       ASSERT_EQ(3U, s[0]->InputCount());
4637       EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1)));
4638       int32_t actual_width = (lsb + width > 32) ? (32 - lsb) : width;
4639       EXPECT_EQ(actual_width, s.ToInt32(s[0]->InputAt(2)));
4640     }
4641   }
4642 }
4643 
TEST_F(InstructionSelectorTest,Word64AndWithImmediateWithWord64Shr)4644 TEST_F(InstructionSelectorTest, Word64AndWithImmediateWithWord64Shr) {
4645   // The available shift operand range is `0 <= imm < 64`, but we also test
4646   // that immediates outside this range are handled properly (modulo-64).
4647   TRACED_FORRANGE(int64_t, shift, -64, 127) {
4648     int64_t lsb = shift & 0x3F;
4649     TRACED_FORRANGE(int64_t, width, 1, 63) {
4650       uint64_t msk = (uint64_t{1} << width) - 1;
4651       StreamBuilder m(this, MachineType::Int64(), MachineType::Int64());
4652       m.Return(m.Word64And(m.Word64Shr(m.Parameter(0), m.Int64Constant(shift)),
4653                            m.Int64Constant(msk)));
4654       Stream s = m.Build();
4655       ASSERT_EQ(1U, s.size());
4656       EXPECT_EQ(kArm64Ubfx, s[0]->arch_opcode());
4657       ASSERT_EQ(3U, s[0]->InputCount());
4658       EXPECT_EQ(lsb, s.ToInt64(s[0]->InputAt(1)));
4659       int64_t actual_width = (lsb + width > 64) ? (64 - lsb) : width;
4660       EXPECT_EQ(actual_width, s.ToInt64(s[0]->InputAt(2)));
4661     }
4662   }
4663   TRACED_FORRANGE(int64_t, shift, -64, 127) {
4664     int64_t lsb = shift & 0x3F;
4665     TRACED_FORRANGE(int64_t, width, 1, 63) {
4666       uint64_t msk = (uint64_t{1} << width) - 1;
4667       StreamBuilder m(this, MachineType::Int64(), MachineType::Int64());
4668       m.Return(
4669           m.Word64And(m.Int64Constant(msk),
4670                       m.Word64Shr(m.Parameter(0), m.Int64Constant(shift))));
4671       Stream s = m.Build();
4672       ASSERT_EQ(1U, s.size());
4673       EXPECT_EQ(kArm64Ubfx, s[0]->arch_opcode());
4674       ASSERT_EQ(3U, s[0]->InputCount());
4675       EXPECT_EQ(lsb, s.ToInt64(s[0]->InputAt(1)));
4676       int64_t actual_width = (lsb + width > 64) ? (64 - lsb) : width;
4677       EXPECT_EQ(actual_width, s.ToInt64(s[0]->InputAt(2)));
4678     }
4679   }
4680 }
4681 
TEST_F(InstructionSelectorTest,Int32MulHighWithParameters)4682 TEST_F(InstructionSelectorTest, Int32MulHighWithParameters) {
4683   StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
4684                   MachineType::Int32());
4685   Node* const p0 = m.Parameter(0);
4686   Node* const p1 = m.Parameter(1);
4687   Node* const n = m.Int32MulHigh(p0, p1);
4688   m.Return(n);
4689   Stream s = m.Build();
4690   ASSERT_EQ(2U, s.size());
4691   EXPECT_EQ(kArm64Smull, s[0]->arch_opcode());
4692   ASSERT_EQ(2U, s[0]->InputCount());
4693   EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
4694   EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
4695   ASSERT_EQ(1U, s[0]->OutputCount());
4696   EXPECT_EQ(kArm64Asr, s[1]->arch_opcode());
4697   ASSERT_EQ(2U, s[1]->InputCount());
4698   EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[1]->InputAt(0)));
4699   EXPECT_EQ(32, s.ToInt64(s[1]->InputAt(1)));
4700   ASSERT_EQ(1U, s[1]->OutputCount());
4701   EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[1]->Output()));
4702 }
4703 
TEST_F(InstructionSelectorTest,Int32MulHighWithSar)4704 TEST_F(InstructionSelectorTest, Int32MulHighWithSar) {
4705   TRACED_FORRANGE(int32_t, shift, -32, 63) {
4706     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
4707                     MachineType::Int32());
4708     Node* const p0 = m.Parameter(0);
4709     Node* const p1 = m.Parameter(1);
4710     Node* const n = m.Word32Sar(m.Int32MulHigh(p0, p1), m.Int32Constant(shift));
4711     m.Return(n);
4712     Stream s = m.Build();
4713     ASSERT_EQ(2U, s.size());
4714     EXPECT_EQ(kArm64Smull, s[0]->arch_opcode());
4715     ASSERT_EQ(2U, s[0]->InputCount());
4716     EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
4717     EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
4718     ASSERT_EQ(1U, s[0]->OutputCount());
4719     EXPECT_EQ(kArm64Asr, s[1]->arch_opcode());
4720     ASSERT_EQ(2U, s[1]->InputCount());
4721     EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[1]->InputAt(0)));
4722     EXPECT_EQ((shift & 0x1F) + 32, s.ToInt64(s[1]->InputAt(1)));
4723     ASSERT_EQ(1U, s[1]->OutputCount());
4724     EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[1]->Output()));
4725   }
4726 }
4727 
TEST_F(InstructionSelectorTest,Int32MulHighWithAdd)4728 TEST_F(InstructionSelectorTest, Int32MulHighWithAdd) {
4729   StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
4730                   MachineType::Int32());
4731   Node* const p0 = m.Parameter(0);
4732   Node* const p1 = m.Parameter(1);
4733   Node* const a = m.Int32Add(m.Int32MulHigh(p0, p1), p0);
4734   // Test only one shift constant here, as we're only interested in it being a
4735   // 32-bit operation; the shift amount is irrelevant.
4736   Node* const n = m.Word32Sar(a, m.Int32Constant(1));
4737   m.Return(n);
4738   Stream s = m.Build();
4739   ASSERT_EQ(3U, s.size());
4740   EXPECT_EQ(kArm64Smull, s[0]->arch_opcode());
4741   ASSERT_EQ(2U, s[0]->InputCount());
4742   EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
4743   EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
4744   ASSERT_EQ(1U, s[0]->OutputCount());
4745   EXPECT_EQ(kArm64Add, s[1]->arch_opcode());
4746   EXPECT_EQ(kMode_Operand2_R_ASR_I, s[1]->addressing_mode());
4747   ASSERT_EQ(3U, s[1]->InputCount());
4748   EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[1]->InputAt(0)));
4749   EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[1]->InputAt(1)));
4750   EXPECT_EQ(32, s.ToInt64(s[1]->InputAt(2)));
4751   ASSERT_EQ(1U, s[1]->OutputCount());
4752   EXPECT_EQ(kArm64Asr32, s[2]->arch_opcode());
4753   ASSERT_EQ(2U, s[2]->InputCount());
4754   EXPECT_EQ(s.ToVreg(s[1]->Output()), s.ToVreg(s[2]->InputAt(0)));
4755   EXPECT_EQ(1, s.ToInt64(s[2]->InputAt(1)));
4756   ASSERT_EQ(1U, s[2]->OutputCount());
4757   EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[2]->Output()));
4758 }
4759 
TEST_F(InstructionSelectorTest,Uint32MulHighWithShr)4760 TEST_F(InstructionSelectorTest, Uint32MulHighWithShr) {
4761   TRACED_FORRANGE(int32_t, shift, -32, 63) {
4762     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
4763                     MachineType::Int32());
4764     Node* const p0 = m.Parameter(0);
4765     Node* const p1 = m.Parameter(1);
4766     Node* const n =
4767         m.Word32Shr(m.Uint32MulHigh(p0, p1), m.Int32Constant(shift));
4768     m.Return(n);
4769     Stream s = m.Build();
4770     ASSERT_EQ(2U, s.size());
4771     EXPECT_EQ(kArm64Umull, s[0]->arch_opcode());
4772     ASSERT_EQ(2U, s[0]->InputCount());
4773     EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
4774     EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
4775     ASSERT_EQ(1U, s[0]->OutputCount());
4776     EXPECT_EQ(kArm64Lsr, s[1]->arch_opcode());
4777     ASSERT_EQ(2U, s[1]->InputCount());
4778     EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[1]->InputAt(0)));
4779     EXPECT_EQ((shift & 0x1F) + 32, s.ToInt64(s[1]->InputAt(1)));
4780     ASSERT_EQ(1U, s[1]->OutputCount());
4781     EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[1]->Output()));
4782   }
4783 }
4784 
TEST_F(InstructionSelectorTest,Word32SarWithWord32Shl)4785 TEST_F(InstructionSelectorTest, Word32SarWithWord32Shl) {
4786   TRACED_FORRANGE(int32_t, shift, 1, 31) {
4787     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
4788     Node* const p0 = m.Parameter(0);
4789     Node* const r = m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(shift)),
4790                                 m.Int32Constant(shift));
4791     m.Return(r);
4792     Stream s = m.Build();
4793     ASSERT_EQ(1U, s.size());
4794     EXPECT_EQ(kArm64Sbfx32, s[0]->arch_opcode());
4795     ASSERT_EQ(3U, s[0]->InputCount());
4796     EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
4797     ASSERT_EQ(1U, s[0]->OutputCount());
4798     EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
4799   }
4800   TRACED_FORRANGE(int32_t, shift, 1, 31) {
4801     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
4802     Node* const p0 = m.Parameter(0);
4803     Node* const r = m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(shift + 32)),
4804                                 m.Int32Constant(shift + 64));
4805     m.Return(r);
4806     Stream s = m.Build();
4807     ASSERT_EQ(1U, s.size());
4808     EXPECT_EQ(kArm64Sbfx32, s[0]->arch_opcode());
4809     ASSERT_EQ(3U, s[0]->InputCount());
4810     EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
4811     ASSERT_EQ(1U, s[0]->OutputCount());
4812     EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
4813   }
4814 }
4815 
TEST_F(InstructionSelectorTest,Word32ShrWithWord32Shl)4816 TEST_F(InstructionSelectorTest, Word32ShrWithWord32Shl) {
4817   TRACED_FORRANGE(int32_t, shift, 1, 31) {
4818     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
4819     Node* const p0 = m.Parameter(0);
4820     Node* const r = m.Word32Shr(m.Word32Shl(p0, m.Int32Constant(shift)),
4821                                 m.Int32Constant(shift));
4822     m.Return(r);
4823     Stream s = m.Build();
4824     ASSERT_EQ(1U, s.size());
4825     EXPECT_EQ(kArm64Ubfx32, s[0]->arch_opcode());
4826     ASSERT_EQ(3U, s[0]->InputCount());
4827     EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
4828     ASSERT_EQ(1U, s[0]->OutputCount());
4829     EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
4830   }
4831   TRACED_FORRANGE(int32_t, shift, 1, 31) {
4832     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
4833     Node* const p0 = m.Parameter(0);
4834     Node* const r = m.Word32Shr(m.Word32Shl(p0, m.Int32Constant(shift + 32)),
4835                                 m.Int32Constant(shift + 64));
4836     m.Return(r);
4837     Stream s = m.Build();
4838     ASSERT_EQ(1U, s.size());
4839     EXPECT_EQ(kArm64Ubfx32, s[0]->arch_opcode());
4840     ASSERT_EQ(3U, s[0]->InputCount());
4841     EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
4842     ASSERT_EQ(1U, s[0]->OutputCount());
4843     EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
4844   }
4845 }
4846 
TEST_F(InstructionSelectorTest,Word32ShlWithWord32And)4847 TEST_F(InstructionSelectorTest, Word32ShlWithWord32And) {
4848   TRACED_FORRANGE(int32_t, shift, 1, 30) {
4849     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
4850     Node* const p0 = m.Parameter(0);
4851     Node* const r =
4852         m.Word32Shl(m.Word32And(p0, m.Int32Constant((1 << (31 - shift)) - 1)),
4853                     m.Int32Constant(shift));
4854     m.Return(r);
4855     Stream s = m.Build();
4856     ASSERT_EQ(1U, s.size());
4857     EXPECT_EQ(kArm64Ubfiz32, s[0]->arch_opcode());
4858     ASSERT_EQ(3U, s[0]->InputCount());
4859     EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
4860     ASSERT_EQ(1U, s[0]->OutputCount());
4861     EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
4862   }
4863   TRACED_FORRANGE(int32_t, shift, 0, 30) {
4864     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
4865     Node* const p0 = m.Parameter(0);
4866     Node* const r =
4867         m.Word32Shl(m.Word32And(p0, m.Int32Constant((1u << (31 - shift)) - 1)),
4868                     m.Int32Constant(shift + 1));
4869     m.Return(r);
4870     Stream s = m.Build();
4871     ASSERT_EQ(1U, s.size());
4872     EXPECT_EQ(kArm64Lsl32, s[0]->arch_opcode());
4873     ASSERT_EQ(2U, s[0]->InputCount());
4874     EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
4875     ASSERT_EQ(1U, s[0]->OutputCount());
4876     EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
4877   }
4878 }
4879 
TEST_F(InstructionSelectorTest,Word32Clz)4880 TEST_F(InstructionSelectorTest, Word32Clz) {
4881   StreamBuilder m(this, MachineType::Uint32(), MachineType::Uint32());
4882   Node* const p0 = m.Parameter(0);
4883   Node* const n = m.Word32Clz(p0);
4884   m.Return(n);
4885   Stream s = m.Build();
4886   ASSERT_EQ(1U, s.size());
4887   EXPECT_EQ(kArm64Clz32, s[0]->arch_opcode());
4888   ASSERT_EQ(1U, s[0]->InputCount());
4889   EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
4890   ASSERT_EQ(1U, s[0]->OutputCount());
4891   EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
4892 }
4893 
TEST_F(InstructionSelectorTest,Float32Abs)4894 TEST_F(InstructionSelectorTest, Float32Abs) {
4895   StreamBuilder m(this, MachineType::Float32(), MachineType::Float32());
4896   Node* const p0 = m.Parameter(0);
4897   Node* const n = m.Float32Abs(p0);
4898   m.Return(n);
4899   Stream s = m.Build();
4900   ASSERT_EQ(1U, s.size());
4901   EXPECT_EQ(kArm64Float32Abs, s[0]->arch_opcode());
4902   ASSERT_EQ(1U, s[0]->InputCount());
4903   EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
4904   ASSERT_EQ(1U, s[0]->OutputCount());
4905   EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
4906 }
4907 
TEST_F(InstructionSelectorTest,Float64Abs)4908 TEST_F(InstructionSelectorTest, Float64Abs) {
4909   StreamBuilder m(this, MachineType::Float64(), MachineType::Float64());
4910   Node* const p0 = m.Parameter(0);
4911   Node* const n = m.Float64Abs(p0);
4912   m.Return(n);
4913   Stream s = m.Build();
4914   ASSERT_EQ(1U, s.size());
4915   EXPECT_EQ(kArm64Float64Abs, s[0]->arch_opcode());
4916   ASSERT_EQ(1U, s[0]->InputCount());
4917   EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
4918   ASSERT_EQ(1U, s[0]->OutputCount());
4919   EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
4920 }
4921 
TEST_F(InstructionSelectorTest,Float32Abd)4922 TEST_F(InstructionSelectorTest, Float32Abd) {
4923   StreamBuilder m(this, MachineType::Float32(), MachineType::Float32(),
4924                   MachineType::Float32());
4925   Node* const p0 = m.Parameter(0);
4926   Node* const p1 = m.Parameter(1);
4927   Node* const fsub = m.Float32Sub(p0, p1);
4928   Node* const fabs = m.Float32Abs(fsub);
4929   m.Return(fabs);
4930   Stream s = m.Build();
4931   ASSERT_EQ(1U, s.size());
4932   EXPECT_EQ(kArm64Float32Abd, s[0]->arch_opcode());
4933   ASSERT_EQ(2U, s[0]->InputCount());
4934   EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
4935   EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
4936   ASSERT_EQ(1U, s[0]->OutputCount());
4937   EXPECT_EQ(s.ToVreg(fabs), s.ToVreg(s[0]->Output()));
4938 }
4939 
TEST_F(InstructionSelectorTest,Float64Abd)4940 TEST_F(InstructionSelectorTest, Float64Abd) {
4941   StreamBuilder m(this, MachineType::Float64(), MachineType::Float64(),
4942                   MachineType::Float64());
4943   Node* const p0 = m.Parameter(0);
4944   Node* const p1 = m.Parameter(1);
4945   Node* const fsub = m.Float64Sub(p0, p1);
4946   Node* const fabs = m.Float64Abs(fsub);
4947   m.Return(fabs);
4948   Stream s = m.Build();
4949   ASSERT_EQ(1U, s.size());
4950   EXPECT_EQ(kArm64Float64Abd, s[0]->arch_opcode());
4951   ASSERT_EQ(2U, s[0]->InputCount());
4952   EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
4953   EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
4954   ASSERT_EQ(1U, s[0]->OutputCount());
4955   EXPECT_EQ(s.ToVreg(fabs), s.ToVreg(s[0]->Output()));
4956 }
4957 
TEST_F(InstructionSelectorTest,Float64Max)4958 TEST_F(InstructionSelectorTest, Float64Max) {
4959   StreamBuilder m(this, MachineType::Float64(), MachineType::Float64(),
4960                   MachineType::Float64());
4961   Node* const p0 = m.Parameter(0);
4962   Node* const p1 = m.Parameter(1);
4963   Node* const n = m.Float64Max(p0, p1);
4964   m.Return(n);
4965   Stream s = m.Build();
4966   ASSERT_EQ(1U, s.size());
4967   EXPECT_EQ(kArm64Float64Max, s[0]->arch_opcode());
4968   ASSERT_EQ(2U, s[0]->InputCount());
4969   EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
4970   EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
4971   ASSERT_EQ(1U, s[0]->OutputCount());
4972   EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
4973 }
4974 
TEST_F(InstructionSelectorTest,Float64Min)4975 TEST_F(InstructionSelectorTest, Float64Min) {
4976   StreamBuilder m(this, MachineType::Float64(), MachineType::Float64(),
4977                   MachineType::Float64());
4978   Node* const p0 = m.Parameter(0);
4979   Node* const p1 = m.Parameter(1);
4980   Node* const n = m.Float64Min(p0, p1);
4981   m.Return(n);
4982   Stream s = m.Build();
4983   ASSERT_EQ(1U, s.size());
4984   EXPECT_EQ(kArm64Float64Min, s[0]->arch_opcode());
4985   ASSERT_EQ(2U, s[0]->InputCount());
4986   EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
4987   EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
4988   ASSERT_EQ(1U, s[0]->OutputCount());
4989   EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
4990 }
4991 
TEST_F(InstructionSelectorTest,Float32Neg)4992 TEST_F(InstructionSelectorTest, Float32Neg) {
4993   StreamBuilder m(this, MachineType::Float32(), MachineType::Float32());
4994   Node* const p0 = m.Parameter(0);
4995   // Don't use m.Float32Neg() as that generates an explicit sub.
4996   Node* const n = m.AddNode(m.machine()->Float32Neg(), m.Parameter(0));
4997   m.Return(n);
4998   Stream s = m.Build();
4999   ASSERT_EQ(1U, s.size());
5000   EXPECT_EQ(kArm64Float32Neg, s[0]->arch_opcode());
5001   ASSERT_EQ(1U, s[0]->InputCount());
5002   EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
5003   ASSERT_EQ(1U, s[0]->OutputCount());
5004   EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
5005 }
5006 
TEST_F(InstructionSelectorTest,Float64Neg)5007 TEST_F(InstructionSelectorTest, Float64Neg) {
5008   StreamBuilder m(this, MachineType::Float64(), MachineType::Float64());
5009   Node* const p0 = m.Parameter(0);
5010   // Don't use m.Float64Neg() as that generates an explicit sub.
5011   Node* const n = m.AddNode(m.machine()->Float64Neg(), m.Parameter(0));
5012   m.Return(n);
5013   Stream s = m.Build();
5014   ASSERT_EQ(1U, s.size());
5015   EXPECT_EQ(kArm64Float64Neg, s[0]->arch_opcode());
5016   ASSERT_EQ(1U, s[0]->InputCount());
5017   EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
5018   ASSERT_EQ(1U, s[0]->OutputCount());
5019   EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
5020 }
5021 
TEST_F(InstructionSelectorTest,Float32NegWithMul)5022 TEST_F(InstructionSelectorTest, Float32NegWithMul) {
5023   StreamBuilder m(this, MachineType::Float32(), MachineType::Float32(),
5024                   MachineType::Float32());
5025   Node* const p0 = m.Parameter(0);
5026   Node* const p1 = m.Parameter(1);
5027   Node* const n1 = m.AddNode(m.machine()->Float32Mul(), p0, p1);
5028   Node* const n2 = m.AddNode(m.machine()->Float32Neg(), n1);
5029   m.Return(n2);
5030   Stream s = m.Build();
5031   ASSERT_EQ(1U, s.size());
5032   EXPECT_EQ(kArm64Float32Fnmul, s[0]->arch_opcode());
5033   ASSERT_EQ(2U, s[0]->InputCount());
5034   EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
5035   EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
5036   ASSERT_EQ(1U, s[0]->OutputCount());
5037   EXPECT_EQ(s.ToVreg(n2), s.ToVreg(s[0]->Output()));
5038 }
5039 
TEST_F(InstructionSelectorTest,Float64NegWithMul)5040 TEST_F(InstructionSelectorTest, Float64NegWithMul) {
5041   StreamBuilder m(this, MachineType::Float64(), MachineType::Float64(),
5042                   MachineType::Float64());
5043   Node* const p0 = m.Parameter(0);
5044   Node* const p1 = m.Parameter(1);
5045   Node* const n1 = m.AddNode(m.machine()->Float64Mul(), p0, p1);
5046   Node* const n2 = m.AddNode(m.machine()->Float64Neg(), n1);
5047   m.Return(n2);
5048   Stream s = m.Build();
5049   ASSERT_EQ(1U, s.size());
5050   EXPECT_EQ(kArm64Float64Fnmul, s[0]->arch_opcode());
5051   ASSERT_EQ(2U, s[0]->InputCount());
5052   EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
5053   EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
5054   ASSERT_EQ(1U, s[0]->OutputCount());
5055   EXPECT_EQ(s.ToVreg(n2), s.ToVreg(s[0]->Output()));
5056 }
5057 
TEST_F(InstructionSelectorTest,Float32MulWithNeg)5058 TEST_F(InstructionSelectorTest, Float32MulWithNeg) {
5059   StreamBuilder m(this, MachineType::Float32(), MachineType::Float32(),
5060                   MachineType::Float32());
5061   Node* const p0 = m.Parameter(0);
5062   Node* const p1 = m.Parameter(1);
5063   Node* const n1 = m.AddNode(m.machine()->Float32Neg(), p0);
5064   Node* const n2 = m.AddNode(m.machine()->Float32Mul(), n1, p1);
5065   m.Return(n2);
5066   Stream s = m.Build();
5067   ASSERT_EQ(1U, s.size());
5068   EXPECT_EQ(kArm64Float32Fnmul, s[0]->arch_opcode());
5069   ASSERT_EQ(2U, s[0]->InputCount());
5070   EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
5071   EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
5072   ASSERT_EQ(1U, s[0]->OutputCount());
5073   EXPECT_EQ(s.ToVreg(n2), s.ToVreg(s[0]->Output()));
5074 }
5075 
TEST_F(InstructionSelectorTest,Float64MulWithNeg)5076 TEST_F(InstructionSelectorTest, Float64MulWithNeg) {
5077   StreamBuilder m(this, MachineType::Float64(), MachineType::Float64(),
5078                   MachineType::Float64());
5079   Node* const p0 = m.Parameter(0);
5080   Node* const p1 = m.Parameter(1);
5081   Node* const n1 = m.AddNode(m.machine()->Float64Neg(), p0);
5082   Node* const n2 = m.AddNode(m.machine()->Float64Mul(), n1, p1);
5083   m.Return(n2);
5084   Stream s = m.Build();
5085   ASSERT_EQ(1U, s.size());
5086   EXPECT_EQ(kArm64Float64Fnmul, s[0]->arch_opcode());
5087   ASSERT_EQ(2U, s[0]->InputCount());
5088   EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
5089   EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
5090   ASSERT_EQ(1U, s[0]->OutputCount());
5091   EXPECT_EQ(s.ToVreg(n2), s.ToVreg(s[0]->Output()));
5092 }
5093 
TEST_F(InstructionSelectorTest,LoadAndShiftRight)5094 TEST_F(InstructionSelectorTest, LoadAndShiftRight) {
5095   {
5096     int32_t immediates[] = {-256, -255, -3,   -2,   -1,    0,    1,
5097                             2,    3,    255,  256,  260,   4096, 4100,
5098                             8192, 8196, 3276, 3280, 16376, 16380};
5099     TRACED_FOREACH(int32_t, index, immediates) {
5100       StreamBuilder m(this, MachineType::Uint64(), MachineType::Pointer());
5101       Node* const load = m.Load(MachineType::Uint64(), m.Parameter(0),
5102                                 m.Int32Constant(index - 4));
5103       Node* const sar = m.Word64Sar(load, m.Int32Constant(32));
5104       // Make sure we don't fold the shift into the following add:
5105       m.Return(m.Int64Add(sar, m.Parameter(0)));
5106       Stream s = m.Build();
5107       ASSERT_EQ(2U, s.size());
5108       EXPECT_EQ(kArm64Ldrsw, s[0]->arch_opcode());
5109       EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
5110       EXPECT_EQ(2U, s[0]->InputCount());
5111       EXPECT_EQ(s.ToVreg(m.Parameter(0)), s.ToVreg(s[0]->InputAt(0)));
5112       ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
5113       EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
5114       ASSERT_EQ(1U, s[0]->OutputCount());
5115     }
5116   }
5117 }
5118 
TEST_F(InstructionSelectorTest,CompareAgainstZero32)5119 TEST_F(InstructionSelectorTest, CompareAgainstZero32) {
5120   TRACED_FOREACH(IntegerCmp, cmp, kBinopCmpZeroRightInstructions) {
5121     StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
5122     Node* const param = m.Parameter(0);
5123     RawMachineLabel a, b;
5124     m.Branch((m.*cmp.mi.constructor)(param, m.Int32Constant(0)), &a, &b);
5125     m.Bind(&a);
5126     m.Return(m.Int32Constant(1));
5127     m.Bind(&b);
5128     m.Return(m.Int32Constant(0));
5129     Stream s = m.Build();
5130     ASSERT_EQ(1U, s.size());
5131     EXPECT_EQ(s.ToVreg(param), s.ToVreg(s[0]->InputAt(0)));
5132     if (cmp.cond == kNegative || cmp.cond == kPositiveOrZero) {
5133       EXPECT_EQ(kArm64TestAndBranch32, s[0]->arch_opcode());
5134       EXPECT_EQ(4U, s[0]->InputCount());  // The labels are also inputs.
5135       EXPECT_EQ((cmp.cond == kNegative) ? kNotEqual : kEqual,
5136                 s[0]->flags_condition());
5137       EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
5138       EXPECT_EQ(31, s.ToInt32(s[0]->InputAt(1)));
5139     } else {
5140       EXPECT_EQ(kArm64CompareAndBranch32, s[0]->arch_opcode());
5141       EXPECT_EQ(3U, s[0]->InputCount());  // The labels are also inputs.
5142       EXPECT_EQ(cmp.cond, s[0]->flags_condition());
5143     }
5144   }
5145 }
5146 
TEST_F(InstructionSelectorTest,CompareAgainstZero64)5147 TEST_F(InstructionSelectorTest, CompareAgainstZero64) {
5148   TRACED_FOREACH(IntegerCmp, cmp, kBinop64CmpZeroRightInstructions) {
5149     StreamBuilder m(this, MachineType::Int64(), MachineType::Int64());
5150     Node* const param = m.Parameter(0);
5151     RawMachineLabel a, b;
5152     m.Branch((m.*cmp.mi.constructor)(param, m.Int64Constant(0)), &a, &b);
5153     m.Bind(&a);
5154     m.Return(m.Int64Constant(1));
5155     m.Bind(&b);
5156     m.Return(m.Int64Constant(0));
5157     Stream s = m.Build();
5158     ASSERT_EQ(1U, s.size());
5159     EXPECT_EQ(s.ToVreg(param), s.ToVreg(s[0]->InputAt(0)));
5160     if (cmp.cond == kNegative || cmp.cond == kPositiveOrZero) {
5161       EXPECT_EQ(kArm64TestAndBranch, s[0]->arch_opcode());
5162       EXPECT_EQ(4U, s[0]->InputCount());  // The labels are also inputs.
5163       EXPECT_EQ((cmp.cond == kNegative) ? kNotEqual : kEqual,
5164                 s[0]->flags_condition());
5165       EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
5166       EXPECT_EQ(63, s.ToInt32(s[0]->InputAt(1)));
5167     } else {
5168       EXPECT_EQ(kArm64CompareAndBranch, s[0]->arch_opcode());
5169       EXPECT_EQ(3U, s[0]->InputCount());  // The labels are also inputs.
5170       EXPECT_EQ(cmp.cond, s[0]->flags_condition());
5171     }
5172   }
5173 }
5174 
TEST_F(InstructionSelectorTest,CompareFloat64HighLessThanZero64)5175 TEST_F(InstructionSelectorTest, CompareFloat64HighLessThanZero64) {
5176   StreamBuilder m(this, MachineType::Int32(), MachineType::Float64());
5177   Node* const param = m.Parameter(0);
5178   Node* const high = m.Float64ExtractHighWord32(param);
5179   RawMachineLabel a, b;
5180   m.Branch(m.Int32LessThan(high, m.Int32Constant(0)), &a, &b);
5181   m.Bind(&a);
5182   m.Return(m.Int32Constant(1));
5183   m.Bind(&b);
5184   m.Return(m.Int32Constant(0));
5185   Stream s = m.Build();
5186   ASSERT_EQ(2U, s.size());
5187   EXPECT_EQ(kArm64U64MoveFloat64, s[0]->arch_opcode());
5188   EXPECT_EQ(kArm64TestAndBranch, s[1]->arch_opcode());
5189   EXPECT_EQ(kNotEqual, s[1]->flags_condition());
5190   EXPECT_EQ(4U, s[1]->InputCount());
5191   EXPECT_EQ(InstructionOperand::IMMEDIATE, s[1]->InputAt(1)->kind());
5192   EXPECT_EQ(63, s.ToInt32(s[1]->InputAt(1)));
5193 }
5194 
TEST_F(InstructionSelectorTest,CompareFloat64HighGreaterThanOrEqualZero64)5195 TEST_F(InstructionSelectorTest, CompareFloat64HighGreaterThanOrEqualZero64) {
5196   StreamBuilder m(this, MachineType::Int32(), MachineType::Float64());
5197   Node* const param = m.Parameter(0);
5198   Node* const high = m.Float64ExtractHighWord32(param);
5199   RawMachineLabel a, b;
5200   m.Branch(m.Int32GreaterThanOrEqual(high, m.Int32Constant(0)), &a, &b);
5201   m.Bind(&a);
5202   m.Return(m.Int32Constant(1));
5203   m.Bind(&b);
5204   m.Return(m.Int32Constant(0));
5205   Stream s = m.Build();
5206   ASSERT_EQ(2U, s.size());
5207   EXPECT_EQ(kArm64U64MoveFloat64, s[0]->arch_opcode());
5208   EXPECT_EQ(kArm64TestAndBranch, s[1]->arch_opcode());
5209   EXPECT_EQ(kEqual, s[1]->flags_condition());
5210   EXPECT_EQ(4U, s[1]->InputCount());
5211   EXPECT_EQ(InstructionOperand::IMMEDIATE, s[1]->InputAt(1)->kind());
5212   EXPECT_EQ(63, s.ToInt32(s[1]->InputAt(1)));
5213 }
5214 
TEST_F(InstructionSelectorTest,ExternalReferenceLoad1)5215 TEST_F(InstructionSelectorTest, ExternalReferenceLoad1) {
5216   // Test offsets we can use kMode_Root for.
5217   const int64_t kOffsets[] = {0, 1, 4, INT32_MIN, INT32_MAX};
5218   TRACED_FOREACH(int64_t, offset, kOffsets) {
5219     StreamBuilder m(this, MachineType::Int64());
5220     ExternalReference reference =
5221         bit_cast<ExternalReference>(isolate()->isolate_root() + offset);
5222     Node* const value =
5223         m.Load(MachineType::Int64(), m.ExternalConstant(reference));
5224     m.Return(value);
5225 
5226     Stream s = m.Build();
5227 
5228     ASSERT_EQ(1U, s.size());
5229     EXPECT_EQ(kArm64Ldr, s[0]->arch_opcode());
5230     EXPECT_EQ(kMode_Root, s[0]->addressing_mode());
5231     EXPECT_EQ(1U, s[0]->InputCount());
5232     EXPECT_EQ(s.ToInt64(s[0]->InputAt(0)), offset);
5233     EXPECT_EQ(1U, s[0]->OutputCount());
5234   }
5235 }
5236 
TEST_F(InstructionSelectorTest,ExternalReferenceLoad2)5237 TEST_F(InstructionSelectorTest, ExternalReferenceLoad2) {
5238   // Offset too large, we cannot use kMode_Root.
5239   StreamBuilder m(this, MachineType::Int64());
5240   int64_t offset = 0x100000000;
5241   ExternalReference reference =
5242       bit_cast<ExternalReference>(isolate()->isolate_root() + offset);
5243   Node* const value =
5244       m.Load(MachineType::Int64(), m.ExternalConstant(reference));
5245   m.Return(value);
5246 
5247   Stream s = m.Build();
5248 
5249   ASSERT_EQ(1U, s.size());
5250   EXPECT_EQ(kArm64Ldr, s[0]->arch_opcode());
5251   EXPECT_NE(kMode_Root, s[0]->addressing_mode());
5252 }
5253 
5254 namespace {
5255 // Builds a call with the specified signature and nodes as arguments.
5256 // Then checks that the correct number of kArm64Poke and kArm64PokePair were
5257 // generated.
TestPokePair(InstructionSelectorTest::StreamBuilder * m,Zone * zone,MachineSignature::Builder * builder,Node * nodes[],int num_nodes,int expected_poke_pair,int expected_poke)5258 void TestPokePair(InstructionSelectorTest::StreamBuilder* m, Zone* zone,
5259                   MachineSignature::Builder* builder, Node* nodes[],
5260                   int num_nodes, int expected_poke_pair, int expected_poke) {
5261   auto call_descriptor =
5262       InstructionSelectorTest::StreamBuilder::MakeSimpleCallDescriptor(
5263           zone, builder->Build());
5264 
5265   m->CallN(call_descriptor, num_nodes, nodes);
5266   m->Return(m->UndefinedConstant());
5267 
5268   auto s = m->Build();
5269   int num_poke_pair = 0;
5270   int num_poke = 0;
5271   for (size_t i = 0; i < s.size(); ++i) {
5272     if (s[i]->arch_opcode() == kArm64PokePair) {
5273       num_poke_pair++;
5274     }
5275 
5276     if (s[i]->arch_opcode() == kArm64Poke) {
5277       num_poke++;
5278     }
5279   }
5280 
5281   EXPECT_EQ(expected_poke_pair, num_poke_pair);
5282   EXPECT_EQ(expected_poke, num_poke);
5283 }
5284 }  // namespace
5285 
TEST_F(InstructionSelectorTest,PokePairPrepareArgumentsInt32)5286 TEST_F(InstructionSelectorTest, PokePairPrepareArgumentsInt32) {
5287   {
5288     MachineSignature::Builder builder(zone(), 0, 3);
5289     builder.AddParam(MachineType::Int32());
5290     builder.AddParam(MachineType::Int32());
5291     builder.AddParam(MachineType::Int32());
5292 
5293     StreamBuilder m(this, MachineType::AnyTagged());
5294     Node* nodes[] = {
5295         m.UndefinedConstant(),
5296         m.Int32Constant(0),
5297         m.Int32Constant(0),
5298         m.Int32Constant(0),
5299     };
5300 
5301     const int expected_poke_pair = 1;
5302     // Note: The `+ 1` here comes from the padding Poke in
5303     // EmitPrepareArguments.
5304     const int expected_poke = 1 + 1;
5305 
5306     TestPokePair(&m, zone(), &builder, nodes, arraysize(nodes),
5307                  expected_poke_pair, expected_poke);
5308   }
5309 
5310   {
5311     MachineSignature::Builder builder(zone(), 0, 4);
5312     builder.AddParam(MachineType::Int32());
5313     builder.AddParam(MachineType::Int32());
5314     builder.AddParam(MachineType::Int32());
5315     builder.AddParam(MachineType::Int32());
5316 
5317     StreamBuilder m(this, MachineType::AnyTagged());
5318     Node* nodes[] = {
5319         m.UndefinedConstant(), m.Int32Constant(0), m.Int32Constant(0),
5320         m.Int32Constant(0),    m.Int32Constant(0),
5321     };
5322 
5323     const int expected_poke_pair = 2;
5324     const int expected_poke = 0;
5325 
5326     TestPokePair(&m, zone(), &builder, nodes, arraysize(nodes),
5327                  expected_poke_pair, expected_poke);
5328   }
5329 }
5330 
TEST_F(InstructionSelectorTest,PokePairPrepareArgumentsInt64)5331 TEST_F(InstructionSelectorTest, PokePairPrepareArgumentsInt64) {
5332   MachineSignature::Builder builder(zone(), 0, 4);
5333   builder.AddParam(MachineType::Int64());
5334   builder.AddParam(MachineType::Int64());
5335   builder.AddParam(MachineType::Int64());
5336   builder.AddParam(MachineType::Int64());
5337 
5338   StreamBuilder m(this, MachineType::AnyTagged());
5339   Node* nodes[] = {
5340       m.UndefinedConstant(), m.Int64Constant(0), m.Int64Constant(0),
5341       m.Int64Constant(0),    m.Int64Constant(0),
5342   };
5343 
5344   const int expected_poke_pair = 2;
5345   const int expected_poke = 0;
5346 
5347   TestPokePair(&m, zone(), &builder, nodes, arraysize(nodes),
5348                expected_poke_pair, expected_poke);
5349 }
5350 
TEST_F(InstructionSelectorTest,PokePairPrepareArgumentsFloat32)5351 TEST_F(InstructionSelectorTest, PokePairPrepareArgumentsFloat32) {
5352   MachineSignature::Builder builder(zone(), 0, 4);
5353   builder.AddParam(MachineType::Float32());
5354   builder.AddParam(MachineType::Float32());
5355   builder.AddParam(MachineType::Float32());
5356   builder.AddParam(MachineType::Float32());
5357 
5358   StreamBuilder m(this, MachineType::AnyTagged());
5359   Node* nodes[] = {
5360       m.UndefinedConstant(),   m.Float32Constant(0.0f), m.Float32Constant(0.0f),
5361       m.Float32Constant(0.0f), m.Float32Constant(0.0f),
5362   };
5363 
5364   const int expected_poke_pair = 2;
5365   const int expected_poke = 0;
5366 
5367   TestPokePair(&m, zone(), &builder, nodes, arraysize(nodes),
5368                expected_poke_pair, expected_poke);
5369 }
5370 
TEST_F(InstructionSelectorTest,PokePairPrepareArgumentsFloat64)5371 TEST_F(InstructionSelectorTest, PokePairPrepareArgumentsFloat64) {
5372   MachineSignature::Builder builder(zone(), 0, 4);
5373   builder.AddParam(MachineType::Float64());
5374   builder.AddParam(MachineType::Float64());
5375   builder.AddParam(MachineType::Float64());
5376   builder.AddParam(MachineType::Float64());
5377 
5378   StreamBuilder m(this, MachineType::AnyTagged());
5379   Node* nodes[] = {
5380       m.UndefinedConstant(),   m.Float64Constant(0.0f), m.Float64Constant(0.0f),
5381       m.Float64Constant(0.0f), m.Float64Constant(0.0f),
5382   };
5383 
5384   const int expected_poke_pair = 2;
5385   const int expected_poke = 0;
5386 
5387   TestPokePair(&m, zone(), &builder, nodes, arraysize(nodes),
5388                expected_poke_pair, expected_poke);
5389 }
5390 
TEST_F(InstructionSelectorTest,PokePairPrepareArgumentsIntFloatMixed)5391 TEST_F(InstructionSelectorTest, PokePairPrepareArgumentsIntFloatMixed) {
5392   {
5393     MachineSignature::Builder builder(zone(), 0, 4);
5394     builder.AddParam(MachineType::Int32());
5395     builder.AddParam(MachineType::Float32());
5396     builder.AddParam(MachineType::Int32());
5397     builder.AddParam(MachineType::Float32());
5398 
5399     StreamBuilder m(this, MachineType::AnyTagged());
5400     Node* nodes[] = {
5401         m.UndefinedConstant(), m.Int32Constant(0),      m.Float32Constant(0.0f),
5402         m.Int32Constant(0),    m.Float32Constant(0.0f),
5403     };
5404 
5405     const int expected_poke_pair = 0;
5406     const int expected_poke = 4;
5407 
5408     TestPokePair(&m, zone(), &builder, nodes, arraysize(nodes),
5409                  expected_poke_pair, expected_poke);
5410   }
5411 
5412   {
5413     MachineSignature::Builder builder(zone(), 0, 7);
5414     builder.AddParam(MachineType::Float32());
5415     builder.AddParam(MachineType::Int32());
5416     builder.AddParam(MachineType::Int32());
5417     builder.AddParam(MachineType::Float64());
5418     builder.AddParam(MachineType::Int64());
5419     builder.AddParam(MachineType::Float64());
5420     builder.AddParam(MachineType::Float64());
5421 
5422     StreamBuilder m(this, MachineType::AnyTagged());
5423     Node* nodes[] = {m.UndefinedConstant(),   m.Float32Constant(0.0f),
5424                      m.Int32Constant(0),      m.Int32Constant(0),
5425                      m.Float64Constant(0.0f), m.Int64Constant(0),
5426                      m.Float64Constant(0.0f), m.Float64Constant(0.0f)};
5427 
5428     const int expected_poke_pair = 2;
5429 
5430     // Note: The `+ 1` here comes from the padding Poke in
5431     // EmitPrepareArguments.
5432     const int expected_poke = 3 + 1;
5433 
5434     TestPokePair(&m, zone(), &builder, nodes, arraysize(nodes),
5435                  expected_poke_pair, expected_poke);
5436   }
5437 }
5438 
TEST_F(InstructionSelectorTest,PokePairPrepareArgumentsSimd128)5439 TEST_F(InstructionSelectorTest, PokePairPrepareArgumentsSimd128) {
5440   MachineSignature::Builder builder(zone(), 0, 2);
5441   builder.AddParam(MachineType::Simd128());
5442   builder.AddParam(MachineType::Simd128());
5443 
5444   StreamBuilder m(this, MachineType::AnyTagged());
5445   Node* nodes[] = {m.UndefinedConstant(),
5446                    m.AddNode(m.machine()->I32x4Splat(), m.Int32Constant(0)),
5447                    m.AddNode(m.machine()->I32x4Splat(), m.Int32Constant(0))};
5448 
5449   const int expected_poke_pair = 0;
5450   const int expected_poke = 2;
5451 
5452   // Using kArm64PokePair is not currently supported for Simd128.
5453   TestPokePair(&m, zone(), &builder, nodes, arraysize(nodes),
5454                expected_poke_pair, expected_poke);
5455 }
5456 
5457 struct SIMDConstZeroFcmTest {
5458   const bool is_zero;
5459   const uint8_t lane_size;
5460   const Operator* (MachineOperatorBuilder::*fcm_operator)();
5461   const ArchOpcode expected_op_left;
5462   const ArchOpcode expected_op_right;
5463   const size_t size;
5464 };
5465 
5466 static const SIMDConstZeroFcmTest SIMDConstZeroFcmTests[] = {
5467     {true, 64, &MachineOperatorBuilder::F64x2Eq, kArm64FEq, kArm64FEq, 1},
5468     {true, 64, &MachineOperatorBuilder::F64x2Ne, kArm64FNe, kArm64FNe, 1},
5469     {true, 64, &MachineOperatorBuilder::F64x2Lt, kArm64FGt, kArm64FLt, 1},
5470     {true, 64, &MachineOperatorBuilder::F64x2Le, kArm64FGe, kArm64FLe, 1},
5471     {false, 64, &MachineOperatorBuilder::F64x2Eq, kArm64FEq, kArm64FEq, 2},
5472     {false, 64, &MachineOperatorBuilder::F64x2Ne, kArm64FNe, kArm64FNe, 2},
5473     {false, 64, &MachineOperatorBuilder::F64x2Lt, kArm64FLt, kArm64FLt, 2},
5474     {false, 64, &MachineOperatorBuilder::F64x2Le, kArm64FLe, kArm64FLe, 2},
5475     {true, 32, &MachineOperatorBuilder::F32x4Eq, kArm64FEq, kArm64FEq, 1},
5476     {true, 32, &MachineOperatorBuilder::F32x4Ne, kArm64FNe, kArm64FNe, 1},
5477     {true, 32, &MachineOperatorBuilder::F32x4Lt, kArm64FGt, kArm64FLt, 1},
5478     {true, 32, &MachineOperatorBuilder::F32x4Le, kArm64FGe, kArm64FLe, 1},
5479     {false, 32, &MachineOperatorBuilder::F32x4Eq, kArm64FEq, kArm64FEq, 2},
5480     {false, 32, &MachineOperatorBuilder::F32x4Ne, kArm64FNe, kArm64FNe, 2},
5481     {false, 32, &MachineOperatorBuilder::F32x4Lt, kArm64FLt, kArm64FLt, 2},
5482     {false, 32, &MachineOperatorBuilder::F32x4Le, kArm64FLe, kArm64FLe, 2},
5483 };
5484 
5485 using InstructionSelectorSIMDConstZeroFcmTest =
5486     InstructionSelectorTestWithParam<SIMDConstZeroFcmTest>;
5487 
TEST_P(InstructionSelectorSIMDConstZeroFcmTest,ConstZero)5488 TEST_P(InstructionSelectorSIMDConstZeroFcmTest, ConstZero) {
5489   const SIMDConstZeroFcmTest param = GetParam();
5490   byte data[16] = {};
5491   if (!param.is_zero) data[0] = 0xff;
5492   // Const node on the left
5493   {
5494     StreamBuilder m(this, MachineType::Simd128(), MachineType::Simd128());
5495     Node* cnst = m.S128Const(data);
5496     Node* fcm =
5497         m.AddNode((m.machine()->*param.fcm_operator)(), cnst, m.Parameter(0));
5498     m.Return(fcm);
5499     Stream s = m.Build();
5500     ASSERT_EQ(param.size, s.size());
5501     if (param.size == 1) {
5502       EXPECT_EQ(param.expected_op_left, s[0]->arch_opcode());
5503       EXPECT_EQ(1U, s[0]->InputCount());
5504       EXPECT_EQ(1U, s[0]->OutputCount());
5505       EXPECT_EQ(param.lane_size, LaneSizeField::decode(s[0]->opcode()));
5506     } else {
5507       EXPECT_EQ(kArm64S128Const, s[0]->arch_opcode());
5508       EXPECT_EQ(param.expected_op_left, s[1]->arch_opcode());
5509       EXPECT_EQ(2U, s[1]->InputCount());
5510       EXPECT_EQ(1U, s[1]->OutputCount());
5511       EXPECT_EQ(param.lane_size, LaneSizeField::decode(s[1]->opcode()));
5512     }
5513   }
5514   //  Const node on the right
5515   {
5516     StreamBuilder m(this, MachineType::Simd128(), MachineType::Simd128());
5517     Node* cnst = m.S128Const(data);
5518     Node* fcm =
5519         m.AddNode((m.machine()->*param.fcm_operator)(), m.Parameter(0), cnst);
5520     m.Return(fcm);
5521     Stream s = m.Build();
5522     ASSERT_EQ(param.size, s.size());
5523     if (param.size == 1) {
5524       EXPECT_EQ(param.expected_op_right, s[0]->arch_opcode());
5525       EXPECT_EQ(1U, s[0]->InputCount());
5526       EXPECT_EQ(1U, s[0]->OutputCount());
5527       EXPECT_EQ(param.lane_size, LaneSizeField::decode(s[0]->opcode()));
5528     } else {
5529       EXPECT_EQ(kArm64S128Const, s[0]->arch_opcode());
5530       EXPECT_EQ(param.expected_op_right, s[1]->arch_opcode());
5531       EXPECT_EQ(2U, s[1]->InputCount());
5532       EXPECT_EQ(1U, s[1]->OutputCount());
5533       EXPECT_EQ(param.lane_size, LaneSizeField::decode(s[1]->opcode()));
5534     }
5535   }
5536 }
5537 
5538 INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest,
5539                          InstructionSelectorSIMDConstZeroFcmTest,
5540                          ::testing::ValuesIn(SIMDConstZeroFcmTests));
5541 
5542 }  // namespace
5543 }  // namespace compiler
5544 }  // namespace internal
5545 }  // namespace v8
5546