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.
5 #include "test/unittests/compiler/instruction-selector-unittest.h"
13 typedef RawMachineAssembler::Label MLabel;
18 const char* constructor_name;
19 ArchOpcode arch_opcode;
20 MachineType machine_type;
23 typedef MachInst<Node* (RawMachineAssembler::*)(Node*)> MachInst1;
24 typedef MachInst<Node* (RawMachineAssembler::*)(Node*, Node*)> MachInst2;
28 std::ostream& operator<<(std::ostream& os, const MachInst<T>& mi) {
29 return os << mi.constructor_name;
39 std::ostream& operator<<(std::ostream& os, const Shift& shift) {
40 return os << shift.mi;
44 // Helper to build Int32Constant or Int64Constant depending on the given
46 Node* BuildConstant(InstructionSelectorTest::StreamBuilder& m, MachineType type,
50 return m.Int32Constant(value);
54 return m.Int64Constant(value);
64 // ARM64 logical instructions.
65 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}};
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.
77 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};
97 // Random subset of 64-bit logical immediates.
98 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,
122 // ARM64 arithmetic instructions.
125 ArchOpcode negate_arch_opcode;
129 std::ostream& operator<<(std::ostream& os, const AddSub& op) {
134 const AddSub kAddSubInstructions[] = {
135 {{&RawMachineAssembler::Int32Add, "Int32Add", kArm64Add32, kMachInt32},
137 {{&RawMachineAssembler::Int64Add, "Int64Add", kArm64Add, kMachInt64},
139 {{&RawMachineAssembler::Int32Sub, "Int32Sub", kArm64Sub32, kMachInt32},
141 {{&RawMachineAssembler::Int64Sub, "Int64Sub", kArm64Sub, kMachInt64},
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.
147 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};
162 // ARM64 flag setting data processing instructions.
163 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}};
170 // ARM64 arithmetic with overflow instructions.
171 const MachInst2 kOvfAddSubInstructions[] = {
172 {&RawMachineAssembler::Int32AddWithOverflow, "Int32AddWithOverflow",
173 kArm64Add32, kMachInt32},
174 {&RawMachineAssembler::Int32SubWithOverflow, "Int32SubWithOverflow",
175 kArm64Sub32, kMachInt32}};
178 // ARM64 shift instructions.
179 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}};
198 // ARM64 Mul/Div instructions.
199 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}};
208 // ARM64 FP arithmetic instructions.
209 const MachInst2 kFPArithInstructions[] = {
210 {&RawMachineAssembler::Float64Add, "Float64Add", kArm64Float64Add,
212 {&RawMachineAssembler::Float64Sub, "Float64Sub", kArm64Float64Sub,
214 {&RawMachineAssembler::Float64Mul, "Float64Mul", kArm64Float64Mul,
216 {&RawMachineAssembler::Float64Div, "Float64Div", kArm64Float64Div,
226 std::ostream& operator<<(std::ostream& os, const FPCmp& cmp) {
231 // ARM64 FP comparison instructions.
232 const FPCmp kFPCmpInstructions[] = {
233 {{&RawMachineAssembler::Float64Equal, "Float64Equal", kArm64Float64Cmp,
236 {{&RawMachineAssembler::Float64LessThan, "Float64LessThan",
237 kArm64Float64Cmp, kMachFloat64},
239 {{&RawMachineAssembler::Float64LessThanOrEqual, "Float64LessThanOrEqual",
240 kArm64Float64Cmp, kMachFloat64},
241 kUnsignedLessThanOrEqual}};
245 // The machine_type field in MachInst1 represents the destination type.
247 MachineType src_machine_type;
251 std::ostream& operator<<(std::ostream& os, const Conversion& conv) {
252 return os << conv.mi;
256 // ARM64 type conversion instructions.
257 const Conversion kConversionInstructions[] = {
258 {{&RawMachineAssembler::ChangeFloat32ToFloat64, "ChangeFloat32ToFloat64",
259 kArm64Float32ToFloat64, kMachFloat64},
261 {{&RawMachineAssembler::TruncateFloat64ToFloat32,
262 "TruncateFloat64ToFloat32", kArm64Float64ToFloat32, kMachFloat32},
264 {{&RawMachineAssembler::ChangeInt32ToInt64, "ChangeInt32ToInt64",
265 kArm64Sxtw, kMachInt64},
267 {{&RawMachineAssembler::ChangeUint32ToUint64, "ChangeUint32ToUint64",
268 kArm64Mov32, kMachUint64},
270 {{&RawMachineAssembler::TruncateInt64ToInt32, "TruncateInt64ToInt32",
271 kArm64Mov32, kMachInt32},
273 {{&RawMachineAssembler::ChangeInt32ToFloat64, "ChangeInt32ToFloat64",
274 kArm64Int32ToFloat64, kMachFloat64},
276 {{&RawMachineAssembler::ChangeUint32ToFloat64, "ChangeUint32ToFloat64",
277 kArm64Uint32ToFloat64, kMachFloat64},
279 {{&RawMachineAssembler::ChangeFloat64ToInt32, "ChangeFloat64ToInt32",
280 kArm64Float64ToInt32, kMachInt32},
282 {{&RawMachineAssembler::ChangeFloat64ToUint32, "ChangeFloat64ToUint32",
283 kArm64Float64ToUint32, kMachUint32},
289 // -----------------------------------------------------------------------------
290 // Logical instructions.
293 typedef InstructionSelectorTestWithParam<MachInst2>
294 InstructionSelectorLogicalTest;
297 TEST_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());
310 TEST_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());
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());
344 TEST_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;
351 TRACED_FORRANGE(int, imm, 0, ((type == kMachInt32) ? 31 : 63)) {
352 StreamBuilder m(this, type, type, type);
353 m.Return((m.*dpi.constructor)(
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());
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)),
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());
384 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorLogicalTest,
385 ::testing::ValuesIn(kLogicalInstructions));
388 // -----------------------------------------------------------------------------
389 // Add and Sub instructions.
391 typedef InstructionSelectorTestWithParam<AddSub> InstructionSelectorAddSubTest;
394 TEST_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());
407 TEST_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);
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());
425 TEST_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);
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());
444 TEST_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;
451 if ((shift.mi.arch_opcode == kArm64Ror32) ||
452 (shift.mi.arch_opcode == kArm64Ror)) {
453 // Not supported by add/sub instructions.
457 TRACED_FORRANGE(int, imm, 0, ((type == kMachInt32) ? 31 : 63)) {
458 StreamBuilder m(this, type, type, type);
459 m.Return((m.*dpi.mi.constructor)(
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());
475 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorAddSubTest,
476 ::testing::ValuesIn(kAddSubInstructions));
479 TEST_F(InstructionSelectorTest, AddImmediateOnLeft) {
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());
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());
511 TEST_F(InstructionSelectorTest, SubZeroOnLeft) {
512 // Subtraction with zero on the left maps to Neg.
515 StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
516 m.Return(m.Int32Sub(m.Int32Constant(0), m.Parameter(0)));
517 Stream s = m.Build();
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());
526 StreamBuilder m(this, kMachInt64, kMachInt64, kMachInt64);
527 m.Return(m.Int64Sub(m.Int64Constant(0), m.Parameter(0)));
528 Stream s = m.Build();
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());
538 TEST_F(InstructionSelectorTest, AddNegImmediateOnLeft) {
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();
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());
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();
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());
574 TEST_F(InstructionSelectorTest, AddShiftByImmediateOnLeft) {
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;
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)),
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());
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;
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)),
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());
619 // -----------------------------------------------------------------------------
620 // Data processing controlled branches.
623 typedef InstructionSelectorTestWithParam<MachInst2>
624 InstructionSelectorDPFlagSetTest;
627 TEST_P(InstructionSelectorDPFlagSetTest, BranchWithParameters) {
628 const MachInst2 dpi = GetParam();
629 const MachineType type = dpi.machine_type;
630 StreamBuilder m(this, type, type, type);
632 m.Branch((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)), &a, &b);
634 m.Return(m.Int32Constant(1));
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());
645 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
646 InstructionSelectorDPFlagSetTest,
647 ::testing::ValuesIn(kDPFlagSetInstructions));
650 TEST_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;
655 StreamBuilder m(this, kMachInt32, kMachInt32);
657 m.Branch(m.Word32And(m.Parameter(0), m.Int32Constant(imm)), &a, &b);
659 m.Return(m.Int32Constant(1));
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());
673 TEST_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;
678 StreamBuilder m(this, kMachInt64, kMachInt64);
680 m.Branch(m.Word64And(m.Parameter(0), m.Int64Constant(imm)), &a, &b);
682 m.Return(m.Int32Constant(1));
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());
696 TEST_F(InstructionSelectorTest, AddBranchWithImmediateOnRight) {
697 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
698 StreamBuilder m(this, kMachInt32, kMachInt32);
700 m.Branch(m.Int32Add(m.Parameter(0), m.Int32Constant(imm)), &a, &b);
702 m.Return(m.Int32Constant(1));
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());
714 TEST_F(InstructionSelectorTest, SubBranchWithImmediateOnRight) {
715 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
716 StreamBuilder m(this, kMachInt32, kMachInt32);
718 m.Branch(m.Int32Sub(m.Parameter(0), m.Int32Constant(imm)), &a, &b);
720 m.Return(m.Int32Constant(1));
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());
732 TEST_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;
737 StreamBuilder m(this, kMachInt32, kMachInt32);
739 m.Branch(m.Word32And(m.Int32Constant(imm), m.Parameter(0)), &a, &b);
741 m.Return(m.Int32Constant(1));
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());
756 TEST_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;
761 StreamBuilder m(this, kMachInt64, kMachInt64);
763 m.Branch(m.Word64And(m.Int64Constant(imm), m.Parameter(0)), &a, &b);
765 m.Return(m.Int32Constant(1));
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());
780 TEST_F(InstructionSelectorTest, AddBranchWithImmediateOnLeft) {
781 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
782 StreamBuilder m(this, kMachInt32, kMachInt32);
784 m.Branch(m.Int32Add(m.Int32Constant(imm), m.Parameter(0)), &a, &b);
786 m.Return(m.Int32Constant(1));
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());
799 TEST_F(InstructionSelectorTest, Word32AndBranchWithOneBitMaskOnRight) {
800 TRACED_FORRANGE(int, bit, 0, 31) {
801 uint32_t mask = 1 << bit;
802 StreamBuilder m(this, kMachInt32, kMachInt32);
804 m.Branch(m.Word32And(m.Parameter(0), m.Int32Constant(mask)), &a, &b);
806 m.Return(m.Int32Constant(1));
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)));
818 TRACED_FORRANGE(int, bit, 0, 31) {
819 uint32_t mask = 1 << bit;
820 StreamBuilder m(this, kMachInt32, kMachInt32);
823 m.Word32BinaryNot(m.Word32And(m.Parameter(0), m.Int32Constant(mask))),
826 m.Return(m.Int32Constant(1));
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)));
840 TEST_F(InstructionSelectorTest, Word32AndBranchWithOneBitMaskOnLeft) {
841 TRACED_FORRANGE(int, bit, 0, 31) {
842 uint32_t mask = 1 << bit;
843 StreamBuilder m(this, kMachInt32, kMachInt32);
845 m.Branch(m.Word32And(m.Int32Constant(mask), m.Parameter(0)), &a, &b);
847 m.Return(m.Int32Constant(1));
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)));
859 TRACED_FORRANGE(int, bit, 0, 31) {
860 uint32_t mask = 1 << bit;
861 StreamBuilder m(this, kMachInt32, kMachInt32);
864 m.Word32BinaryNot(m.Word32And(m.Int32Constant(mask), m.Parameter(0))),
867 m.Return(m.Int32Constant(1));
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)));
881 TEST_F(InstructionSelectorTest, Word64AndBranchWithOneBitMaskOnRight) {
882 TRACED_FORRANGE(int, bit, 0, 63) {
883 uint64_t mask = 1L << bit;
884 StreamBuilder m(this, kMachInt64, kMachInt64);
886 m.Branch(m.Word64And(m.Parameter(0), m.Int64Constant(mask)), &a, &b);
888 m.Return(m.Int32Constant(1));
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)));
900 TRACED_FORRANGE(int, bit, 0, 63) {
901 uint64_t mask = 1L << bit;
902 StreamBuilder m(this, kMachInt64, kMachInt64);
905 m.Word64BinaryNot(m.Word64And(m.Parameter(0), m.Int64Constant(mask))),
908 m.Return(m.Int32Constant(1));
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)));
922 TEST_F(InstructionSelectorTest, Word64AndBranchWithOneBitMaskOnLeft) {
923 TRACED_FORRANGE(int, bit, 0, 63) {
924 uint64_t mask = 1L << bit;
925 StreamBuilder m(this, kMachInt64, kMachInt64);
927 m.Branch(m.Word64And(m.Int64Constant(mask), m.Parameter(0)), &a, &b);
929 m.Return(m.Int32Constant(1));
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)));
941 TRACED_FORRANGE(int, bit, 0, 63) {
942 uint64_t mask = 1L << bit;
943 StreamBuilder m(this, kMachInt64, kMachInt64);
946 m.Word64BinaryNot(m.Word64And(m.Int64Constant(mask), m.Parameter(0))),
949 m.Return(m.Int32Constant(1));
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)));
963 TEST_F(InstructionSelectorTest, CompareAgainstZeroAndBranch) {
965 StreamBuilder m(this, kMachInt32, kMachInt32);
967 Node* p0 = m.Parameter(0);
968 m.Branch(p0, &a, &b);
970 m.Return(m.Int32Constant(1));
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)));
982 StreamBuilder m(this, kMachInt32, kMachInt32);
984 Node* p0 = m.Parameter(0);
985 m.Branch(m.Word32BinaryNot(p0), &a, &b);
987 m.Return(m.Int32Constant(1));
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)));
1000 // -----------------------------------------------------------------------------
1001 // Add and subtract instructions with overflow.
1004 typedef InstructionSelectorTestWithParam<MachInst2>
1005 InstructionSelectorOvfAddSubTest;
1008 TEST_P(InstructionSelectorOvfAddSubTest, OvfParameter) {
1009 const MachInst2 dpi = GetParam();
1010 const MachineType type = dpi.machine_type;
1011 StreamBuilder m(this, type, type, type);
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());
1024 TEST_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());
1043 TEST_P(InstructionSelectorOvfAddSubTest, ValParameter) {
1044 const MachInst2 dpi = GetParam();
1045 const MachineType type = dpi.machine_type;
1046 StreamBuilder m(this, type, type, type);
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());
1058 TEST_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());
1076 TEST_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());
1092 TEST_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());
1111 TEST_P(InstructionSelectorOvfAddSubTest, BranchWithParameters) {
1112 const MachInst2 dpi = GetParam();
1113 const MachineType type = dpi.machine_type;
1114 StreamBuilder m(this, type, type, type);
1116 Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Parameter(1));
1117 m.Branch(m.Projection(1, n), &a, &b);
1119 m.Return(m.Int32Constant(0));
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());
1132 TEST_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);
1138 Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm));
1139 m.Branch(m.Projection(1, n), &a, &b);
1141 m.Return(m.Int32Constant(0));
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());
1155 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
1156 InstructionSelectorOvfAddSubTest,
1157 ::testing::ValuesIn(kOvfAddSubInstructions));
1160 TEST_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();
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());
1178 TEST_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();
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());
1195 TEST_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();
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());
1213 TEST_F(InstructionSelectorTest, OvfBranchWithImmediateOnLeft) {
1214 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
1215 StreamBuilder m(this, kMachInt32, kMachInt32);
1217 Node* n = m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0));
1218 m.Branch(m.Projection(1, n), &a, &b);
1220 m.Return(m.Int32Constant(0));
1222 m.Return(m.Projection(0, n));
1223 Stream s = m.Build();
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());
1236 // -----------------------------------------------------------------------------
1237 // Shift instructions.
1240 typedef InstructionSelectorTestWithParam<Shift> InstructionSelectorShiftTest;
1243 TEST_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());
1256 TEST_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());
1273 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorShiftTest,
1274 ::testing::ValuesIn(kShiftInstructions));
1277 TEST_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));
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()));
1295 TEST_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));
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()));
1313 TEST_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)));
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)));
1329 TEST_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)));
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)));
1347 // -----------------------------------------------------------------------------
1348 // Mul and Div instructions.
1351 typedef InstructionSelectorTestWithParam<MachInst2>
1352 InstructionSelectorMulDivTest;
1355 TEST_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());
1368 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorMulDivTest,
1369 ::testing::ValuesIn(kMulDivInstructions));
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;
1386 std::ostream& operator<<(std::ostream& os, const MulDPInst& inst) {
1387 return os << inst.mul_constructor_name;
1393 static const MulDPInst kMulDPInstructions[] = {
1394 {"Int32Mul", &RawMachineAssembler::Int32Mul, &RawMachineAssembler::Int32Add,
1395 &RawMachineAssembler::Int32Sub, kArm64Madd32, kArm64Msub32, kArm64Mneg32,
1397 {"Int64Mul", &RawMachineAssembler::Int64Mul, &RawMachineAssembler::Int64Add,
1398 &RawMachineAssembler::Int64Sub, kArm64Madd, kArm64Msub, kArm64Mneg,
1402 typedef InstructionSelectorTestWithParam<MulDPInst>
1403 InstructionSelectorIntDPWithIntMulTest;
1406 TEST_P(InstructionSelectorIntDPWithIntMulTest, AddWithMul) {
1407 const MulDPInst mdpi = GetParam();
1408 const MachineType type = mdpi.machine_type;
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());
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());
1432 TEST_P(InstructionSelectorIntDPWithIntMulTest, SubWithMul) {
1433 const MulDPInst mdpi = GetParam();
1434 const MachineType type = mdpi.machine_type;
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());
1448 TEST_P(InstructionSelectorIntDPWithIntMulTest, NegativeMul) {
1449 const MulDPInst mdpi = GetParam();
1450 const MachineType type = mdpi.machine_type;
1452 StreamBuilder m(this, type, type, type);
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());
1463 StreamBuilder m(this, type, type, type);
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());
1476 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
1477 InstructionSelectorIntDPWithIntMulTest,
1478 ::testing::ValuesIn(kMulDPInstructions));
1481 // -----------------------------------------------------------------------------
1482 // Floating point instructions.
1484 typedef InstructionSelectorTestWithParam<MachInst2>
1485 InstructionSelectorFPArithTest;
1488 TEST_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());
1500 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorFPArithTest,
1501 ::testing::ValuesIn(kFPArithInstructions));
1504 typedef InstructionSelectorTestWithParam<FPCmp> InstructionSelectorFPCmpTest;
1507 TEST_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());
1521 TEST_P(InstructionSelectorFPCmpTest, WithImmediateZeroOnRight) {
1522 const FPCmp cmp = GetParam();
1523 StreamBuilder m(this, kMachInt32, cmp.mi.machine_type);
1524 m.Return((m.*cmp.mi.constructor)(m.Parameter(0), m.Float64Constant(0.0)));
1525 Stream s = m.Build();
1526 ASSERT_EQ(1U, s.size());
1527 EXPECT_EQ(cmp.mi.arch_opcode, s[0]->arch_opcode());
1528 EXPECT_EQ(2U, s[0]->InputCount());
1529 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
1530 EXPECT_EQ(1U, s[0]->OutputCount());
1531 EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1532 EXPECT_EQ(cmp.cond, s[0]->flags_condition());
1536 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorFPCmpTest,
1537 ::testing::ValuesIn(kFPCmpInstructions));
1540 TEST_F(InstructionSelectorTest, Float64EqualWithImmediateZeroOnLeft) {
1541 StreamBuilder m(this, kMachInt32, kMachFloat64);
1542 m.Return(m.Float64Equal(m.Float64Constant(0.0), m.Parameter(0)));
1543 Stream s = m.Build();
1544 ASSERT_EQ(1U, s.size());
1545 EXPECT_EQ(kArm64Float64Cmp, s[0]->arch_opcode());
1546 EXPECT_EQ(2U, s[0]->InputCount());
1547 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
1548 EXPECT_EQ(1U, s[0]->OutputCount());
1549 EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1550 EXPECT_EQ(kEqual, s[0]->flags_condition());
1554 // -----------------------------------------------------------------------------
1557 typedef InstructionSelectorTestWithParam<Conversion>
1558 InstructionSelectorConversionTest;
1561 TEST_P(InstructionSelectorConversionTest, Parameter) {
1562 const Conversion conv = GetParam();
1563 StreamBuilder m(this, conv.mi.machine_type, conv.src_machine_type);
1564 m.Return((m.*conv.mi.constructor)(m.Parameter(0)));
1565 Stream s = m.Build();
1566 ASSERT_EQ(1U, s.size());
1567 EXPECT_EQ(conv.mi.arch_opcode, s[0]->arch_opcode());
1568 EXPECT_EQ(1U, s[0]->InputCount());
1569 EXPECT_EQ(1U, s[0]->OutputCount());
1573 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
1574 InstructionSelectorConversionTest,
1575 ::testing::ValuesIn(kConversionInstructions));
1578 // -----------------------------------------------------------------------------
1579 // Memory access instructions.
1584 struct MemoryAccess {
1586 ArchOpcode ldr_opcode;
1587 ArchOpcode str_opcode;
1588 const int32_t immediates[20];
1592 std::ostream& operator<<(std::ostream& os, const MemoryAccess& memacc) {
1593 return os << memacc.type;
1599 static const MemoryAccess kMemoryAccesses[] = {
1603 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 257, 258, 1000, 1001, 2121,
1604 2442, 4093, 4094, 4095}},
1608 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 257, 258, 1000, 1001, 2121,
1609 2442, 4093, 4094, 4095}},
1613 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 258, 260, 4096, 4098, 4100,
1614 4242, 6786, 8188, 8190}},
1618 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 258, 260, 4096, 4098, 4100,
1619 4242, 6786, 8188, 8190}},
1623 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 260, 4096, 4100, 8192, 8196,
1624 3276, 3280, 16376, 16380}},
1628 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 260, 4096, 4100, 8192, 8196,
1629 3276, 3280, 16376, 16380}},
1633 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 264, 4096, 4104, 8192, 8200,
1634 16384, 16392, 32752, 32760}},
1638 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 264, 4096, 4104, 8192, 8200,
1639 16384, 16392, 32752, 32760}},
1643 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 260, 4096, 4100, 8192, 8196,
1644 3276, 3280, 16376, 16380}},
1648 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 264, 4096, 4104, 8192, 8200,
1649 16384, 16392, 32752, 32760}}};
1652 typedef InstructionSelectorTestWithParam<MemoryAccess>
1653 InstructionSelectorMemoryAccessTest;
1656 TEST_P(InstructionSelectorMemoryAccessTest, LoadWithParameters) {
1657 const MemoryAccess memacc = GetParam();
1658 StreamBuilder m(this, memacc.type, kMachPtr, kMachInt32);
1659 m.Return(m.Load(memacc.type, m.Parameter(0), m.Parameter(1)));
1660 Stream s = m.Build();
1661 ASSERT_EQ(1U, s.size());
1662 EXPECT_EQ(memacc.ldr_opcode, s[0]->arch_opcode());
1663 EXPECT_EQ(kMode_MRR, s[0]->addressing_mode());
1664 EXPECT_EQ(2U, s[0]->InputCount());
1665 EXPECT_EQ(1U, s[0]->OutputCount());
1669 TEST_P(InstructionSelectorMemoryAccessTest, LoadWithImmediateIndex) {
1670 const MemoryAccess memacc = GetParam();
1671 TRACED_FOREACH(int32_t, index, memacc.immediates) {
1672 StreamBuilder m(this, memacc.type, kMachPtr);
1673 m.Return(m.Load(memacc.type, m.Parameter(0), m.Int32Constant(index)));
1674 Stream s = m.Build();
1675 ASSERT_EQ(1U, s.size());
1676 EXPECT_EQ(memacc.ldr_opcode, s[0]->arch_opcode());
1677 EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
1678 EXPECT_EQ(2U, s[0]->InputCount());
1679 ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
1680 EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
1681 ASSERT_EQ(1U, s[0]->OutputCount());
1686 TEST_P(InstructionSelectorMemoryAccessTest, StoreWithParameters) {
1687 const MemoryAccess memacc = GetParam();
1688 StreamBuilder m(this, kMachInt32, kMachPtr, kMachInt32, memacc.type);
1689 m.Store(memacc.type, m.Parameter(0), m.Parameter(1), m.Parameter(2));
1690 m.Return(m.Int32Constant(0));
1691 Stream s = m.Build();
1692 ASSERT_EQ(1U, s.size());
1693 EXPECT_EQ(memacc.str_opcode, s[0]->arch_opcode());
1694 EXPECT_EQ(kMode_MRR, s[0]->addressing_mode());
1695 EXPECT_EQ(3U, s[0]->InputCount());
1696 EXPECT_EQ(0U, s[0]->OutputCount());
1700 TEST_P(InstructionSelectorMemoryAccessTest, StoreWithImmediateIndex) {
1701 const MemoryAccess memacc = GetParam();
1702 TRACED_FOREACH(int32_t, index, memacc.immediates) {
1703 StreamBuilder m(this, kMachInt32, kMachPtr, memacc.type);
1704 m.Store(memacc.type, m.Parameter(0), m.Int32Constant(index),
1706 m.Return(m.Int32Constant(0));
1707 Stream s = m.Build();
1708 ASSERT_EQ(1U, s.size());
1709 EXPECT_EQ(memacc.str_opcode, s[0]->arch_opcode());
1710 EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
1711 ASSERT_EQ(3U, s[0]->InputCount());
1712 ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
1713 EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
1714 EXPECT_EQ(0U, s[0]->OutputCount());
1719 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
1720 InstructionSelectorMemoryAccessTest,
1721 ::testing::ValuesIn(kMemoryAccesses));
1724 // -----------------------------------------------------------------------------
1725 // Comparison instructions.
1727 static const MachInst2 kComparisonInstructions[] = {
1728 {&RawMachineAssembler::Word32Equal, "Word32Equal", kArm64Cmp32, kMachInt32},
1729 {&RawMachineAssembler::Word64Equal, "Word64Equal", kArm64Cmp, kMachInt64},
1733 typedef InstructionSelectorTestWithParam<MachInst2>
1734 InstructionSelectorComparisonTest;
1737 TEST_P(InstructionSelectorComparisonTest, WithParameters) {
1738 const MachInst2 cmp = GetParam();
1739 const MachineType type = cmp.machine_type;
1740 StreamBuilder m(this, type, type, type);
1741 m.Return((m.*cmp.constructor)(m.Parameter(0), m.Parameter(1)));
1742 Stream s = m.Build();
1743 ASSERT_EQ(1U, s.size());
1744 EXPECT_EQ(cmp.arch_opcode, s[0]->arch_opcode());
1745 EXPECT_EQ(2U, s[0]->InputCount());
1746 EXPECT_EQ(1U, s[0]->OutputCount());
1747 EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1748 EXPECT_EQ(kEqual, s[0]->flags_condition());
1752 TEST_P(InstructionSelectorComparisonTest, WithImmediate) {
1753 const MachInst2 cmp = GetParam();
1754 const MachineType type = cmp.machine_type;
1755 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
1756 // Compare with 0 are turned into tst instruction.
1757 if (imm == 0) continue;
1758 StreamBuilder m(this, type, type);
1759 m.Return((m.*cmp.constructor)(m.Parameter(0), BuildConstant(m, type, imm)));
1760 Stream s = m.Build();
1761 ASSERT_EQ(1U, s.size());
1762 EXPECT_EQ(cmp.arch_opcode, s[0]->arch_opcode());
1763 ASSERT_EQ(2U, s[0]->InputCount());
1764 ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
1765 EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1)));
1766 EXPECT_EQ(1U, s[0]->OutputCount());
1767 EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1768 EXPECT_EQ(kEqual, s[0]->flags_condition());
1770 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
1771 // Compare with 0 are turned into tst instruction.
1772 if (imm == 0) continue;
1773 StreamBuilder m(this, type, type);
1774 m.Return((m.*cmp.constructor)(BuildConstant(m, type, imm), m.Parameter(0)));
1775 Stream s = m.Build();
1776 ASSERT_EQ(1U, s.size());
1777 EXPECT_EQ(cmp.arch_opcode, s[0]->arch_opcode());
1778 ASSERT_EQ(2U, s[0]->InputCount());
1779 ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
1780 EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1)));
1781 EXPECT_EQ(1U, s[0]->OutputCount());
1782 EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1783 EXPECT_EQ(kEqual, s[0]->flags_condition());
1787 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
1788 InstructionSelectorComparisonTest,
1789 ::testing::ValuesIn(kComparisonInstructions));
1792 TEST_F(InstructionSelectorTest, Word32EqualWithZero) {
1794 StreamBuilder m(this, kMachInt32, kMachInt32);
1795 m.Return(m.Word32Equal(m.Parameter(0), m.Int32Constant(0)));
1796 Stream s = m.Build();
1797 ASSERT_EQ(1U, s.size());
1798 EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode());
1799 ASSERT_EQ(2U, s[0]->InputCount());
1800 EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
1801 EXPECT_EQ(1U, s[0]->OutputCount());
1802 EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1803 EXPECT_EQ(kEqual, s[0]->flags_condition());
1806 StreamBuilder m(this, kMachInt32, kMachInt32);
1807 m.Return(m.Word32Equal(m.Int32Constant(0), m.Parameter(0)));
1808 Stream s = m.Build();
1809 ASSERT_EQ(1U, s.size());
1810 EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode());
1811 ASSERT_EQ(2U, s[0]->InputCount());
1812 EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
1813 EXPECT_EQ(1U, s[0]->OutputCount());
1814 EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1815 EXPECT_EQ(kEqual, s[0]->flags_condition());
1820 TEST_F(InstructionSelectorTest, Word64EqualWithZero) {
1822 StreamBuilder m(this, kMachInt64, kMachInt64);
1823 m.Return(m.Word64Equal(m.Parameter(0), m.Int64Constant(0)));
1824 Stream s = m.Build();
1825 ASSERT_EQ(1U, s.size());
1826 EXPECT_EQ(kArm64Tst, s[0]->arch_opcode());
1827 ASSERT_EQ(2U, s[0]->InputCount());
1828 EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
1829 EXPECT_EQ(1U, s[0]->OutputCount());
1830 EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1831 EXPECT_EQ(kEqual, s[0]->flags_condition());
1834 StreamBuilder m(this, kMachInt64, kMachInt64);
1835 m.Return(m.Word64Equal(m.Int64Constant(0), m.Parameter(0)));
1836 Stream s = m.Build();
1837 ASSERT_EQ(1U, s.size());
1838 EXPECT_EQ(kArm64Tst, s[0]->arch_opcode());
1839 ASSERT_EQ(2U, s[0]->InputCount());
1840 EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
1841 EXPECT_EQ(1U, s[0]->OutputCount());
1842 EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1843 EXPECT_EQ(kEqual, s[0]->flags_condition());
1848 // -----------------------------------------------------------------------------
1852 static const MachInst2 kLogicalWithNotRHSs[] = {
1853 {&RawMachineAssembler::Word32And, "Word32And", kArm64Bic32, kMachInt32},
1854 {&RawMachineAssembler::Word64And, "Word64And", kArm64Bic, kMachInt64},
1855 {&RawMachineAssembler::Word32Or, "Word32Or", kArm64Orn32, kMachInt32},
1856 {&RawMachineAssembler::Word64Or, "Word64Or", kArm64Orn, kMachInt64},
1857 {&RawMachineAssembler::Word32Xor, "Word32Xor", kArm64Eon32, kMachInt32},
1858 {&RawMachineAssembler::Word64Xor, "Word64Xor", kArm64Eon, kMachInt64}};
1861 typedef InstructionSelectorTestWithParam<MachInst2>
1862 InstructionSelectorLogicalWithNotRHSTest;
1865 TEST_P(InstructionSelectorLogicalWithNotRHSTest, Parameter) {
1866 const MachInst2 inst = GetParam();
1867 const MachineType type = inst.machine_type;
1868 // Test cases where RHS is Xor(x, -1).
1870 StreamBuilder m(this, type, type, type);
1871 if (type == kMachInt32) {
1872 m.Return((m.*inst.constructor)(
1873 m.Parameter(0), m.Word32Xor(m.Parameter(1), m.Int32Constant(-1))));
1875 ASSERT_EQ(kMachInt64, type);
1876 m.Return((m.*inst.constructor)(
1877 m.Parameter(0), m.Word64Xor(m.Parameter(1), m.Int64Constant(-1))));
1879 Stream s = m.Build();
1880 ASSERT_EQ(1U, s.size());
1881 EXPECT_EQ(inst.arch_opcode, s[0]->arch_opcode());
1882 EXPECT_EQ(2U, s[0]->InputCount());
1883 EXPECT_EQ(1U, s[0]->OutputCount());
1886 StreamBuilder m(this, type, type, type);
1887 if (type == kMachInt32) {
1888 m.Return((m.*inst.constructor)(
1889 m.Word32Xor(m.Parameter(0), m.Int32Constant(-1)), m.Parameter(1)));
1891 ASSERT_EQ(kMachInt64, type);
1892 m.Return((m.*inst.constructor)(
1893 m.Word64Xor(m.Parameter(0), m.Int64Constant(-1)), m.Parameter(1)));
1895 Stream s = m.Build();
1896 ASSERT_EQ(1U, s.size());
1897 EXPECT_EQ(inst.arch_opcode, s[0]->arch_opcode());
1898 EXPECT_EQ(2U, s[0]->InputCount());
1899 EXPECT_EQ(1U, s[0]->OutputCount());
1901 // Test cases where RHS is Not(x).
1903 StreamBuilder m(this, type, type, type);
1904 if (type == kMachInt32) {
1906 (m.*inst.constructor)(m.Parameter(0), m.Word32Not(m.Parameter(1))));
1908 ASSERT_EQ(kMachInt64, type);
1910 (m.*inst.constructor)(m.Parameter(0), m.Word64Not(m.Parameter(1))));
1912 Stream s = m.Build();
1913 ASSERT_EQ(1U, s.size());
1914 EXPECT_EQ(inst.arch_opcode, s[0]->arch_opcode());
1915 EXPECT_EQ(2U, s[0]->InputCount());
1916 EXPECT_EQ(1U, s[0]->OutputCount());
1919 StreamBuilder m(this, type, type, type);
1920 if (type == kMachInt32) {
1922 (m.*inst.constructor)(m.Word32Not(m.Parameter(0)), m.Parameter(1)));
1924 ASSERT_EQ(kMachInt64, type);
1926 (m.*inst.constructor)(m.Word64Not(m.Parameter(0)), m.Parameter(1)));
1928 Stream s = m.Build();
1929 ASSERT_EQ(1U, s.size());
1930 EXPECT_EQ(inst.arch_opcode, s[0]->arch_opcode());
1931 EXPECT_EQ(2U, s[0]->InputCount());
1932 EXPECT_EQ(1U, s[0]->OutputCount());
1937 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
1938 InstructionSelectorLogicalWithNotRHSTest,
1939 ::testing::ValuesIn(kLogicalWithNotRHSs));
1942 TEST_F(InstructionSelectorTest, Word32NotWithParameter) {
1943 StreamBuilder m(this, kMachInt32, kMachInt32);
1944 m.Return(m.Word32Not(m.Parameter(0)));
1945 Stream s = m.Build();
1946 ASSERT_EQ(1U, s.size());
1947 EXPECT_EQ(kArm64Not32, s[0]->arch_opcode());
1948 EXPECT_EQ(1U, s[0]->InputCount());
1949 EXPECT_EQ(1U, s[0]->OutputCount());
1953 TEST_F(InstructionSelectorTest, Word64NotWithParameter) {
1954 StreamBuilder m(this, kMachInt64, kMachInt64);
1955 m.Return(m.Word64Not(m.Parameter(0)));
1956 Stream s = m.Build();
1957 ASSERT_EQ(1U, s.size());
1958 EXPECT_EQ(kArm64Not, s[0]->arch_opcode());
1959 EXPECT_EQ(1U, s[0]->InputCount());
1960 EXPECT_EQ(1U, s[0]->OutputCount());
1964 TEST_F(InstructionSelectorTest, Word32XorMinusOneWithParameter) {
1966 StreamBuilder m(this, kMachInt32, kMachInt32);
1967 m.Return(m.Word32Xor(m.Parameter(0), m.Int32Constant(-1)));
1968 Stream s = m.Build();
1969 ASSERT_EQ(1U, s.size());
1970 EXPECT_EQ(kArm64Not32, s[0]->arch_opcode());
1971 EXPECT_EQ(1U, s[0]->InputCount());
1972 EXPECT_EQ(1U, s[0]->OutputCount());
1975 StreamBuilder m(this, kMachInt32, kMachInt32);
1976 m.Return(m.Word32Xor(m.Int32Constant(-1), m.Parameter(0)));
1977 Stream s = m.Build();
1978 ASSERT_EQ(1U, s.size());
1979 EXPECT_EQ(kArm64Not32, s[0]->arch_opcode());
1980 EXPECT_EQ(1U, s[0]->InputCount());
1981 EXPECT_EQ(1U, s[0]->OutputCount());
1986 TEST_F(InstructionSelectorTest, Word64XorMinusOneWithParameter) {
1988 StreamBuilder m(this, kMachInt64, kMachInt64);
1989 m.Return(m.Word64Xor(m.Parameter(0), m.Int64Constant(-1)));
1990 Stream s = m.Build();
1991 ASSERT_EQ(1U, s.size());
1992 EXPECT_EQ(kArm64Not, s[0]->arch_opcode());
1993 EXPECT_EQ(1U, s[0]->InputCount());
1994 EXPECT_EQ(1U, s[0]->OutputCount());
1997 StreamBuilder m(this, kMachInt64, kMachInt64);
1998 m.Return(m.Word64Xor(m.Int64Constant(-1), m.Parameter(0)));
1999 Stream s = m.Build();
2000 ASSERT_EQ(1U, s.size());
2001 EXPECT_EQ(kArm64Not, s[0]->arch_opcode());
2002 EXPECT_EQ(1U, s[0]->InputCount());
2003 EXPECT_EQ(1U, s[0]->OutputCount());
2008 TEST_F(InstructionSelectorTest, Word32ShrWithWord32AndWithImmediate) {
2009 TRACED_FORRANGE(int32_t, lsb, 1, 31) {
2010 TRACED_FORRANGE(int32_t, width, 1, 32 - lsb) {
2011 uint32_t jnk = rng()->NextInt();
2013 uint32_t msk = ((0xffffffffu >> (32 - width)) << lsb) | jnk;
2014 StreamBuilder m(this, kMachInt32, kMachInt32);
2015 m.Return(m.Word32Shr(m.Word32And(m.Parameter(0), m.Int32Constant(msk)),
2016 m.Int32Constant(lsb)));
2017 Stream s = m.Build();
2018 ASSERT_EQ(1U, s.size());
2019 EXPECT_EQ(kArm64Ubfx32, s[0]->arch_opcode());
2020 ASSERT_EQ(3U, s[0]->InputCount());
2021 EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1)));
2022 EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2)));
2025 TRACED_FORRANGE(int32_t, lsb, 1, 31) {
2026 TRACED_FORRANGE(int32_t, width, 1, 32 - lsb) {
2027 uint32_t jnk = rng()->NextInt();
2029 uint32_t msk = ((0xffffffffu >> (32 - width)) << lsb) | jnk;
2030 StreamBuilder m(this, kMachInt32, kMachInt32);
2031 m.Return(m.Word32Shr(m.Word32And(m.Int32Constant(msk), m.Parameter(0)),
2032 m.Int32Constant(lsb)));
2033 Stream s = m.Build();
2034 ASSERT_EQ(1U, s.size());
2035 EXPECT_EQ(kArm64Ubfx32, s[0]->arch_opcode());
2036 ASSERT_EQ(3U, s[0]->InputCount());
2037 EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1)));
2038 EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2)));
2044 TEST_F(InstructionSelectorTest, Word64ShrWithWord64AndWithImmediate) {
2045 TRACED_FORRANGE(int32_t, lsb, 1, 63) {
2046 TRACED_FORRANGE(int32_t, width, 1, 64 - lsb) {
2047 uint64_t jnk = rng()->NextInt64();
2050 ((V8_UINT64_C(0xffffffffffffffff) >> (64 - width)) << lsb) | jnk;
2051 StreamBuilder m(this, kMachInt64, kMachInt64);
2052 m.Return(m.Word64Shr(m.Word64And(m.Parameter(0), m.Int64Constant(msk)),
2053 m.Int64Constant(lsb)));
2054 Stream s = m.Build();
2055 ASSERT_EQ(1U, s.size());
2056 EXPECT_EQ(kArm64Ubfx, s[0]->arch_opcode());
2057 ASSERT_EQ(3U, s[0]->InputCount());
2058 EXPECT_EQ(lsb, s.ToInt64(s[0]->InputAt(1)));
2059 EXPECT_EQ(width, s.ToInt64(s[0]->InputAt(2)));
2062 TRACED_FORRANGE(int32_t, lsb, 1, 63) {
2063 TRACED_FORRANGE(int32_t, width, 1, 64 - lsb) {
2064 uint64_t jnk = rng()->NextInt64();
2067 ((V8_UINT64_C(0xffffffffffffffff) >> (64 - width)) << lsb) | jnk;
2068 StreamBuilder m(this, kMachInt64, kMachInt64);
2069 m.Return(m.Word64Shr(m.Word64And(m.Int64Constant(msk), m.Parameter(0)),
2070 m.Int64Constant(lsb)));
2071 Stream s = m.Build();
2072 ASSERT_EQ(1U, s.size());
2073 EXPECT_EQ(kArm64Ubfx, s[0]->arch_opcode());
2074 ASSERT_EQ(3U, s[0]->InputCount());
2075 EXPECT_EQ(lsb, s.ToInt64(s[0]->InputAt(1)));
2076 EXPECT_EQ(width, s.ToInt64(s[0]->InputAt(2)));
2082 TEST_F(InstructionSelectorTest, Word32AndWithImmediateWithWord32Shr) {
2083 TRACED_FORRANGE(int32_t, lsb, 1, 31) {
2084 TRACED_FORRANGE(int32_t, width, 1, 31) {
2085 uint32_t msk = (1 << width) - 1;
2086 StreamBuilder m(this, kMachInt32, kMachInt32);
2087 m.Return(m.Word32And(m.Word32Shr(m.Parameter(0), m.Int32Constant(lsb)),
2088 m.Int32Constant(msk)));
2089 Stream s = m.Build();
2090 ASSERT_EQ(1U, s.size());
2091 EXPECT_EQ(kArm64Ubfx32, s[0]->arch_opcode());
2092 ASSERT_EQ(3U, s[0]->InputCount());
2093 EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1)));
2094 int32_t actual_width = (lsb + width > 32) ? (32 - lsb) : width;
2095 EXPECT_EQ(actual_width, s.ToInt32(s[0]->InputAt(2)));
2098 TRACED_FORRANGE(int32_t, lsb, 1, 31) {
2099 TRACED_FORRANGE(int32_t, width, 1, 31) {
2100 uint32_t msk = (1 << width) - 1;
2101 StreamBuilder m(this, kMachInt32, kMachInt32);
2102 m.Return(m.Word32And(m.Int32Constant(msk),
2103 m.Word32Shr(m.Parameter(0), m.Int32Constant(lsb))));
2104 Stream s = m.Build();
2105 ASSERT_EQ(1U, s.size());
2106 EXPECT_EQ(kArm64Ubfx32, s[0]->arch_opcode());
2107 ASSERT_EQ(3U, s[0]->InputCount());
2108 EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1)));
2109 int32_t actual_width = (lsb + width > 32) ? (32 - lsb) : width;
2110 EXPECT_EQ(actual_width, s.ToInt32(s[0]->InputAt(2)));
2116 TEST_F(InstructionSelectorTest, Word64AndWithImmediateWithWord64Shr) {
2117 TRACED_FORRANGE(int64_t, lsb, 1, 63) {
2118 TRACED_FORRANGE(int64_t, width, 1, 63) {
2119 uint64_t msk = (V8_UINT64_C(1) << width) - 1;
2120 StreamBuilder m(this, kMachInt64, kMachInt64);
2121 m.Return(m.Word64And(m.Word64Shr(m.Parameter(0), m.Int64Constant(lsb)),
2122 m.Int64Constant(msk)));
2123 Stream s = m.Build();
2124 ASSERT_EQ(1U, s.size());
2125 EXPECT_EQ(kArm64Ubfx, s[0]->arch_opcode());
2126 ASSERT_EQ(3U, s[0]->InputCount());
2127 EXPECT_EQ(lsb, s.ToInt64(s[0]->InputAt(1)));
2128 int64_t actual_width = (lsb + width > 64) ? (64 - lsb) : width;
2129 EXPECT_EQ(actual_width, s.ToInt64(s[0]->InputAt(2)));
2132 TRACED_FORRANGE(int64_t, lsb, 1, 63) {
2133 TRACED_FORRANGE(int64_t, width, 1, 63) {
2134 uint64_t msk = (V8_UINT64_C(1) << width) - 1;
2135 StreamBuilder m(this, kMachInt64, kMachInt64);
2136 m.Return(m.Word64And(m.Int64Constant(msk),
2137 m.Word64Shr(m.Parameter(0), m.Int64Constant(lsb))));
2138 Stream s = m.Build();
2139 ASSERT_EQ(1U, s.size());
2140 EXPECT_EQ(kArm64Ubfx, s[0]->arch_opcode());
2141 ASSERT_EQ(3U, s[0]->InputCount());
2142 EXPECT_EQ(lsb, s.ToInt64(s[0]->InputAt(1)));
2143 int64_t actual_width = (lsb + width > 64) ? (64 - lsb) : width;
2144 EXPECT_EQ(actual_width, s.ToInt64(s[0]->InputAt(2)));
2150 TEST_F(InstructionSelectorTest, Int32MulHighWithParameters) {
2151 StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
2152 Node* const p0 = m.Parameter(0);
2153 Node* const p1 = m.Parameter(1);
2154 Node* const n = m.Int32MulHigh(p0, p1);
2156 Stream s = m.Build();
2157 ASSERT_EQ(2U, s.size());
2158 EXPECT_EQ(kArm64Smull, s[0]->arch_opcode());
2159 ASSERT_EQ(2U, s[0]->InputCount());
2160 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
2161 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
2162 ASSERT_EQ(1U, s[0]->OutputCount());
2163 EXPECT_EQ(kArm64Asr, s[1]->arch_opcode());
2164 ASSERT_EQ(2U, s[1]->InputCount());
2165 EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[1]->InputAt(0)));
2166 EXPECT_EQ(32, s.ToInt64(s[1]->InputAt(1)));
2167 ASSERT_EQ(1U, s[1]->OutputCount());
2168 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[1]->Output()));
2172 TEST_F(InstructionSelectorTest, Word32SarWithWord32Shl) {
2174 StreamBuilder m(this, kMachInt32, kMachInt32);
2175 Node* const p0 = m.Parameter(0);
2177 m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(24)), m.Int32Constant(24));
2179 Stream s = m.Build();
2180 ASSERT_EQ(1U, s.size());
2181 EXPECT_EQ(kArm64Sxtb32, s[0]->arch_opcode());
2182 ASSERT_EQ(1U, s[0]->InputCount());
2183 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
2184 ASSERT_EQ(1U, s[0]->OutputCount());
2185 EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
2188 StreamBuilder m(this, kMachInt32, kMachInt32);
2189 Node* const p0 = m.Parameter(0);
2191 m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(16)), m.Int32Constant(16));
2193 Stream s = m.Build();
2194 ASSERT_EQ(1U, s.size());
2195 EXPECT_EQ(kArm64Sxth32, s[0]->arch_opcode());
2196 ASSERT_EQ(1U, s[0]->InputCount());
2197 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
2198 ASSERT_EQ(1U, s[0]->OutputCount());
2199 EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
2203 } // namespace compiler
2204 } // namespace internal