OLD | NEW |
| (Empty) |
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> | |
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. | |
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", kArm64Eor32, kMachInt32}, | |
62 {&RawMachineAssembler::Word64Xor, "Word64Xor", kArm64Eor, 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 | |
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 | |
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::ChangeFloat32ToFloat64, "ChangeFloat32ToFloat64", | |
201 kArm64Float32ToFloat64, kMachFloat64}, | |
202 kMachFloat32}, | |
203 {{&RawMachineAssembler::TruncateFloat64ToFloat32, | |
204 "TruncateFloat64ToFloat32", kArm64Float64ToFloat32, kMachFloat32}, | |
205 kMachFloat64}, | |
206 {{&RawMachineAssembler::ChangeInt32ToInt64, "ChangeInt32ToInt64", | |
207 kArm64Sxtw, kMachInt64}, | |
208 kMachInt32}, | |
209 {{&RawMachineAssembler::ChangeUint32ToUint64, "ChangeUint32ToUint64", | |
210 kArm64Mov32, kMachUint64}, | |
211 kMachUint32}, | |
212 {{&RawMachineAssembler::TruncateInt64ToInt32, "TruncateInt64ToInt32", | |
213 kArm64Mov32, kMachInt32}, | |
214 kMachInt64}, | |
215 {{&RawMachineAssembler::ChangeInt32ToFloat64, "ChangeInt32ToFloat64", | |
216 kArm64Int32ToFloat64, kMachFloat64}, | |
217 kMachInt32}, | |
218 {{&RawMachineAssembler::ChangeUint32ToFloat64, "ChangeUint32ToFloat64", | |
219 kArm64Uint32ToFloat64, kMachFloat64}, | |
220 kMachUint32}, | |
221 {{&RawMachineAssembler::ChangeFloat64ToInt32, "ChangeFloat64ToInt32", | |
222 kArm64Float64ToInt32, kMachInt32}, | |
223 kMachFloat64}, | |
224 {{&RawMachineAssembler::ChangeFloat64ToUint32, "ChangeFloat64ToUint32", | |
225 kArm64Float64ToUint32, kMachUint32}, | |
226 kMachFloat64}}; | |
227 | |
228 } // namespace | |
229 | |
230 | |
231 // ----------------------------------------------------------------------------- | |
232 // Logical instructions. | |
233 | |
234 | |
235 typedef InstructionSelectorTestWithParam<MachInst2> | |
236 InstructionSelectorLogicalTest; | |
237 | |
238 | |
239 TEST_P(InstructionSelectorLogicalTest, Parameter) { | |
240 const MachInst2 dpi = GetParam(); | |
241 const MachineType type = dpi.machine_type; | |
242 StreamBuilder m(this, type, type, type); | |
243 m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1))); | |
244 Stream s = m.Build(); | |
245 ASSERT_EQ(1U, s.size()); | |
246 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); | |
247 EXPECT_EQ(2U, s[0]->InputCount()); | |
248 EXPECT_EQ(1U, s[0]->OutputCount()); | |
249 } | |
250 | |
251 | |
252 TEST_P(InstructionSelectorLogicalTest, Immediate) { | |
253 const MachInst2 dpi = GetParam(); | |
254 const MachineType type = dpi.machine_type; | |
255 // TODO(all): Add support for testing 64-bit immediates. | |
256 if (type == kMachInt32) { | |
257 // Immediate on the right. | |
258 TRACED_FOREACH(int32_t, imm, kLogicalImmediates) { | |
259 StreamBuilder m(this, type, type); | |
260 m.Return((m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm))); | |
261 Stream s = m.Build(); | |
262 ASSERT_EQ(1U, s.size()); | |
263 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); | |
264 ASSERT_EQ(2U, s[0]->InputCount()); | |
265 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate()); | |
266 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); | |
267 EXPECT_EQ(1U, s[0]->OutputCount()); | |
268 } | |
269 | |
270 // Immediate on the left; all logical ops should commute. | |
271 TRACED_FOREACH(int32_t, imm, kLogicalImmediates) { | |
272 StreamBuilder m(this, type, type); | |
273 m.Return((m.*dpi.constructor)(m.Int32Constant(imm), m.Parameter(0))); | |
274 Stream s = m.Build(); | |
275 ASSERT_EQ(1U, s.size()); | |
276 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); | |
277 ASSERT_EQ(2U, s[0]->InputCount()); | |
278 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate()); | |
279 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); | |
280 EXPECT_EQ(1U, s[0]->OutputCount()); | |
281 } | |
282 } | |
283 } | |
284 | |
285 | |
286 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorLogicalTest, | |
287 ::testing::ValuesIn(kLogicalInstructions)); | |
288 | |
289 | |
290 // ----------------------------------------------------------------------------- | |
291 // Add and Sub instructions. | |
292 | |
293 typedef InstructionSelectorTestWithParam<MachInst2> | |
294 InstructionSelectorAddSubTest; | |
295 | |
296 | |
297 TEST_P(InstructionSelectorAddSubTest, Parameter) { | |
298 const MachInst2 dpi = GetParam(); | |
299 const MachineType type = dpi.machine_type; | |
300 StreamBuilder m(this, type, type, type); | |
301 m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1))); | |
302 Stream s = m.Build(); | |
303 ASSERT_EQ(1U, s.size()); | |
304 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); | |
305 EXPECT_EQ(2U, s[0]->InputCount()); | |
306 EXPECT_EQ(1U, s[0]->OutputCount()); | |
307 } | |
308 | |
309 | |
310 TEST_P(InstructionSelectorAddSubTest, ImmediateOnRight) { | |
311 const MachInst2 dpi = GetParam(); | |
312 const MachineType type = dpi.machine_type; | |
313 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { | |
314 StreamBuilder m(this, type, type); | |
315 m.Return((m.*dpi.constructor)(m.Parameter(0), BuildConstant(m, type, imm))); | |
316 Stream s = m.Build(); | |
317 ASSERT_EQ(1U, s.size()); | |
318 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); | |
319 ASSERT_EQ(2U, s[0]->InputCount()); | |
320 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate()); | |
321 EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1))); | |
322 EXPECT_EQ(1U, s[0]->OutputCount()); | |
323 } | |
324 } | |
325 | |
326 | |
327 TEST_P(InstructionSelectorAddSubTest, ImmediateOnLeft) { | |
328 const MachInst2 dpi = GetParam(); | |
329 const MachineType type = dpi.machine_type; | |
330 | |
331 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { | |
332 StreamBuilder m(this, type, type); | |
333 m.Return((m.*dpi.constructor)(BuildConstant(m, type, imm), m.Parameter(0))); | |
334 Stream s = m.Build(); | |
335 | |
336 // Add can support an immediate on the left by commuting, but Sub can't | |
337 // commute. We test zero-on-left Sub later. | |
338 if (strstr(dpi.constructor_name, "Add") != NULL) { | |
339 ASSERT_EQ(1U, s.size()); | |
340 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); | |
341 ASSERT_EQ(2U, s[0]->InputCount()); | |
342 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate()); | |
343 EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1))); | |
344 EXPECT_EQ(1U, s[0]->OutputCount()); | |
345 } | |
346 } | |
347 } | |
348 | |
349 | |
350 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorAddSubTest, | |
351 ::testing::ValuesIn(kAddSubInstructions)); | |
352 | |
353 | |
354 TEST_F(InstructionSelectorTest, SubZeroOnLeft) { | |
355 // Subtraction with zero on the left maps to Neg. | |
356 { | |
357 // 32-bit subtract. | |
358 StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32); | |
359 m.Return(m.Int32Sub(m.Int32Constant(0), m.Parameter(0))); | |
360 Stream s = m.Build(); | |
361 | |
362 ASSERT_EQ(1U, s.size()); | |
363 EXPECT_EQ(kArm64Neg32, s[0]->arch_opcode()); | |
364 EXPECT_EQ(1U, s[0]->InputCount()); | |
365 EXPECT_EQ(1U, s[0]->OutputCount()); | |
366 } | |
367 { | |
368 // 64-bit subtract. | |
369 StreamBuilder m(this, kMachInt64, kMachInt64, kMachInt64); | |
370 m.Return(m.Int64Sub(m.Int64Constant(0), m.Parameter(0))); | |
371 Stream s = m.Build(); | |
372 | |
373 ASSERT_EQ(1U, s.size()); | |
374 EXPECT_EQ(kArm64Neg, s[0]->arch_opcode()); | |
375 EXPECT_EQ(1U, s[0]->InputCount()); | |
376 EXPECT_EQ(1U, s[0]->OutputCount()); | |
377 } | |
378 } | |
379 | |
380 | |
381 // ----------------------------------------------------------------------------- | |
382 // Data processing controlled branches. | |
383 | |
384 | |
385 typedef InstructionSelectorTestWithParam<MachInst2> | |
386 InstructionSelectorDPFlagSetTest; | |
387 | |
388 | |
389 TEST_P(InstructionSelectorDPFlagSetTest, BranchWithParameters) { | |
390 const MachInst2 dpi = GetParam(); | |
391 const MachineType type = dpi.machine_type; | |
392 StreamBuilder m(this, type, type, type); | |
393 MLabel a, b; | |
394 m.Branch((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)), &a, &b); | |
395 m.Bind(&a); | |
396 m.Return(m.Int32Constant(1)); | |
397 m.Bind(&b); | |
398 m.Return(m.Int32Constant(0)); | |
399 Stream s = m.Build(); | |
400 ASSERT_EQ(1U, s.size()); | |
401 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); | |
402 EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); | |
403 EXPECT_EQ(kNotEqual, s[0]->flags_condition()); | |
404 } | |
405 | |
406 | |
407 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, | |
408 InstructionSelectorDPFlagSetTest, | |
409 ::testing::ValuesIn(kDPFlagSetInstructions)); | |
410 | |
411 | |
412 TEST_F(InstructionSelectorTest, AndBranchWithImmediateOnRight) { | |
413 TRACED_FOREACH(int32_t, imm, kLogicalImmediates) { | |
414 StreamBuilder m(this, kMachInt32, kMachInt32); | |
415 MLabel a, b; | |
416 m.Branch(m.Word32And(m.Parameter(0), m.Int32Constant(imm)), &a, &b); | |
417 m.Bind(&a); | |
418 m.Return(m.Int32Constant(1)); | |
419 m.Bind(&b); | |
420 m.Return(m.Int32Constant(0)); | |
421 Stream s = m.Build(); | |
422 ASSERT_EQ(1U, s.size()); | |
423 EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode()); | |
424 EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); | |
425 EXPECT_EQ(kNotEqual, s[0]->flags_condition()); | |
426 } | |
427 } | |
428 | |
429 | |
430 TEST_F(InstructionSelectorTest, AddBranchWithImmediateOnRight) { | |
431 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { | |
432 StreamBuilder m(this, kMachInt32, kMachInt32); | |
433 MLabel a, b; | |
434 m.Branch(m.Int32Add(m.Parameter(0), m.Int32Constant(imm)), &a, &b); | |
435 m.Bind(&a); | |
436 m.Return(m.Int32Constant(1)); | |
437 m.Bind(&b); | |
438 m.Return(m.Int32Constant(0)); | |
439 Stream s = m.Build(); | |
440 ASSERT_EQ(1U, s.size()); | |
441 EXPECT_EQ(kArm64Cmn32, s[0]->arch_opcode()); | |
442 EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); | |
443 EXPECT_EQ(kNotEqual, s[0]->flags_condition()); | |
444 } | |
445 } | |
446 | |
447 | |
448 TEST_F(InstructionSelectorTest, SubBranchWithImmediateOnRight) { | |
449 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { | |
450 StreamBuilder m(this, kMachInt32, kMachInt32); | |
451 MLabel a, b; | |
452 m.Branch(m.Int32Sub(m.Parameter(0), m.Int32Constant(imm)), &a, &b); | |
453 m.Bind(&a); | |
454 m.Return(m.Int32Constant(1)); | |
455 m.Bind(&b); | |
456 m.Return(m.Int32Constant(0)); | |
457 Stream s = m.Build(); | |
458 ASSERT_EQ(1U, s.size()); | |
459 EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode()); | |
460 EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); | |
461 EXPECT_EQ(kNotEqual, s[0]->flags_condition()); | |
462 } | |
463 } | |
464 | |
465 | |
466 TEST_F(InstructionSelectorTest, AndBranchWithImmediateOnLeft) { | |
467 TRACED_FOREACH(int32_t, imm, kLogicalImmediates) { | |
468 StreamBuilder m(this, kMachInt32, kMachInt32); | |
469 MLabel a, b; | |
470 m.Branch(m.Word32And(m.Int32Constant(imm), m.Parameter(0)), &a, &b); | |
471 m.Bind(&a); | |
472 m.Return(m.Int32Constant(1)); | |
473 m.Bind(&b); | |
474 m.Return(m.Int32Constant(0)); | |
475 Stream s = m.Build(); | |
476 ASSERT_EQ(1U, s.size()); | |
477 EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode()); | |
478 ASSERT_LE(1U, s[0]->InputCount()); | |
479 EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); | |
480 EXPECT_EQ(kNotEqual, s[0]->flags_condition()); | |
481 } | |
482 } | |
483 | |
484 | |
485 TEST_F(InstructionSelectorTest, AddBranchWithImmediateOnLeft) { | |
486 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { | |
487 StreamBuilder m(this, kMachInt32, kMachInt32); | |
488 MLabel a, b; | |
489 m.Branch(m.Int32Add(m.Int32Constant(imm), m.Parameter(0)), &a, &b); | |
490 m.Bind(&a); | |
491 m.Return(m.Int32Constant(1)); | |
492 m.Bind(&b); | |
493 m.Return(m.Int32Constant(0)); | |
494 Stream s = m.Build(); | |
495 ASSERT_EQ(1U, s.size()); | |
496 EXPECT_EQ(kArm64Cmn32, s[0]->arch_opcode()); | |
497 ASSERT_LE(1U, s[0]->InputCount()); | |
498 EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); | |
499 EXPECT_EQ(kNotEqual, s[0]->flags_condition()); | |
500 } | |
501 } | |
502 | |
503 | |
504 // ----------------------------------------------------------------------------- | |
505 // Add and subtract instructions with overflow. | |
506 | |
507 | |
508 typedef InstructionSelectorTestWithParam<MachInst2> | |
509 InstructionSelectorOvfAddSubTest; | |
510 | |
511 | |
512 TEST_P(InstructionSelectorOvfAddSubTest, OvfParameter) { | |
513 const MachInst2 dpi = GetParam(); | |
514 const MachineType type = dpi.machine_type; | |
515 StreamBuilder m(this, type, type, type); | |
516 m.Return( | |
517 m.Projection(1, (m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)))); | |
518 Stream s = m.Build(); | |
519 ASSERT_EQ(1U, s.size()); | |
520 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); | |
521 EXPECT_EQ(2U, s[0]->InputCount()); | |
522 EXPECT_LE(1U, s[0]->OutputCount()); | |
523 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); | |
524 EXPECT_EQ(kOverflow, s[0]->flags_condition()); | |
525 } | |
526 | |
527 | |
528 TEST_P(InstructionSelectorOvfAddSubTest, OvfImmediateOnRight) { | |
529 const MachInst2 dpi = GetParam(); | |
530 const MachineType type = dpi.machine_type; | |
531 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { | |
532 StreamBuilder m(this, type, type); | |
533 m.Return(m.Projection( | |
534 1, (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm)))); | |
535 Stream s = m.Build(); | |
536 ASSERT_EQ(1U, s.size()); | |
537 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); | |
538 ASSERT_EQ(2U, s[0]->InputCount()); | |
539 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); | |
540 EXPECT_LE(1U, s[0]->OutputCount()); | |
541 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); | |
542 EXPECT_EQ(kOverflow, s[0]->flags_condition()); | |
543 } | |
544 } | |
545 | |
546 | |
547 TEST_P(InstructionSelectorOvfAddSubTest, ValParameter) { | |
548 const MachInst2 dpi = GetParam(); | |
549 const MachineType type = dpi.machine_type; | |
550 StreamBuilder m(this, type, type, type); | |
551 m.Return( | |
552 m.Projection(0, (m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)))); | |
553 Stream s = m.Build(); | |
554 ASSERT_EQ(1U, s.size()); | |
555 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); | |
556 EXPECT_EQ(2U, s[0]->InputCount()); | |
557 EXPECT_LE(1U, s[0]->OutputCount()); | |
558 EXPECT_EQ(kFlags_none, s[0]->flags_mode()); | |
559 } | |
560 | |
561 | |
562 TEST_P(InstructionSelectorOvfAddSubTest, ValImmediateOnRight) { | |
563 const MachInst2 dpi = GetParam(); | |
564 const MachineType type = dpi.machine_type; | |
565 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { | |
566 StreamBuilder m(this, type, type); | |
567 m.Return(m.Projection( | |
568 0, (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm)))); | |
569 Stream s = m.Build(); | |
570 ASSERT_EQ(1U, s.size()); | |
571 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); | |
572 ASSERT_EQ(2U, s[0]->InputCount()); | |
573 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); | |
574 EXPECT_LE(1U, s[0]->OutputCount()); | |
575 EXPECT_EQ(kFlags_none, s[0]->flags_mode()); | |
576 } | |
577 } | |
578 | |
579 | |
580 TEST_P(InstructionSelectorOvfAddSubTest, BothParameter) { | |
581 const MachInst2 dpi = GetParam(); | |
582 const MachineType type = dpi.machine_type; | |
583 StreamBuilder m(this, type, type, type); | |
584 Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)); | |
585 m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n))); | |
586 Stream s = m.Build(); | |
587 ASSERT_LE(1U, s.size()); | |
588 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); | |
589 EXPECT_EQ(2U, s[0]->InputCount()); | |
590 EXPECT_EQ(2U, s[0]->OutputCount()); | |
591 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); | |
592 EXPECT_EQ(kOverflow, s[0]->flags_condition()); | |
593 } | |
594 | |
595 | |
596 TEST_P(InstructionSelectorOvfAddSubTest, BothImmediateOnRight) { | |
597 const MachInst2 dpi = GetParam(); | |
598 const MachineType type = dpi.machine_type; | |
599 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { | |
600 StreamBuilder m(this, type, type); | |
601 Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm)); | |
602 m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n))); | |
603 Stream s = m.Build(); | |
604 ASSERT_LE(1U, s.size()); | |
605 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); | |
606 ASSERT_EQ(2U, s[0]->InputCount()); | |
607 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); | |
608 EXPECT_EQ(2U, s[0]->OutputCount()); | |
609 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); | |
610 EXPECT_EQ(kOverflow, s[0]->flags_condition()); | |
611 } | |
612 } | |
613 | |
614 | |
615 TEST_P(InstructionSelectorOvfAddSubTest, BranchWithParameters) { | |
616 const MachInst2 dpi = GetParam(); | |
617 const MachineType type = dpi.machine_type; | |
618 StreamBuilder m(this, type, type, type); | |
619 MLabel a, b; | |
620 Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)); | |
621 m.Branch(m.Projection(1, n), &a, &b); | |
622 m.Bind(&a); | |
623 m.Return(m.Int32Constant(0)); | |
624 m.Bind(&b); | |
625 m.Return(m.Projection(0, n)); | |
626 Stream s = m.Build(); | |
627 ASSERT_EQ(1U, s.size()); | |
628 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); | |
629 EXPECT_EQ(4U, s[0]->InputCount()); | |
630 EXPECT_EQ(1U, s[0]->OutputCount()); | |
631 EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); | |
632 EXPECT_EQ(kOverflow, s[0]->flags_condition()); | |
633 } | |
634 | |
635 | |
636 TEST_P(InstructionSelectorOvfAddSubTest, BranchWithImmediateOnRight) { | |
637 const MachInst2 dpi = GetParam(); | |
638 const MachineType type = dpi.machine_type; | |
639 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { | |
640 StreamBuilder m(this, type, type); | |
641 MLabel a, b; | |
642 Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm)); | |
643 m.Branch(m.Projection(1, n), &a, &b); | |
644 m.Bind(&a); | |
645 m.Return(m.Int32Constant(0)); | |
646 m.Bind(&b); | |
647 m.Return(m.Projection(0, n)); | |
648 Stream s = m.Build(); | |
649 ASSERT_EQ(1U, s.size()); | |
650 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); | |
651 ASSERT_EQ(4U, s[0]->InputCount()); | |
652 EXPECT_EQ(1U, s[0]->OutputCount()); | |
653 EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); | |
654 EXPECT_EQ(kOverflow, s[0]->flags_condition()); | |
655 } | |
656 } | |
657 | |
658 | |
659 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, | |
660 InstructionSelectorOvfAddSubTest, | |
661 ::testing::ValuesIn(kOvfAddSubInstructions)); | |
662 | |
663 | |
664 TEST_F(InstructionSelectorTest, OvfFlagAddImmediateOnLeft) { | |
665 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { | |
666 StreamBuilder m(this, kMachInt32, kMachInt32); | |
667 m.Return(m.Projection( | |
668 1, m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0)))); | |
669 Stream s = m.Build(); | |
670 | |
671 ASSERT_EQ(1U, s.size()); | |
672 EXPECT_EQ(kArm64Add32, s[0]->arch_opcode()); | |
673 EXPECT_EQ(2U, s[0]->InputCount()); | |
674 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); | |
675 EXPECT_LE(1U, s[0]->OutputCount()); | |
676 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); | |
677 EXPECT_EQ(kOverflow, s[0]->flags_condition()); | |
678 } | |
679 } | |
680 | |
681 | |
682 TEST_F(InstructionSelectorTest, OvfValAddImmediateOnLeft) { | |
683 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { | |
684 StreamBuilder m(this, kMachInt32, kMachInt32); | |
685 m.Return(m.Projection( | |
686 0, m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0)))); | |
687 Stream s = m.Build(); | |
688 | |
689 ASSERT_EQ(1U, s.size()); | |
690 EXPECT_EQ(kArm64Add32, s[0]->arch_opcode()); | |
691 ASSERT_EQ(2U, s[0]->InputCount()); | |
692 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); | |
693 EXPECT_LE(1U, s[0]->OutputCount()); | |
694 EXPECT_EQ(kFlags_none, s[0]->flags_mode()); | |
695 } | |
696 } | |
697 | |
698 | |
699 TEST_F(InstructionSelectorTest, OvfBothAddImmediateOnLeft) { | |
700 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { | |
701 StreamBuilder m(this, kMachInt32, kMachInt32); | |
702 Node* n = m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0)); | |
703 m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n))); | |
704 Stream s = m.Build(); | |
705 | |
706 ASSERT_LE(1U, s.size()); | |
707 EXPECT_EQ(kArm64Add32, s[0]->arch_opcode()); | |
708 ASSERT_EQ(2U, s[0]->InputCount()); | |
709 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); | |
710 EXPECT_EQ(2U, s[0]->OutputCount()); | |
711 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); | |
712 EXPECT_EQ(kOverflow, s[0]->flags_condition()); | |
713 } | |
714 } | |
715 | |
716 | |
717 TEST_F(InstructionSelectorTest, OvfBranchWithImmediateOnLeft) { | |
718 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { | |
719 StreamBuilder m(this, kMachInt32, kMachInt32); | |
720 MLabel a, b; | |
721 Node* n = m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0)); | |
722 m.Branch(m.Projection(1, n), &a, &b); | |
723 m.Bind(&a); | |
724 m.Return(m.Int32Constant(0)); | |
725 m.Bind(&b); | |
726 m.Return(m.Projection(0, n)); | |
727 Stream s = m.Build(); | |
728 | |
729 ASSERT_EQ(1U, s.size()); | |
730 EXPECT_EQ(kArm64Add32, s[0]->arch_opcode()); | |
731 ASSERT_EQ(4U, s[0]->InputCount()); | |
732 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); | |
733 EXPECT_EQ(1U, s[0]->OutputCount()); | |
734 EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); | |
735 EXPECT_EQ(kOverflow, s[0]->flags_condition()); | |
736 } | |
737 } | |
738 | |
739 | |
740 // ----------------------------------------------------------------------------- | |
741 // Shift instructions. | |
742 | |
743 | |
744 typedef InstructionSelectorTestWithParam<MachInst2> | |
745 InstructionSelectorShiftTest; | |
746 | |
747 | |
748 TEST_P(InstructionSelectorShiftTest, Parameter) { | |
749 const MachInst2 dpi = GetParam(); | |
750 const MachineType type = dpi.machine_type; | |
751 StreamBuilder m(this, type, type, type); | |
752 m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1))); | |
753 Stream s = m.Build(); | |
754 ASSERT_EQ(1U, s.size()); | |
755 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); | |
756 EXPECT_EQ(2U, s[0]->InputCount()); | |
757 EXPECT_EQ(1U, s[0]->OutputCount()); | |
758 } | |
759 | |
760 | |
761 TEST_P(InstructionSelectorShiftTest, Immediate) { | |
762 const MachInst2 dpi = GetParam(); | |
763 const MachineType type = dpi.machine_type; | |
764 TRACED_FORRANGE(int32_t, imm, 0, (ElementSizeOf(type) * 8) - 1) { | |
765 StreamBuilder m(this, type, type); | |
766 m.Return((m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm))); | |
767 Stream s = m.Build(); | |
768 ASSERT_EQ(1U, s.size()); | |
769 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); | |
770 EXPECT_EQ(2U, s[0]->InputCount()); | |
771 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate()); | |
772 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); | |
773 EXPECT_EQ(1U, s[0]->OutputCount()); | |
774 } | |
775 } | |
776 | |
777 | |
778 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorShiftTest, | |
779 ::testing::ValuesIn(kShiftInstructions)); | |
780 | |
781 | |
782 // ----------------------------------------------------------------------------- | |
783 // Mul and Div instructions. | |
784 | |
785 | |
786 typedef InstructionSelectorTestWithParam<MachInst2> | |
787 InstructionSelectorMulDivTest; | |
788 | |
789 | |
790 TEST_P(InstructionSelectorMulDivTest, Parameter) { | |
791 const MachInst2 dpi = GetParam(); | |
792 const MachineType type = dpi.machine_type; | |
793 StreamBuilder m(this, type, type, type); | |
794 m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1))); | |
795 Stream s = m.Build(); | |
796 ASSERT_EQ(1U, s.size()); | |
797 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); | |
798 EXPECT_EQ(2U, s[0]->InputCount()); | |
799 EXPECT_EQ(1U, s[0]->OutputCount()); | |
800 } | |
801 | |
802 | |
803 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorMulDivTest, | |
804 ::testing::ValuesIn(kMulDivInstructions)); | |
805 | |
806 | |
807 namespace { | |
808 | |
809 struct MulDPInst { | |
810 const char* mul_constructor_name; | |
811 Node* (RawMachineAssembler::*mul_constructor)(Node*, Node*); | |
812 Node* (RawMachineAssembler::*add_constructor)(Node*, Node*); | |
813 Node* (RawMachineAssembler::*sub_constructor)(Node*, Node*); | |
814 ArchOpcode add_arch_opcode; | |
815 ArchOpcode sub_arch_opcode; | |
816 ArchOpcode neg_arch_opcode; | |
817 MachineType machine_type; | |
818 }; | |
819 | |
820 | |
821 std::ostream& operator<<(std::ostream& os, const MulDPInst& inst) { | |
822 return os << inst.mul_constructor_name; | |
823 } | |
824 | |
825 } // namespace | |
826 | |
827 | |
828 static const MulDPInst kMulDPInstructions[] = { | |
829 {"Int32Mul", &RawMachineAssembler::Int32Mul, &RawMachineAssembler::Int32Add, | |
830 &RawMachineAssembler::Int32Sub, kArm64Madd32, kArm64Msub32, kArm64Mneg32, | |
831 kMachInt32}, | |
832 {"Int64Mul", &RawMachineAssembler::Int64Mul, &RawMachineAssembler::Int64Add, | |
833 &RawMachineAssembler::Int64Sub, kArm64Madd, kArm64Msub, kArm64Mneg, | |
834 kMachInt64}}; | |
835 | |
836 | |
837 typedef InstructionSelectorTestWithParam<MulDPInst> | |
838 InstructionSelectorIntDPWithIntMulTest; | |
839 | |
840 | |
841 TEST_P(InstructionSelectorIntDPWithIntMulTest, AddWithMul) { | |
842 const MulDPInst mdpi = GetParam(); | |
843 const MachineType type = mdpi.machine_type; | |
844 { | |
845 StreamBuilder m(this, type, type, type, type); | |
846 Node* n = (m.*mdpi.mul_constructor)(m.Parameter(1), m.Parameter(2)); | |
847 m.Return((m.*mdpi.add_constructor)(m.Parameter(0), n)); | |
848 Stream s = m.Build(); | |
849 ASSERT_EQ(1U, s.size()); | |
850 EXPECT_EQ(mdpi.add_arch_opcode, s[0]->arch_opcode()); | |
851 EXPECT_EQ(3U, s[0]->InputCount()); | |
852 EXPECT_EQ(1U, s[0]->OutputCount()); | |
853 } | |
854 { | |
855 StreamBuilder m(this, type, type, type, type); | |
856 Node* n = (m.*mdpi.mul_constructor)(m.Parameter(0), m.Parameter(1)); | |
857 m.Return((m.*mdpi.add_constructor)(n, m.Parameter(2))); | |
858 Stream s = m.Build(); | |
859 ASSERT_EQ(1U, s.size()); | |
860 EXPECT_EQ(mdpi.add_arch_opcode, s[0]->arch_opcode()); | |
861 EXPECT_EQ(3U, s[0]->InputCount()); | |
862 EXPECT_EQ(1U, s[0]->OutputCount()); | |
863 } | |
864 } | |
865 | |
866 | |
867 TEST_P(InstructionSelectorIntDPWithIntMulTest, SubWithMul) { | |
868 const MulDPInst mdpi = GetParam(); | |
869 const MachineType type = mdpi.machine_type; | |
870 { | |
871 StreamBuilder m(this, type, type, type, type); | |
872 Node* n = (m.*mdpi.mul_constructor)(m.Parameter(1), m.Parameter(2)); | |
873 m.Return((m.*mdpi.sub_constructor)(m.Parameter(0), n)); | |
874 Stream s = m.Build(); | |
875 ASSERT_EQ(1U, s.size()); | |
876 EXPECT_EQ(mdpi.sub_arch_opcode, s[0]->arch_opcode()); | |
877 EXPECT_EQ(3U, s[0]->InputCount()); | |
878 EXPECT_EQ(1U, s[0]->OutputCount()); | |
879 } | |
880 } | |
881 | |
882 | |
883 TEST_P(InstructionSelectorIntDPWithIntMulTest, NegativeMul) { | |
884 const MulDPInst mdpi = GetParam(); | |
885 const MachineType type = mdpi.machine_type; | |
886 { | |
887 StreamBuilder m(this, type, type, type); | |
888 Node* n = | |
889 (m.*mdpi.sub_constructor)(BuildConstant(m, type, 0), m.Parameter(0)); | |
890 m.Return((m.*mdpi.mul_constructor)(n, m.Parameter(1))); | |
891 Stream s = m.Build(); | |
892 ASSERT_EQ(1U, s.size()); | |
893 EXPECT_EQ(mdpi.neg_arch_opcode, s[0]->arch_opcode()); | |
894 EXPECT_EQ(2U, s[0]->InputCount()); | |
895 EXPECT_EQ(1U, s[0]->OutputCount()); | |
896 } | |
897 { | |
898 StreamBuilder m(this, type, type, type); | |
899 Node* n = | |
900 (m.*mdpi.sub_constructor)(BuildConstant(m, type, 0), m.Parameter(1)); | |
901 m.Return((m.*mdpi.mul_constructor)(m.Parameter(0), n)); | |
902 Stream s = m.Build(); | |
903 ASSERT_EQ(1U, s.size()); | |
904 EXPECT_EQ(mdpi.neg_arch_opcode, s[0]->arch_opcode()); | |
905 EXPECT_EQ(2U, s[0]->InputCount()); | |
906 EXPECT_EQ(1U, s[0]->OutputCount()); | |
907 } | |
908 } | |
909 | |
910 | |
911 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, | |
912 InstructionSelectorIntDPWithIntMulTest, | |
913 ::testing::ValuesIn(kMulDPInstructions)); | |
914 | |
915 | |
916 // ----------------------------------------------------------------------------- | |
917 // Floating point instructions. | |
918 | |
919 typedef InstructionSelectorTestWithParam<MachInst2> | |
920 InstructionSelectorFPArithTest; | |
921 | |
922 | |
923 TEST_P(InstructionSelectorFPArithTest, Parameter) { | |
924 const MachInst2 fpa = GetParam(); | |
925 StreamBuilder m(this, fpa.machine_type, fpa.machine_type, fpa.machine_type); | |
926 m.Return((m.*fpa.constructor)(m.Parameter(0), m.Parameter(1))); | |
927 Stream s = m.Build(); | |
928 ASSERT_EQ(1U, s.size()); | |
929 EXPECT_EQ(fpa.arch_opcode, s[0]->arch_opcode()); | |
930 EXPECT_EQ(2U, s[0]->InputCount()); | |
931 EXPECT_EQ(1U, s[0]->OutputCount()); | |
932 } | |
933 | |
934 | |
935 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorFPArithTest, | |
936 ::testing::ValuesIn(kFPArithInstructions)); | |
937 | |
938 | |
939 typedef InstructionSelectorTestWithParam<FPCmp> InstructionSelectorFPCmpTest; | |
940 | |
941 | |
942 TEST_P(InstructionSelectorFPCmpTest, Parameter) { | |
943 const FPCmp cmp = GetParam(); | |
944 StreamBuilder m(this, kMachInt32, cmp.mi.machine_type, cmp.mi.machine_type); | |
945 m.Return((m.*cmp.mi.constructor)(m.Parameter(0), m.Parameter(1))); | |
946 Stream s = m.Build(); | |
947 ASSERT_EQ(1U, s.size()); | |
948 EXPECT_EQ(cmp.mi.arch_opcode, s[0]->arch_opcode()); | |
949 EXPECT_EQ(2U, s[0]->InputCount()); | |
950 EXPECT_EQ(1U, s[0]->OutputCount()); | |
951 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); | |
952 EXPECT_EQ(cmp.cond, s[0]->flags_condition()); | |
953 } | |
954 | |
955 | |
956 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorFPCmpTest, | |
957 ::testing::ValuesIn(kFPCmpInstructions)); | |
958 | |
959 | |
960 // ----------------------------------------------------------------------------- | |
961 // Conversions. | |
962 | |
963 typedef InstructionSelectorTestWithParam<Conversion> | |
964 InstructionSelectorConversionTest; | |
965 | |
966 | |
967 TEST_P(InstructionSelectorConversionTest, Parameter) { | |
968 const Conversion conv = GetParam(); | |
969 StreamBuilder m(this, conv.mi.machine_type, conv.src_machine_type); | |
970 m.Return((m.*conv.mi.constructor)(m.Parameter(0))); | |
971 Stream s = m.Build(); | |
972 ASSERT_EQ(1U, s.size()); | |
973 EXPECT_EQ(conv.mi.arch_opcode, s[0]->arch_opcode()); | |
974 EXPECT_EQ(1U, s[0]->InputCount()); | |
975 EXPECT_EQ(1U, s[0]->OutputCount()); | |
976 } | |
977 | |
978 | |
979 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, | |
980 InstructionSelectorConversionTest, | |
981 ::testing::ValuesIn(kConversionInstructions)); | |
982 | |
983 | |
984 // ----------------------------------------------------------------------------- | |
985 // Memory access instructions. | |
986 | |
987 | |
988 namespace { | |
989 | |
990 struct MemoryAccess { | |
991 MachineType type; | |
992 ArchOpcode ldr_opcode; | |
993 ArchOpcode str_opcode; | |
994 const int32_t immediates[20]; | |
995 }; | |
996 | |
997 | |
998 std::ostream& operator<<(std::ostream& os, const MemoryAccess& memacc) { | |
999 return os << memacc.type; | |
1000 } | |
1001 | |
1002 } // namespace | |
1003 | |
1004 | |
1005 static const MemoryAccess kMemoryAccesses[] = { | |
1006 {kMachInt8, kArm64Ldrsb, kArm64Strb, | |
1007 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 257, 258, 1000, 1001, | |
1008 2121, 2442, 4093, 4094, 4095}}, | |
1009 {kMachUint8, kArm64Ldrb, kArm64Strb, | |
1010 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 257, 258, 1000, 1001, | |
1011 2121, 2442, 4093, 4094, 4095}}, | |
1012 {kMachInt16, kArm64Ldrsh, kArm64Strh, | |
1013 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 258, 260, 4096, 4098, | |
1014 4100, 4242, 6786, 8188, 8190}}, | |
1015 {kMachUint16, kArm64Ldrh, kArm64Strh, | |
1016 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 258, 260, 4096, 4098, | |
1017 4100, 4242, 6786, 8188, 8190}}, | |
1018 {kMachInt32, kArm64LdrW, kArm64StrW, | |
1019 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 260, 4096, 4100, 8192, | |
1020 8196, 3276, 3280, 16376, 16380}}, | |
1021 {kMachUint32, kArm64LdrW, kArm64StrW, | |
1022 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 260, 4096, 4100, 8192, | |
1023 8196, 3276, 3280, 16376, 16380}}, | |
1024 {kMachInt64, kArm64Ldr, kArm64Str, | |
1025 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 264, 4096, 4104, 8192, | |
1026 8200, 16384, 16392, 32752, 32760}}, | |
1027 {kMachUint64, kArm64Ldr, kArm64Str, | |
1028 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 264, 4096, 4104, 8192, | |
1029 8200, 16384, 16392, 32752, 32760}}, | |
1030 {kMachFloat32, kArm64LdrS, kArm64StrS, | |
1031 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 260, 4096, 4100, 8192, | |
1032 8196, 3276, 3280, 16376, 16380}}, | |
1033 {kMachFloat64, kArm64LdrD, kArm64StrD, | |
1034 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 264, 4096, 4104, 8192, | |
1035 8200, 16384, 16392, 32752, 32760}}}; | |
1036 | |
1037 | |
1038 typedef InstructionSelectorTestWithParam<MemoryAccess> | |
1039 InstructionSelectorMemoryAccessTest; | |
1040 | |
1041 | |
1042 TEST_P(InstructionSelectorMemoryAccessTest, LoadWithParameters) { | |
1043 const MemoryAccess memacc = GetParam(); | |
1044 StreamBuilder m(this, memacc.type, kMachPtr, kMachInt32); | |
1045 m.Return(m.Load(memacc.type, m.Parameter(0), m.Parameter(1))); | |
1046 Stream s = m.Build(); | |
1047 ASSERT_EQ(1U, s.size()); | |
1048 EXPECT_EQ(memacc.ldr_opcode, s[0]->arch_opcode()); | |
1049 EXPECT_EQ(kMode_MRR, s[0]->addressing_mode()); | |
1050 EXPECT_EQ(2U, s[0]->InputCount()); | |
1051 EXPECT_EQ(1U, s[0]->OutputCount()); | |
1052 } | |
1053 | |
1054 | |
1055 TEST_P(InstructionSelectorMemoryAccessTest, LoadWithImmediateIndex) { | |
1056 const MemoryAccess memacc = GetParam(); | |
1057 TRACED_FOREACH(int32_t, index, memacc.immediates) { | |
1058 StreamBuilder m(this, memacc.type, kMachPtr); | |
1059 m.Return(m.Load(memacc.type, m.Parameter(0), m.Int32Constant(index))); | |
1060 Stream s = m.Build(); | |
1061 ASSERT_EQ(1U, s.size()); | |
1062 EXPECT_EQ(memacc.ldr_opcode, s[0]->arch_opcode()); | |
1063 EXPECT_EQ(kMode_MRI, s[0]->addressing_mode()); | |
1064 EXPECT_EQ(2U, s[0]->InputCount()); | |
1065 ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind()); | |
1066 EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1))); | |
1067 ASSERT_EQ(1U, s[0]->OutputCount()); | |
1068 } | |
1069 } | |
1070 | |
1071 | |
1072 TEST_P(InstructionSelectorMemoryAccessTest, StoreWithParameters) { | |
1073 const MemoryAccess memacc = GetParam(); | |
1074 StreamBuilder m(this, kMachInt32, kMachPtr, kMachInt32, memacc.type); | |
1075 m.Store(memacc.type, m.Parameter(0), m.Parameter(1), m.Parameter(2)); | |
1076 m.Return(m.Int32Constant(0)); | |
1077 Stream s = m.Build(); | |
1078 ASSERT_EQ(1U, s.size()); | |
1079 EXPECT_EQ(memacc.str_opcode, s[0]->arch_opcode()); | |
1080 EXPECT_EQ(kMode_MRR, s[0]->addressing_mode()); | |
1081 EXPECT_EQ(3U, s[0]->InputCount()); | |
1082 EXPECT_EQ(0U, s[0]->OutputCount()); | |
1083 } | |
1084 | |
1085 | |
1086 TEST_P(InstructionSelectorMemoryAccessTest, StoreWithImmediateIndex) { | |
1087 const MemoryAccess memacc = GetParam(); | |
1088 TRACED_FOREACH(int32_t, index, memacc.immediates) { | |
1089 StreamBuilder m(this, kMachInt32, kMachPtr, memacc.type); | |
1090 m.Store(memacc.type, m.Parameter(0), m.Int32Constant(index), | |
1091 m.Parameter(1)); | |
1092 m.Return(m.Int32Constant(0)); | |
1093 Stream s = m.Build(); | |
1094 ASSERT_EQ(1U, s.size()); | |
1095 EXPECT_EQ(memacc.str_opcode, s[0]->arch_opcode()); | |
1096 EXPECT_EQ(kMode_MRI, s[0]->addressing_mode()); | |
1097 ASSERT_EQ(3U, s[0]->InputCount()); | |
1098 ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind()); | |
1099 EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1))); | |
1100 EXPECT_EQ(0U, s[0]->OutputCount()); | |
1101 } | |
1102 } | |
1103 | |
1104 | |
1105 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, | |
1106 InstructionSelectorMemoryAccessTest, | |
1107 ::testing::ValuesIn(kMemoryAccesses)); | |
1108 | |
1109 | |
1110 // ----------------------------------------------------------------------------- | |
1111 // Comparison instructions. | |
1112 | |
1113 static const MachInst2 kComparisonInstructions[] = { | |
1114 {&RawMachineAssembler::Word32Equal, "Word32Equal", kArm64Cmp32, kMachInt32}, | |
1115 {&RawMachineAssembler::Word64Equal, "Word64Equal", kArm64Cmp, kMachInt64}, | |
1116 }; | |
1117 | |
1118 | |
1119 typedef InstructionSelectorTestWithParam<MachInst2> | |
1120 InstructionSelectorComparisonTest; | |
1121 | |
1122 | |
1123 TEST_P(InstructionSelectorComparisonTest, WithParameters) { | |
1124 const MachInst2 cmp = GetParam(); | |
1125 const MachineType type = cmp.machine_type; | |
1126 StreamBuilder m(this, type, type, type); | |
1127 m.Return((m.*cmp.constructor)(m.Parameter(0), m.Parameter(1))); | |
1128 Stream s = m.Build(); | |
1129 ASSERT_EQ(1U, s.size()); | |
1130 EXPECT_EQ(cmp.arch_opcode, s[0]->arch_opcode()); | |
1131 EXPECT_EQ(2U, s[0]->InputCount()); | |
1132 EXPECT_EQ(1U, s[0]->OutputCount()); | |
1133 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); | |
1134 EXPECT_EQ(kEqual, s[0]->flags_condition()); | |
1135 } | |
1136 | |
1137 | |
1138 TEST_P(InstructionSelectorComparisonTest, WithImmediate) { | |
1139 const MachInst2 cmp = GetParam(); | |
1140 const MachineType type = cmp.machine_type; | |
1141 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { | |
1142 // Compare with 0 are turned into tst instruction. | |
1143 if (imm == 0) continue; | |
1144 StreamBuilder m(this, type, type); | |
1145 m.Return((m.*cmp.constructor)(m.Parameter(0), BuildConstant(m, type, imm))); | |
1146 Stream s = m.Build(); | |
1147 ASSERT_EQ(1U, s.size()); | |
1148 EXPECT_EQ(cmp.arch_opcode, s[0]->arch_opcode()); | |
1149 ASSERT_EQ(2U, s[0]->InputCount()); | |
1150 ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind()); | |
1151 EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1))); | |
1152 EXPECT_EQ(1U, s[0]->OutputCount()); | |
1153 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); | |
1154 EXPECT_EQ(kEqual, s[0]->flags_condition()); | |
1155 } | |
1156 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { | |
1157 // Compare with 0 are turned into tst instruction. | |
1158 if (imm == 0) continue; | |
1159 StreamBuilder m(this, type, type); | |
1160 m.Return((m.*cmp.constructor)(BuildConstant(m, type, imm), m.Parameter(0))); | |
1161 Stream s = m.Build(); | |
1162 ASSERT_EQ(1U, s.size()); | |
1163 EXPECT_EQ(cmp.arch_opcode, s[0]->arch_opcode()); | |
1164 ASSERT_EQ(2U, s[0]->InputCount()); | |
1165 ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind()); | |
1166 EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1))); | |
1167 EXPECT_EQ(1U, s[0]->OutputCount()); | |
1168 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); | |
1169 EXPECT_EQ(kEqual, s[0]->flags_condition()); | |
1170 } | |
1171 } | |
1172 | |
1173 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, | |
1174 InstructionSelectorComparisonTest, | |
1175 ::testing::ValuesIn(kComparisonInstructions)); | |
1176 | |
1177 | |
1178 TEST_F(InstructionSelectorTest, Word32EqualWithZero) { | |
1179 { | |
1180 StreamBuilder m(this, kMachInt32, kMachInt32); | |
1181 m.Return(m.Word32Equal(m.Parameter(0), m.Int32Constant(0))); | |
1182 Stream s = m.Build(); | |
1183 ASSERT_EQ(1U, s.size()); | |
1184 EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode()); | |
1185 ASSERT_EQ(2U, s[0]->InputCount()); | |
1186 EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1))); | |
1187 EXPECT_EQ(1U, s[0]->OutputCount()); | |
1188 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); | |
1189 EXPECT_EQ(kEqual, s[0]->flags_condition()); | |
1190 } | |
1191 { | |
1192 StreamBuilder m(this, kMachInt32, kMachInt32); | |
1193 m.Return(m.Word32Equal(m.Int32Constant(0), m.Parameter(0))); | |
1194 Stream s = m.Build(); | |
1195 ASSERT_EQ(1U, s.size()); | |
1196 EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode()); | |
1197 ASSERT_EQ(2U, s[0]->InputCount()); | |
1198 EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1))); | |
1199 EXPECT_EQ(1U, s[0]->OutputCount()); | |
1200 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); | |
1201 EXPECT_EQ(kEqual, s[0]->flags_condition()); | |
1202 } | |
1203 } | |
1204 | |
1205 | |
1206 TEST_F(InstructionSelectorTest, Word64EqualWithZero) { | |
1207 { | |
1208 StreamBuilder m(this, kMachInt64, kMachInt64); | |
1209 m.Return(m.Word64Equal(m.Parameter(0), m.Int64Constant(0))); | |
1210 Stream s = m.Build(); | |
1211 ASSERT_EQ(1U, s.size()); | |
1212 EXPECT_EQ(kArm64Tst, s[0]->arch_opcode()); | |
1213 ASSERT_EQ(2U, s[0]->InputCount()); | |
1214 EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1))); | |
1215 EXPECT_EQ(1U, s[0]->OutputCount()); | |
1216 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); | |
1217 EXPECT_EQ(kEqual, s[0]->flags_condition()); | |
1218 } | |
1219 { | |
1220 StreamBuilder m(this, kMachInt64, kMachInt64); | |
1221 m.Return(m.Word64Equal(m.Int64Constant(0), m.Parameter(0))); | |
1222 Stream s = m.Build(); | |
1223 ASSERT_EQ(1U, s.size()); | |
1224 EXPECT_EQ(kArm64Tst, s[0]->arch_opcode()); | |
1225 ASSERT_EQ(2U, s[0]->InputCount()); | |
1226 EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1))); | |
1227 EXPECT_EQ(1U, s[0]->OutputCount()); | |
1228 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); | |
1229 EXPECT_EQ(kEqual, s[0]->flags_condition()); | |
1230 } | |
1231 } | |
1232 | |
1233 | |
1234 // ----------------------------------------------------------------------------- | |
1235 // Miscellaneous | |
1236 | |
1237 | |
1238 static const MachInst2 kLogicalWithNotRHSs[] = { | |
1239 {&RawMachineAssembler::Word32And, "Word32And", kArm64Bic32, kMachInt32}, | |
1240 {&RawMachineAssembler::Word64And, "Word64And", kArm64Bic, kMachInt64}, | |
1241 {&RawMachineAssembler::Word32Or, "Word32Or", kArm64Orn32, kMachInt32}, | |
1242 {&RawMachineAssembler::Word64Or, "Word64Or", kArm64Orn, kMachInt64}, | |
1243 {&RawMachineAssembler::Word32Xor, "Word32Xor", kArm64Eon32, kMachInt32}, | |
1244 {&RawMachineAssembler::Word64Xor, "Word64Xor", kArm64Eon, kMachInt64}}; | |
1245 | |
1246 | |
1247 typedef InstructionSelectorTestWithParam<MachInst2> | |
1248 InstructionSelectorLogicalWithNotRHSTest; | |
1249 | |
1250 | |
1251 TEST_P(InstructionSelectorLogicalWithNotRHSTest, Parameter) { | |
1252 const MachInst2 inst = GetParam(); | |
1253 const MachineType type = inst.machine_type; | |
1254 // Test cases where RHS is Xor(x, -1). | |
1255 { | |
1256 StreamBuilder m(this, type, type, type); | |
1257 if (type == kMachInt32) { | |
1258 m.Return((m.*inst.constructor)( | |
1259 m.Parameter(0), m.Word32Xor(m.Parameter(1), m.Int32Constant(-1)))); | |
1260 } else { | |
1261 ASSERT_EQ(kMachInt64, type); | |
1262 m.Return((m.*inst.constructor)( | |
1263 m.Parameter(0), m.Word64Xor(m.Parameter(1), m.Int64Constant(-1)))); | |
1264 } | |
1265 Stream s = m.Build(); | |
1266 ASSERT_EQ(1U, s.size()); | |
1267 EXPECT_EQ(inst.arch_opcode, s[0]->arch_opcode()); | |
1268 EXPECT_EQ(2U, s[0]->InputCount()); | |
1269 EXPECT_EQ(1U, s[0]->OutputCount()); | |
1270 } | |
1271 { | |
1272 StreamBuilder m(this, type, type, type); | |
1273 if (type == kMachInt32) { | |
1274 m.Return((m.*inst.constructor)( | |
1275 m.Word32Xor(m.Parameter(0), m.Int32Constant(-1)), m.Parameter(1))); | |
1276 } else { | |
1277 ASSERT_EQ(kMachInt64, type); | |
1278 m.Return((m.*inst.constructor)( | |
1279 m.Word64Xor(m.Parameter(0), m.Int64Constant(-1)), m.Parameter(1))); | |
1280 } | |
1281 Stream s = m.Build(); | |
1282 ASSERT_EQ(1U, s.size()); | |
1283 EXPECT_EQ(inst.arch_opcode, s[0]->arch_opcode()); | |
1284 EXPECT_EQ(2U, s[0]->InputCount()); | |
1285 EXPECT_EQ(1U, s[0]->OutputCount()); | |
1286 } | |
1287 // Test cases where RHS is Not(x). | |
1288 { | |
1289 StreamBuilder m(this, type, type, type); | |
1290 if (type == kMachInt32) { | |
1291 m.Return( | |
1292 (m.*inst.constructor)(m.Parameter(0), m.Word32Not(m.Parameter(1)))); | |
1293 } else { | |
1294 ASSERT_EQ(kMachInt64, type); | |
1295 m.Return( | |
1296 (m.*inst.constructor)(m.Parameter(0), m.Word64Not(m.Parameter(1)))); | |
1297 } | |
1298 Stream s = m.Build(); | |
1299 ASSERT_EQ(1U, s.size()); | |
1300 EXPECT_EQ(inst.arch_opcode, s[0]->arch_opcode()); | |
1301 EXPECT_EQ(2U, s[0]->InputCount()); | |
1302 EXPECT_EQ(1U, s[0]->OutputCount()); | |
1303 } | |
1304 { | |
1305 StreamBuilder m(this, type, type, type); | |
1306 if (type == kMachInt32) { | |
1307 m.Return( | |
1308 (m.*inst.constructor)(m.Word32Not(m.Parameter(0)), m.Parameter(1))); | |
1309 } else { | |
1310 ASSERT_EQ(kMachInt64, type); | |
1311 m.Return( | |
1312 (m.*inst.constructor)(m.Word64Not(m.Parameter(0)), m.Parameter(1))); | |
1313 } | |
1314 Stream s = m.Build(); | |
1315 ASSERT_EQ(1U, s.size()); | |
1316 EXPECT_EQ(inst.arch_opcode, s[0]->arch_opcode()); | |
1317 EXPECT_EQ(2U, s[0]->InputCount()); | |
1318 EXPECT_EQ(1U, s[0]->OutputCount()); | |
1319 } | |
1320 } | |
1321 | |
1322 | |
1323 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, | |
1324 InstructionSelectorLogicalWithNotRHSTest, | |
1325 ::testing::ValuesIn(kLogicalWithNotRHSs)); | |
1326 | |
1327 | |
1328 TEST_F(InstructionSelectorTest, Word32NotWithParameter) { | |
1329 StreamBuilder m(this, kMachInt32, kMachInt32); | |
1330 m.Return(m.Word32Not(m.Parameter(0))); | |
1331 Stream s = m.Build(); | |
1332 ASSERT_EQ(1U, s.size()); | |
1333 EXPECT_EQ(kArm64Not32, s[0]->arch_opcode()); | |
1334 EXPECT_EQ(1U, s[0]->InputCount()); | |
1335 EXPECT_EQ(1U, s[0]->OutputCount()); | |
1336 } | |
1337 | |
1338 | |
1339 TEST_F(InstructionSelectorTest, Word64NotWithParameter) { | |
1340 StreamBuilder m(this, kMachInt64, kMachInt64); | |
1341 m.Return(m.Word64Not(m.Parameter(0))); | |
1342 Stream s = m.Build(); | |
1343 ASSERT_EQ(1U, s.size()); | |
1344 EXPECT_EQ(kArm64Not, s[0]->arch_opcode()); | |
1345 EXPECT_EQ(1U, s[0]->InputCount()); | |
1346 EXPECT_EQ(1U, s[0]->OutputCount()); | |
1347 } | |
1348 | |
1349 | |
1350 TEST_F(InstructionSelectorTest, Word32XorMinusOneWithParameter) { | |
1351 { | |
1352 StreamBuilder m(this, kMachInt32, kMachInt32); | |
1353 m.Return(m.Word32Xor(m.Parameter(0), m.Int32Constant(-1))); | |
1354 Stream s = m.Build(); | |
1355 ASSERT_EQ(1U, s.size()); | |
1356 EXPECT_EQ(kArm64Not32, s[0]->arch_opcode()); | |
1357 EXPECT_EQ(1U, s[0]->InputCount()); | |
1358 EXPECT_EQ(1U, s[0]->OutputCount()); | |
1359 } | |
1360 { | |
1361 StreamBuilder m(this, kMachInt32, kMachInt32); | |
1362 m.Return(m.Word32Xor(m.Int32Constant(-1), m.Parameter(0))); | |
1363 Stream s = m.Build(); | |
1364 ASSERT_EQ(1U, s.size()); | |
1365 EXPECT_EQ(kArm64Not32, s[0]->arch_opcode()); | |
1366 EXPECT_EQ(1U, s[0]->InputCount()); | |
1367 EXPECT_EQ(1U, s[0]->OutputCount()); | |
1368 } | |
1369 } | |
1370 | |
1371 | |
1372 TEST_F(InstructionSelectorTest, Word64XorMinusOneWithParameter) { | |
1373 { | |
1374 StreamBuilder m(this, kMachInt64, kMachInt64); | |
1375 m.Return(m.Word64Xor(m.Parameter(0), m.Int64Constant(-1))); | |
1376 Stream s = m.Build(); | |
1377 ASSERT_EQ(1U, s.size()); | |
1378 EXPECT_EQ(kArm64Not, s[0]->arch_opcode()); | |
1379 EXPECT_EQ(1U, s[0]->InputCount()); | |
1380 EXPECT_EQ(1U, s[0]->OutputCount()); | |
1381 } | |
1382 { | |
1383 StreamBuilder m(this, kMachInt64, kMachInt64); | |
1384 m.Return(m.Word64Xor(m.Int64Constant(-1), m.Parameter(0))); | |
1385 Stream s = m.Build(); | |
1386 ASSERT_EQ(1U, s.size()); | |
1387 EXPECT_EQ(kArm64Not, s[0]->arch_opcode()); | |
1388 EXPECT_EQ(1U, s[0]->InputCount()); | |
1389 EXPECT_EQ(1U, s[0]->OutputCount()); | |
1390 } | |
1391 } | |
1392 | |
1393 } // namespace compiler | |
1394 } // namespace internal | |
1395 } // namespace v8 | |
OLD | NEW |