1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <list>
6
7 #include "src/compiler/instruction-selector-unittest.h"
8
9 namespace v8 {
10 namespace internal {
11 namespace compiler {
12
13 namespace {
14
15 typedef RawMachineAssembler::Label MLabel;
16
17 template <typename T>
18 struct MachInst {
19 T constructor;
20 const char* constructor_name;
21 ArchOpcode arch_opcode;
22 MachineType machine_type;
23 };
24
25 typedef MachInst<Node* (RawMachineAssembler::*)(Node*)> MachInst1;
26 typedef MachInst<Node* (RawMachineAssembler::*)(Node*, Node*)> MachInst2;
27
28
29 template <typename T>
operator <<(std::ostream & os,const MachInst<T> & mi)30 std::ostream& operator<<(std::ostream& os, const MachInst<T>& mi) {
31 return os << mi.constructor_name;
32 }
33
34
35 // Helper to build Int32Constant or Int64Constant depending on the given
36 // machine type.
BuildConstant(InstructionSelectorTest::StreamBuilder & m,MachineType type,int64_t value)37 Node* BuildConstant(InstructionSelectorTest::StreamBuilder& m, MachineType type,
38 int64_t value) {
39 switch (type) {
40 case kMachInt32:
41 return m.Int32Constant(value);
42 break;
43
44 case kMachInt64:
45 return m.Int64Constant(value);
46 break;
47
48 default:
49 UNIMPLEMENTED();
50 }
51 return NULL;
52 }
53
54
55 // ARM64 logical instructions.
56 static const MachInst2 kLogicalInstructions[] = {
57 {&RawMachineAssembler::Word32And, "Word32And", kArm64And32, kMachInt32},
58 {&RawMachineAssembler::Word64And, "Word64And", kArm64And, kMachInt64},
59 {&RawMachineAssembler::Word32Or, "Word32Or", kArm64Or32, kMachInt32},
60 {&RawMachineAssembler::Word64Or, "Word64Or", kArm64Or, kMachInt64},
61 {&RawMachineAssembler::Word32Xor, "Word32Xor", kArm64Xor32, kMachInt32},
62 {&RawMachineAssembler::Word64Xor, "Word64Xor", kArm64Xor, kMachInt64}};
63
64
65 // ARM64 logical immediates: contiguous set bits, rotated about a power of two
66 // sized block. The block is then duplicated across the word. Below is a random
67 // subset of the 32-bit immediates.
68 static const uint32_t kLogicalImmediates[] = {
69 0x00000002, 0x00000003, 0x00000070, 0x00000080, 0x00000100, 0x000001c0,
70 0x00000300, 0x000007e0, 0x00003ffc, 0x00007fc0, 0x0003c000, 0x0003f000,
71 0x0003ffc0, 0x0003fff8, 0x0007ff00, 0x0007ffe0, 0x000e0000, 0x001e0000,
72 0x001ffffc, 0x003f0000, 0x003f8000, 0x00780000, 0x007fc000, 0x00ff0000,
73 0x01800000, 0x01800180, 0x01f801f8, 0x03fe0000, 0x03ffffc0, 0x03fffffc,
74 0x06000000, 0x07fc0000, 0x07ffc000, 0x07ffffc0, 0x07ffffe0, 0x0ffe0ffe,
75 0x0ffff800, 0x0ffffff0, 0x0fffffff, 0x18001800, 0x1f001f00, 0x1f801f80,
76 0x30303030, 0x3ff03ff0, 0x3ff83ff8, 0x3fff0000, 0x3fff8000, 0x3fffffc0,
77 0x70007000, 0x7f7f7f7f, 0x7fc00000, 0x7fffffc0, 0x8000001f, 0x800001ff,
78 0x81818181, 0x9fff9fff, 0xc00007ff, 0xc0ffffff, 0xdddddddd, 0xe00001ff,
79 0xe00003ff, 0xe007ffff, 0xefffefff, 0xf000003f, 0xf001f001, 0xf3fff3ff,
80 0xf800001f, 0xf80fffff, 0xf87ff87f, 0xfbfbfbfb, 0xfc00001f, 0xfc0000ff,
81 0xfc0001ff, 0xfc03fc03, 0xfe0001ff, 0xff000001, 0xff03ff03, 0xff800000,
82 0xff800fff, 0xff801fff, 0xff87ffff, 0xffc0003f, 0xffc007ff, 0xffcfffcf,
83 0xffe00003, 0xffe1ffff, 0xfff0001f, 0xfff07fff, 0xfff80007, 0xfff87fff,
84 0xfffc00ff, 0xfffe07ff, 0xffff00ff, 0xffffc001, 0xfffff007, 0xfffff3ff,
85 0xfffff807, 0xfffff9ff, 0xfffffc0f, 0xfffffeff};
86
87
88 // ARM64 arithmetic instructions.
89 static const MachInst2 kAddSubInstructions[] = {
90 {&RawMachineAssembler::Int32Add, "Int32Add", kArm64Add32, kMachInt32},
91 {&RawMachineAssembler::Int64Add, "Int64Add", kArm64Add, kMachInt64},
92 {&RawMachineAssembler::Int32Sub, "Int32Sub", kArm64Sub32, kMachInt32},
93 {&RawMachineAssembler::Int64Sub, "Int64Sub", kArm64Sub, kMachInt64}};
94
95
96 // ARM64 Add/Sub immediates: 12-bit immediate optionally shifted by 12.
97 // Below is a combination of a random subset and some edge values.
98 static const int32_t kAddSubImmediates[] = {
99 0, 1, 69, 493, 599, 701, 719,
100 768, 818, 842, 945, 1246, 1286, 1429,
101 1669, 2171, 2179, 2182, 2254, 2334, 2338,
102 2343, 2396, 2449, 2610, 2732, 2855, 2876,
103 2944, 3377, 3458, 3475, 3476, 3540, 3574,
104 3601, 3813, 3871, 3917, 4095, 4096, 16384,
105 364544, 462848, 970752, 1523712, 1863680, 2363392, 3219456,
106 3280896, 4247552, 4526080, 4575232, 4960256, 5505024, 5894144,
107 6004736, 6193152, 6385664, 6795264, 7114752, 7233536, 7348224,
108 7499776, 7573504, 7729152, 8634368, 8937472, 9465856, 10354688,
109 10682368, 11059200, 11460608, 13168640, 13176832, 14336000, 15028224,
110 15597568, 15892480, 16773120};
111
112
113 // ARM64 flag setting data processing instructions.
114 static const MachInst2 kDPFlagSetInstructions[] = {
115 {&RawMachineAssembler::Word32And, "Word32And", kArm64Tst32, kMachInt32},
116 {&RawMachineAssembler::Int32Add, "Int32Add", kArm64Cmn32, kMachInt32},
117 {&RawMachineAssembler::Int32Sub, "Int32Sub", kArm64Cmp32, kMachInt32}};
118
119
120 // ARM64 arithmetic with overflow instructions.
121 static const MachInst2 kOvfAddSubInstructions[] = {
122 {&RawMachineAssembler::Int32AddWithOverflow, "Int32AddWithOverflow",
123 kArm64Add32, kMachInt32},
124 {&RawMachineAssembler::Int32SubWithOverflow, "Int32SubWithOverflow",
125 kArm64Sub32, kMachInt32}};
126
127
128 // ARM64 shift instructions.
129 static const MachInst2 kShiftInstructions[] = {
130 {&RawMachineAssembler::Word32Shl, "Word32Shl", kArm64Shl32, kMachInt32},
131 {&RawMachineAssembler::Word64Shl, "Word64Shl", kArm64Shl, kMachInt64},
132 {&RawMachineAssembler::Word32Shr, "Word32Shr", kArm64Shr32, kMachInt32},
133 {&RawMachineAssembler::Word64Shr, "Word64Shr", kArm64Shr, kMachInt64},
134 {&RawMachineAssembler::Word32Sar, "Word32Sar", kArm64Sar32, kMachInt32},
135 {&RawMachineAssembler::Word64Sar, "Word64Sar", kArm64Sar, kMachInt64},
136 {&RawMachineAssembler::Word32Ror, "Word32Ror", kArm64Ror32, kMachInt32},
137 {&RawMachineAssembler::Word64Ror, "Word64Ror", kArm64Ror, kMachInt64}};
138
139
140 // ARM64 Mul/Div instructions.
141 static const MachInst2 kMulDivInstructions[] = {
142 {&RawMachineAssembler::Int32Mul, "Int32Mul", kArm64Mul32, kMachInt32},
143 {&RawMachineAssembler::Int64Mul, "Int64Mul", kArm64Mul, kMachInt64},
144 {&RawMachineAssembler::Int32Div, "Int32Div", kArm64Idiv32, kMachInt32},
145 {&RawMachineAssembler::Int64Div, "Int64Div", kArm64Idiv, kMachInt64},
146 {&RawMachineAssembler::Int32UDiv, "Int32UDiv", kArm64Udiv32, kMachInt32},
147 {&RawMachineAssembler::Int64UDiv, "Int64UDiv", kArm64Udiv, kMachInt64}};
148
149
150 // ARM64 FP arithmetic instructions.
151 static const MachInst2 kFPArithInstructions[] = {
152 {&RawMachineAssembler::Float64Add, "Float64Add", kArm64Float64Add,
153 kMachFloat64},
154 {&RawMachineAssembler::Float64Sub, "Float64Sub", kArm64Float64Sub,
155 kMachFloat64},
156 {&RawMachineAssembler::Float64Mul, "Float64Mul", kArm64Float64Mul,
157 kMachFloat64},
158 {&RawMachineAssembler::Float64Div, "Float64Div", kArm64Float64Div,
159 kMachFloat64}};
160
161
162 struct FPCmp {
163 MachInst2 mi;
164 FlagsCondition cond;
165 };
166
167
operator <<(std::ostream & os,const FPCmp & cmp)168 std::ostream& operator<<(std::ostream& os, const FPCmp& cmp) {
169 return os << cmp.mi;
170 }
171
172
173 // ARM64 FP comparison instructions.
174 static const FPCmp kFPCmpInstructions[] = {
175 {{&RawMachineAssembler::Float64Equal, "Float64Equal", kArm64Float64Cmp,
176 kMachFloat64},
177 kUnorderedEqual},
178 {{&RawMachineAssembler::Float64LessThan, "Float64LessThan",
179 kArm64Float64Cmp, kMachFloat64},
180 kUnorderedLessThan},
181 {{&RawMachineAssembler::Float64LessThanOrEqual, "Float64LessThanOrEqual",
182 kArm64Float64Cmp, kMachFloat64},
183 kUnorderedLessThanOrEqual}};
184
185
186 struct Conversion {
187 // The machine_type field in MachInst1 represents the destination type.
188 MachInst1 mi;
189 MachineType src_machine_type;
190 };
191
192
operator <<(std::ostream & os,const Conversion & conv)193 std::ostream& operator<<(std::ostream& os, const Conversion& conv) {
194 return os << conv.mi;
195 }
196
197
198 // ARM64 type conversion instructions.
199 static const Conversion kConversionInstructions[] = {
200 {{&RawMachineAssembler::ChangeInt32ToInt64, "ChangeInt32ToInt64",
201 kArm64Sxtw, kMachInt64},
202 kMachInt32},
203 {{&RawMachineAssembler::ChangeUint32ToUint64, "ChangeUint32ToUint64",
204 kArm64Mov32, kMachUint64},
205 kMachUint32},
206 {{&RawMachineAssembler::TruncateInt64ToInt32, "TruncateInt64ToInt32",
207 kArm64Mov32, kMachInt32},
208 kMachInt64},
209 {{&RawMachineAssembler::ChangeInt32ToFloat64, "ChangeInt32ToFloat64",
210 kArm64Int32ToFloat64, kMachFloat64},
211 kMachInt32},
212 {{&RawMachineAssembler::ChangeUint32ToFloat64, "ChangeUint32ToFloat64",
213 kArm64Uint32ToFloat64, kMachFloat64},
214 kMachUint32},
215 {{&RawMachineAssembler::ChangeFloat64ToInt32, "ChangeFloat64ToInt32",
216 kArm64Float64ToInt32, kMachInt32},
217 kMachFloat64},
218 {{&RawMachineAssembler::ChangeFloat64ToUint32, "ChangeFloat64ToUint32",
219 kArm64Float64ToUint32, kMachUint32},
220 kMachFloat64}};
221
222 } // namespace
223
224
225 // -----------------------------------------------------------------------------
226 // Logical instructions.
227
228
229 typedef InstructionSelectorTestWithParam<MachInst2>
230 InstructionSelectorLogicalTest;
231
232
TEST_P(InstructionSelectorLogicalTest,Parameter)233 TEST_P(InstructionSelectorLogicalTest, Parameter) {
234 const MachInst2 dpi = GetParam();
235 const MachineType type = dpi.machine_type;
236 StreamBuilder m(this, type, type, type);
237 m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)));
238 Stream s = m.Build();
239 ASSERT_EQ(1U, s.size());
240 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
241 EXPECT_EQ(2U, s[0]->InputCount());
242 EXPECT_EQ(1U, s[0]->OutputCount());
243 }
244
245
TEST_P(InstructionSelectorLogicalTest,Immediate)246 TEST_P(InstructionSelectorLogicalTest, Immediate) {
247 const MachInst2 dpi = GetParam();
248 const MachineType type = dpi.machine_type;
249 // TODO(all): Add support for testing 64-bit immediates.
250 if (type == kMachInt32) {
251 // Immediate on the right.
252 TRACED_FOREACH(int32_t, imm, kLogicalImmediates) {
253 StreamBuilder m(this, type, type);
254 m.Return((m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm)));
255 Stream s = m.Build();
256 ASSERT_EQ(1U, s.size());
257 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
258 ASSERT_EQ(2U, s[0]->InputCount());
259 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
260 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
261 EXPECT_EQ(1U, s[0]->OutputCount());
262 }
263
264 // Immediate on the left; all logical ops should commute.
265 TRACED_FOREACH(int32_t, imm, kLogicalImmediates) {
266 StreamBuilder m(this, type, type);
267 m.Return((m.*dpi.constructor)(m.Int32Constant(imm), m.Parameter(0)));
268 Stream s = m.Build();
269 ASSERT_EQ(1U, s.size());
270 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
271 ASSERT_EQ(2U, s[0]->InputCount());
272 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
273 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
274 EXPECT_EQ(1U, s[0]->OutputCount());
275 }
276 }
277 }
278
279
280 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorLogicalTest,
281 ::testing::ValuesIn(kLogicalInstructions));
282
283
284 // -----------------------------------------------------------------------------
285 // Add and Sub instructions.
286
287 typedef InstructionSelectorTestWithParam<MachInst2>
288 InstructionSelectorAddSubTest;
289
290
TEST_P(InstructionSelectorAddSubTest,Parameter)291 TEST_P(InstructionSelectorAddSubTest, Parameter) {
292 const MachInst2 dpi = GetParam();
293 const MachineType type = dpi.machine_type;
294 StreamBuilder m(this, type, type, type);
295 m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)));
296 Stream s = m.Build();
297 ASSERT_EQ(1U, s.size());
298 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
299 EXPECT_EQ(2U, s[0]->InputCount());
300 EXPECT_EQ(1U, s[0]->OutputCount());
301 }
302
303
TEST_P(InstructionSelectorAddSubTest,ImmediateOnRight)304 TEST_P(InstructionSelectorAddSubTest, ImmediateOnRight) {
305 const MachInst2 dpi = GetParam();
306 const MachineType type = dpi.machine_type;
307 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
308 StreamBuilder m(this, type, type);
309 m.Return((m.*dpi.constructor)(m.Parameter(0), BuildConstant(m, type, imm)));
310 Stream s = m.Build();
311 ASSERT_EQ(1U, s.size());
312 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
313 ASSERT_EQ(2U, s[0]->InputCount());
314 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
315 EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1)));
316 EXPECT_EQ(1U, s[0]->OutputCount());
317 }
318 }
319
320
TEST_P(InstructionSelectorAddSubTest,ImmediateOnLeft)321 TEST_P(InstructionSelectorAddSubTest, ImmediateOnLeft) {
322 const MachInst2 dpi = GetParam();
323 const MachineType type = dpi.machine_type;
324
325 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
326 StreamBuilder m(this, type, type);
327 m.Return((m.*dpi.constructor)(BuildConstant(m, type, imm), m.Parameter(0)));
328 Stream s = m.Build();
329
330 // Add can support an immediate on the left by commuting, but Sub can't
331 // commute. We test zero-on-left Sub later.
332 if (strstr(dpi.constructor_name, "Add") != NULL) {
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.ToInt64(s[0]->InputAt(1)));
338 EXPECT_EQ(1U, s[0]->OutputCount());
339 }
340 }
341 }
342
343
344 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorAddSubTest,
345 ::testing::ValuesIn(kAddSubInstructions));
346
347
TEST_F(InstructionSelectorTest,SubZeroOnLeft)348 TEST_F(InstructionSelectorTest, SubZeroOnLeft) {
349 // Subtraction with zero on the left maps to Neg.
350 {
351 // 32-bit subtract.
352 StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
353 m.Return(m.Int32Sub(m.Int32Constant(0), m.Parameter(0)));
354 Stream s = m.Build();
355
356 ASSERT_EQ(1U, s.size());
357 EXPECT_EQ(kArm64Neg32, s[0]->arch_opcode());
358 EXPECT_EQ(1U, s[0]->InputCount());
359 EXPECT_EQ(1U, s[0]->OutputCount());
360 }
361 {
362 // 64-bit subtract.
363 StreamBuilder m(this, kMachInt64, kMachInt64, kMachInt64);
364 m.Return(m.Int64Sub(m.Int64Constant(0), m.Parameter(0)));
365 Stream s = m.Build();
366
367 ASSERT_EQ(1U, s.size());
368 EXPECT_EQ(kArm64Neg, s[0]->arch_opcode());
369 EXPECT_EQ(1U, s[0]->InputCount());
370 EXPECT_EQ(1U, s[0]->OutputCount());
371 }
372 }
373
374
375 // -----------------------------------------------------------------------------
376 // Data processing controlled branches.
377
378
379 typedef InstructionSelectorTestWithParam<MachInst2>
380 InstructionSelectorDPFlagSetTest;
381
382
TEST_P(InstructionSelectorDPFlagSetTest,BranchWithParameters)383 TEST_P(InstructionSelectorDPFlagSetTest, BranchWithParameters) {
384 const MachInst2 dpi = GetParam();
385 const MachineType type = dpi.machine_type;
386 StreamBuilder m(this, type, type, type);
387 MLabel a, b;
388 m.Branch((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)), &a, &b);
389 m.Bind(&a);
390 m.Return(m.Int32Constant(1));
391 m.Bind(&b);
392 m.Return(m.Int32Constant(0));
393 Stream s = m.Build();
394 ASSERT_EQ(1U, s.size());
395 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
396 EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
397 EXPECT_EQ(kNotEqual, s[0]->flags_condition());
398 }
399
400
401 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
402 InstructionSelectorDPFlagSetTest,
403 ::testing::ValuesIn(kDPFlagSetInstructions));
404
405
TEST_F(InstructionSelectorTest,AndBranchWithImmediateOnRight)406 TEST_F(InstructionSelectorTest, AndBranchWithImmediateOnRight) {
407 TRACED_FOREACH(int32_t, imm, kLogicalImmediates) {
408 StreamBuilder m(this, kMachInt32, kMachInt32);
409 MLabel a, b;
410 m.Branch(m.Word32And(m.Parameter(0), m.Int32Constant(imm)), &a, &b);
411 m.Bind(&a);
412 m.Return(m.Int32Constant(1));
413 m.Bind(&b);
414 m.Return(m.Int32Constant(0));
415 Stream s = m.Build();
416 ASSERT_EQ(1U, s.size());
417 EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode());
418 EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
419 EXPECT_EQ(kNotEqual, s[0]->flags_condition());
420 }
421 }
422
423
TEST_F(InstructionSelectorTest,AddBranchWithImmediateOnRight)424 TEST_F(InstructionSelectorTest, AddBranchWithImmediateOnRight) {
425 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
426 StreamBuilder m(this, kMachInt32, kMachInt32);
427 MLabel a, b;
428 m.Branch(m.Int32Add(m.Parameter(0), m.Int32Constant(imm)), &a, &b);
429 m.Bind(&a);
430 m.Return(m.Int32Constant(1));
431 m.Bind(&b);
432 m.Return(m.Int32Constant(0));
433 Stream s = m.Build();
434 ASSERT_EQ(1U, s.size());
435 EXPECT_EQ(kArm64Cmn32, s[0]->arch_opcode());
436 EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
437 EXPECT_EQ(kNotEqual, s[0]->flags_condition());
438 }
439 }
440
441
TEST_F(InstructionSelectorTest,SubBranchWithImmediateOnRight)442 TEST_F(InstructionSelectorTest, SubBranchWithImmediateOnRight) {
443 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
444 StreamBuilder m(this, kMachInt32, kMachInt32);
445 MLabel a, b;
446 m.Branch(m.Int32Sub(m.Parameter(0), m.Int32Constant(imm)), &a, &b);
447 m.Bind(&a);
448 m.Return(m.Int32Constant(1));
449 m.Bind(&b);
450 m.Return(m.Int32Constant(0));
451 Stream s = m.Build();
452 ASSERT_EQ(1U, s.size());
453 EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode());
454 EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
455 EXPECT_EQ(kNotEqual, s[0]->flags_condition());
456 }
457 }
458
459
TEST_F(InstructionSelectorTest,AndBranchWithImmediateOnLeft)460 TEST_F(InstructionSelectorTest, AndBranchWithImmediateOnLeft) {
461 TRACED_FOREACH(int32_t, imm, kLogicalImmediates) {
462 StreamBuilder m(this, kMachInt32, kMachInt32);
463 MLabel a, b;
464 m.Branch(m.Word32And(m.Int32Constant(imm), m.Parameter(0)), &a, &b);
465 m.Bind(&a);
466 m.Return(m.Int32Constant(1));
467 m.Bind(&b);
468 m.Return(m.Int32Constant(0));
469 Stream s = m.Build();
470 ASSERT_EQ(1U, s.size());
471 EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode());
472 ASSERT_LE(1U, s[0]->InputCount());
473 EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
474 EXPECT_EQ(kNotEqual, s[0]->flags_condition());
475 }
476 }
477
478
TEST_F(InstructionSelectorTest,AddBranchWithImmediateOnLeft)479 TEST_F(InstructionSelectorTest, AddBranchWithImmediateOnLeft) {
480 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
481 StreamBuilder m(this, kMachInt32, kMachInt32);
482 MLabel a, b;
483 m.Branch(m.Int32Add(m.Int32Constant(imm), m.Parameter(0)), &a, &b);
484 m.Bind(&a);
485 m.Return(m.Int32Constant(1));
486 m.Bind(&b);
487 m.Return(m.Int32Constant(0));
488 Stream s = m.Build();
489 ASSERT_EQ(1U, s.size());
490 EXPECT_EQ(kArm64Cmn32, s[0]->arch_opcode());
491 ASSERT_LE(1U, s[0]->InputCount());
492 EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
493 EXPECT_EQ(kNotEqual, s[0]->flags_condition());
494 }
495 }
496
497
498 // -----------------------------------------------------------------------------
499 // Add and subtract instructions with overflow.
500
501
502 typedef InstructionSelectorTestWithParam<MachInst2>
503 InstructionSelectorOvfAddSubTest;
504
505
TEST_P(InstructionSelectorOvfAddSubTest,OvfParameter)506 TEST_P(InstructionSelectorOvfAddSubTest, OvfParameter) {
507 const MachInst2 dpi = GetParam();
508 const MachineType type = dpi.machine_type;
509 StreamBuilder m(this, type, type, type);
510 m.Return(
511 m.Projection(1, (m.*dpi.constructor)(m.Parameter(0), m.Parameter(1))));
512 Stream s = m.Build();
513 ASSERT_EQ(1U, s.size());
514 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
515 EXPECT_EQ(2U, s[0]->InputCount());
516 EXPECT_LE(1U, s[0]->OutputCount());
517 EXPECT_EQ(kFlags_set, s[0]->flags_mode());
518 EXPECT_EQ(kOverflow, s[0]->flags_condition());
519 }
520
521
TEST_P(InstructionSelectorOvfAddSubTest,OvfImmediateOnRight)522 TEST_P(InstructionSelectorOvfAddSubTest, OvfImmediateOnRight) {
523 const MachInst2 dpi = GetParam();
524 const MachineType type = dpi.machine_type;
525 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
526 StreamBuilder m(this, type, type);
527 m.Return(m.Projection(
528 1, (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm))));
529 Stream s = m.Build();
530 ASSERT_EQ(1U, s.size());
531 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
532 ASSERT_EQ(2U, s[0]->InputCount());
533 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
534 EXPECT_LE(1U, s[0]->OutputCount());
535 EXPECT_EQ(kFlags_set, s[0]->flags_mode());
536 EXPECT_EQ(kOverflow, s[0]->flags_condition());
537 }
538 }
539
540
TEST_P(InstructionSelectorOvfAddSubTest,ValParameter)541 TEST_P(InstructionSelectorOvfAddSubTest, ValParameter) {
542 const MachInst2 dpi = GetParam();
543 const MachineType type = dpi.machine_type;
544 StreamBuilder m(this, type, type, type);
545 m.Return(
546 m.Projection(0, (m.*dpi.constructor)(m.Parameter(0), m.Parameter(1))));
547 Stream s = m.Build();
548 ASSERT_EQ(1U, s.size());
549 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
550 EXPECT_EQ(2U, s[0]->InputCount());
551 EXPECT_LE(1U, s[0]->OutputCount());
552 EXPECT_EQ(kFlags_none, s[0]->flags_mode());
553 }
554
555
TEST_P(InstructionSelectorOvfAddSubTest,ValImmediateOnRight)556 TEST_P(InstructionSelectorOvfAddSubTest, ValImmediateOnRight) {
557 const MachInst2 dpi = GetParam();
558 const MachineType type = dpi.machine_type;
559 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
560 StreamBuilder m(this, type, type);
561 m.Return(m.Projection(
562 0, (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm))));
563 Stream s = m.Build();
564 ASSERT_EQ(1U, s.size());
565 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
566 ASSERT_EQ(2U, s[0]->InputCount());
567 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
568 EXPECT_LE(1U, s[0]->OutputCount());
569 EXPECT_EQ(kFlags_none, s[0]->flags_mode());
570 }
571 }
572
573
TEST_P(InstructionSelectorOvfAddSubTest,BothParameter)574 TEST_P(InstructionSelectorOvfAddSubTest, BothParameter) {
575 const MachInst2 dpi = GetParam();
576 const MachineType type = dpi.machine_type;
577 StreamBuilder m(this, type, type, type);
578 Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Parameter(1));
579 m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
580 Stream s = m.Build();
581 ASSERT_LE(1U, s.size());
582 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
583 EXPECT_EQ(2U, s[0]->InputCount());
584 EXPECT_EQ(2U, s[0]->OutputCount());
585 EXPECT_EQ(kFlags_set, s[0]->flags_mode());
586 EXPECT_EQ(kOverflow, s[0]->flags_condition());
587 }
588
589
TEST_P(InstructionSelectorOvfAddSubTest,BothImmediateOnRight)590 TEST_P(InstructionSelectorOvfAddSubTest, BothImmediateOnRight) {
591 const MachInst2 dpi = GetParam();
592 const MachineType type = dpi.machine_type;
593 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
594 StreamBuilder m(this, type, type);
595 Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm));
596 m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
597 Stream s = m.Build();
598 ASSERT_LE(1U, s.size());
599 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
600 ASSERT_EQ(2U, s[0]->InputCount());
601 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
602 EXPECT_EQ(2U, s[0]->OutputCount());
603 EXPECT_EQ(kFlags_set, s[0]->flags_mode());
604 EXPECT_EQ(kOverflow, s[0]->flags_condition());
605 }
606 }
607
608
TEST_P(InstructionSelectorOvfAddSubTest,BranchWithParameters)609 TEST_P(InstructionSelectorOvfAddSubTest, BranchWithParameters) {
610 const MachInst2 dpi = GetParam();
611 const MachineType type = dpi.machine_type;
612 StreamBuilder m(this, type, type, type);
613 MLabel a, b;
614 Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Parameter(1));
615 m.Branch(m.Projection(1, n), &a, &b);
616 m.Bind(&a);
617 m.Return(m.Int32Constant(0));
618 m.Bind(&b);
619 m.Return(m.Projection(0, n));
620 Stream s = m.Build();
621 ASSERT_EQ(1U, s.size());
622 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
623 EXPECT_EQ(4U, s[0]->InputCount());
624 EXPECT_EQ(1U, s[0]->OutputCount());
625 EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
626 EXPECT_EQ(kOverflow, s[0]->flags_condition());
627 }
628
629
TEST_P(InstructionSelectorOvfAddSubTest,BranchWithImmediateOnRight)630 TEST_P(InstructionSelectorOvfAddSubTest, BranchWithImmediateOnRight) {
631 const MachInst2 dpi = GetParam();
632 const MachineType type = dpi.machine_type;
633 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
634 StreamBuilder m(this, type, type);
635 MLabel a, b;
636 Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm));
637 m.Branch(m.Projection(1, n), &a, &b);
638 m.Bind(&a);
639 m.Return(m.Int32Constant(0));
640 m.Bind(&b);
641 m.Return(m.Projection(0, n));
642 Stream s = m.Build();
643 ASSERT_EQ(1U, s.size());
644 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
645 ASSERT_EQ(4U, s[0]->InputCount());
646 EXPECT_EQ(1U, s[0]->OutputCount());
647 EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
648 EXPECT_EQ(kOverflow, s[0]->flags_condition());
649 }
650 }
651
652
653 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
654 InstructionSelectorOvfAddSubTest,
655 ::testing::ValuesIn(kOvfAddSubInstructions));
656
657
TEST_F(InstructionSelectorTest,OvfFlagAddImmediateOnLeft)658 TEST_F(InstructionSelectorTest, OvfFlagAddImmediateOnLeft) {
659 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
660 StreamBuilder m(this, kMachInt32, kMachInt32);
661 m.Return(m.Projection(
662 1, m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0))));
663 Stream s = m.Build();
664
665 ASSERT_EQ(1U, s.size());
666 EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
667 EXPECT_EQ(2U, s[0]->InputCount());
668 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
669 EXPECT_LE(1U, s[0]->OutputCount());
670 EXPECT_EQ(kFlags_set, s[0]->flags_mode());
671 EXPECT_EQ(kOverflow, s[0]->flags_condition());
672 }
673 }
674
675
TEST_F(InstructionSelectorTest,OvfValAddImmediateOnLeft)676 TEST_F(InstructionSelectorTest, OvfValAddImmediateOnLeft) {
677 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
678 StreamBuilder m(this, kMachInt32, kMachInt32);
679 m.Return(m.Projection(
680 0, m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0))));
681 Stream s = m.Build();
682
683 ASSERT_EQ(1U, s.size());
684 EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
685 ASSERT_EQ(2U, s[0]->InputCount());
686 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
687 EXPECT_LE(1U, s[0]->OutputCount());
688 EXPECT_EQ(kFlags_none, s[0]->flags_mode());
689 }
690 }
691
692
TEST_F(InstructionSelectorTest,OvfBothAddImmediateOnLeft)693 TEST_F(InstructionSelectorTest, OvfBothAddImmediateOnLeft) {
694 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
695 StreamBuilder m(this, kMachInt32, kMachInt32);
696 Node* n = m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0));
697 m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
698 Stream s = m.Build();
699
700 ASSERT_LE(1U, s.size());
701 EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
702 ASSERT_EQ(2U, s[0]->InputCount());
703 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
704 EXPECT_EQ(2U, s[0]->OutputCount());
705 EXPECT_EQ(kFlags_set, s[0]->flags_mode());
706 EXPECT_EQ(kOverflow, s[0]->flags_condition());
707 }
708 }
709
710
TEST_F(InstructionSelectorTest,OvfBranchWithImmediateOnLeft)711 TEST_F(InstructionSelectorTest, OvfBranchWithImmediateOnLeft) {
712 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
713 StreamBuilder m(this, kMachInt32, kMachInt32);
714 MLabel a, b;
715 Node* n = m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0));
716 m.Branch(m.Projection(1, n), &a, &b);
717 m.Bind(&a);
718 m.Return(m.Int32Constant(0));
719 m.Bind(&b);
720 m.Return(m.Projection(0, n));
721 Stream s = m.Build();
722
723 ASSERT_EQ(1U, s.size());
724 EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
725 ASSERT_EQ(4U, s[0]->InputCount());
726 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
727 EXPECT_EQ(1U, s[0]->OutputCount());
728 EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
729 EXPECT_EQ(kOverflow, s[0]->flags_condition());
730 }
731 }
732
733
734 // -----------------------------------------------------------------------------
735 // Shift instructions.
736
737
738 typedef InstructionSelectorTestWithParam<MachInst2>
739 InstructionSelectorShiftTest;
740
741
TEST_P(InstructionSelectorShiftTest,Parameter)742 TEST_P(InstructionSelectorShiftTest, Parameter) {
743 const MachInst2 dpi = GetParam();
744 const MachineType type = dpi.machine_type;
745 StreamBuilder m(this, type, type, type);
746 m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)));
747 Stream s = m.Build();
748 ASSERT_EQ(1U, s.size());
749 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
750 EXPECT_EQ(2U, s[0]->InputCount());
751 EXPECT_EQ(1U, s[0]->OutputCount());
752 }
753
754
TEST_P(InstructionSelectorShiftTest,Immediate)755 TEST_P(InstructionSelectorShiftTest, Immediate) {
756 const MachInst2 dpi = GetParam();
757 const MachineType type = dpi.machine_type;
758 TRACED_FORRANGE(int32_t, imm, 0, (ElementSizeOf(type) * 8) - 1) {
759 StreamBuilder m(this, type, type);
760 m.Return((m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm)));
761 Stream s = m.Build();
762 ASSERT_EQ(1U, s.size());
763 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
764 EXPECT_EQ(2U, s[0]->InputCount());
765 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
766 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
767 EXPECT_EQ(1U, s[0]->OutputCount());
768 }
769 }
770
771
772 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorShiftTest,
773 ::testing::ValuesIn(kShiftInstructions));
774
775
776 // -----------------------------------------------------------------------------
777 // Mul and Div instructions.
778
779
780 typedef InstructionSelectorTestWithParam<MachInst2>
781 InstructionSelectorMulDivTest;
782
783
TEST_P(InstructionSelectorMulDivTest,Parameter)784 TEST_P(InstructionSelectorMulDivTest, Parameter) {
785 const MachInst2 dpi = GetParam();
786 const MachineType type = dpi.machine_type;
787 StreamBuilder m(this, type, type, type);
788 m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)));
789 Stream s = m.Build();
790 ASSERT_EQ(1U, s.size());
791 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
792 EXPECT_EQ(2U, s[0]->InputCount());
793 EXPECT_EQ(1U, s[0]->OutputCount());
794 }
795
796 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorMulDivTest,
797 ::testing::ValuesIn(kMulDivInstructions));
798
799
800 // -----------------------------------------------------------------------------
801 // Floating point instructions.
802
803 typedef InstructionSelectorTestWithParam<MachInst2>
804 InstructionSelectorFPArithTest;
805
806
TEST_P(InstructionSelectorFPArithTest,Parameter)807 TEST_P(InstructionSelectorFPArithTest, Parameter) {
808 const MachInst2 fpa = GetParam();
809 StreamBuilder m(this, fpa.machine_type, fpa.machine_type, fpa.machine_type);
810 m.Return((m.*fpa.constructor)(m.Parameter(0), m.Parameter(1)));
811 Stream s = m.Build();
812 ASSERT_EQ(1U, s.size());
813 EXPECT_EQ(fpa.arch_opcode, s[0]->arch_opcode());
814 EXPECT_EQ(2U, s[0]->InputCount());
815 EXPECT_EQ(1U, s[0]->OutputCount());
816 }
817
818
819 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorFPArithTest,
820 ::testing::ValuesIn(kFPArithInstructions));
821
822
823 typedef InstructionSelectorTestWithParam<FPCmp> InstructionSelectorFPCmpTest;
824
825
TEST_P(InstructionSelectorFPCmpTest,Parameter)826 TEST_P(InstructionSelectorFPCmpTest, Parameter) {
827 const FPCmp cmp = GetParam();
828 StreamBuilder m(this, kMachInt32, cmp.mi.machine_type, cmp.mi.machine_type);
829 m.Return((m.*cmp.mi.constructor)(m.Parameter(0), m.Parameter(1)));
830 Stream s = m.Build();
831 ASSERT_EQ(1U, s.size());
832 EXPECT_EQ(cmp.mi.arch_opcode, s[0]->arch_opcode());
833 EXPECT_EQ(2U, s[0]->InputCount());
834 EXPECT_EQ(1U, s[0]->OutputCount());
835 EXPECT_EQ(kFlags_set, s[0]->flags_mode());
836 EXPECT_EQ(cmp.cond, s[0]->flags_condition());
837 }
838
839
840 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorFPCmpTest,
841 ::testing::ValuesIn(kFPCmpInstructions));
842
843
844 // -----------------------------------------------------------------------------
845 // Conversions.
846
847 typedef InstructionSelectorTestWithParam<Conversion>
848 InstructionSelectorConversionTest;
849
850
TEST_P(InstructionSelectorConversionTest,Parameter)851 TEST_P(InstructionSelectorConversionTest, Parameter) {
852 const Conversion conv = GetParam();
853 StreamBuilder m(this, conv.mi.machine_type, conv.src_machine_type);
854 m.Return((m.*conv.mi.constructor)(m.Parameter(0)));
855 Stream s = m.Build();
856 ASSERT_EQ(1U, s.size());
857 EXPECT_EQ(conv.mi.arch_opcode, s[0]->arch_opcode());
858 EXPECT_EQ(1U, s[0]->InputCount());
859 EXPECT_EQ(1U, s[0]->OutputCount());
860 }
861
862
863 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
864 InstructionSelectorConversionTest,
865 ::testing::ValuesIn(kConversionInstructions));
866
867
868 // -----------------------------------------------------------------------------
869 // Memory access instructions.
870
871
872 namespace {
873
874 struct MemoryAccess {
875 MachineType type;
876 ArchOpcode ldr_opcode;
877 ArchOpcode str_opcode;
878 const int32_t immediates[20];
879 };
880
881
operator <<(std::ostream & os,const MemoryAccess & memacc)882 std::ostream& operator<<(std::ostream& os, const MemoryAccess& memacc) {
883 OStringStream ost;
884 ost << memacc.type;
885 return os << ost.c_str();
886 }
887
888 } // namespace
889
890
891 static const MemoryAccess kMemoryAccesses[] = {
892 {kMachInt8, kArm64Ldrsb, kArm64Strb,
893 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 257, 258, 1000, 1001,
894 2121, 2442, 4093, 4094, 4095}},
895 {kMachUint8, kArm64Ldrb, kArm64Strb,
896 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 257, 258, 1000, 1001,
897 2121, 2442, 4093, 4094, 4095}},
898 {kMachInt16, kArm64Ldrsh, kArm64Strh,
899 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 258, 260, 4096, 4098,
900 4100, 4242, 6786, 8188, 8190}},
901 {kMachUint16, kArm64Ldrh, kArm64Strh,
902 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 258, 260, 4096, 4098,
903 4100, 4242, 6786, 8188, 8190}},
904 {kMachInt32, kArm64LdrW, kArm64StrW,
905 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 260, 4096, 4100, 8192,
906 8196, 3276, 3280, 16376, 16380}},
907 {kMachUint32, kArm64LdrW, kArm64StrW,
908 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 260, 4096, 4100, 8192,
909 8196, 3276, 3280, 16376, 16380}},
910 {kMachInt64, kArm64Ldr, kArm64Str,
911 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 264, 4096, 4104, 8192,
912 8200, 16384, 16392, 32752, 32760}},
913 {kMachUint64, kArm64Ldr, kArm64Str,
914 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 264, 4096, 4104, 8192,
915 8200, 16384, 16392, 32752, 32760}},
916 {kMachFloat32, kArm64LdrS, kArm64StrS,
917 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 260, 4096, 4100, 8192,
918 8196, 3276, 3280, 16376, 16380}},
919 {kMachFloat64, kArm64LdrD, kArm64StrD,
920 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 264, 4096, 4104, 8192,
921 8200, 16384, 16392, 32752, 32760}}};
922
923
924 typedef InstructionSelectorTestWithParam<MemoryAccess>
925 InstructionSelectorMemoryAccessTest;
926
927
TEST_P(InstructionSelectorMemoryAccessTest,LoadWithParameters)928 TEST_P(InstructionSelectorMemoryAccessTest, LoadWithParameters) {
929 const MemoryAccess memacc = GetParam();
930 StreamBuilder m(this, memacc.type, kMachPtr, kMachInt32);
931 m.Return(m.Load(memacc.type, m.Parameter(0), m.Parameter(1)));
932 Stream s = m.Build();
933 ASSERT_EQ(1U, s.size());
934 EXPECT_EQ(memacc.ldr_opcode, s[0]->arch_opcode());
935 EXPECT_EQ(kMode_MRR, s[0]->addressing_mode());
936 EXPECT_EQ(2U, s[0]->InputCount());
937 EXPECT_EQ(1U, s[0]->OutputCount());
938 }
939
940
TEST_P(InstructionSelectorMemoryAccessTest,LoadWithImmediateIndex)941 TEST_P(InstructionSelectorMemoryAccessTest, LoadWithImmediateIndex) {
942 const MemoryAccess memacc = GetParam();
943 TRACED_FOREACH(int32_t, index, memacc.immediates) {
944 StreamBuilder m(this, memacc.type, kMachPtr);
945 m.Return(m.Load(memacc.type, m.Parameter(0), m.Int32Constant(index)));
946 Stream s = m.Build();
947 ASSERT_EQ(1U, s.size());
948 EXPECT_EQ(memacc.ldr_opcode, s[0]->arch_opcode());
949 EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
950 EXPECT_EQ(2U, s[0]->InputCount());
951 ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
952 EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
953 ASSERT_EQ(1U, s[0]->OutputCount());
954 }
955 }
956
957
TEST_P(InstructionSelectorMemoryAccessTest,StoreWithParameters)958 TEST_P(InstructionSelectorMemoryAccessTest, StoreWithParameters) {
959 const MemoryAccess memacc = GetParam();
960 StreamBuilder m(this, kMachInt32, kMachPtr, kMachInt32, memacc.type);
961 m.Store(memacc.type, m.Parameter(0), m.Parameter(1), m.Parameter(2));
962 m.Return(m.Int32Constant(0));
963 Stream s = m.Build();
964 ASSERT_EQ(1U, s.size());
965 EXPECT_EQ(memacc.str_opcode, s[0]->arch_opcode());
966 EXPECT_EQ(kMode_MRR, s[0]->addressing_mode());
967 EXPECT_EQ(3U, s[0]->InputCount());
968 EXPECT_EQ(0U, s[0]->OutputCount());
969 }
970
971
TEST_P(InstructionSelectorMemoryAccessTest,StoreWithImmediateIndex)972 TEST_P(InstructionSelectorMemoryAccessTest, StoreWithImmediateIndex) {
973 const MemoryAccess memacc = GetParam();
974 TRACED_FOREACH(int32_t, index, memacc.immediates) {
975 StreamBuilder m(this, kMachInt32, kMachPtr, memacc.type);
976 m.Store(memacc.type, m.Parameter(0), m.Int32Constant(index),
977 m.Parameter(1));
978 m.Return(m.Int32Constant(0));
979 Stream s = m.Build();
980 ASSERT_EQ(1U, s.size());
981 EXPECT_EQ(memacc.str_opcode, s[0]->arch_opcode());
982 EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
983 ASSERT_EQ(3U, s[0]->InputCount());
984 ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
985 EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
986 EXPECT_EQ(0U, s[0]->OutputCount());
987 }
988 }
989
990
991 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
992 InstructionSelectorMemoryAccessTest,
993 ::testing::ValuesIn(kMemoryAccesses));
994
995
996 // -----------------------------------------------------------------------------
997 // Comparison instructions.
998
999 static const MachInst2 kComparisonInstructions[] = {
1000 {&RawMachineAssembler::Word32Equal, "Word32Equal", kArm64Cmp32, kMachInt32},
1001 {&RawMachineAssembler::Word64Equal, "Word64Equal", kArm64Cmp, kMachInt64},
1002 };
1003
1004
1005 typedef InstructionSelectorTestWithParam<MachInst2>
1006 InstructionSelectorComparisonTest;
1007
1008
TEST_P(InstructionSelectorComparisonTest,WithParameters)1009 TEST_P(InstructionSelectorComparisonTest, WithParameters) {
1010 const MachInst2 cmp = GetParam();
1011 const MachineType type = cmp.machine_type;
1012 StreamBuilder m(this, type, type, type);
1013 m.Return((m.*cmp.constructor)(m.Parameter(0), m.Parameter(1)));
1014 Stream s = m.Build();
1015 ASSERT_EQ(1U, s.size());
1016 EXPECT_EQ(cmp.arch_opcode, s[0]->arch_opcode());
1017 EXPECT_EQ(2U, s[0]->InputCount());
1018 EXPECT_EQ(1U, s[0]->OutputCount());
1019 EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1020 EXPECT_EQ(kEqual, s[0]->flags_condition());
1021 }
1022
1023
TEST_P(InstructionSelectorComparisonTest,WithImmediate)1024 TEST_P(InstructionSelectorComparisonTest, WithImmediate) {
1025 const MachInst2 cmp = GetParam();
1026 const MachineType type = cmp.machine_type;
1027 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
1028 // Compare with 0 are turned into tst instruction.
1029 if (imm == 0) continue;
1030 StreamBuilder m(this, type, type);
1031 m.Return((m.*cmp.constructor)(m.Parameter(0), BuildConstant(m, type, imm)));
1032 Stream s = m.Build();
1033 ASSERT_EQ(1U, s.size());
1034 EXPECT_EQ(cmp.arch_opcode, s[0]->arch_opcode());
1035 ASSERT_EQ(2U, s[0]->InputCount());
1036 ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
1037 EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1)));
1038 EXPECT_EQ(1U, s[0]->OutputCount());
1039 EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1040 EXPECT_EQ(kEqual, s[0]->flags_condition());
1041 }
1042 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
1043 // Compare with 0 are turned into tst instruction.
1044 if (imm == 0) continue;
1045 StreamBuilder m(this, type, type);
1046 m.Return((m.*cmp.constructor)(m.Parameter(0), BuildConstant(m, type, imm)));
1047 Stream s = m.Build();
1048 ASSERT_EQ(1U, s.size());
1049 EXPECT_EQ(cmp.arch_opcode, s[0]->arch_opcode());
1050 ASSERT_EQ(2U, s[0]->InputCount());
1051 ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
1052 EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1)));
1053 EXPECT_EQ(1U, s[0]->OutputCount());
1054 EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1055 EXPECT_EQ(kEqual, s[0]->flags_condition());
1056 }
1057 }
1058
1059 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
1060 InstructionSelectorComparisonTest,
1061 ::testing::ValuesIn(kComparisonInstructions));
1062
1063
TEST_F(InstructionSelectorTest,Word32EqualWithZero)1064 TEST_F(InstructionSelectorTest, Word32EqualWithZero) {
1065 {
1066 StreamBuilder m(this, kMachInt32, kMachInt32);
1067 m.Return(m.Word32Equal(m.Parameter(0), m.Int32Constant(0)));
1068 Stream s = m.Build();
1069 ASSERT_EQ(1U, s.size());
1070 EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode());
1071 ASSERT_EQ(2U, s[0]->InputCount());
1072 EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
1073 EXPECT_EQ(1U, s[0]->OutputCount());
1074 EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1075 EXPECT_EQ(kEqual, s[0]->flags_condition());
1076 }
1077 {
1078 StreamBuilder m(this, kMachInt32, kMachInt32);
1079 m.Return(m.Word32Equal(m.Int32Constant(0), m.Parameter(0)));
1080 Stream s = m.Build();
1081 ASSERT_EQ(1U, s.size());
1082 EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode());
1083 ASSERT_EQ(2U, s[0]->InputCount());
1084 EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
1085 EXPECT_EQ(1U, s[0]->OutputCount());
1086 EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1087 EXPECT_EQ(kEqual, s[0]->flags_condition());
1088 }
1089 }
1090
1091
TEST_F(InstructionSelectorTest,Word64EqualWithZero)1092 TEST_F(InstructionSelectorTest, Word64EqualWithZero) {
1093 {
1094 StreamBuilder m(this, kMachInt64, kMachInt64);
1095 m.Return(m.Word64Equal(m.Parameter(0), m.Int64Constant(0)));
1096 Stream s = m.Build();
1097 ASSERT_EQ(1U, s.size());
1098 EXPECT_EQ(kArm64Tst, s[0]->arch_opcode());
1099 ASSERT_EQ(2U, s[0]->InputCount());
1100 EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
1101 EXPECT_EQ(1U, s[0]->OutputCount());
1102 EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1103 EXPECT_EQ(kEqual, s[0]->flags_condition());
1104 }
1105 {
1106 StreamBuilder m(this, kMachInt64, kMachInt64);
1107 m.Return(m.Word64Equal(m.Int64Constant(0), m.Parameter(0)));
1108 Stream s = m.Build();
1109 ASSERT_EQ(1U, s.size());
1110 EXPECT_EQ(kArm64Tst, s[0]->arch_opcode());
1111 ASSERT_EQ(2U, s[0]->InputCount());
1112 EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
1113 EXPECT_EQ(1U, s[0]->OutputCount());
1114 EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1115 EXPECT_EQ(kEqual, s[0]->flags_condition());
1116 }
1117 }
1118
1119 } // namespace compiler
1120 } // namespace internal
1121 } // namespace v8
1122