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