blob: cd3ce090f7043a4e444f37604ef926534621d3c7 [file] [log] [blame]
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001// Copyright 2014 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "test/unittests/compiler/instruction-selector-unittest.h"
6
7namespace v8 {
8namespace internal {
9namespace compiler {
10
11namespace {
12
13typedef RawMachineAssembler::Label MLabel;
14
15template <typename T>
16struct MachInst {
17 T constructor;
18 const char* constructor_name;
19 ArchOpcode arch_opcode;
20 MachineType machine_type;
21};
22
23typedef MachInst<Node* (RawMachineAssembler::*)(Node*)> MachInst1;
24typedef MachInst<Node* (RawMachineAssembler::*)(Node*, Node*)> MachInst2;
25
26
27template <typename T>
28std::ostream& operator<<(std::ostream& os, const MachInst<T>& mi) {
29 return os << mi.constructor_name;
30}
31
32
33struct Shift {
34 MachInst2 mi;
35 AddressingMode mode;
36};
37
38
39std::ostream& operator<<(std::ostream& os, const Shift& shift) {
40 return os << shift.mi;
41}
42
43
44// Helper to build Int32Constant or Int64Constant depending on the given
45// machine type.
46Node* BuildConstant(InstructionSelectorTest::StreamBuilder& m, MachineType type,
47 int64_t value) {
48 switch (type) {
49 case kMachInt32:
50 return m.Int32Constant(value);
51 break;
52
53 case kMachInt64:
54 return m.Int64Constant(value);
55 break;
56
57 default:
58 UNIMPLEMENTED();
59 }
60 return NULL;
61}
62
63
64// ARM64 logical instructions.
65static const MachInst2 kLogicalInstructions[] = {
66 {&RawMachineAssembler::Word32And, "Word32And", kArm64And32, kMachInt32},
67 {&RawMachineAssembler::Word64And, "Word64And", kArm64And, kMachInt64},
68 {&RawMachineAssembler::Word32Or, "Word32Or", kArm64Or32, kMachInt32},
69 {&RawMachineAssembler::Word64Or, "Word64Or", kArm64Or, kMachInt64},
70 {&RawMachineAssembler::Word32Xor, "Word32Xor", kArm64Eor32, kMachInt32},
71 {&RawMachineAssembler::Word64Xor, "Word64Xor", kArm64Eor, kMachInt64}};
72
73
74// ARM64 logical immediates: contiguous set bits, rotated about a power of two
75// sized block. The block is then duplicated across the word. Below is a random
76// subset of the 32-bit immediates.
77static const uint32_t kLogical32Immediates[] = {
78 0x00000002, 0x00000003, 0x00000070, 0x00000080, 0x00000100, 0x000001c0,
79 0x00000300, 0x000007e0, 0x00003ffc, 0x00007fc0, 0x0003c000, 0x0003f000,
80 0x0003ffc0, 0x0003fff8, 0x0007ff00, 0x0007ffe0, 0x000e0000, 0x001e0000,
81 0x001ffffc, 0x003f0000, 0x003f8000, 0x00780000, 0x007fc000, 0x00ff0000,
82 0x01800000, 0x01800180, 0x01f801f8, 0x03fe0000, 0x03ffffc0, 0x03fffffc,
83 0x06000000, 0x07fc0000, 0x07ffc000, 0x07ffffc0, 0x07ffffe0, 0x0ffe0ffe,
84 0x0ffff800, 0x0ffffff0, 0x0fffffff, 0x18001800, 0x1f001f00, 0x1f801f80,
85 0x30303030, 0x3ff03ff0, 0x3ff83ff8, 0x3fff0000, 0x3fff8000, 0x3fffffc0,
86 0x70007000, 0x7f7f7f7f, 0x7fc00000, 0x7fffffc0, 0x8000001f, 0x800001ff,
87 0x81818181, 0x9fff9fff, 0xc00007ff, 0xc0ffffff, 0xdddddddd, 0xe00001ff,
88 0xe00003ff, 0xe007ffff, 0xefffefff, 0xf000003f, 0xf001f001, 0xf3fff3ff,
89 0xf800001f, 0xf80fffff, 0xf87ff87f, 0xfbfbfbfb, 0xfc00001f, 0xfc0000ff,
90 0xfc0001ff, 0xfc03fc03, 0xfe0001ff, 0xff000001, 0xff03ff03, 0xff800000,
91 0xff800fff, 0xff801fff, 0xff87ffff, 0xffc0003f, 0xffc007ff, 0xffcfffcf,
92 0xffe00003, 0xffe1ffff, 0xfff0001f, 0xfff07fff, 0xfff80007, 0xfff87fff,
93 0xfffc00ff, 0xfffe07ff, 0xffff00ff, 0xffffc001, 0xfffff007, 0xfffff3ff,
94 0xfffff807, 0xfffff9ff, 0xfffffc0f, 0xfffffeff};
95
96
97// Random subset of 64-bit logical immediates.
98static const uint64_t kLogical64Immediates[] = {
99 0x0000000000000001, 0x0000000000000002, 0x0000000000000003,
100 0x0000000000000070, 0x0000000000000080, 0x0000000000000100,
101 0x00000000000001c0, 0x0000000000000300, 0x0000000000000600,
102 0x00000000000007e0, 0x0000000000003ffc, 0x0000000000007fc0,
103 0x0000000600000000, 0x0000003ffffffffc, 0x000000f000000000,
104 0x000001f800000000, 0x0003fc0000000000, 0x0003fc000003fc00,
105 0x0003ffffffc00000, 0x0003ffffffffffc0, 0x0006000000060000,
106 0x003ffffffffc0000, 0x0180018001800180, 0x01f801f801f801f8,
107 0x0600000000000000, 0x1000000010000000, 0x1000100010001000,
108 0x1010101010101010, 0x1111111111111111, 0x1f001f001f001f00,
109 0x1f1f1f1f1f1f1f1f, 0x1ffffffffffffffe, 0x3ffc3ffc3ffc3ffc,
110 0x5555555555555555, 0x7f7f7f7f7f7f7f7f, 0x8000000000000000,
111 0x8000001f8000001f, 0x8181818181818181, 0x9999999999999999,
112 0x9fff9fff9fff9fff, 0xaaaaaaaaaaaaaaaa, 0xdddddddddddddddd,
113 0xe0000000000001ff, 0xf800000000000000, 0xf8000000000001ff,
114 0xf807f807f807f807, 0xfefefefefefefefe, 0xfffefffefffefffe,
115 0xfffff807fffff807, 0xfffff9fffffff9ff, 0xfffffc0ffffffc0f,
116 0xfffffc0fffffffff, 0xfffffefffffffeff, 0xfffffeffffffffff,
117 0xffffff8000000000, 0xfffffffefffffffe, 0xffffffffefffffff,
118 0xfffffffff9ffffff, 0xffffffffff800000, 0xffffffffffffc0ff,
119 0xfffffffffffffffe};
120
121
122// ARM64 arithmetic instructions.
123struct AddSub {
124 MachInst2 mi;
125 ArchOpcode negate_arch_opcode;
126};
127
128
129std::ostream& operator<<(std::ostream& os, const AddSub& op) {
130 return os << op.mi;
131}
132
133
134static const AddSub kAddSubInstructions[] = {
135 {{&RawMachineAssembler::Int32Add, "Int32Add", kArm64Add32, kMachInt32},
136 kArm64Sub32},
137 {{&RawMachineAssembler::Int64Add, "Int64Add", kArm64Add, kMachInt64},
138 kArm64Sub},
139 {{&RawMachineAssembler::Int32Sub, "Int32Sub", kArm64Sub32, kMachInt32},
140 kArm64Add32},
141 {{&RawMachineAssembler::Int64Sub, "Int64Sub", kArm64Sub, kMachInt64},
142 kArm64Add}};
143
144
145// ARM64 Add/Sub immediates: 12-bit immediate optionally shifted by 12.
146// Below is a combination of a random subset and some edge values.
147static const int32_t kAddSubImmediates[] = {
148 0, 1, 69, 493, 599, 701, 719,
149 768, 818, 842, 945, 1246, 1286, 1429,
150 1669, 2171, 2179, 2182, 2254, 2334, 2338,
151 2343, 2396, 2449, 2610, 2732, 2855, 2876,
152 2944, 3377, 3458, 3475, 3476, 3540, 3574,
153 3601, 3813, 3871, 3917, 4095, 4096, 16384,
154 364544, 462848, 970752, 1523712, 1863680, 2363392, 3219456,
155 3280896, 4247552, 4526080, 4575232, 4960256, 5505024, 5894144,
156 6004736, 6193152, 6385664, 6795264, 7114752, 7233536, 7348224,
157 7499776, 7573504, 7729152, 8634368, 8937472, 9465856, 10354688,
158 10682368, 11059200, 11460608, 13168640, 13176832, 14336000, 15028224,
159 15597568, 15892480, 16773120};
160
161
162// ARM64 flag setting data processing instructions.
163static const MachInst2 kDPFlagSetInstructions[] = {
164 {&RawMachineAssembler::Word32And, "Word32And", kArm64Tst32, kMachInt32},
165 {&RawMachineAssembler::Int32Add, "Int32Add", kArm64Cmn32, kMachInt32},
166 {&RawMachineAssembler::Int32Sub, "Int32Sub", kArm64Cmp32, kMachInt32},
167 {&RawMachineAssembler::Word64And, "Word64And", kArm64Tst, kMachInt64}};
168
169
170// ARM64 arithmetic with overflow instructions.
171static const MachInst2 kOvfAddSubInstructions[] = {
172 {&RawMachineAssembler::Int32AddWithOverflow, "Int32AddWithOverflow",
173 kArm64Add32, kMachInt32},
174 {&RawMachineAssembler::Int32SubWithOverflow, "Int32SubWithOverflow",
175 kArm64Sub32, kMachInt32}};
176
177
178// ARM64 shift instructions.
179static const Shift kShiftInstructions[] = {
180 {{&RawMachineAssembler::Word32Shl, "Word32Shl", kArm64Lsl32, kMachInt32},
181 kMode_Operand2_R_LSL_I},
182 {{&RawMachineAssembler::Word64Shl, "Word64Shl", kArm64Lsl, kMachInt64},
183 kMode_Operand2_R_LSL_I},
184 {{&RawMachineAssembler::Word32Shr, "Word32Shr", kArm64Lsr32, kMachInt32},
185 kMode_Operand2_R_LSR_I},
186 {{&RawMachineAssembler::Word64Shr, "Word64Shr", kArm64Lsr, kMachInt64},
187 kMode_Operand2_R_LSR_I},
188 {{&RawMachineAssembler::Word32Sar, "Word32Sar", kArm64Asr32, kMachInt32},
189 kMode_Operand2_R_ASR_I},
190 {{&RawMachineAssembler::Word64Sar, "Word64Sar", kArm64Asr, kMachInt64},
191 kMode_Operand2_R_ASR_I},
192 {{&RawMachineAssembler::Word32Ror, "Word32Ror", kArm64Ror32, kMachInt32},
193 kMode_Operand2_R_ROR_I},
194 {{&RawMachineAssembler::Word64Ror, "Word64Ror", kArm64Ror, kMachInt64},
195 kMode_Operand2_R_ROR_I}};
196
197
198// ARM64 Mul/Div instructions.
199static const MachInst2 kMulDivInstructions[] = {
200 {&RawMachineAssembler::Int32Mul, "Int32Mul", kArm64Mul32, kMachInt32},
201 {&RawMachineAssembler::Int64Mul, "Int64Mul", kArm64Mul, kMachInt64},
202 {&RawMachineAssembler::Int32Div, "Int32Div", kArm64Idiv32, kMachInt32},
203 {&RawMachineAssembler::Int64Div, "Int64Div", kArm64Idiv, kMachInt64},
204 {&RawMachineAssembler::Uint32Div, "Uint32Div", kArm64Udiv32, kMachInt32},
205 {&RawMachineAssembler::Uint64Div, "Uint64Div", kArm64Udiv, kMachInt64}};
206
207
208// ARM64 FP arithmetic instructions.
209static const MachInst2 kFPArithInstructions[] = {
210 {&RawMachineAssembler::Float64Add, "Float64Add", kArm64Float64Add,
211 kMachFloat64},
212 {&RawMachineAssembler::Float64Sub, "Float64Sub", kArm64Float64Sub,
213 kMachFloat64},
214 {&RawMachineAssembler::Float64Mul, "Float64Mul", kArm64Float64Mul,
215 kMachFloat64},
216 {&RawMachineAssembler::Float64Div, "Float64Div", kArm64Float64Div,
217 kMachFloat64}};
218
219
220struct FPCmp {
221 MachInst2 mi;
222 FlagsCondition cond;
223};
224
225
226std::ostream& operator<<(std::ostream& os, const FPCmp& cmp) {
227 return os << cmp.mi;
228}
229
230
231// ARM64 FP comparison instructions.
232static const FPCmp kFPCmpInstructions[] = {
233 {{&RawMachineAssembler::Float64Equal, "Float64Equal", kArm64Float64Cmp,
234 kMachFloat64},
235 kUnorderedEqual},
236 {{&RawMachineAssembler::Float64LessThan, "Float64LessThan",
237 kArm64Float64Cmp, kMachFloat64},
238 kUnorderedLessThan},
239 {{&RawMachineAssembler::Float64LessThanOrEqual, "Float64LessThanOrEqual",
240 kArm64Float64Cmp, kMachFloat64},
241 kUnorderedLessThanOrEqual}};
242
243
244struct Conversion {
245 // The machine_type field in MachInst1 represents the destination type.
246 MachInst1 mi;
247 MachineType src_machine_type;
248};
249
250
251std::ostream& operator<<(std::ostream& os, const Conversion& conv) {
252 return os << conv.mi;
253}
254
255
256// ARM64 type conversion instructions.
257static const Conversion kConversionInstructions[] = {
258 {{&RawMachineAssembler::ChangeFloat32ToFloat64, "ChangeFloat32ToFloat64",
259 kArm64Float32ToFloat64, kMachFloat64},
260 kMachFloat32},
261 {{&RawMachineAssembler::TruncateFloat64ToFloat32,
262 "TruncateFloat64ToFloat32", kArm64Float64ToFloat32, kMachFloat32},
263 kMachFloat64},
264 {{&RawMachineAssembler::ChangeInt32ToInt64, "ChangeInt32ToInt64",
265 kArm64Sxtw, kMachInt64},
266 kMachInt32},
267 {{&RawMachineAssembler::ChangeUint32ToUint64, "ChangeUint32ToUint64",
268 kArm64Mov32, kMachUint64},
269 kMachUint32},
270 {{&RawMachineAssembler::TruncateInt64ToInt32, "TruncateInt64ToInt32",
271 kArm64Mov32, kMachInt32},
272 kMachInt64},
273 {{&RawMachineAssembler::ChangeInt32ToFloat64, "ChangeInt32ToFloat64",
274 kArm64Int32ToFloat64, kMachFloat64},
275 kMachInt32},
276 {{&RawMachineAssembler::ChangeUint32ToFloat64, "ChangeUint32ToFloat64",
277 kArm64Uint32ToFloat64, kMachFloat64},
278 kMachUint32},
279 {{&RawMachineAssembler::ChangeFloat64ToInt32, "ChangeFloat64ToInt32",
280 kArm64Float64ToInt32, kMachInt32},
281 kMachFloat64},
282 {{&RawMachineAssembler::ChangeFloat64ToUint32, "ChangeFloat64ToUint32",
283 kArm64Float64ToUint32, kMachUint32},
284 kMachFloat64}};
285
286} // namespace
287
288
289// -----------------------------------------------------------------------------
290// Logical instructions.
291
292
293typedef InstructionSelectorTestWithParam<MachInst2>
294 InstructionSelectorLogicalTest;
295
296
297TEST_P(InstructionSelectorLogicalTest, Parameter) {
298 const MachInst2 dpi = GetParam();
299 const MachineType type = dpi.machine_type;
300 StreamBuilder m(this, type, type, type);
301 m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)));
302 Stream s = m.Build();
303 ASSERT_EQ(1U, s.size());
304 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
305 EXPECT_EQ(2U, s[0]->InputCount());
306 EXPECT_EQ(1U, s[0]->OutputCount());
307}
308
309
310TEST_P(InstructionSelectorLogicalTest, Immediate) {
311 const MachInst2 dpi = GetParam();
312 const MachineType type = dpi.machine_type;
313 // TODO(all): Add support for testing 64-bit immediates.
314 if (type == kMachInt32) {
315 // Immediate on the right.
316 TRACED_FOREACH(int32_t, imm, kLogical32Immediates) {
317 StreamBuilder m(this, type, type);
318 m.Return((m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm)));
319 Stream s = m.Build();
320 ASSERT_EQ(1U, s.size());
321 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
322 ASSERT_EQ(2U, s[0]->InputCount());
323 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
324 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
325 EXPECT_EQ(1U, s[0]->OutputCount());
326 }
327
328 // Immediate on the left; all logical ops should commute.
329 TRACED_FOREACH(int32_t, imm, kLogical32Immediates) {
330 StreamBuilder m(this, type, type);
331 m.Return((m.*dpi.constructor)(m.Int32Constant(imm), m.Parameter(0)));
332 Stream s = m.Build();
333 ASSERT_EQ(1U, s.size());
334 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
335 ASSERT_EQ(2U, s[0]->InputCount());
336 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
337 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
338 EXPECT_EQ(1U, s[0]->OutputCount());
339 }
340 }
341}
342
343
344TEST_P(InstructionSelectorLogicalTest, ShiftByImmediate) {
345 const MachInst2 dpi = GetParam();
346 const MachineType type = dpi.machine_type;
347 TRACED_FOREACH(Shift, shift, kShiftInstructions) {
348 // Only test 64-bit shifted operands with 64-bit instructions.
349 if (shift.mi.machine_type != type) continue;
350
351 TRACED_FORRANGE(int, imm, 0, ((type == kMachInt32) ? 31 : 63)) {
352 StreamBuilder m(this, type, type, type);
353 m.Return((m.*dpi.constructor)(
354 m.Parameter(0),
355 (m.*shift.mi.constructor)(m.Parameter(1),
356 BuildConstant(m, type, imm))));
357 Stream s = m.Build();
358 ASSERT_EQ(1U, s.size());
359 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
360 EXPECT_EQ(shift.mode, s[0]->addressing_mode());
361 EXPECT_EQ(3U, s[0]->InputCount());
362 EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(2)));
363 EXPECT_EQ(1U, s[0]->OutputCount());
364 }
365
366 TRACED_FORRANGE(int, imm, 0, ((type == kMachInt32) ? 31 : 63)) {
367 StreamBuilder m(this, type, type, type);
368 m.Return((m.*dpi.constructor)(
369 (m.*shift.mi.constructor)(m.Parameter(1),
370 BuildConstant(m, type, imm)),
371 m.Parameter(0)));
372 Stream s = m.Build();
373 ASSERT_EQ(1U, s.size());
374 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
375 EXPECT_EQ(shift.mode, s[0]->addressing_mode());
376 EXPECT_EQ(3U, s[0]->InputCount());
377 EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(2)));
378 EXPECT_EQ(1U, s[0]->OutputCount());
379 }
380 }
381}
382
383
384INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorLogicalTest,
385 ::testing::ValuesIn(kLogicalInstructions));
386
387
388// -----------------------------------------------------------------------------
389// Add and Sub instructions.
390
391typedef InstructionSelectorTestWithParam<AddSub> InstructionSelectorAddSubTest;
392
393
394TEST_P(InstructionSelectorAddSubTest, Parameter) {
395 const AddSub dpi = GetParam();
396 const MachineType type = dpi.mi.machine_type;
397 StreamBuilder m(this, type, type, type);
398 m.Return((m.*dpi.mi.constructor)(m.Parameter(0), m.Parameter(1)));
399 Stream s = m.Build();
400 ASSERT_EQ(1U, s.size());
401 EXPECT_EQ(dpi.mi.arch_opcode, s[0]->arch_opcode());
402 EXPECT_EQ(2U, s[0]->InputCount());
403 EXPECT_EQ(1U, s[0]->OutputCount());
404}
405
406
407TEST_P(InstructionSelectorAddSubTest, ImmediateOnRight) {
408 const AddSub dpi = GetParam();
409 const MachineType type = dpi.mi.machine_type;
410 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
411 StreamBuilder m(this, type, type);
412 m.Return(
413 (m.*dpi.mi.constructor)(m.Parameter(0), BuildConstant(m, type, imm)));
414 Stream s = m.Build();
415 ASSERT_EQ(1U, s.size());
416 EXPECT_EQ(dpi.mi.arch_opcode, s[0]->arch_opcode());
417 ASSERT_EQ(2U, s[0]->InputCount());
418 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
419 EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1)));
420 EXPECT_EQ(1U, s[0]->OutputCount());
421 }
422}
423
424
425TEST_P(InstructionSelectorAddSubTest, NegImmediateOnRight) {
426 const AddSub dpi = GetParam();
427 const MachineType type = dpi.mi.machine_type;
428 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
429 if (imm == 0) continue;
430 StreamBuilder m(this, type, type);
431 m.Return(
432 (m.*dpi.mi.constructor)(m.Parameter(0), BuildConstant(m, type, -imm)));
433 Stream s = m.Build();
434 ASSERT_EQ(1U, s.size());
435 EXPECT_EQ(dpi.negate_arch_opcode, s[0]->arch_opcode());
436 ASSERT_EQ(2U, s[0]->InputCount());
437 ASSERT_TRUE(s[0]->InputAt(1)->IsImmediate());
438 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
439 EXPECT_EQ(1U, s[0]->OutputCount());
440 }
441}
442
443
444TEST_P(InstructionSelectorAddSubTest, ShiftByImmediateOnRight) {
445 const AddSub dpi = GetParam();
446 const MachineType type = dpi.mi.machine_type;
447 TRACED_FOREACH(Shift, shift, kShiftInstructions) {
448 // Only test 64-bit shifted operands with 64-bit instructions.
449 if (shift.mi.machine_type != type) continue;
450
451 if ((shift.mi.arch_opcode == kArm64Ror32) ||
452 (shift.mi.arch_opcode == kArm64Ror)) {
453 // Not supported by add/sub instructions.
454 continue;
455 }
456
457 TRACED_FORRANGE(int, imm, 0, ((type == kMachInt32) ? 31 : 63)) {
458 StreamBuilder m(this, type, type, type);
459 m.Return((m.*dpi.mi.constructor)(
460 m.Parameter(0),
461 (m.*shift.mi.constructor)(m.Parameter(1),
462 BuildConstant(m, type, imm))));
463 Stream s = m.Build();
464 ASSERT_EQ(1U, s.size());
465 EXPECT_EQ(dpi.mi.arch_opcode, s[0]->arch_opcode());
466 EXPECT_EQ(shift.mode, s[0]->addressing_mode());
467 EXPECT_EQ(3U, s[0]->InputCount());
468 EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(2)));
469 EXPECT_EQ(1U, s[0]->OutputCount());
470 }
471 }
472}
473
474
475INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorAddSubTest,
476 ::testing::ValuesIn(kAddSubInstructions));
477
478
479TEST_F(InstructionSelectorTest, AddImmediateOnLeft) {
480 {
481 // 32-bit add.
482 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
483 StreamBuilder m(this, kMachInt32, kMachInt32);
484 m.Return(m.Int32Add(m.Int32Constant(imm), m.Parameter(0)));
485 Stream s = m.Build();
486 ASSERT_EQ(1U, s.size());
487 EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
488 ASSERT_EQ(2U, s[0]->InputCount());
489 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
490 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
491 EXPECT_EQ(1U, s[0]->OutputCount());
492 }
493 }
494 {
495 // 64-bit add.
496 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
497 StreamBuilder m(this, kMachInt64, kMachInt64);
498 m.Return(m.Int64Add(m.Int64Constant(imm), m.Parameter(0)));
499 Stream s = m.Build();
500 ASSERT_EQ(1U, s.size());
501 EXPECT_EQ(kArm64Add, 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}
509
510
511TEST_F(InstructionSelectorTest, SubZeroOnLeft) {
512 // Subtraction with zero on the left maps to Neg.
513 {
514 // 32-bit subtract.
515 StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
516 m.Return(m.Int32Sub(m.Int32Constant(0), m.Parameter(0)));
517 Stream s = m.Build();
518
519 ASSERT_EQ(1U, s.size());
520 EXPECT_EQ(kArm64Neg32, s[0]->arch_opcode());
521 EXPECT_EQ(1U, s[0]->InputCount());
522 EXPECT_EQ(1U, s[0]->OutputCount());
523 }
524 {
525 // 64-bit subtract.
526 StreamBuilder m(this, kMachInt64, kMachInt64, kMachInt64);
527 m.Return(m.Int64Sub(m.Int64Constant(0), m.Parameter(0)));
528 Stream s = m.Build();
529
530 ASSERT_EQ(1U, s.size());
531 EXPECT_EQ(kArm64Neg, s[0]->arch_opcode());
532 EXPECT_EQ(1U, s[0]->InputCount());
533 EXPECT_EQ(1U, s[0]->OutputCount());
534 }
535}
536
537
538TEST_F(InstructionSelectorTest, AddNegImmediateOnLeft) {
539 {
540 // 32-bit add.
541 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
542 if (imm == 0) continue;
543 StreamBuilder m(this, kMachInt32, kMachInt32);
544 m.Return(m.Int32Add(m.Int32Constant(-imm), m.Parameter(0)));
545 Stream s = m.Build();
546
547 ASSERT_EQ(1U, s.size());
548 EXPECT_EQ(kArm64Sub32, s[0]->arch_opcode());
549 ASSERT_EQ(2U, s[0]->InputCount());
550 ASSERT_TRUE(s[0]->InputAt(1)->IsImmediate());
551 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
552 EXPECT_EQ(1U, s[0]->OutputCount());
553 }
554 }
555 {
556 // 64-bit add.
557 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
558 if (imm == 0) continue;
559 StreamBuilder m(this, kMachInt64, kMachInt64);
560 m.Return(m.Int64Add(m.Int64Constant(-imm), m.Parameter(0)));
561 Stream s = m.Build();
562
563 ASSERT_EQ(1U, s.size());
564 EXPECT_EQ(kArm64Sub, s[0]->arch_opcode());
565 ASSERT_EQ(2U, s[0]->InputCount());
566 ASSERT_TRUE(s[0]->InputAt(1)->IsImmediate());
567 EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1)));
568 EXPECT_EQ(1U, s[0]->OutputCount());
569 }
570 }
571}
572
573
574TEST_F(InstructionSelectorTest, AddShiftByImmediateOnLeft) {
575 // 32-bit add.
576 TRACED_FOREACH(Shift, shift, kShiftInstructions) {
577 // Only test relevant shifted operands.
578 if (shift.mi.machine_type != kMachInt32) continue;
579 if (shift.mi.arch_opcode == kArm64Ror32) continue;
580
581 TRACED_FORRANGE(int, imm, 0, 31) {
582 StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
583 m.Return((m.Int32Add)(
584 (m.*shift.mi.constructor)(m.Parameter(1), m.Int32Constant(imm)),
585 m.Parameter(0)));
586 Stream s = m.Build();
587 ASSERT_EQ(1U, s.size());
588 EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
589 EXPECT_EQ(shift.mode, s[0]->addressing_mode());
590 EXPECT_EQ(3U, s[0]->InputCount());
591 EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(2)));
592 EXPECT_EQ(1U, s[0]->OutputCount());
593 }
594 }
595
596 // 64-bit add.
597 TRACED_FOREACH(Shift, shift, kShiftInstructions) {
598 // Only test relevant shifted operands.
599 if (shift.mi.machine_type != kMachInt64) continue;
600 if (shift.mi.arch_opcode == kArm64Ror) continue;
601
602 TRACED_FORRANGE(int, imm, 0, 63) {
603 StreamBuilder m(this, kMachInt64, kMachInt64, kMachInt64);
604 m.Return((m.Int64Add)(
605 (m.*shift.mi.constructor)(m.Parameter(1), m.Int64Constant(imm)),
606 m.Parameter(0)));
607 Stream s = m.Build();
608 ASSERT_EQ(1U, s.size());
609 EXPECT_EQ(kArm64Add, s[0]->arch_opcode());
610 EXPECT_EQ(shift.mode, s[0]->addressing_mode());
611 EXPECT_EQ(3U, s[0]->InputCount());
612 EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(2)));
613 EXPECT_EQ(1U, s[0]->OutputCount());
614 }
615 }
616}
617
618
619// -----------------------------------------------------------------------------
620// Data processing controlled branches.
621
622
623typedef InstructionSelectorTestWithParam<MachInst2>
624 InstructionSelectorDPFlagSetTest;
625
626
627TEST_P(InstructionSelectorDPFlagSetTest, BranchWithParameters) {
628 const MachInst2 dpi = GetParam();
629 const MachineType type = dpi.machine_type;
630 StreamBuilder m(this, type, type, type);
631 MLabel a, b;
632 m.Branch((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)), &a, &b);
633 m.Bind(&a);
634 m.Return(m.Int32Constant(1));
635 m.Bind(&b);
636 m.Return(m.Int32Constant(0));
637 Stream s = m.Build();
638 ASSERT_EQ(1U, s.size());
639 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
640 EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
641 EXPECT_EQ(kNotEqual, s[0]->flags_condition());
642}
643
644
645INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
646 InstructionSelectorDPFlagSetTest,
647 ::testing::ValuesIn(kDPFlagSetInstructions));
648
649
650TEST_F(InstructionSelectorTest, Word32AndBranchWithImmediateOnRight) {
651 TRACED_FOREACH(int32_t, imm, kLogical32Immediates) {
652 // Skip the cases where the instruction selector would use tbz/tbnz.
653 if (base::bits::CountPopulation32(imm) == 1) continue;
654
655 StreamBuilder m(this, kMachInt32, kMachInt32);
656 MLabel a, b;
657 m.Branch(m.Word32And(m.Parameter(0), m.Int32Constant(imm)), &a, &b);
658 m.Bind(&a);
659 m.Return(m.Int32Constant(1));
660 m.Bind(&b);
661 m.Return(m.Int32Constant(0));
662 Stream s = m.Build();
663 ASSERT_EQ(1U, s.size());
664 EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode());
665 EXPECT_EQ(4U, s[0]->InputCount());
666 EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
667 EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
668 EXPECT_EQ(kNotEqual, s[0]->flags_condition());
669 }
670}
671
672
673TEST_F(InstructionSelectorTest, Word64AndBranchWithImmediateOnRight) {
674 TRACED_FOREACH(int64_t, imm, kLogical64Immediates) {
675 // Skip the cases where the instruction selector would use tbz/tbnz.
676 if (base::bits::CountPopulation64(imm) == 1) continue;
677
678 StreamBuilder m(this, kMachInt64, kMachInt64);
679 MLabel a, b;
680 m.Branch(m.Word64And(m.Parameter(0), m.Int64Constant(imm)), &a, &b);
681 m.Bind(&a);
682 m.Return(m.Int32Constant(1));
683 m.Bind(&b);
684 m.Return(m.Int32Constant(0));
685 Stream s = m.Build();
686 ASSERT_EQ(1U, s.size());
687 EXPECT_EQ(kArm64Tst, s[0]->arch_opcode());
688 EXPECT_EQ(4U, s[0]->InputCount());
689 EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
690 EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
691 EXPECT_EQ(kNotEqual, s[0]->flags_condition());
692 }
693}
694
695
696TEST_F(InstructionSelectorTest, AddBranchWithImmediateOnRight) {
697 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
698 StreamBuilder m(this, kMachInt32, kMachInt32);
699 MLabel a, b;
700 m.Branch(m.Int32Add(m.Parameter(0), m.Int32Constant(imm)), &a, &b);
701 m.Bind(&a);
702 m.Return(m.Int32Constant(1));
703 m.Bind(&b);
704 m.Return(m.Int32Constant(0));
705 Stream s = m.Build();
706 ASSERT_EQ(1U, s.size());
707 EXPECT_EQ(kArm64Cmn32, s[0]->arch_opcode());
708 EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
709 EXPECT_EQ(kNotEqual, s[0]->flags_condition());
710 }
711}
712
713
714TEST_F(InstructionSelectorTest, SubBranchWithImmediateOnRight) {
715 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
716 StreamBuilder m(this, kMachInt32, kMachInt32);
717 MLabel a, b;
718 m.Branch(m.Int32Sub(m.Parameter(0), m.Int32Constant(imm)), &a, &b);
719 m.Bind(&a);
720 m.Return(m.Int32Constant(1));
721 m.Bind(&b);
722 m.Return(m.Int32Constant(0));
723 Stream s = m.Build();
724 ASSERT_EQ(1U, s.size());
725 EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode());
726 EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
727 EXPECT_EQ(kNotEqual, s[0]->flags_condition());
728 }
729}
730
731
732TEST_F(InstructionSelectorTest, Word32AndBranchWithImmediateOnLeft) {
733 TRACED_FOREACH(int32_t, imm, kLogical32Immediates) {
734 // Skip the cases where the instruction selector would use tbz/tbnz.
735 if (base::bits::CountPopulation32(imm) == 1) continue;
736
737 StreamBuilder m(this, kMachInt32, kMachInt32);
738 MLabel a, b;
739 m.Branch(m.Word32And(m.Int32Constant(imm), m.Parameter(0)), &a, &b);
740 m.Bind(&a);
741 m.Return(m.Int32Constant(1));
742 m.Bind(&b);
743 m.Return(m.Int32Constant(0));
744 Stream s = m.Build();
745 ASSERT_EQ(1U, s.size());
746 EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode());
747 EXPECT_EQ(4U, s[0]->InputCount());
748 EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
749 ASSERT_LE(1U, s[0]->InputCount());
750 EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
751 EXPECT_EQ(kNotEqual, s[0]->flags_condition());
752 }
753}
754
755
756TEST_F(InstructionSelectorTest, Word64AndBranchWithImmediateOnLeft) {
757 TRACED_FOREACH(int64_t, imm, kLogical64Immediates) {
758 // Skip the cases where the instruction selector would use tbz/tbnz.
759 if (base::bits::CountPopulation64(imm) == 1) continue;
760
761 StreamBuilder m(this, kMachInt64, kMachInt64);
762 MLabel a, b;
763 m.Branch(m.Word64And(m.Int64Constant(imm), m.Parameter(0)), &a, &b);
764 m.Bind(&a);
765 m.Return(m.Int32Constant(1));
766 m.Bind(&b);
767 m.Return(m.Int32Constant(0));
768 Stream s = m.Build();
769 ASSERT_EQ(1U, s.size());
770 EXPECT_EQ(kArm64Tst, s[0]->arch_opcode());
771 EXPECT_EQ(4U, s[0]->InputCount());
772 EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
773 ASSERT_LE(1U, s[0]->InputCount());
774 EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
775 EXPECT_EQ(kNotEqual, s[0]->flags_condition());
776 }
777}
778
779
780TEST_F(InstructionSelectorTest, AddBranchWithImmediateOnLeft) {
781 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
782 StreamBuilder m(this, kMachInt32, kMachInt32);
783 MLabel a, b;
784 m.Branch(m.Int32Add(m.Int32Constant(imm), m.Parameter(0)), &a, &b);
785 m.Bind(&a);
786 m.Return(m.Int32Constant(1));
787 m.Bind(&b);
788 m.Return(m.Int32Constant(0));
789 Stream s = m.Build();
790 ASSERT_EQ(1U, s.size());
791 EXPECT_EQ(kArm64Cmn32, s[0]->arch_opcode());
792 ASSERT_LE(1U, s[0]->InputCount());
793 EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
794 EXPECT_EQ(kNotEqual, s[0]->flags_condition());
795 }
796}
797
798
799TEST_F(InstructionSelectorTest, Word32AndBranchWithOneBitMaskOnRight) {
800 TRACED_FORRANGE(int, bit, 0, 31) {
801 uint32_t mask = 1 << bit;
802 StreamBuilder m(this, kMachInt32, kMachInt32);
803 MLabel a, b;
804 m.Branch(m.Word32And(m.Parameter(0), m.Int32Constant(mask)), &a, &b);
805 m.Bind(&a);
806 m.Return(m.Int32Constant(1));
807 m.Bind(&b);
808 m.Return(m.Int32Constant(0));
809 Stream s = m.Build();
810 ASSERT_EQ(1U, s.size());
811 EXPECT_EQ(kArm64TestAndBranch32, s[0]->arch_opcode());
812 EXPECT_EQ(kNotEqual, s[0]->flags_condition());
813 EXPECT_EQ(4U, s[0]->InputCount());
814 EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
815 EXPECT_EQ(bit, s.ToInt32(s[0]->InputAt(1)));
816 }
817
818 TRACED_FORRANGE(int, bit, 0, 31) {
819 uint32_t mask = 1 << bit;
820 StreamBuilder m(this, kMachInt32, kMachInt32);
821 MLabel a, b;
822 m.Branch(
823 m.Word32BinaryNot(m.Word32And(m.Parameter(0), m.Int32Constant(mask))),
824 &a, &b);
825 m.Bind(&a);
826 m.Return(m.Int32Constant(1));
827 m.Bind(&b);
828 m.Return(m.Int32Constant(0));
829 Stream s = m.Build();
830 ASSERT_EQ(1U, s.size());
831 EXPECT_EQ(kArm64TestAndBranch32, s[0]->arch_opcode());
832 EXPECT_EQ(kEqual, s[0]->flags_condition());
833 EXPECT_EQ(4U, s[0]->InputCount());
834 EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
835 EXPECT_EQ(bit, s.ToInt32(s[0]->InputAt(1)));
836 }
837}
838
839
840TEST_F(InstructionSelectorTest, Word32AndBranchWithOneBitMaskOnLeft) {
841 TRACED_FORRANGE(int, bit, 0, 31) {
842 uint32_t mask = 1 << bit;
843 StreamBuilder m(this, kMachInt32, kMachInt32);
844 MLabel a, b;
845 m.Branch(m.Word32And(m.Int32Constant(mask), m.Parameter(0)), &a, &b);
846 m.Bind(&a);
847 m.Return(m.Int32Constant(1));
848 m.Bind(&b);
849 m.Return(m.Int32Constant(0));
850 Stream s = m.Build();
851 ASSERT_EQ(1U, s.size());
852 EXPECT_EQ(kArm64TestAndBranch32, s[0]->arch_opcode());
853 EXPECT_EQ(kNotEqual, s[0]->flags_condition());
854 EXPECT_EQ(4U, s[0]->InputCount());
855 EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
856 EXPECT_EQ(bit, s.ToInt32(s[0]->InputAt(1)));
857 }
858
859 TRACED_FORRANGE(int, bit, 0, 31) {
860 uint32_t mask = 1 << bit;
861 StreamBuilder m(this, kMachInt32, kMachInt32);
862 MLabel a, b;
863 m.Branch(
864 m.Word32BinaryNot(m.Word32And(m.Int32Constant(mask), m.Parameter(0))),
865 &a, &b);
866 m.Bind(&a);
867 m.Return(m.Int32Constant(1));
868 m.Bind(&b);
869 m.Return(m.Int32Constant(0));
870 Stream s = m.Build();
871 ASSERT_EQ(1U, s.size());
872 EXPECT_EQ(kArm64TestAndBranch32, s[0]->arch_opcode());
873 EXPECT_EQ(kEqual, s[0]->flags_condition());
874 EXPECT_EQ(4U, s[0]->InputCount());
875 EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
876 EXPECT_EQ(bit, s.ToInt32(s[0]->InputAt(1)));
877 }
878}
879
880
881TEST_F(InstructionSelectorTest, Word64AndBranchWithOneBitMaskOnRight) {
882 TRACED_FORRANGE(int, bit, 0, 63) {
883 uint64_t mask = 1L << bit;
884 StreamBuilder m(this, kMachInt64, kMachInt64);
885 MLabel a, b;
886 m.Branch(m.Word64And(m.Parameter(0), m.Int64Constant(mask)), &a, &b);
887 m.Bind(&a);
888 m.Return(m.Int32Constant(1));
889 m.Bind(&b);
890 m.Return(m.Int32Constant(0));
891 Stream s = m.Build();
892 ASSERT_EQ(1U, s.size());
893 EXPECT_EQ(kArm64TestAndBranch, s[0]->arch_opcode());
894 EXPECT_EQ(kNotEqual, s[0]->flags_condition());
895 EXPECT_EQ(4U, s[0]->InputCount());
896 EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
897 EXPECT_EQ(bit, s.ToInt64(s[0]->InputAt(1)));
898 }
899
900 TRACED_FORRANGE(int, bit, 0, 63) {
901 uint64_t mask = 1L << bit;
902 StreamBuilder m(this, kMachInt64, kMachInt64);
903 MLabel a, b;
904 m.Branch(
905 m.Word64BinaryNot(m.Word64And(m.Parameter(0), m.Int64Constant(mask))),
906 &a, &b);
907 m.Bind(&a);
908 m.Return(m.Int32Constant(1));
909 m.Bind(&b);
910 m.Return(m.Int32Constant(0));
911 Stream s = m.Build();
912 ASSERT_EQ(1U, s.size());
913 EXPECT_EQ(kArm64TestAndBranch, s[0]->arch_opcode());
914 EXPECT_EQ(kEqual, s[0]->flags_condition());
915 EXPECT_EQ(4U, s[0]->InputCount());
916 EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
917 EXPECT_EQ(bit, s.ToInt64(s[0]->InputAt(1)));
918 }
919}
920
921
922TEST_F(InstructionSelectorTest, Word64AndBranchWithOneBitMaskOnLeft) {
923 TRACED_FORRANGE(int, bit, 0, 63) {
924 uint64_t mask = 1L << bit;
925 StreamBuilder m(this, kMachInt64, kMachInt64);
926 MLabel a, b;
927 m.Branch(m.Word64And(m.Int64Constant(mask), m.Parameter(0)), &a, &b);
928 m.Bind(&a);
929 m.Return(m.Int32Constant(1));
930 m.Bind(&b);
931 m.Return(m.Int32Constant(0));
932 Stream s = m.Build();
933 ASSERT_EQ(1U, s.size());
934 EXPECT_EQ(kArm64TestAndBranch, s[0]->arch_opcode());
935 EXPECT_EQ(kNotEqual, s[0]->flags_condition());
936 EXPECT_EQ(4U, s[0]->InputCount());
937 EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
938 EXPECT_EQ(bit, s.ToInt64(s[0]->InputAt(1)));
939 }
940
941 TRACED_FORRANGE(int, bit, 0, 63) {
942 uint64_t mask = 1L << bit;
943 StreamBuilder m(this, kMachInt64, kMachInt64);
944 MLabel a, b;
945 m.Branch(
946 m.Word64BinaryNot(m.Word64And(m.Int64Constant(mask), m.Parameter(0))),
947 &a, &b);
948 m.Bind(&a);
949 m.Return(m.Int32Constant(1));
950 m.Bind(&b);
951 m.Return(m.Int32Constant(0));
952 Stream s = m.Build();
953 ASSERT_EQ(1U, s.size());
954 EXPECT_EQ(kArm64TestAndBranch, s[0]->arch_opcode());
955 EXPECT_EQ(kEqual, s[0]->flags_condition());
956 EXPECT_EQ(4U, s[0]->InputCount());
957 EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
958 EXPECT_EQ(bit, s.ToInt64(s[0]->InputAt(1)));
959 }
960}
961
962
963TEST_F(InstructionSelectorTest, CompareAgainstZeroAndBranch) {
964 {
965 StreamBuilder m(this, kMachInt32, kMachInt32);
966 MLabel a, b;
967 Node* p0 = m.Parameter(0);
968 m.Branch(p0, &a, &b);
969 m.Bind(&a);
970 m.Return(m.Int32Constant(1));
971 m.Bind(&b);
972 m.Return(m.Int32Constant(0));
973 Stream s = m.Build();
974 ASSERT_EQ(1U, s.size());
975 EXPECT_EQ(kArm64CompareAndBranch32, s[0]->arch_opcode());
976 EXPECT_EQ(kNotEqual, s[0]->flags_condition());
977 EXPECT_EQ(3U, s[0]->InputCount());
978 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
979 }
980
981 {
982 StreamBuilder m(this, kMachInt32, kMachInt32);
983 MLabel a, b;
984 Node* p0 = m.Parameter(0);
985 m.Branch(m.Word32BinaryNot(p0), &a, &b);
986 m.Bind(&a);
987 m.Return(m.Int32Constant(1));
988 m.Bind(&b);
989 m.Return(m.Int32Constant(0));
990 Stream s = m.Build();
991 ASSERT_EQ(1U, s.size());
992 EXPECT_EQ(kArm64CompareAndBranch32, s[0]->arch_opcode());
993 EXPECT_EQ(kEqual, s[0]->flags_condition());
994 EXPECT_EQ(3U, s[0]->InputCount());
995 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
996 }
997}
998
999
1000// -----------------------------------------------------------------------------
1001// Add and subtract instructions with overflow.
1002
1003
1004typedef InstructionSelectorTestWithParam<MachInst2>
1005 InstructionSelectorOvfAddSubTest;
1006
1007
1008TEST_P(InstructionSelectorOvfAddSubTest, OvfParameter) {
1009 const MachInst2 dpi = GetParam();
1010 const MachineType type = dpi.machine_type;
1011 StreamBuilder m(this, type, type, type);
1012 m.Return(
1013 m.Projection(1, (m.*dpi.constructor)(m.Parameter(0), m.Parameter(1))));
1014 Stream s = m.Build();
1015 ASSERT_EQ(1U, s.size());
1016 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
1017 EXPECT_EQ(2U, s[0]->InputCount());
1018 EXPECT_LE(1U, s[0]->OutputCount());
1019 EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1020 EXPECT_EQ(kOverflow, s[0]->flags_condition());
1021}
1022
1023
1024TEST_P(InstructionSelectorOvfAddSubTest, OvfImmediateOnRight) {
1025 const MachInst2 dpi = GetParam();
1026 const MachineType type = dpi.machine_type;
1027 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
1028 StreamBuilder m(this, type, type);
1029 m.Return(m.Projection(
1030 1, (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm))));
1031 Stream s = m.Build();
1032 ASSERT_EQ(1U, s.size());
1033 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
1034 ASSERT_EQ(2U, s[0]->InputCount());
1035 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
1036 EXPECT_LE(1U, s[0]->OutputCount());
1037 EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1038 EXPECT_EQ(kOverflow, s[0]->flags_condition());
1039 }
1040}
1041
1042
1043TEST_P(InstructionSelectorOvfAddSubTest, ValParameter) {
1044 const MachInst2 dpi = GetParam();
1045 const MachineType type = dpi.machine_type;
1046 StreamBuilder m(this, type, type, type);
1047 m.Return(
1048 m.Projection(0, (m.*dpi.constructor)(m.Parameter(0), m.Parameter(1))));
1049 Stream s = m.Build();
1050 ASSERT_EQ(1U, s.size());
1051 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
1052 EXPECT_EQ(2U, s[0]->InputCount());
1053 EXPECT_LE(1U, s[0]->OutputCount());
1054 EXPECT_EQ(kFlags_none, s[0]->flags_mode());
1055}
1056
1057
1058TEST_P(InstructionSelectorOvfAddSubTest, ValImmediateOnRight) {
1059 const MachInst2 dpi = GetParam();
1060 const MachineType type = dpi.machine_type;
1061 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
1062 StreamBuilder m(this, type, type);
1063 m.Return(m.Projection(
1064 0, (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm))));
1065 Stream s = m.Build();
1066 ASSERT_EQ(1U, s.size());
1067 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
1068 ASSERT_EQ(2U, s[0]->InputCount());
1069 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
1070 EXPECT_LE(1U, s[0]->OutputCount());
1071 EXPECT_EQ(kFlags_none, s[0]->flags_mode());
1072 }
1073}
1074
1075
1076TEST_P(InstructionSelectorOvfAddSubTest, BothParameter) {
1077 const MachInst2 dpi = GetParam();
1078 const MachineType type = dpi.machine_type;
1079 StreamBuilder m(this, type, type, type);
1080 Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Parameter(1));
1081 m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
1082 Stream s = m.Build();
1083 ASSERT_LE(1U, s.size());
1084 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
1085 EXPECT_EQ(2U, s[0]->InputCount());
1086 EXPECT_EQ(2U, s[0]->OutputCount());
1087 EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1088 EXPECT_EQ(kOverflow, s[0]->flags_condition());
1089}
1090
1091
1092TEST_P(InstructionSelectorOvfAddSubTest, BothImmediateOnRight) {
1093 const MachInst2 dpi = GetParam();
1094 const MachineType type = dpi.machine_type;
1095 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
1096 StreamBuilder m(this, type, type);
1097 Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm));
1098 m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
1099 Stream s = m.Build();
1100 ASSERT_LE(1U, s.size());
1101 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
1102 ASSERT_EQ(2U, s[0]->InputCount());
1103 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
1104 EXPECT_EQ(2U, s[0]->OutputCount());
1105 EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1106 EXPECT_EQ(kOverflow, s[0]->flags_condition());
1107 }
1108}
1109
1110
1111TEST_P(InstructionSelectorOvfAddSubTest, BranchWithParameters) {
1112 const MachInst2 dpi = GetParam();
1113 const MachineType type = dpi.machine_type;
1114 StreamBuilder m(this, type, type, type);
1115 MLabel a, b;
1116 Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Parameter(1));
1117 m.Branch(m.Projection(1, n), &a, &b);
1118 m.Bind(&a);
1119 m.Return(m.Int32Constant(0));
1120 m.Bind(&b);
1121 m.Return(m.Projection(0, n));
1122 Stream s = m.Build();
1123 ASSERT_EQ(1U, s.size());
1124 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
1125 EXPECT_EQ(4U, s[0]->InputCount());
1126 EXPECT_EQ(1U, s[0]->OutputCount());
1127 EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
1128 EXPECT_EQ(kOverflow, s[0]->flags_condition());
1129}
1130
1131
1132TEST_P(InstructionSelectorOvfAddSubTest, BranchWithImmediateOnRight) {
1133 const MachInst2 dpi = GetParam();
1134 const MachineType type = dpi.machine_type;
1135 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
1136 StreamBuilder m(this, type, type);
1137 MLabel a, b;
1138 Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm));
1139 m.Branch(m.Projection(1, n), &a, &b);
1140 m.Bind(&a);
1141 m.Return(m.Int32Constant(0));
1142 m.Bind(&b);
1143 m.Return(m.Projection(0, n));
1144 Stream s = m.Build();
1145 ASSERT_EQ(1U, s.size());
1146 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
1147 ASSERT_EQ(4U, s[0]->InputCount());
1148 EXPECT_EQ(1U, s[0]->OutputCount());
1149 EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
1150 EXPECT_EQ(kOverflow, s[0]->flags_condition());
1151 }
1152}
1153
1154
1155INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
1156 InstructionSelectorOvfAddSubTest,
1157 ::testing::ValuesIn(kOvfAddSubInstructions));
1158
1159
1160TEST_F(InstructionSelectorTest, OvfFlagAddImmediateOnLeft) {
1161 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
1162 StreamBuilder m(this, kMachInt32, kMachInt32);
1163 m.Return(m.Projection(
1164 1, m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0))));
1165 Stream s = m.Build();
1166
1167 ASSERT_EQ(1U, s.size());
1168 EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
1169 EXPECT_EQ(2U, s[0]->InputCount());
1170 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
1171 EXPECT_LE(1U, s[0]->OutputCount());
1172 EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1173 EXPECT_EQ(kOverflow, s[0]->flags_condition());
1174 }
1175}
1176
1177
1178TEST_F(InstructionSelectorTest, OvfValAddImmediateOnLeft) {
1179 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
1180 StreamBuilder m(this, kMachInt32, kMachInt32);
1181 m.Return(m.Projection(
1182 0, m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0))));
1183 Stream s = m.Build();
1184
1185 ASSERT_EQ(1U, s.size());
1186 EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
1187 ASSERT_EQ(2U, s[0]->InputCount());
1188 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
1189 EXPECT_LE(1U, s[0]->OutputCount());
1190 EXPECT_EQ(kFlags_none, s[0]->flags_mode());
1191 }
1192}
1193
1194
1195TEST_F(InstructionSelectorTest, OvfBothAddImmediateOnLeft) {
1196 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
1197 StreamBuilder m(this, kMachInt32, kMachInt32);
1198 Node* n = m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0));
1199 m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
1200 Stream s = m.Build();
1201
1202 ASSERT_LE(1U, s.size());
1203 EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
1204 ASSERT_EQ(2U, s[0]->InputCount());
1205 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
1206 EXPECT_EQ(2U, s[0]->OutputCount());
1207 EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1208 EXPECT_EQ(kOverflow, s[0]->flags_condition());
1209 }
1210}
1211
1212
1213TEST_F(InstructionSelectorTest, OvfBranchWithImmediateOnLeft) {
1214 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
1215 StreamBuilder m(this, kMachInt32, kMachInt32);
1216 MLabel a, b;
1217 Node* n = m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0));
1218 m.Branch(m.Projection(1, n), &a, &b);
1219 m.Bind(&a);
1220 m.Return(m.Int32Constant(0));
1221 m.Bind(&b);
1222 m.Return(m.Projection(0, n));
1223 Stream s = m.Build();
1224
1225 ASSERT_EQ(1U, s.size());
1226 EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
1227 ASSERT_EQ(4U, s[0]->InputCount());
1228 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
1229 EXPECT_EQ(1U, s[0]->OutputCount());
1230 EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
1231 EXPECT_EQ(kOverflow, s[0]->flags_condition());
1232 }
1233}
1234
1235
1236// -----------------------------------------------------------------------------
1237// Shift instructions.
1238
1239
1240typedef InstructionSelectorTestWithParam<Shift> InstructionSelectorShiftTest;
1241
1242
1243TEST_P(InstructionSelectorShiftTest, Parameter) {
1244 const Shift shift = GetParam();
1245 const MachineType type = shift.mi.machine_type;
1246 StreamBuilder m(this, type, type, type);
1247 m.Return((m.*shift.mi.constructor)(m.Parameter(0), m.Parameter(1)));
1248 Stream s = m.Build();
1249 ASSERT_EQ(1U, s.size());
1250 EXPECT_EQ(shift.mi.arch_opcode, s[0]->arch_opcode());
1251 EXPECT_EQ(2U, s[0]->InputCount());
1252 EXPECT_EQ(1U, s[0]->OutputCount());
1253}
1254
1255
1256TEST_P(InstructionSelectorShiftTest, Immediate) {
1257 const Shift shift = GetParam();
1258 const MachineType type = shift.mi.machine_type;
1259 TRACED_FORRANGE(int32_t, imm, 0, (ElementSizeOf(type) * 8) - 1) {
1260 StreamBuilder m(this, type, type);
1261 m.Return((m.*shift.mi.constructor)(m.Parameter(0), m.Int32Constant(imm)));
1262 Stream s = m.Build();
1263 ASSERT_EQ(1U, s.size());
1264 EXPECT_EQ(shift.mi.arch_opcode, s[0]->arch_opcode());
1265 EXPECT_EQ(2U, s[0]->InputCount());
1266 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
1267 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
1268 EXPECT_EQ(1U, s[0]->OutputCount());
1269 }
1270}
1271
1272
1273INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorShiftTest,
1274 ::testing::ValuesIn(kShiftInstructions));
1275
1276
1277TEST_F(InstructionSelectorTest, Word64ShlWithChangeInt32ToInt64) {
1278 TRACED_FORRANGE(int64_t, x, 32, 63) {
1279 StreamBuilder m(this, kMachInt64, kMachInt32);
1280 Node* const p0 = m.Parameter(0);
1281 Node* const n = m.Word64Shl(m.ChangeInt32ToInt64(p0), m.Int64Constant(x));
1282 m.Return(n);
1283 Stream s = m.Build();
1284 ASSERT_EQ(1U, s.size());
1285 EXPECT_EQ(kArm64Lsl, s[0]->arch_opcode());
1286 ASSERT_EQ(2U, s[0]->InputCount());
1287 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1288 EXPECT_EQ(x, s.ToInt64(s[0]->InputAt(1)));
1289 ASSERT_EQ(1U, s[0]->OutputCount());
1290 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
1291 }
1292}
1293
1294
1295TEST_F(InstructionSelectorTest, Word64ShlWithChangeUint32ToUint64) {
1296 TRACED_FORRANGE(int64_t, x, 32, 63) {
1297 StreamBuilder m(this, kMachInt64, kMachUint32);
1298 Node* const p0 = m.Parameter(0);
1299 Node* const n = m.Word64Shl(m.ChangeUint32ToUint64(p0), m.Int64Constant(x));
1300 m.Return(n);
1301 Stream s = m.Build();
1302 ASSERT_EQ(1U, s.size());
1303 EXPECT_EQ(kArm64Lsl, s[0]->arch_opcode());
1304 ASSERT_EQ(2U, s[0]->InputCount());
1305 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1306 EXPECT_EQ(x, s.ToInt64(s[0]->InputAt(1)));
1307 ASSERT_EQ(1U, s[0]->OutputCount());
1308 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
1309 }
1310}
1311
1312
1313TEST_F(InstructionSelectorTest, TruncateInt64ToInt32WithWord64Sar) {
1314 StreamBuilder m(this, kMachInt32, kMachInt64);
1315 Node* const p = m.Parameter(0);
1316 Node* const t = m.TruncateInt64ToInt32(m.Word64Sar(p, m.Int64Constant(32)));
1317 m.Return(t);
1318 Stream s = m.Build();
1319 ASSERT_EQ(1U, s.size());
1320 EXPECT_EQ(kArm64Lsr, s[0]->arch_opcode());
1321 ASSERT_EQ(2U, s[0]->InputCount());
1322 EXPECT_EQ(s.ToVreg(p), s.ToVreg(s[0]->InputAt(0)));
1323 EXPECT_EQ(32, s.ToInt64(s[0]->InputAt(1)));
1324 ASSERT_EQ(1U, s[0]->OutputCount());
1325 EXPECT_EQ(s.ToVreg(t), s.ToVreg(s[0]->OutputAt(0)));
1326}
1327
1328
1329TEST_F(InstructionSelectorTest, TruncateInt64ToInt32WithWord64Shr) {
1330 TRACED_FORRANGE(int64_t, x, 32, 63) {
1331 StreamBuilder m(this, kMachInt32, kMachInt64);
1332 Node* const p = m.Parameter(0);
1333 Node* const t = m.TruncateInt64ToInt32(m.Word64Shr(p, m.Int64Constant(x)));
1334 m.Return(t);
1335 Stream s = m.Build();
1336 ASSERT_EQ(1U, s.size());
1337 EXPECT_EQ(kArm64Lsr, s[0]->arch_opcode());
1338 ASSERT_EQ(2U, s[0]->InputCount());
1339 EXPECT_EQ(s.ToVreg(p), s.ToVreg(s[0]->InputAt(0)));
1340 EXPECT_EQ(x, s.ToInt64(s[0]->InputAt(1)));
1341 ASSERT_EQ(1U, s[0]->OutputCount());
1342 EXPECT_EQ(s.ToVreg(t), s.ToVreg(s[0]->OutputAt(0)));
1343 }
1344}
1345
1346
1347// -----------------------------------------------------------------------------
1348// Mul and Div instructions.
1349
1350
1351typedef InstructionSelectorTestWithParam<MachInst2>
1352 InstructionSelectorMulDivTest;
1353
1354
1355TEST_P(InstructionSelectorMulDivTest, Parameter) {
1356 const MachInst2 dpi = GetParam();
1357 const MachineType type = dpi.machine_type;
1358 StreamBuilder m(this, type, type, type);
1359 m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)));
1360 Stream s = m.Build();
1361 ASSERT_EQ(1U, s.size());
1362 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
1363 EXPECT_EQ(2U, s[0]->InputCount());
1364 EXPECT_EQ(1U, s[0]->OutputCount());
1365}
1366
1367
1368INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorMulDivTest,
1369 ::testing::ValuesIn(kMulDivInstructions));
1370
1371
1372namespace {
1373
1374struct MulDPInst {
1375 const char* mul_constructor_name;
1376 Node* (RawMachineAssembler::*mul_constructor)(Node*, Node*);
1377 Node* (RawMachineAssembler::*add_constructor)(Node*, Node*);
1378 Node* (RawMachineAssembler::*sub_constructor)(Node*, Node*);
1379 ArchOpcode add_arch_opcode;
1380 ArchOpcode sub_arch_opcode;
1381 ArchOpcode neg_arch_opcode;
1382 MachineType machine_type;
1383};
1384
1385
1386std::ostream& operator<<(std::ostream& os, const MulDPInst& inst) {
1387 return os << inst.mul_constructor_name;
1388}
1389
1390} // namespace
1391
1392
1393static const MulDPInst kMulDPInstructions[] = {
1394 {"Int32Mul", &RawMachineAssembler::Int32Mul, &RawMachineAssembler::Int32Add,
1395 &RawMachineAssembler::Int32Sub, kArm64Madd32, kArm64Msub32, kArm64Mneg32,
1396 kMachInt32},
1397 {"Int64Mul", &RawMachineAssembler::Int64Mul, &RawMachineAssembler::Int64Add,
1398 &RawMachineAssembler::Int64Sub, kArm64Madd, kArm64Msub, kArm64Mneg,
1399 kMachInt64}};
1400
1401
1402typedef InstructionSelectorTestWithParam<MulDPInst>
1403 InstructionSelectorIntDPWithIntMulTest;
1404
1405
1406TEST_P(InstructionSelectorIntDPWithIntMulTest, AddWithMul) {
1407 const MulDPInst mdpi = GetParam();
1408 const MachineType type = mdpi.machine_type;
1409 {
1410 StreamBuilder m(this, type, type, type, type);
1411 Node* n = (m.*mdpi.mul_constructor)(m.Parameter(1), m.Parameter(2));
1412 m.Return((m.*mdpi.add_constructor)(m.Parameter(0), n));
1413 Stream s = m.Build();
1414 ASSERT_EQ(1U, s.size());
1415 EXPECT_EQ(mdpi.add_arch_opcode, s[0]->arch_opcode());
1416 EXPECT_EQ(3U, s[0]->InputCount());
1417 EXPECT_EQ(1U, s[0]->OutputCount());
1418 }
1419 {
1420 StreamBuilder m(this, type, type, type, type);
1421 Node* n = (m.*mdpi.mul_constructor)(m.Parameter(0), m.Parameter(1));
1422 m.Return((m.*mdpi.add_constructor)(n, m.Parameter(2)));
1423 Stream s = m.Build();
1424 ASSERT_EQ(1U, s.size());
1425 EXPECT_EQ(mdpi.add_arch_opcode, s[0]->arch_opcode());
1426 EXPECT_EQ(3U, s[0]->InputCount());
1427 EXPECT_EQ(1U, s[0]->OutputCount());
1428 }
1429}
1430
1431
1432TEST_P(InstructionSelectorIntDPWithIntMulTest, SubWithMul) {
1433 const MulDPInst mdpi = GetParam();
1434 const MachineType type = mdpi.machine_type;
1435 {
1436 StreamBuilder m(this, type, type, type, type);
1437 Node* n = (m.*mdpi.mul_constructor)(m.Parameter(1), m.Parameter(2));
1438 m.Return((m.*mdpi.sub_constructor)(m.Parameter(0), n));
1439 Stream s = m.Build();
1440 ASSERT_EQ(1U, s.size());
1441 EXPECT_EQ(mdpi.sub_arch_opcode, s[0]->arch_opcode());
1442 EXPECT_EQ(3U, s[0]->InputCount());
1443 EXPECT_EQ(1U, s[0]->OutputCount());
1444 }
1445}
1446
1447
1448TEST_P(InstructionSelectorIntDPWithIntMulTest, NegativeMul) {
1449 const MulDPInst mdpi = GetParam();
1450 const MachineType type = mdpi.machine_type;
1451 {
1452 StreamBuilder m(this, type, type, type);
1453 Node* n =
1454 (m.*mdpi.sub_constructor)(BuildConstant(m, type, 0), m.Parameter(0));
1455 m.Return((m.*mdpi.mul_constructor)(n, m.Parameter(1)));
1456 Stream s = m.Build();
1457 ASSERT_EQ(1U, s.size());
1458 EXPECT_EQ(mdpi.neg_arch_opcode, s[0]->arch_opcode());
1459 EXPECT_EQ(2U, s[0]->InputCount());
1460 EXPECT_EQ(1U, s[0]->OutputCount());
1461 }
1462 {
1463 StreamBuilder m(this, type, type, type);
1464 Node* n =
1465 (m.*mdpi.sub_constructor)(BuildConstant(m, type, 0), m.Parameter(1));
1466 m.Return((m.*mdpi.mul_constructor)(m.Parameter(0), n));
1467 Stream s = m.Build();
1468 ASSERT_EQ(1U, s.size());
1469 EXPECT_EQ(mdpi.neg_arch_opcode, s[0]->arch_opcode());
1470 EXPECT_EQ(2U, s[0]->InputCount());
1471 EXPECT_EQ(1U, s[0]->OutputCount());
1472 }
1473}
1474
1475
1476INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
1477 InstructionSelectorIntDPWithIntMulTest,
1478 ::testing::ValuesIn(kMulDPInstructions));
1479
1480
1481// -----------------------------------------------------------------------------
1482// Floating point instructions.
1483
1484typedef InstructionSelectorTestWithParam<MachInst2>
1485 InstructionSelectorFPArithTest;
1486
1487
1488TEST_P(InstructionSelectorFPArithTest, Parameter) {
1489 const MachInst2 fpa = GetParam();
1490 StreamBuilder m(this, fpa.machine_type, fpa.machine_type, fpa.machine_type);
1491 m.Return((m.*fpa.constructor)(m.Parameter(0), m.Parameter(1)));
1492 Stream s = m.Build();
1493 ASSERT_EQ(1U, s.size());
1494 EXPECT_EQ(fpa.arch_opcode, s[0]->arch_opcode());
1495 EXPECT_EQ(2U, s[0]->InputCount());
1496 EXPECT_EQ(1U, s[0]->OutputCount());
1497}
1498
1499
1500INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorFPArithTest,
1501 ::testing::ValuesIn(kFPArithInstructions));
1502
1503
1504typedef InstructionSelectorTestWithParam<FPCmp> InstructionSelectorFPCmpTest;
1505
1506
1507TEST_P(InstructionSelectorFPCmpTest, Parameter) {
1508 const FPCmp cmp = GetParam();
1509 StreamBuilder m(this, kMachInt32, cmp.mi.machine_type, cmp.mi.machine_type);
1510 m.Return((m.*cmp.mi.constructor)(m.Parameter(0), m.Parameter(1)));
1511 Stream s = m.Build();
1512 ASSERT_EQ(1U, s.size());
1513 EXPECT_EQ(cmp.mi.arch_opcode, s[0]->arch_opcode());
1514 EXPECT_EQ(2U, s[0]->InputCount());
1515 EXPECT_EQ(1U, s[0]->OutputCount());
1516 EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1517 EXPECT_EQ(cmp.cond, s[0]->flags_condition());
1518}
1519
1520
1521INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorFPCmpTest,
1522 ::testing::ValuesIn(kFPCmpInstructions));
1523
1524
1525// -----------------------------------------------------------------------------
1526// Conversions.
1527
1528typedef InstructionSelectorTestWithParam<Conversion>
1529 InstructionSelectorConversionTest;
1530
1531
1532TEST_P(InstructionSelectorConversionTest, Parameter) {
1533 const Conversion conv = GetParam();
1534 StreamBuilder m(this, conv.mi.machine_type, conv.src_machine_type);
1535 m.Return((m.*conv.mi.constructor)(m.Parameter(0)));
1536 Stream s = m.Build();
1537 ASSERT_EQ(1U, s.size());
1538 EXPECT_EQ(conv.mi.arch_opcode, s[0]->arch_opcode());
1539 EXPECT_EQ(1U, s[0]->InputCount());
1540 EXPECT_EQ(1U, s[0]->OutputCount());
1541}
1542
1543
1544INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
1545 InstructionSelectorConversionTest,
1546 ::testing::ValuesIn(kConversionInstructions));
1547
1548
1549// -----------------------------------------------------------------------------
1550// Memory access instructions.
1551
1552
1553namespace {
1554
1555struct MemoryAccess {
1556 MachineType type;
1557 ArchOpcode ldr_opcode;
1558 ArchOpcode str_opcode;
1559 const int32_t immediates[20];
1560};
1561
1562
1563std::ostream& operator<<(std::ostream& os, const MemoryAccess& memacc) {
1564 return os << memacc.type;
1565}
1566
1567} // namespace
1568
1569
1570static const MemoryAccess kMemoryAccesses[] = {
1571 {kMachInt8,
1572 kArm64Ldrsb,
1573 kArm64Strb,
1574 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 257, 258, 1000, 1001, 2121,
1575 2442, 4093, 4094, 4095}},
1576 {kMachUint8,
1577 kArm64Ldrb,
1578 kArm64Strb,
1579 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 257, 258, 1000, 1001, 2121,
1580 2442, 4093, 4094, 4095}},
1581 {kMachInt16,
1582 kArm64Ldrsh,
1583 kArm64Strh,
1584 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 258, 260, 4096, 4098, 4100,
1585 4242, 6786, 8188, 8190}},
1586 {kMachUint16,
1587 kArm64Ldrh,
1588 kArm64Strh,
1589 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 258, 260, 4096, 4098, 4100,
1590 4242, 6786, 8188, 8190}},
1591 {kMachInt32,
1592 kArm64LdrW,
1593 kArm64StrW,
1594 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 260, 4096, 4100, 8192, 8196,
1595 3276, 3280, 16376, 16380}},
1596 {kMachUint32,
1597 kArm64LdrW,
1598 kArm64StrW,
1599 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 260, 4096, 4100, 8192, 8196,
1600 3276, 3280, 16376, 16380}},
1601 {kMachInt64,
1602 kArm64Ldr,
1603 kArm64Str,
1604 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 264, 4096, 4104, 8192, 8200,
1605 16384, 16392, 32752, 32760}},
1606 {kMachUint64,
1607 kArm64Ldr,
1608 kArm64Str,
1609 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 264, 4096, 4104, 8192, 8200,
1610 16384, 16392, 32752, 32760}},
1611 {kMachFloat32,
1612 kArm64LdrS,
1613 kArm64StrS,
1614 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 260, 4096, 4100, 8192, 8196,
1615 3276, 3280, 16376, 16380}},
1616 {kMachFloat64,
1617 kArm64LdrD,
1618 kArm64StrD,
1619 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 264, 4096, 4104, 8192, 8200,
1620 16384, 16392, 32752, 32760}}};
1621
1622
1623typedef InstructionSelectorTestWithParam<MemoryAccess>
1624 InstructionSelectorMemoryAccessTest;
1625
1626
1627TEST_P(InstructionSelectorMemoryAccessTest, LoadWithParameters) {
1628 const MemoryAccess memacc = GetParam();
1629 StreamBuilder m(this, memacc.type, kMachPtr, kMachInt32);
1630 m.Return(m.Load(memacc.type, m.Parameter(0), m.Parameter(1)));
1631 Stream s = m.Build();
1632 ASSERT_EQ(1U, s.size());
1633 EXPECT_EQ(memacc.ldr_opcode, s[0]->arch_opcode());
1634 EXPECT_EQ(kMode_MRR, s[0]->addressing_mode());
1635 EXPECT_EQ(2U, s[0]->InputCount());
1636 EXPECT_EQ(1U, s[0]->OutputCount());
1637}
1638
1639
1640TEST_P(InstructionSelectorMemoryAccessTest, LoadWithImmediateIndex) {
1641 const MemoryAccess memacc = GetParam();
1642 TRACED_FOREACH(int32_t, index, memacc.immediates) {
1643 StreamBuilder m(this, memacc.type, kMachPtr);
1644 m.Return(m.Load(memacc.type, m.Parameter(0), m.Int32Constant(index)));
1645 Stream s = m.Build();
1646 ASSERT_EQ(1U, s.size());
1647 EXPECT_EQ(memacc.ldr_opcode, s[0]->arch_opcode());
1648 EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
1649 EXPECT_EQ(2U, s[0]->InputCount());
1650 ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
1651 EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
1652 ASSERT_EQ(1U, s[0]->OutputCount());
1653 }
1654}
1655
1656
1657TEST_P(InstructionSelectorMemoryAccessTest, StoreWithParameters) {
1658 const MemoryAccess memacc = GetParam();
1659 StreamBuilder m(this, kMachInt32, kMachPtr, kMachInt32, memacc.type);
1660 m.Store(memacc.type, m.Parameter(0), m.Parameter(1), m.Parameter(2));
1661 m.Return(m.Int32Constant(0));
1662 Stream s = m.Build();
1663 ASSERT_EQ(1U, s.size());
1664 EXPECT_EQ(memacc.str_opcode, s[0]->arch_opcode());
1665 EXPECT_EQ(kMode_MRR, s[0]->addressing_mode());
1666 EXPECT_EQ(3U, s[0]->InputCount());
1667 EXPECT_EQ(0U, s[0]->OutputCount());
1668}
1669
1670
1671TEST_P(InstructionSelectorMemoryAccessTest, StoreWithImmediateIndex) {
1672 const MemoryAccess memacc = GetParam();
1673 TRACED_FOREACH(int32_t, index, memacc.immediates) {
1674 StreamBuilder m(this, kMachInt32, kMachPtr, memacc.type);
1675 m.Store(memacc.type, m.Parameter(0), m.Int32Constant(index),
1676 m.Parameter(1));
1677 m.Return(m.Int32Constant(0));
1678 Stream s = m.Build();
1679 ASSERT_EQ(1U, s.size());
1680 EXPECT_EQ(memacc.str_opcode, s[0]->arch_opcode());
1681 EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
1682 ASSERT_EQ(3U, s[0]->InputCount());
1683 ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
1684 EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
1685 EXPECT_EQ(0U, s[0]->OutputCount());
1686 }
1687}
1688
1689
1690INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
1691 InstructionSelectorMemoryAccessTest,
1692 ::testing::ValuesIn(kMemoryAccesses));
1693
1694
1695// -----------------------------------------------------------------------------
1696// Comparison instructions.
1697
1698static const MachInst2 kComparisonInstructions[] = {
1699 {&RawMachineAssembler::Word32Equal, "Word32Equal", kArm64Cmp32, kMachInt32},
1700 {&RawMachineAssembler::Word64Equal, "Word64Equal", kArm64Cmp, kMachInt64},
1701};
1702
1703
1704typedef InstructionSelectorTestWithParam<MachInst2>
1705 InstructionSelectorComparisonTest;
1706
1707
1708TEST_P(InstructionSelectorComparisonTest, WithParameters) {
1709 const MachInst2 cmp = GetParam();
1710 const MachineType type = cmp.machine_type;
1711 StreamBuilder m(this, type, type, type);
1712 m.Return((m.*cmp.constructor)(m.Parameter(0), m.Parameter(1)));
1713 Stream s = m.Build();
1714 ASSERT_EQ(1U, s.size());
1715 EXPECT_EQ(cmp.arch_opcode, s[0]->arch_opcode());
1716 EXPECT_EQ(2U, s[0]->InputCount());
1717 EXPECT_EQ(1U, s[0]->OutputCount());
1718 EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1719 EXPECT_EQ(kEqual, s[0]->flags_condition());
1720}
1721
1722
1723TEST_P(InstructionSelectorComparisonTest, WithImmediate) {
1724 const MachInst2 cmp = GetParam();
1725 const MachineType type = cmp.machine_type;
1726 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
1727 // Compare with 0 are turned into tst instruction.
1728 if (imm == 0) continue;
1729 StreamBuilder m(this, type, type);
1730 m.Return((m.*cmp.constructor)(m.Parameter(0), BuildConstant(m, type, imm)));
1731 Stream s = m.Build();
1732 ASSERT_EQ(1U, s.size());
1733 EXPECT_EQ(cmp.arch_opcode, s[0]->arch_opcode());
1734 ASSERT_EQ(2U, s[0]->InputCount());
1735 ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
1736 EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1)));
1737 EXPECT_EQ(1U, s[0]->OutputCount());
1738 EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1739 EXPECT_EQ(kEqual, s[0]->flags_condition());
1740 }
1741 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
1742 // Compare with 0 are turned into tst instruction.
1743 if (imm == 0) continue;
1744 StreamBuilder m(this, type, type);
1745 m.Return((m.*cmp.constructor)(BuildConstant(m, type, imm), m.Parameter(0)));
1746 Stream s = m.Build();
1747 ASSERT_EQ(1U, s.size());
1748 EXPECT_EQ(cmp.arch_opcode, s[0]->arch_opcode());
1749 ASSERT_EQ(2U, s[0]->InputCount());
1750 ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
1751 EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1)));
1752 EXPECT_EQ(1U, s[0]->OutputCount());
1753 EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1754 EXPECT_EQ(kEqual, s[0]->flags_condition());
1755 }
1756}
1757
1758INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
1759 InstructionSelectorComparisonTest,
1760 ::testing::ValuesIn(kComparisonInstructions));
1761
1762
1763TEST_F(InstructionSelectorTest, Word32EqualWithZero) {
1764 {
1765 StreamBuilder m(this, kMachInt32, kMachInt32);
1766 m.Return(m.Word32Equal(m.Parameter(0), m.Int32Constant(0)));
1767 Stream s = m.Build();
1768 ASSERT_EQ(1U, s.size());
1769 EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode());
1770 ASSERT_EQ(2U, s[0]->InputCount());
1771 EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
1772 EXPECT_EQ(1U, s[0]->OutputCount());
1773 EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1774 EXPECT_EQ(kEqual, s[0]->flags_condition());
1775 }
1776 {
1777 StreamBuilder m(this, kMachInt32, kMachInt32);
1778 m.Return(m.Word32Equal(m.Int32Constant(0), m.Parameter(0)));
1779 Stream s = m.Build();
1780 ASSERT_EQ(1U, s.size());
1781 EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode());
1782 ASSERT_EQ(2U, s[0]->InputCount());
1783 EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
1784 EXPECT_EQ(1U, s[0]->OutputCount());
1785 EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1786 EXPECT_EQ(kEqual, s[0]->flags_condition());
1787 }
1788}
1789
1790
1791TEST_F(InstructionSelectorTest, Word64EqualWithZero) {
1792 {
1793 StreamBuilder m(this, kMachInt64, kMachInt64);
1794 m.Return(m.Word64Equal(m.Parameter(0), m.Int64Constant(0)));
1795 Stream s = m.Build();
1796 ASSERT_EQ(1U, s.size());
1797 EXPECT_EQ(kArm64Tst, s[0]->arch_opcode());
1798 ASSERT_EQ(2U, s[0]->InputCount());
1799 EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
1800 EXPECT_EQ(1U, s[0]->OutputCount());
1801 EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1802 EXPECT_EQ(kEqual, s[0]->flags_condition());
1803 }
1804 {
1805 StreamBuilder m(this, kMachInt64, kMachInt64);
1806 m.Return(m.Word64Equal(m.Int64Constant(0), m.Parameter(0)));
1807 Stream s = m.Build();
1808 ASSERT_EQ(1U, s.size());
1809 EXPECT_EQ(kArm64Tst, s[0]->arch_opcode());
1810 ASSERT_EQ(2U, s[0]->InputCount());
1811 EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
1812 EXPECT_EQ(1U, s[0]->OutputCount());
1813 EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1814 EXPECT_EQ(kEqual, s[0]->flags_condition());
1815 }
1816}
1817
1818
1819// -----------------------------------------------------------------------------
1820// Miscellaneous
1821
1822
1823static const MachInst2 kLogicalWithNotRHSs[] = {
1824 {&RawMachineAssembler::Word32And, "Word32And", kArm64Bic32, kMachInt32},
1825 {&RawMachineAssembler::Word64And, "Word64And", kArm64Bic, kMachInt64},
1826 {&RawMachineAssembler::Word32Or, "Word32Or", kArm64Orn32, kMachInt32},
1827 {&RawMachineAssembler::Word64Or, "Word64Or", kArm64Orn, kMachInt64},
1828 {&RawMachineAssembler::Word32Xor, "Word32Xor", kArm64Eon32, kMachInt32},
1829 {&RawMachineAssembler::Word64Xor, "Word64Xor", kArm64Eon, kMachInt64}};
1830
1831
1832typedef InstructionSelectorTestWithParam<MachInst2>
1833 InstructionSelectorLogicalWithNotRHSTest;
1834
1835
1836TEST_P(InstructionSelectorLogicalWithNotRHSTest, Parameter) {
1837 const MachInst2 inst = GetParam();
1838 const MachineType type = inst.machine_type;
1839 // Test cases where RHS is Xor(x, -1).
1840 {
1841 StreamBuilder m(this, type, type, type);
1842 if (type == kMachInt32) {
1843 m.Return((m.*inst.constructor)(
1844 m.Parameter(0), m.Word32Xor(m.Parameter(1), m.Int32Constant(-1))));
1845 } else {
1846 ASSERT_EQ(kMachInt64, type);
1847 m.Return((m.*inst.constructor)(
1848 m.Parameter(0), m.Word64Xor(m.Parameter(1), m.Int64Constant(-1))));
1849 }
1850 Stream s = m.Build();
1851 ASSERT_EQ(1U, s.size());
1852 EXPECT_EQ(inst.arch_opcode, s[0]->arch_opcode());
1853 EXPECT_EQ(2U, s[0]->InputCount());
1854 EXPECT_EQ(1U, s[0]->OutputCount());
1855 }
1856 {
1857 StreamBuilder m(this, type, type, type);
1858 if (type == kMachInt32) {
1859 m.Return((m.*inst.constructor)(
1860 m.Word32Xor(m.Parameter(0), m.Int32Constant(-1)), m.Parameter(1)));
1861 } else {
1862 ASSERT_EQ(kMachInt64, type);
1863 m.Return((m.*inst.constructor)(
1864 m.Word64Xor(m.Parameter(0), m.Int64Constant(-1)), m.Parameter(1)));
1865 }
1866 Stream s = m.Build();
1867 ASSERT_EQ(1U, s.size());
1868 EXPECT_EQ(inst.arch_opcode, s[0]->arch_opcode());
1869 EXPECT_EQ(2U, s[0]->InputCount());
1870 EXPECT_EQ(1U, s[0]->OutputCount());
1871 }
1872 // Test cases where RHS is Not(x).
1873 {
1874 StreamBuilder m(this, type, type, type);
1875 if (type == kMachInt32) {
1876 m.Return(
1877 (m.*inst.constructor)(m.Parameter(0), m.Word32Not(m.Parameter(1))));
1878 } else {
1879 ASSERT_EQ(kMachInt64, type);
1880 m.Return(
1881 (m.*inst.constructor)(m.Parameter(0), m.Word64Not(m.Parameter(1))));
1882 }
1883 Stream s = m.Build();
1884 ASSERT_EQ(1U, s.size());
1885 EXPECT_EQ(inst.arch_opcode, s[0]->arch_opcode());
1886 EXPECT_EQ(2U, s[0]->InputCount());
1887 EXPECT_EQ(1U, s[0]->OutputCount());
1888 }
1889 {
1890 StreamBuilder m(this, type, type, type);
1891 if (type == kMachInt32) {
1892 m.Return(
1893 (m.*inst.constructor)(m.Word32Not(m.Parameter(0)), m.Parameter(1)));
1894 } else {
1895 ASSERT_EQ(kMachInt64, type);
1896 m.Return(
1897 (m.*inst.constructor)(m.Word64Not(m.Parameter(0)), m.Parameter(1)));
1898 }
1899 Stream s = m.Build();
1900 ASSERT_EQ(1U, s.size());
1901 EXPECT_EQ(inst.arch_opcode, s[0]->arch_opcode());
1902 EXPECT_EQ(2U, s[0]->InputCount());
1903 EXPECT_EQ(1U, s[0]->OutputCount());
1904 }
1905}
1906
1907
1908INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
1909 InstructionSelectorLogicalWithNotRHSTest,
1910 ::testing::ValuesIn(kLogicalWithNotRHSs));
1911
1912
1913TEST_F(InstructionSelectorTest, Word32NotWithParameter) {
1914 StreamBuilder m(this, kMachInt32, kMachInt32);
1915 m.Return(m.Word32Not(m.Parameter(0)));
1916 Stream s = m.Build();
1917 ASSERT_EQ(1U, s.size());
1918 EXPECT_EQ(kArm64Not32, s[0]->arch_opcode());
1919 EXPECT_EQ(1U, s[0]->InputCount());
1920 EXPECT_EQ(1U, s[0]->OutputCount());
1921}
1922
1923
1924TEST_F(InstructionSelectorTest, Word64NotWithParameter) {
1925 StreamBuilder m(this, kMachInt64, kMachInt64);
1926 m.Return(m.Word64Not(m.Parameter(0)));
1927 Stream s = m.Build();
1928 ASSERT_EQ(1U, s.size());
1929 EXPECT_EQ(kArm64Not, s[0]->arch_opcode());
1930 EXPECT_EQ(1U, s[0]->InputCount());
1931 EXPECT_EQ(1U, s[0]->OutputCount());
1932}
1933
1934
1935TEST_F(InstructionSelectorTest, Word32XorMinusOneWithParameter) {
1936 {
1937 StreamBuilder m(this, kMachInt32, kMachInt32);
1938 m.Return(m.Word32Xor(m.Parameter(0), m.Int32Constant(-1)));
1939 Stream s = m.Build();
1940 ASSERT_EQ(1U, s.size());
1941 EXPECT_EQ(kArm64Not32, s[0]->arch_opcode());
1942 EXPECT_EQ(1U, s[0]->InputCount());
1943 EXPECT_EQ(1U, s[0]->OutputCount());
1944 }
1945 {
1946 StreamBuilder m(this, kMachInt32, kMachInt32);
1947 m.Return(m.Word32Xor(m.Int32Constant(-1), m.Parameter(0)));
1948 Stream s = m.Build();
1949 ASSERT_EQ(1U, s.size());
1950 EXPECT_EQ(kArm64Not32, s[0]->arch_opcode());
1951 EXPECT_EQ(1U, s[0]->InputCount());
1952 EXPECT_EQ(1U, s[0]->OutputCount());
1953 }
1954}
1955
1956
1957TEST_F(InstructionSelectorTest, Word64XorMinusOneWithParameter) {
1958 {
1959 StreamBuilder m(this, kMachInt64, kMachInt64);
1960 m.Return(m.Word64Xor(m.Parameter(0), m.Int64Constant(-1)));
1961 Stream s = m.Build();
1962 ASSERT_EQ(1U, s.size());
1963 EXPECT_EQ(kArm64Not, s[0]->arch_opcode());
1964 EXPECT_EQ(1U, s[0]->InputCount());
1965 EXPECT_EQ(1U, s[0]->OutputCount());
1966 }
1967 {
1968 StreamBuilder m(this, kMachInt64, kMachInt64);
1969 m.Return(m.Word64Xor(m.Int64Constant(-1), m.Parameter(0)));
1970 Stream s = m.Build();
1971 ASSERT_EQ(1U, s.size());
1972 EXPECT_EQ(kArm64Not, s[0]->arch_opcode());
1973 EXPECT_EQ(1U, s[0]->InputCount());
1974 EXPECT_EQ(1U, s[0]->OutputCount());
1975 }
1976}
1977
1978
1979TEST_F(InstructionSelectorTest, Word32ShrWithWord32AndWithImmediate) {
1980 TRACED_FORRANGE(int32_t, lsb, 1, 31) {
1981 TRACED_FORRANGE(int32_t, width, 1, 32 - lsb) {
1982 uint32_t jnk = rng()->NextInt();
1983 jnk >>= 32 - lsb;
1984 uint32_t msk = ((0xffffffffu >> (32 - width)) << lsb) | jnk;
1985 StreamBuilder m(this, kMachInt32, kMachInt32);
1986 m.Return(m.Word32Shr(m.Word32And(m.Parameter(0), m.Int32Constant(msk)),
1987 m.Int32Constant(lsb)));
1988 Stream s = m.Build();
1989 ASSERT_EQ(1U, s.size());
1990 EXPECT_EQ(kArm64Ubfx32, s[0]->arch_opcode());
1991 ASSERT_EQ(3U, s[0]->InputCount());
1992 EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1)));
1993 EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2)));
1994 }
1995 }
1996 TRACED_FORRANGE(int32_t, lsb, 1, 31) {
1997 TRACED_FORRANGE(int32_t, width, 1, 32 - lsb) {
1998 uint32_t jnk = rng()->NextInt();
1999 jnk >>= 32 - lsb;
2000 uint32_t msk = ((0xffffffffu >> (32 - width)) << lsb) | jnk;
2001 StreamBuilder m(this, kMachInt32, kMachInt32);
2002 m.Return(m.Word32Shr(m.Word32And(m.Int32Constant(msk), m.Parameter(0)),
2003 m.Int32Constant(lsb)));
2004 Stream s = m.Build();
2005 ASSERT_EQ(1U, s.size());
2006 EXPECT_EQ(kArm64Ubfx32, s[0]->arch_opcode());
2007 ASSERT_EQ(3U, s[0]->InputCount());
2008 EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1)));
2009 EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2)));
2010 }
2011 }
2012}
2013
2014
2015TEST_F(InstructionSelectorTest, Word64ShrWithWord64AndWithImmediate) {
2016 TRACED_FORRANGE(int32_t, lsb, 1, 63) {
2017 TRACED_FORRANGE(int32_t, width, 1, 64 - lsb) {
2018 uint64_t jnk = rng()->NextInt64();
2019 jnk >>= 64 - lsb;
2020 uint64_t msk =
2021 ((V8_UINT64_C(0xffffffffffffffff) >> (64 - width)) << lsb) | jnk;
2022 StreamBuilder m(this, kMachInt64, kMachInt64);
2023 m.Return(m.Word64Shr(m.Word64And(m.Parameter(0), m.Int64Constant(msk)),
2024 m.Int64Constant(lsb)));
2025 Stream s = m.Build();
2026 ASSERT_EQ(1U, s.size());
2027 EXPECT_EQ(kArm64Ubfx, s[0]->arch_opcode());
2028 ASSERT_EQ(3U, s[0]->InputCount());
2029 EXPECT_EQ(lsb, s.ToInt64(s[0]->InputAt(1)));
2030 EXPECT_EQ(width, s.ToInt64(s[0]->InputAt(2)));
2031 }
2032 }
2033 TRACED_FORRANGE(int32_t, lsb, 1, 63) {
2034 TRACED_FORRANGE(int32_t, width, 1, 64 - lsb) {
2035 uint64_t jnk = rng()->NextInt64();
2036 jnk >>= 64 - lsb;
2037 uint64_t msk =
2038 ((V8_UINT64_C(0xffffffffffffffff) >> (64 - width)) << lsb) | jnk;
2039 StreamBuilder m(this, kMachInt64, kMachInt64);
2040 m.Return(m.Word64Shr(m.Word64And(m.Int64Constant(msk), m.Parameter(0)),
2041 m.Int64Constant(lsb)));
2042 Stream s = m.Build();
2043 ASSERT_EQ(1U, s.size());
2044 EXPECT_EQ(kArm64Ubfx, s[0]->arch_opcode());
2045 ASSERT_EQ(3U, s[0]->InputCount());
2046 EXPECT_EQ(lsb, s.ToInt64(s[0]->InputAt(1)));
2047 EXPECT_EQ(width, s.ToInt64(s[0]->InputAt(2)));
2048 }
2049 }
2050}
2051
2052
2053TEST_F(InstructionSelectorTest, Word32AndWithImmediateWithWord32Shr) {
2054 TRACED_FORRANGE(int32_t, lsb, 1, 31) {
2055 TRACED_FORRANGE(int32_t, width, 1, 31) {
2056 uint32_t msk = (1 << width) - 1;
2057 StreamBuilder m(this, kMachInt32, kMachInt32);
2058 m.Return(m.Word32And(m.Word32Shr(m.Parameter(0), m.Int32Constant(lsb)),
2059 m.Int32Constant(msk)));
2060 Stream s = m.Build();
2061 ASSERT_EQ(1U, s.size());
2062 EXPECT_EQ(kArm64Ubfx32, s[0]->arch_opcode());
2063 ASSERT_EQ(3U, s[0]->InputCount());
2064 EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1)));
2065 int32_t actual_width = (lsb + width > 32) ? (32 - lsb) : width;
2066 EXPECT_EQ(actual_width, s.ToInt32(s[0]->InputAt(2)));
2067 }
2068 }
2069 TRACED_FORRANGE(int32_t, lsb, 1, 31) {
2070 TRACED_FORRANGE(int32_t, width, 1, 31) {
2071 uint32_t msk = (1 << width) - 1;
2072 StreamBuilder m(this, kMachInt32, kMachInt32);
2073 m.Return(m.Word32And(m.Int32Constant(msk),
2074 m.Word32Shr(m.Parameter(0), m.Int32Constant(lsb))));
2075 Stream s = m.Build();
2076 ASSERT_EQ(1U, s.size());
2077 EXPECT_EQ(kArm64Ubfx32, s[0]->arch_opcode());
2078 ASSERT_EQ(3U, s[0]->InputCount());
2079 EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1)));
2080 int32_t actual_width = (lsb + width > 32) ? (32 - lsb) : width;
2081 EXPECT_EQ(actual_width, s.ToInt32(s[0]->InputAt(2)));
2082 }
2083 }
2084}
2085
2086
2087TEST_F(InstructionSelectorTest, Word64AndWithImmediateWithWord64Shr) {
2088 TRACED_FORRANGE(int64_t, lsb, 1, 63) {
2089 TRACED_FORRANGE(int64_t, width, 1, 63) {
2090 uint64_t msk = (V8_UINT64_C(1) << width) - 1;
2091 StreamBuilder m(this, kMachInt64, kMachInt64);
2092 m.Return(m.Word64And(m.Word64Shr(m.Parameter(0), m.Int64Constant(lsb)),
2093 m.Int64Constant(msk)));
2094 Stream s = m.Build();
2095 ASSERT_EQ(1U, s.size());
2096 EXPECT_EQ(kArm64Ubfx, s[0]->arch_opcode());
2097 ASSERT_EQ(3U, s[0]->InputCount());
2098 EXPECT_EQ(lsb, s.ToInt64(s[0]->InputAt(1)));
2099 int64_t actual_width = (lsb + width > 64) ? (64 - lsb) : width;
2100 EXPECT_EQ(actual_width, s.ToInt64(s[0]->InputAt(2)));
2101 }
2102 }
2103 TRACED_FORRANGE(int64_t, lsb, 1, 63) {
2104 TRACED_FORRANGE(int64_t, width, 1, 63) {
2105 uint64_t msk = (V8_UINT64_C(1) << width) - 1;
2106 StreamBuilder m(this, kMachInt64, kMachInt64);
2107 m.Return(m.Word64And(m.Int64Constant(msk),
2108 m.Word64Shr(m.Parameter(0), m.Int64Constant(lsb))));
2109 Stream s = m.Build();
2110 ASSERT_EQ(1U, s.size());
2111 EXPECT_EQ(kArm64Ubfx, s[0]->arch_opcode());
2112 ASSERT_EQ(3U, s[0]->InputCount());
2113 EXPECT_EQ(lsb, s.ToInt64(s[0]->InputAt(1)));
2114 int64_t actual_width = (lsb + width > 64) ? (64 - lsb) : width;
2115 EXPECT_EQ(actual_width, s.ToInt64(s[0]->InputAt(2)));
2116 }
2117 }
2118}
2119
2120
2121TEST_F(InstructionSelectorTest, Int32MulHighWithParameters) {
2122 StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
2123 Node* const p0 = m.Parameter(0);
2124 Node* const p1 = m.Parameter(1);
2125 Node* const n = m.Int32MulHigh(p0, p1);
2126 m.Return(n);
2127 Stream s = m.Build();
2128 ASSERT_EQ(2U, s.size());
2129 EXPECT_EQ(kArm64Smull, s[0]->arch_opcode());
2130 ASSERT_EQ(2U, s[0]->InputCount());
2131 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
2132 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
2133 ASSERT_EQ(1U, s[0]->OutputCount());
2134 EXPECT_EQ(kArm64Asr, s[1]->arch_opcode());
2135 ASSERT_EQ(2U, s[1]->InputCount());
2136 EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[1]->InputAt(0)));
2137 EXPECT_EQ(32, s.ToInt64(s[1]->InputAt(1)));
2138 ASSERT_EQ(1U, s[1]->OutputCount());
2139 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[1]->Output()));
2140}
2141
2142
2143TEST_F(InstructionSelectorTest, Word32SarWithWord32Shl) {
2144 {
2145 StreamBuilder m(this, kMachInt32, kMachInt32);
2146 Node* const p0 = m.Parameter(0);
2147 Node* const r =
2148 m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(24)), m.Int32Constant(24));
2149 m.Return(r);
2150 Stream s = m.Build();
2151 ASSERT_EQ(1U, s.size());
2152 EXPECT_EQ(kArm64Sxtb32, s[0]->arch_opcode());
2153 ASSERT_EQ(1U, s[0]->InputCount());
2154 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
2155 ASSERT_EQ(1U, s[0]->OutputCount());
2156 EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
2157 }
2158 {
2159 StreamBuilder m(this, kMachInt32, kMachInt32);
2160 Node* const p0 = m.Parameter(0);
2161 Node* const r =
2162 m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(16)), m.Int32Constant(16));
2163 m.Return(r);
2164 Stream s = m.Build();
2165 ASSERT_EQ(1U, s.size());
2166 EXPECT_EQ(kArm64Sxth32, s[0]->arch_opcode());
2167 ASSERT_EQ(1U, s[0]->InputCount());
2168 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
2169 ASSERT_EQ(1U, s[0]->OutputCount());
2170 EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
2171 }
2172}
2173
2174} // namespace compiler
2175} // namespace internal
2176} // namespace v8