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 "test/unittests/compiler/backend/instruction-selector-unittest.h"
6
7 #include "src/objects/objects-inl.h"
8
9 namespace v8 {
10 namespace internal {
11 namespace compiler {
12
13 namespace {
14 template <typename T>
15 struct MachInst {
16 T constructor;
17 const char* constructor_name;
18 ArchOpcode arch_opcode;
19 MachineType machine_type;
20 };
21
22 template <typename T>
operator <<(std::ostream & os,const MachInst<T> & mi)23 std::ostream& operator<<(std::ostream& os, const MachInst<T>& mi) {
24 return os << mi.constructor_name;
25 }
26
27 using MachInst1 = MachInst<Node* (RawMachineAssembler::*)(Node*)>;
28 using MachInst2 = MachInst<Node* (RawMachineAssembler::*)(Node*, Node*)>;
29
30 // To avoid duplicated code IntCmp helper structure
31 // is created. It contains MachInst2 with two nodes and expected_size
32 // because different cmp instructions have different size.
33 struct IntCmp {
34 MachInst2 mi;
35 uint32_t expected_size;
36 };
37
38 struct FPCmp {
39 MachInst2 mi;
40 FlagsCondition cond;
41 };
42
43 const FPCmp kFPCmpInstructions[] = {
44 {{&RawMachineAssembler::Float64Equal, "Float64Equal", kMips64CmpD,
45 MachineType::Float64()},
46 kEqual},
47 {{&RawMachineAssembler::Float64LessThan, "Float64LessThan", kMips64CmpD,
48 MachineType::Float64()},
49 kUnsignedLessThan},
50 {{&RawMachineAssembler::Float64LessThanOrEqual, "Float64LessThanOrEqual",
51 kMips64CmpD, MachineType::Float64()},
52 kUnsignedLessThanOrEqual},
53 {{&RawMachineAssembler::Float64GreaterThan, "Float64GreaterThan",
54 kMips64CmpD, MachineType::Float64()},
55 kUnsignedLessThan},
56 {{&RawMachineAssembler::Float64GreaterThanOrEqual,
57 "Float64GreaterThanOrEqual", kMips64CmpD, MachineType::Float64()},
58 kUnsignedLessThanOrEqual}};
59
60 struct Conversion {
61 // The machine_type field in MachInst1 represents the destination type.
62 MachInst1 mi;
63 MachineType src_machine_type;
64 };
65
66
67 // ----------------------------------------------------------------------------
68 // Logical instructions.
69 // ----------------------------------------------------------------------------
70
71 const MachInst2 kLogicalInstructions[] = {
72 {&RawMachineAssembler::Word32And, "Word32And", kMips64And32,
73 MachineType::Int32()},
74 {&RawMachineAssembler::Word64And, "Word64And", kMips64And,
75 MachineType::Int64()},
76 {&RawMachineAssembler::Word32Or, "Word32Or", kMips64Or32,
77 MachineType::Int32()},
78 {&RawMachineAssembler::Word64Or, "Word64Or", kMips64Or,
79 MachineType::Int64()},
80 {&RawMachineAssembler::Word32Xor, "Word32Xor", kMips64Xor32,
81 MachineType::Int32()},
82 {&RawMachineAssembler::Word64Xor, "Word64Xor", kMips64Xor,
83 MachineType::Int64()}};
84
85 // ----------------------------------------------------------------------------
86 // Shift instructions.
87 // ----------------------------------------------------------------------------
88
89
90 const MachInst2 kShiftInstructions[] = {
91 {&RawMachineAssembler::Word32Shl, "Word32Shl", kMips64Shl,
92 MachineType::Int32()},
93 {&RawMachineAssembler::Word64Shl, "Word64Shl", kMips64Dshl,
94 MachineType::Int64()},
95 {&RawMachineAssembler::Word32Shr, "Word32Shr", kMips64Shr,
96 MachineType::Int32()},
97 {&RawMachineAssembler::Word64Shr, "Word64Shr", kMips64Dshr,
98 MachineType::Int64()},
99 {&RawMachineAssembler::Word32Sar, "Word32Sar", kMips64Sar,
100 MachineType::Int32()},
101 {&RawMachineAssembler::Word64Sar, "Word64Sar", kMips64Dsar,
102 MachineType::Int64()},
103 {&RawMachineAssembler::Word32Ror, "Word32Ror", kMips64Ror,
104 MachineType::Int32()},
105 {&RawMachineAssembler::Word64Ror, "Word64Ror", kMips64Dror,
106 MachineType::Int64()}};
107
108
109 // ----------------------------------------------------------------------------
110 // MUL/DIV instructions.
111 // ----------------------------------------------------------------------------
112
113
114 const MachInst2 kMulDivInstructions[] = {
115 {&RawMachineAssembler::Int32Mul, "Int32Mul", kMips64Mul,
116 MachineType::Int32()},
117 {&RawMachineAssembler::Int32Div, "Int32Div", kMips64Div,
118 MachineType::Int32()},
119 {&RawMachineAssembler::Uint32Div, "Uint32Div", kMips64DivU,
120 MachineType::Uint32()},
121 {&RawMachineAssembler::Int64Mul, "Int64Mul", kMips64Dmul,
122 MachineType::Int64()},
123 {&RawMachineAssembler::Int64Div, "Int64Div", kMips64Ddiv,
124 MachineType::Int64()},
125 {&RawMachineAssembler::Uint64Div, "Uint64Div", kMips64DdivU,
126 MachineType::Uint64()},
127 {&RawMachineAssembler::Float64Mul, "Float64Mul", kMips64MulD,
128 MachineType::Float64()},
129 {&RawMachineAssembler::Float64Div, "Float64Div", kMips64DivD,
130 MachineType::Float64()}};
131
132
133 // ----------------------------------------------------------------------------
134 // MOD instructions.
135 // ----------------------------------------------------------------------------
136
137
138 const MachInst2 kModInstructions[] = {
139 {&RawMachineAssembler::Int32Mod, "Int32Mod", kMips64Mod,
140 MachineType::Int32()},
141 {&RawMachineAssembler::Uint32Mod, "Uint32Mod", kMips64ModU,
142 MachineType::Int32()},
143 {&RawMachineAssembler::Float64Mod, "Float64Mod", kMips64ModD,
144 MachineType::Float64()}};
145
146
147 // ----------------------------------------------------------------------------
148 // Arithmetic FPU instructions.
149 // ----------------------------------------------------------------------------
150
151
152 const MachInst2 kFPArithInstructions[] = {
153 {&RawMachineAssembler::Float64Add, "Float64Add", kMips64AddD,
154 MachineType::Float64()},
155 {&RawMachineAssembler::Float64Sub, "Float64Sub", kMips64SubD,
156 MachineType::Float64()}};
157
158
159 // ----------------------------------------------------------------------------
160 // IntArithTest instructions, two nodes.
161 // ----------------------------------------------------------------------------
162
163
164 const MachInst2 kAddSubInstructions[] = {
165 {&RawMachineAssembler::Int32Add, "Int32Add", kMips64Add,
166 MachineType::Int32()},
167 {&RawMachineAssembler::Int64Add, "Int64Add", kMips64Dadd,
168 MachineType::Int64()},
169 {&RawMachineAssembler::Int32Sub, "Int32Sub", kMips64Sub,
170 MachineType::Int32()},
171 {&RawMachineAssembler::Int64Sub, "Int64Sub", kMips64Dsub,
172 MachineType::Int64()}};
173
174
175 // ----------------------------------------------------------------------------
176 // IntArithTest instructions, one node.
177 // ----------------------------------------------------------------------------
178
179
180 const MachInst1 kAddSubOneInstructions[] = {
181 {&RawMachineAssembler::Int32Neg, "Int32Neg", kMips64Sub,
182 MachineType::Int32()},
183 {&RawMachineAssembler::Int64Neg, "Int64Neg", kMips64Dsub,
184 MachineType::Int64()}};
185
186
187 // ----------------------------------------------------------------------------
188 // Arithmetic compare instructions.
189 // ----------------------------------------------------------------------------
190
191
192 const IntCmp kCmpInstructions[] = {
193 {{&RawMachineAssembler::WordEqual, "WordEqual", kMips64Cmp,
194 MachineType::Int64()},
195 1U},
196 {{&RawMachineAssembler::WordNotEqual, "WordNotEqual", kMips64Cmp,
197 MachineType::Int64()},
198 1U},
199 {{&RawMachineAssembler::Word32Equal, "Word32Equal", kMips64Cmp,
200 MachineType::Int32()},
201 1U},
202 {{&RawMachineAssembler::Word32NotEqual, "Word32NotEqual", kMips64Cmp,
203 MachineType::Int32()},
204 1U},
205 {{&RawMachineAssembler::Int32LessThan, "Int32LessThan", kMips64Cmp,
206 MachineType::Int32()},
207 1U},
208 {{&RawMachineAssembler::Int32LessThanOrEqual, "Int32LessThanOrEqual",
209 kMips64Cmp, MachineType::Int32()},
210 1U},
211 {{&RawMachineAssembler::Int32GreaterThan, "Int32GreaterThan", kMips64Cmp,
212 MachineType::Int32()},
213 1U},
214 {{&RawMachineAssembler::Int32GreaterThanOrEqual, "Int32GreaterThanOrEqual",
215 kMips64Cmp, MachineType::Int32()},
216 1U},
217 {{&RawMachineAssembler::Uint32LessThan, "Uint32LessThan", kMips64Cmp,
218 MachineType::Uint32()},
219 1U},
220 {{&RawMachineAssembler::Uint32LessThanOrEqual, "Uint32LessThanOrEqual",
221 kMips64Cmp, MachineType::Uint32()},
222 1U}};
223
224
225 // ----------------------------------------------------------------------------
226 // Conversion instructions.
227 // ----------------------------------------------------------------------------
228
229 const Conversion kConversionInstructions[] = {
230 // Conversion instructions are related to machine_operator.h:
231 // FPU conversions:
232 // Convert representation of integers between float64 and int32/uint32.
233 // The precise rounding mode and handling of out of range inputs are *not*
234 // defined for these operators, since they are intended only for use with
235 // integers.
236 // mips instructions:
237 // mtc1, cvt.d.w
238 {{&RawMachineAssembler::ChangeInt32ToFloat64, "ChangeInt32ToFloat64",
239 kMips64CvtDW, MachineType::Float64()},
240 MachineType::Int32()},
241
242 // mips instructions:
243 // cvt.d.uw
244 {{&RawMachineAssembler::ChangeUint32ToFloat64, "ChangeUint32ToFloat64",
245 kMips64CvtDUw, MachineType::Float64()},
246 MachineType::Int32()},
247
248 // mips instructions:
249 // mfc1, trunc double to word, for more details look at mips macro
250 // asm and mips asm file
251 {{&RawMachineAssembler::ChangeFloat64ToInt32, "ChangeFloat64ToInt32",
252 kMips64TruncWD, MachineType::Float64()},
253 MachineType::Int32()},
254
255 // mips instructions:
256 // trunc double to unsigned word, for more details look at mips macro
257 // asm and mips asm file
258 {{&RawMachineAssembler::ChangeFloat64ToUint32, "ChangeFloat64ToUint32",
259 kMips64TruncUwD, MachineType::Float64()},
260 MachineType::Int32()}};
261
262 const Conversion kFloat64RoundInstructions[] = {
263 {{&RawMachineAssembler::Float64RoundUp, "Float64RoundUp", kMips64CeilWD,
264 MachineType::Int32()},
265 MachineType::Float64()},
266 {{&RawMachineAssembler::Float64RoundDown, "Float64RoundDown",
267 kMips64FloorWD, MachineType::Int32()},
268 MachineType::Float64()},
269 {{&RawMachineAssembler::Float64RoundTiesEven, "Float64RoundTiesEven",
270 kMips64RoundWD, MachineType::Int32()},
271 MachineType::Float64()},
272 {{&RawMachineAssembler::Float64RoundTruncate, "Float64RoundTruncate",
273 kMips64TruncWD, MachineType::Int32()},
274 MachineType::Float64()}};
275
276 const Conversion kFloat32RoundInstructions[] = {
277 {{&RawMachineAssembler::Float32RoundUp, "Float32RoundUp", kMips64CeilWS,
278 MachineType::Int32()},
279 MachineType::Float32()},
280 {{&RawMachineAssembler::Float32RoundDown, "Float32RoundDown",
281 kMips64FloorWS, MachineType::Int32()},
282 MachineType::Float32()},
283 {{&RawMachineAssembler::Float32RoundTiesEven, "Float32RoundTiesEven",
284 kMips64RoundWS, MachineType::Int32()},
285 MachineType::Float32()},
286 {{&RawMachineAssembler::Float32RoundTruncate, "Float32RoundTruncate",
287 kMips64TruncWS, MachineType::Int32()},
288 MachineType::Float32()}};
289
290 // MIPS64 instructions that clear the top 32 bits of the destination.
291 const MachInst2 kCanElideChangeUint32ToUint64[] = {
292 {&RawMachineAssembler::Word32Equal, "Word32Equal", kMips64Cmp,
293 MachineType::Uint32()},
294 {&RawMachineAssembler::Int32LessThan, "Int32LessThan", kMips64Cmp,
295 MachineType::Uint32()},
296 {&RawMachineAssembler::Int32LessThanOrEqual, "Int32LessThanOrEqual",
297 kMips64Cmp, MachineType::Uint32()},
298 {&RawMachineAssembler::Uint32LessThan, "Uint32LessThan", kMips64Cmp,
299 MachineType::Uint32()},
300 {&RawMachineAssembler::Uint32LessThanOrEqual, "Uint32LessThanOrEqual",
301 kMips64Cmp, MachineType::Uint32()},
302 };
303
304 } // namespace
305
306 using InstructionSelectorFPCmpTest = InstructionSelectorTestWithParam<FPCmp>;
307
TEST_P(InstructionSelectorFPCmpTest,Parameter)308 TEST_P(InstructionSelectorFPCmpTest, Parameter) {
309 const FPCmp cmp = GetParam();
310 StreamBuilder m(this, MachineType::Int32(), cmp.mi.machine_type,
311 cmp.mi.machine_type);
312 m.Return((m.*cmp.mi.constructor)(m.Parameter(0), m.Parameter(1)));
313 Stream s = m.Build();
314 ASSERT_EQ(1U, s.size());
315 EXPECT_EQ(cmp.mi.arch_opcode, s[0]->arch_opcode());
316 EXPECT_EQ(2U, s[0]->InputCount());
317 EXPECT_EQ(1U, s[0]->OutputCount());
318 EXPECT_EQ(kFlags_set, s[0]->flags_mode());
319 EXPECT_EQ(cmp.cond, s[0]->flags_condition());
320 }
321
322 INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest, InstructionSelectorFPCmpTest,
323 ::testing::ValuesIn(kFPCmpInstructions));
324
325 // ----------------------------------------------------------------------------
326 // Arithmetic compare instructions integers
327 // ----------------------------------------------------------------------------
328 using InstructionSelectorCmpTest = InstructionSelectorTestWithParam<IntCmp>;
329
TEST_P(InstructionSelectorCmpTest,Parameter)330 TEST_P(InstructionSelectorCmpTest, Parameter) {
331 const IntCmp cmp = GetParam();
332 const MachineType type = cmp.mi.machine_type;
333 StreamBuilder m(this, type, type, type);
334 m.Return((m.*cmp.mi.constructor)(m.Parameter(0), m.Parameter(1)));
335 Stream s = m.Build();
336
337 if (FLAG_debug_code &&
338 type.representation() == MachineRepresentation::kWord32) {
339 ASSERT_EQ(6U, s.size());
340
341 EXPECT_EQ(cmp.mi.arch_opcode, s[0]->arch_opcode());
342 EXPECT_EQ(2U, s[0]->InputCount());
343 EXPECT_EQ(1U, s[0]->OutputCount());
344
345 EXPECT_EQ(kMips64Dshl, s[1]->arch_opcode());
346 EXPECT_EQ(2U, s[1]->InputCount());
347 EXPECT_EQ(1U, s[1]->OutputCount());
348
349 EXPECT_EQ(kMips64Dshl, s[2]->arch_opcode());
350 EXPECT_EQ(2U, s[2]->InputCount());
351 EXPECT_EQ(1U, s[2]->OutputCount());
352
353 EXPECT_EQ(cmp.mi.arch_opcode, s[3]->arch_opcode());
354 EXPECT_EQ(2U, s[3]->InputCount());
355 EXPECT_EQ(1U, s[3]->OutputCount());
356
357 EXPECT_EQ(kMips64AssertEqual, s[4]->arch_opcode());
358 EXPECT_EQ(3U, s[4]->InputCount());
359 EXPECT_EQ(0U, s[4]->OutputCount());
360
361 EXPECT_EQ(cmp.mi.arch_opcode, s[5]->arch_opcode());
362 EXPECT_EQ(2U, s[5]->InputCount());
363 EXPECT_EQ(1U, s[5]->OutputCount());
364 } else {
365 ASSERT_EQ(cmp.expected_size, s.size());
366 EXPECT_EQ(cmp.mi.arch_opcode, s[0]->arch_opcode());
367 EXPECT_EQ(2U, s[0]->InputCount());
368 EXPECT_EQ(1U, s[0]->OutputCount());
369 }
370 }
371
372 INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest, InstructionSelectorCmpTest,
373 ::testing::ValuesIn(kCmpInstructions));
374
375 // ----------------------------------------------------------------------------
376 // Shift instructions.
377 // ----------------------------------------------------------------------------
378 using InstructionSelectorShiftTest =
379 InstructionSelectorTestWithParam<MachInst2>;
380
TEST_P(InstructionSelectorShiftTest,Immediate)381 TEST_P(InstructionSelectorShiftTest, Immediate) {
382 const MachInst2 dpi = GetParam();
383 const MachineType type = dpi.machine_type;
384 TRACED_FORRANGE(int32_t, imm, 0,
385 ((1 << ElementSizeLog2Of(type.representation())) * 8) - 1) {
386 StreamBuilder m(this, type, type);
387 m.Return((m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm)));
388 Stream s = m.Build();
389 ASSERT_EQ(1U, s.size());
390 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
391 EXPECT_EQ(2U, s[0]->InputCount());
392 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
393 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
394 EXPECT_EQ(1U, s[0]->OutputCount());
395 }
396 }
397
398 INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest, InstructionSelectorShiftTest,
399 ::testing::ValuesIn(kShiftInstructions));
400
TEST_F(InstructionSelectorTest,Word32ShrWithWord32AndWithImmediate)401 TEST_F(InstructionSelectorTest, Word32ShrWithWord32AndWithImmediate) {
402 // The available shift operand range is `0 <= imm < 32`, but we also test
403 // that immediates outside this range are handled properly (modulo-32).
404 TRACED_FORRANGE(int32_t, shift, -32, 63) {
405 int32_t lsb = shift & 0x1F;
406 TRACED_FORRANGE(int32_t, width, 1, 32 - lsb) {
407 uint32_t jnk = rng()->NextInt();
408 jnk = (lsb > 0) ? (jnk >> (32 - lsb)) : 0;
409 uint32_t msk = ((0xFFFFFFFFu >> (32 - width)) << lsb) | jnk;
410 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
411 m.Return(m.Word32Shr(m.Word32And(m.Parameter(0), m.Int32Constant(msk)),
412 m.Int32Constant(shift)));
413 Stream s = m.Build();
414 ASSERT_EQ(1U, s.size());
415 EXPECT_EQ(kMips64Ext, s[0]->arch_opcode());
416 ASSERT_EQ(3U, s[0]->InputCount());
417 EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1)));
418 EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2)));
419 }
420 }
421 TRACED_FORRANGE(int32_t, shift, -32, 63) {
422 int32_t lsb = shift & 0x1F;
423 TRACED_FORRANGE(int32_t, width, 1, 32 - lsb) {
424 uint32_t jnk = rng()->NextInt();
425 jnk = (lsb > 0) ? (jnk >> (32 - lsb)) : 0;
426 uint32_t msk = ((0xFFFFFFFFu >> (32 - width)) << lsb) | jnk;
427 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
428 m.Return(m.Word32Shr(m.Word32And(m.Int32Constant(msk), m.Parameter(0)),
429 m.Int32Constant(shift)));
430 Stream s = m.Build();
431 ASSERT_EQ(1U, s.size());
432 EXPECT_EQ(kMips64Ext, s[0]->arch_opcode());
433 ASSERT_EQ(3U, s[0]->InputCount());
434 EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1)));
435 EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2)));
436 }
437 }
438 }
439
440
TEST_F(InstructionSelectorTest,Word64ShrWithWord64AndWithImmediate)441 TEST_F(InstructionSelectorTest, Word64ShrWithWord64AndWithImmediate) {
442 // The available shift operand range is `0 <= imm < 64`, but we also test
443 // that immediates outside this range are handled properly (modulo-64).
444 TRACED_FORRANGE(int32_t, shift, -64, 127) {
445 int32_t lsb = shift & 0x3F;
446 TRACED_FORRANGE(int32_t, width, 1, 64 - lsb) {
447 uint64_t jnk = rng()->NextInt64();
448 jnk = (lsb > 0) ? (jnk >> (64 - lsb)) : 0;
449 uint64_t msk =
450 ((uint64_t{0xFFFFFFFFFFFFFFFF} >> (64 - width)) << lsb) | jnk;
451 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64());
452 m.Return(m.Word64Shr(m.Word64And(m.Parameter(0), m.Int64Constant(msk)),
453 m.Int64Constant(shift)));
454 Stream s = m.Build();
455 ASSERT_EQ(1U, s.size());
456 EXPECT_EQ(kMips64Dext, s[0]->arch_opcode());
457 ASSERT_EQ(3U, s[0]->InputCount());
458 EXPECT_EQ(lsb, s.ToInt64(s[0]->InputAt(1)));
459 EXPECT_EQ(width, s.ToInt64(s[0]->InputAt(2)));
460 }
461 }
462 TRACED_FORRANGE(int32_t, shift, -64, 127) {
463 int32_t lsb = shift & 0x3F;
464 TRACED_FORRANGE(int32_t, width, 1, 64 - lsb) {
465 uint64_t jnk = rng()->NextInt64();
466 jnk = (lsb > 0) ? (jnk >> (64 - lsb)) : 0;
467 uint64_t msk =
468 ((uint64_t{0xFFFFFFFFFFFFFFFF} >> (64 - width)) << lsb) | jnk;
469 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64());
470 m.Return(m.Word64Shr(m.Word64And(m.Int64Constant(msk), m.Parameter(0)),
471 m.Int64Constant(shift)));
472 Stream s = m.Build();
473 ASSERT_EQ(1U, s.size());
474 EXPECT_EQ(kMips64Dext, s[0]->arch_opcode());
475 ASSERT_EQ(3U, s[0]->InputCount());
476 EXPECT_EQ(lsb, s.ToInt64(s[0]->InputAt(1)));
477 EXPECT_EQ(width, s.ToInt64(s[0]->InputAt(2)));
478 }
479 }
480 }
481
482
TEST_F(InstructionSelectorTest,Word32AndToClearBits)483 TEST_F(InstructionSelectorTest, Word32AndToClearBits) {
484 TRACED_FORRANGE(int32_t, shift, 1, 31) {
485 int32_t mask = ~((1 << shift) - 1);
486 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
487 m.Return(m.Word32And(m.Parameter(0), m.Int32Constant(mask)));
488 Stream s = m.Build();
489 ASSERT_EQ(1U, s.size());
490 EXPECT_EQ(kMips64Ins, s[0]->arch_opcode());
491 ASSERT_EQ(3U, s[0]->InputCount());
492 EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(1)));
493 EXPECT_EQ(shift, s.ToInt32(s[0]->InputAt(2)));
494 }
495 TRACED_FORRANGE(int32_t, shift, 1, 31) {
496 int32_t mask = ~((1 << shift) - 1);
497 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
498 m.Return(m.Word32And(m.Int32Constant(mask), m.Parameter(0)));
499 Stream s = m.Build();
500 ASSERT_EQ(1U, s.size());
501 EXPECT_EQ(kMips64Ins, s[0]->arch_opcode());
502 ASSERT_EQ(3U, s[0]->InputCount());
503 EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(1)));
504 EXPECT_EQ(shift, s.ToInt32(s[0]->InputAt(2)));
505 }
506 }
507
508
TEST_F(InstructionSelectorTest,Word64AndToClearBits)509 TEST_F(InstructionSelectorTest, Word64AndToClearBits) {
510 TRACED_FORRANGE(int32_t, shift, 1, 31) {
511 int64_t mask = ~((1 << shift) - 1);
512 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64());
513 m.Return(m.Word64And(m.Parameter(0), m.Int64Constant(mask)));
514 Stream s = m.Build();
515 ASSERT_EQ(1U, s.size());
516 EXPECT_EQ(kMips64Dins, s[0]->arch_opcode());
517 ASSERT_EQ(3U, s[0]->InputCount());
518 EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(1)));
519 EXPECT_EQ(shift, s.ToInt32(s[0]->InputAt(2)));
520 }
521 TRACED_FORRANGE(int32_t, shift, 1, 31) {
522 int64_t mask = ~((1 << shift) - 1);
523 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64());
524 m.Return(m.Word64And(m.Int64Constant(mask), m.Parameter(0)));
525 Stream s = m.Build();
526 ASSERT_EQ(1U, s.size());
527 EXPECT_EQ(kMips64Dins, s[0]->arch_opcode());
528 ASSERT_EQ(3U, s[0]->InputCount());
529 EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(1)));
530 EXPECT_EQ(shift, s.ToInt32(s[0]->InputAt(2)));
531 }
532 }
533
534
535 // ----------------------------------------------------------------------------
536 // Logical instructions.
537 // ----------------------------------------------------------------------------
538 using InstructionSelectorLogicalTest =
539 InstructionSelectorTestWithParam<MachInst2>;
540
TEST_P(InstructionSelectorLogicalTest,Parameter)541 TEST_P(InstructionSelectorLogicalTest, Parameter) {
542 const MachInst2 dpi = GetParam();
543 const MachineType type = dpi.machine_type;
544 StreamBuilder m(this, type, type, type);
545 m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)));
546 Stream s = m.Build();
547 ASSERT_EQ(1U, s.size());
548 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
549 EXPECT_EQ(2U, s[0]->InputCount());
550 EXPECT_EQ(1U, s[0]->OutputCount());
551 }
552
553 INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest,
554 InstructionSelectorLogicalTest,
555 ::testing::ValuesIn(kLogicalInstructions));
556
TEST_F(InstructionSelectorTest,Word64XorMinusOneWithParameter)557 TEST_F(InstructionSelectorTest, Word64XorMinusOneWithParameter) {
558 {
559 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64());
560 m.Return(m.Word64Xor(m.Parameter(0), m.Int64Constant(-1)));
561 Stream s = m.Build();
562 ASSERT_EQ(1U, s.size());
563 EXPECT_EQ(kMips64Nor, s[0]->arch_opcode());
564 EXPECT_EQ(2U, s[0]->InputCount());
565 EXPECT_EQ(1U, s[0]->OutputCount());
566 }
567 {
568 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64());
569 m.Return(m.Word64Xor(m.Int64Constant(-1), m.Parameter(0)));
570 Stream s = m.Build();
571 ASSERT_EQ(1U, s.size());
572 EXPECT_EQ(kMips64Nor, s[0]->arch_opcode());
573 EXPECT_EQ(2U, s[0]->InputCount());
574 EXPECT_EQ(1U, s[0]->OutputCount());
575 }
576 }
577
578
TEST_F(InstructionSelectorTest,Word32XorMinusOneWithParameter)579 TEST_F(InstructionSelectorTest, Word32XorMinusOneWithParameter) {
580 {
581 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
582 m.Return(m.Word32Xor(m.Parameter(0), m.Int32Constant(-1)));
583 Stream s = m.Build();
584 ASSERT_EQ(1U, s.size());
585 EXPECT_EQ(kMips64Nor32, s[0]->arch_opcode());
586 EXPECT_EQ(2U, s[0]->InputCount());
587 EXPECT_EQ(1U, s[0]->OutputCount());
588 }
589 {
590 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
591 m.Return(m.Word32Xor(m.Int32Constant(-1), m.Parameter(0)));
592 Stream s = m.Build();
593 ASSERT_EQ(1U, s.size());
594 EXPECT_EQ(kMips64Nor32, s[0]->arch_opcode());
595 EXPECT_EQ(2U, s[0]->InputCount());
596 EXPECT_EQ(1U, s[0]->OutputCount());
597 }
598 }
599
600
TEST_F(InstructionSelectorTest,Word64XorMinusOneWithWord64Or)601 TEST_F(InstructionSelectorTest, Word64XorMinusOneWithWord64Or) {
602 {
603 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64());
604 m.Return(m.Word64Xor(m.Word64Or(m.Parameter(0), m.Parameter(0)),
605 m.Int64Constant(-1)));
606 Stream s = m.Build();
607 ASSERT_EQ(1U, s.size());
608 EXPECT_EQ(kMips64Nor, s[0]->arch_opcode());
609 EXPECT_EQ(2U, s[0]->InputCount());
610 EXPECT_EQ(1U, s[0]->OutputCount());
611 }
612 {
613 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64());
614 m.Return(m.Word64Xor(m.Int64Constant(-1),
615 m.Word64Or(m.Parameter(0), m.Parameter(0))));
616 Stream s = m.Build();
617 ASSERT_EQ(1U, s.size());
618 EXPECT_EQ(kMips64Nor, s[0]->arch_opcode());
619 EXPECT_EQ(2U, s[0]->InputCount());
620 EXPECT_EQ(1U, s[0]->OutputCount());
621 }
622 }
623
624
TEST_F(InstructionSelectorTest,Word32XorMinusOneWithWord32Or)625 TEST_F(InstructionSelectorTest, Word32XorMinusOneWithWord32Or) {
626 {
627 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
628 m.Return(m.Word32Xor(m.Word32Or(m.Parameter(0), m.Parameter(0)),
629 m.Int32Constant(-1)));
630 Stream s = m.Build();
631 ASSERT_EQ(1U, s.size());
632 EXPECT_EQ(kMips64Nor32, s[0]->arch_opcode());
633 EXPECT_EQ(2U, s[0]->InputCount());
634 EXPECT_EQ(1U, s[0]->OutputCount());
635 }
636 {
637 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
638 m.Return(m.Word32Xor(m.Int32Constant(-1),
639 m.Word32Or(m.Parameter(0), m.Parameter(0))));
640 Stream s = m.Build();
641 ASSERT_EQ(1U, s.size());
642 EXPECT_EQ(kMips64Nor32, s[0]->arch_opcode());
643 EXPECT_EQ(2U, s[0]->InputCount());
644 EXPECT_EQ(1U, s[0]->OutputCount());
645 }
646 }
647
648
TEST_F(InstructionSelectorTest,Word32AndWithImmediateWithWord32Shr)649 TEST_F(InstructionSelectorTest, Word32AndWithImmediateWithWord32Shr) {
650 // The available shift operand range is `0 <= imm < 32`, but we also test
651 // that immediates outside this range are handled properly (modulo-32).
652 TRACED_FORRANGE(int32_t, shift, -32, 63) {
653 int32_t lsb = shift & 0x1F;
654 TRACED_FORRANGE(int32_t, width, 1, 31) {
655 uint32_t msk = (1 << width) - 1;
656 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
657 m.Return(m.Word32And(m.Word32Shr(m.Parameter(0), m.Int32Constant(shift)),
658 m.Int32Constant(msk)));
659 Stream s = m.Build();
660 ASSERT_EQ(1U, s.size());
661 EXPECT_EQ(kMips64Ext, s[0]->arch_opcode());
662 ASSERT_EQ(3U, s[0]->InputCount());
663 EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1)));
664 int32_t actual_width = (lsb + width > 32) ? (32 - lsb) : width;
665 EXPECT_EQ(actual_width, s.ToInt32(s[0]->InputAt(2)));
666 }
667 }
668 TRACED_FORRANGE(int32_t, shift, -32, 63) {
669 int32_t lsb = shift & 0x1F;
670 TRACED_FORRANGE(int32_t, width, 1, 31) {
671 uint32_t msk = (1 << width) - 1;
672 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
673 m.Return(
674 m.Word32And(m.Int32Constant(msk),
675 m.Word32Shr(m.Parameter(0), m.Int32Constant(shift))));
676 Stream s = m.Build();
677 ASSERT_EQ(1U, s.size());
678 EXPECT_EQ(kMips64Ext, s[0]->arch_opcode());
679 ASSERT_EQ(3U, s[0]->InputCount());
680 EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1)));
681 int32_t actual_width = (lsb + width > 32) ? (32 - lsb) : width;
682 EXPECT_EQ(actual_width, s.ToInt32(s[0]->InputAt(2)));
683 }
684 }
685 }
686
687
TEST_F(InstructionSelectorTest,Word64AndWithImmediateWithWord64Shr)688 TEST_F(InstructionSelectorTest, Word64AndWithImmediateWithWord64Shr) {
689 // The available shift operand range is `0 <= imm < 64`, but we also test
690 // that immediates outside this range are handled properly (modulo-64).
691 TRACED_FORRANGE(int64_t, shift, -64, 127) {
692 int64_t lsb = shift & 0x3F;
693 TRACED_FORRANGE(int64_t, width, 1, 63) {
694 uint64_t msk = (uint64_t{1} << width) - 1;
695 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64());
696 m.Return(m.Word64And(m.Word64Shr(m.Parameter(0), m.Int64Constant(shift)),
697 m.Int64Constant(msk)));
698 Stream s = m.Build();
699 ASSERT_EQ(1U, s.size());
700 EXPECT_EQ(kMips64Dext, s[0]->arch_opcode());
701 ASSERT_EQ(3U, s[0]->InputCount());
702 EXPECT_EQ(lsb, s.ToInt64(s[0]->InputAt(1)));
703 int64_t actual_width = (lsb + width > 64) ? (64 - lsb) : width;
704 EXPECT_EQ(actual_width, s.ToInt64(s[0]->InputAt(2)));
705 }
706 }
707 TRACED_FORRANGE(int64_t, shift, -64, 127) {
708 int64_t lsb = shift & 0x3F;
709 TRACED_FORRANGE(int64_t, width, 1, 63) {
710 uint64_t msk = (uint64_t{1} << width) - 1;
711 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64());
712 m.Return(
713 m.Word64And(m.Int64Constant(msk),
714 m.Word64Shr(m.Parameter(0), m.Int64Constant(shift))));
715 Stream s = m.Build();
716 ASSERT_EQ(1U, s.size());
717 EXPECT_EQ(kMips64Dext, s[0]->arch_opcode());
718 ASSERT_EQ(3U, s[0]->InputCount());
719 EXPECT_EQ(lsb, s.ToInt64(s[0]->InputAt(1)));
720 int64_t actual_width = (lsb + width > 64) ? (64 - lsb) : width;
721 EXPECT_EQ(actual_width, s.ToInt64(s[0]->InputAt(2)));
722 }
723 }
724 }
725
726
TEST_F(InstructionSelectorTest,Word32ShlWithWord32And)727 TEST_F(InstructionSelectorTest, Word32ShlWithWord32And) {
728 TRACED_FORRANGE(int32_t, shift, 0, 30) {
729 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
730 Node* const p0 = m.Parameter(0);
731 Node* const r =
732 m.Word32Shl(m.Word32And(p0, m.Int32Constant((1 << (31 - shift)) - 1)),
733 m.Int32Constant(shift + 1));
734 m.Return(r);
735 Stream s = m.Build();
736 ASSERT_EQ(1U, s.size());
737 EXPECT_EQ(kMips64Shl, s[0]->arch_opcode());
738 ASSERT_EQ(2U, s[0]->InputCount());
739 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
740 ASSERT_EQ(1U, s[0]->OutputCount());
741 EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
742 }
743 }
744
745
TEST_F(InstructionSelectorTest,Word64ShlWithWord64And)746 TEST_F(InstructionSelectorTest, Word64ShlWithWord64And) {
747 TRACED_FORRANGE(int32_t, shift, 0, 62) {
748 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64());
749 Node* const p0 = m.Parameter(0);
750 Node* const r =
751 m.Word64Shl(m.Word64And(p0, m.Int64Constant((1L << (63 - shift)) - 1)),
752 m.Int64Constant(shift + 1));
753 m.Return(r);
754 Stream s = m.Build();
755 ASSERT_EQ(1U, s.size());
756 EXPECT_EQ(kMips64Dshl, s[0]->arch_opcode());
757 ASSERT_EQ(2U, s[0]->InputCount());
758 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
759 ASSERT_EQ(1U, s[0]->OutputCount());
760 EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
761 }
762 }
763
TEST_F(InstructionSelectorTest,Word32SarWithWord32Shl)764 TEST_F(InstructionSelectorTest, Word32SarWithWord32Shl) {
765 {
766 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
767 Node* const p0 = m.Parameter(0);
768 Node* const r =
769 m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(24)), m.Int32Constant(24));
770 m.Return(r);
771 Stream s = m.Build();
772 ASSERT_EQ(1U, s.size());
773 EXPECT_EQ(kMips64Seb, s[0]->arch_opcode());
774 ASSERT_EQ(1U, s[0]->InputCount());
775 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
776 ASSERT_EQ(1U, s[0]->OutputCount());
777 EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
778 }
779 {
780 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
781 Node* const p0 = m.Parameter(0);
782 Node* const r =
783 m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(16)), m.Int32Constant(16));
784 m.Return(r);
785 Stream s = m.Build();
786 ASSERT_EQ(1U, s.size());
787 EXPECT_EQ(kMips64Seh, s[0]->arch_opcode());
788 ASSERT_EQ(1U, s[0]->InputCount());
789 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
790 ASSERT_EQ(1U, s[0]->OutputCount());
791 EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
792 }
793 {
794 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
795 Node* const p0 = m.Parameter(0);
796 Node* const r =
797 m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(32)), m.Int32Constant(32));
798 m.Return(r);
799 Stream s = m.Build();
800 ASSERT_EQ(1U, s.size());
801 EXPECT_EQ(kMips64Shl, s[0]->arch_opcode());
802 ASSERT_EQ(2U, s[0]->InputCount());
803 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
804 EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(1)));
805 ASSERT_EQ(1U, s[0]->OutputCount());
806 EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
807 }
808 }
809
810 // ----------------------------------------------------------------------------
811 // MUL/DIV instructions.
812 // ----------------------------------------------------------------------------
813 using InstructionSelectorMulDivTest =
814 InstructionSelectorTestWithParam<MachInst2>;
815
TEST_P(InstructionSelectorMulDivTest,Parameter)816 TEST_P(InstructionSelectorMulDivTest, Parameter) {
817 const MachInst2 dpi = GetParam();
818 const MachineType type = dpi.machine_type;
819 StreamBuilder m(this, type, type, type);
820 m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)));
821 Stream s = m.Build();
822 ASSERT_EQ(1U, s.size());
823 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
824 EXPECT_EQ(2U, s[0]->InputCount());
825 EXPECT_EQ(1U, s[0]->OutputCount());
826 }
827
828 INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest, InstructionSelectorMulDivTest,
829 ::testing::ValuesIn(kMulDivInstructions));
830
831 // ----------------------------------------------------------------------------
832 // MOD instructions.
833 // ----------------------------------------------------------------------------
834 using InstructionSelectorModTest = InstructionSelectorTestWithParam<MachInst2>;
835
TEST_P(InstructionSelectorModTest,Parameter)836 TEST_P(InstructionSelectorModTest, Parameter) {
837 const MachInst2 dpi = GetParam();
838 const MachineType type = dpi.machine_type;
839 StreamBuilder m(this, type, type, type);
840 m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)));
841 Stream s = m.Build();
842 ASSERT_EQ(1U, s.size());
843 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
844 EXPECT_EQ(2U, s[0]->InputCount());
845 EXPECT_EQ(1U, s[0]->OutputCount());
846 }
847
848 INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest, InstructionSelectorModTest,
849 ::testing::ValuesIn(kModInstructions));
850
851 // ----------------------------------------------------------------------------
852 // Floating point instructions.
853 // ----------------------------------------------------------------------------
854 using InstructionSelectorFPArithTest =
855 InstructionSelectorTestWithParam<MachInst2>;
856
TEST_P(InstructionSelectorFPArithTest,Parameter)857 TEST_P(InstructionSelectorFPArithTest, Parameter) {
858 const MachInst2 fpa = GetParam();
859 StreamBuilder m(this, fpa.machine_type, fpa.machine_type, fpa.machine_type);
860 m.Return((m.*fpa.constructor)(m.Parameter(0), m.Parameter(1)));
861 Stream s = m.Build();
862 ASSERT_EQ(1U, s.size());
863 EXPECT_EQ(fpa.arch_opcode, s[0]->arch_opcode());
864 EXPECT_EQ(2U, s[0]->InputCount());
865 EXPECT_EQ(1U, s[0]->OutputCount());
866 }
867
868 INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest,
869 InstructionSelectorFPArithTest,
870 ::testing::ValuesIn(kFPArithInstructions));
871 // ----------------------------------------------------------------------------
872 // Integer arithmetic
873 // ----------------------------------------------------------------------------
874 using InstructionSelectorIntArithTwoTest =
875 InstructionSelectorTestWithParam<MachInst2>;
876
TEST_P(InstructionSelectorIntArithTwoTest,Parameter)877 TEST_P(InstructionSelectorIntArithTwoTest, Parameter) {
878 const MachInst2 intpa = GetParam();
879 StreamBuilder m(this, intpa.machine_type, intpa.machine_type,
880 intpa.machine_type);
881 m.Return((m.*intpa.constructor)(m.Parameter(0), m.Parameter(1)));
882 Stream s = m.Build();
883 ASSERT_EQ(1U, s.size());
884 EXPECT_EQ(intpa.arch_opcode, s[0]->arch_opcode());
885 EXPECT_EQ(2U, s[0]->InputCount());
886 EXPECT_EQ(1U, s[0]->OutputCount());
887 }
888
889 INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest,
890 InstructionSelectorIntArithTwoTest,
891 ::testing::ValuesIn(kAddSubInstructions));
892
893 // ----------------------------------------------------------------------------
894 // One node.
895 // ----------------------------------------------------------------------------
896
897 using InstructionSelectorIntArithOneTest =
898 InstructionSelectorTestWithParam<MachInst1>;
899
TEST_P(InstructionSelectorIntArithOneTest,Parameter)900 TEST_P(InstructionSelectorIntArithOneTest, Parameter) {
901 const MachInst1 intpa = GetParam();
902 StreamBuilder m(this, intpa.machine_type, intpa.machine_type,
903 intpa.machine_type);
904 m.Return((m.*intpa.constructor)(m.Parameter(0)));
905 Stream s = m.Build();
906 ASSERT_EQ(1U, s.size());
907 EXPECT_EQ(intpa.arch_opcode, s[0]->arch_opcode());
908 EXPECT_EQ(2U, s[0]->InputCount());
909 EXPECT_EQ(1U, s[0]->OutputCount());
910 }
911
912 INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest,
913 InstructionSelectorIntArithOneTest,
914 ::testing::ValuesIn(kAddSubOneInstructions));
915 // ----------------------------------------------------------------------------
916 // Conversions.
917 // ----------------------------------------------------------------------------
918 using InstructionSelectorConversionTest =
919 InstructionSelectorTestWithParam<Conversion>;
920
TEST_P(InstructionSelectorConversionTest,Parameter)921 TEST_P(InstructionSelectorConversionTest, Parameter) {
922 const Conversion conv = GetParam();
923 StreamBuilder m(this, conv.mi.machine_type, conv.src_machine_type);
924 m.Return((m.*conv.mi.constructor)(m.Parameter(0)));
925 Stream s = m.Build();
926 ASSERT_EQ(1U, s.size());
927 EXPECT_EQ(conv.mi.arch_opcode, s[0]->arch_opcode());
928 EXPECT_EQ(1U, s[0]->InputCount());
929 EXPECT_EQ(1U, s[0]->OutputCount());
930 }
931
932 INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest,
933 InstructionSelectorConversionTest,
934 ::testing::ValuesIn(kConversionInstructions));
935
TEST_F(InstructionSelectorTest,ChangesFromToSmi)936 TEST_F(InstructionSelectorTest, ChangesFromToSmi) {
937 {
938 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
939 m.Return(m.TruncateInt64ToInt32(
940 m.Word64Sar(m.Parameter(0), m.Int32Constant(32))));
941 Stream s = m.Build();
942 ASSERT_EQ(1U, s.size());
943 EXPECT_EQ(kMips64Dsar, s[0]->arch_opcode());
944 EXPECT_EQ(kMode_None, s[0]->addressing_mode());
945 ASSERT_EQ(2U, s[0]->InputCount());
946 EXPECT_EQ(1U, s[0]->OutputCount());
947 }
948 {
949 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
950 m.Return(
951 m.Word64Shl(m.ChangeInt32ToInt64(m.Parameter(0)), m.Int32Constant(32)));
952 Stream s = m.Build();
953 ASSERT_EQ(1U, s.size());
954 EXPECT_EQ(kMips64Dshl, s[0]->arch_opcode());
955 ASSERT_EQ(2U, s[0]->InputCount());
956 EXPECT_EQ(1U, s[0]->OutputCount());
957 }
958 }
959
960 using CombineChangeFloat64ToInt32WithRoundFloat64 =
961 InstructionSelectorTestWithParam<Conversion>;
962
TEST_P(CombineChangeFloat64ToInt32WithRoundFloat64,Parameter)963 TEST_P(CombineChangeFloat64ToInt32WithRoundFloat64, Parameter) {
964 {
965 const Conversion conv = GetParam();
966 StreamBuilder m(this, conv.mi.machine_type, conv.src_machine_type);
967 m.Return(m.ChangeFloat64ToInt32((m.*conv.mi.constructor)(m.Parameter(0))));
968 Stream s = m.Build();
969 ASSERT_EQ(1U, s.size());
970 EXPECT_EQ(conv.mi.arch_opcode, s[0]->arch_opcode());
971 EXPECT_EQ(kMode_None, s[0]->addressing_mode());
972 ASSERT_EQ(1U, s[0]->InputCount());
973 EXPECT_EQ(1U, s[0]->OutputCount());
974 }
975 }
976
977 INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest,
978 CombineChangeFloat64ToInt32WithRoundFloat64,
979 ::testing::ValuesIn(kFloat64RoundInstructions));
980
981 using CombineChangeFloat32ToInt32WithRoundFloat32 =
982 InstructionSelectorTestWithParam<Conversion>;
983
TEST_P(CombineChangeFloat32ToInt32WithRoundFloat32,Parameter)984 TEST_P(CombineChangeFloat32ToInt32WithRoundFloat32, Parameter) {
985 {
986 const Conversion conv = GetParam();
987 StreamBuilder m(this, conv.mi.machine_type, conv.src_machine_type);
988 m.Return(m.ChangeFloat64ToInt32(
989 m.ChangeFloat32ToFloat64((m.*conv.mi.constructor)(m.Parameter(0)))));
990 Stream s = m.Build();
991 ASSERT_EQ(1U, s.size());
992 EXPECT_EQ(conv.mi.arch_opcode, s[0]->arch_opcode());
993 EXPECT_EQ(kMode_None, s[0]->addressing_mode());
994 ASSERT_EQ(1U, s[0]->InputCount());
995 EXPECT_EQ(1U, s[0]->OutputCount());
996 }
997 }
998
999 INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest,
1000 CombineChangeFloat32ToInt32WithRoundFloat32,
1001 ::testing::ValuesIn(kFloat32RoundInstructions));
1002
TEST_F(InstructionSelectorTest,ChangeFloat64ToInt32OfChangeFloat32ToFloat64)1003 TEST_F(InstructionSelectorTest, ChangeFloat64ToInt32OfChangeFloat32ToFloat64) {
1004 {
1005 StreamBuilder m(this, MachineType::Int32(), MachineType::Float32());
1006 m.Return(m.ChangeFloat64ToInt32(m.ChangeFloat32ToFloat64(m.Parameter(0))));
1007 Stream s = m.Build();
1008 ASSERT_EQ(1U, s.size());
1009 EXPECT_EQ(kMips64TruncWS, s[0]->arch_opcode());
1010 EXPECT_EQ(kMode_None, s[0]->addressing_mode());
1011 ASSERT_EQ(1U, s[0]->InputCount());
1012 EXPECT_EQ(1U, s[0]->OutputCount());
1013 }
1014 }
1015
1016
TEST_F(InstructionSelectorTest,TruncateFloat64ToFloat32OfChangeInt32ToFloat64)1017 TEST_F(InstructionSelectorTest,
1018 TruncateFloat64ToFloat32OfChangeInt32ToFloat64) {
1019 {
1020 StreamBuilder m(this, MachineType::Float32(), MachineType::Int32());
1021 m.Return(
1022 m.TruncateFloat64ToFloat32(m.ChangeInt32ToFloat64(m.Parameter(0))));
1023 Stream s = m.Build();
1024 ASSERT_EQ(1U, s.size());
1025 EXPECT_EQ(kMips64CvtSW, s[0]->arch_opcode());
1026 EXPECT_EQ(kMode_None, s[0]->addressing_mode());
1027 ASSERT_EQ(1U, s[0]->InputCount());
1028 EXPECT_EQ(1U, s[0]->OutputCount());
1029 }
1030 }
1031
1032
TEST_F(InstructionSelectorTest,CombineShiftsWithMul)1033 TEST_F(InstructionSelectorTest, CombineShiftsWithMul) {
1034 {
1035 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
1036 m.Return(m.Int32Mul(m.Word64Sar(m.Parameter(0), m.Int32Constant(32)),
1037 m.Word64Sar(m.Parameter(0), m.Int32Constant(32))));
1038 Stream s = m.Build();
1039 ASSERT_EQ(1U, s.size());
1040 EXPECT_EQ(kMips64DMulHigh, s[0]->arch_opcode());
1041 EXPECT_EQ(kMode_None, s[0]->addressing_mode());
1042 ASSERT_EQ(2U, s[0]->InputCount());
1043 EXPECT_EQ(1U, s[0]->OutputCount());
1044 }
1045 }
1046
1047
TEST_F(InstructionSelectorTest,CombineShiftsWithDivMod)1048 TEST_F(InstructionSelectorTest, CombineShiftsWithDivMod) {
1049 {
1050 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
1051 m.Return(m.Int32Div(m.Word64Sar(m.Parameter(0), m.Int32Constant(32)),
1052 m.Word64Sar(m.Parameter(0), m.Int32Constant(32))));
1053 Stream s = m.Build();
1054 ASSERT_EQ(1U, s.size());
1055 EXPECT_EQ(kMips64Ddiv, s[0]->arch_opcode());
1056 EXPECT_EQ(kMode_None, s[0]->addressing_mode());
1057 ASSERT_EQ(2U, s[0]->InputCount());
1058 EXPECT_EQ(1U, s[0]->OutputCount());
1059 }
1060 {
1061 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
1062 m.Return(m.Int32Mod(m.Word64Sar(m.Parameter(0), m.Int32Constant(32)),
1063 m.Word64Sar(m.Parameter(0), m.Int32Constant(32))));
1064 Stream s = m.Build();
1065 ASSERT_EQ(1U, s.size());
1066 EXPECT_EQ(kMips64Dmod, s[0]->arch_opcode());
1067 EXPECT_EQ(kMode_None, s[0]->addressing_mode());
1068 ASSERT_EQ(2U, s[0]->InputCount());
1069 EXPECT_EQ(1U, s[0]->OutputCount());
1070 }
1071 }
1072
TEST_F(InstructionSelectorTest,ChangeInt32ToInt64AfterLoad)1073 TEST_F(InstructionSelectorTest, ChangeInt32ToInt64AfterLoad) {
1074 // For each case, test that the conversion is merged into the load
1075 // operation.
1076 // ChangeInt32ToInt64(Load_Uint8) -> Lbu
1077 {
1078 StreamBuilder m(this, MachineType::Int64(), MachineType::Pointer(),
1079 MachineType::Int32());
1080 m.Return(m.ChangeInt32ToInt64(
1081 m.Load(MachineType::Uint8(), m.Parameter(0), m.Parameter(1))));
1082 Stream s = m.Build();
1083 ASSERT_EQ(2U, s.size());
1084 EXPECT_EQ(kMips64Lbu, s[1]->arch_opcode());
1085 EXPECT_EQ(kMode_MRI, s[1]->addressing_mode());
1086 EXPECT_EQ(2U, s[1]->InputCount());
1087 EXPECT_EQ(1U, s[1]->OutputCount());
1088 }
1089 // ChangeInt32ToInt64(Load_Int8) -> Lb
1090 {
1091 StreamBuilder m(this, MachineType::Int64(), MachineType::Pointer(),
1092 MachineType::Int32());
1093 m.Return(m.ChangeInt32ToInt64(
1094 m.Load(MachineType::Int8(), m.Parameter(0), m.Parameter(1))));
1095 Stream s = m.Build();
1096 ASSERT_EQ(2U, s.size());
1097 EXPECT_EQ(kMips64Lb, s[1]->arch_opcode());
1098 EXPECT_EQ(kMode_MRI, s[1]->addressing_mode());
1099 EXPECT_EQ(2U, s[1]->InputCount());
1100 EXPECT_EQ(1U, s[1]->OutputCount());
1101 }
1102 // ChangeInt32ToInt64(Load_Uint16) -> Lhu
1103 {
1104 StreamBuilder m(this, MachineType::Int64(), MachineType::Pointer(),
1105 MachineType::Int32());
1106 m.Return(m.ChangeInt32ToInt64(
1107 m.Load(MachineType::Uint16(), m.Parameter(0), m.Parameter(1))));
1108 Stream s = m.Build();
1109 ASSERT_EQ(2U, s.size());
1110 EXPECT_EQ(kMips64Lhu, s[1]->arch_opcode());
1111 EXPECT_EQ(kMode_MRI, s[1]->addressing_mode());
1112 EXPECT_EQ(2U, s[1]->InputCount());
1113 EXPECT_EQ(1U, s[1]->OutputCount());
1114 }
1115 // ChangeInt32ToInt64(Load_Int16) -> Lh
1116 {
1117 StreamBuilder m(this, MachineType::Int64(), MachineType::Pointer(),
1118 MachineType::Int32());
1119 m.Return(m.ChangeInt32ToInt64(
1120 m.Load(MachineType::Int16(), m.Parameter(0), m.Parameter(1))));
1121 Stream s = m.Build();
1122 ASSERT_EQ(2U, s.size());
1123 EXPECT_EQ(kMips64Lh, s[1]->arch_opcode());
1124 EXPECT_EQ(kMode_MRI, s[1]->addressing_mode());
1125 EXPECT_EQ(2U, s[1]->InputCount());
1126 EXPECT_EQ(1U, s[1]->OutputCount());
1127 }
1128 // ChangeInt32ToInt64(Load_Uint32) -> Lw
1129 {
1130 StreamBuilder m(this, MachineType::Int64(), MachineType::Pointer(),
1131 MachineType::Int32());
1132 m.Return(m.ChangeInt32ToInt64(
1133 m.Load(MachineType::Uint32(), m.Parameter(0), m.Parameter(1))));
1134 Stream s = m.Build();
1135 ASSERT_EQ(2U, s.size());
1136 EXPECT_EQ(kMips64Lw, s[1]->arch_opcode());
1137 EXPECT_EQ(kMode_MRI, s[1]->addressing_mode());
1138 EXPECT_EQ(2U, s[1]->InputCount());
1139 EXPECT_EQ(1U, s[1]->OutputCount());
1140 }
1141 // ChangeInt32ToInt64(Load_Int32) -> Lw
1142 {
1143 StreamBuilder m(this, MachineType::Int64(), MachineType::Pointer(),
1144 MachineType::Int32());
1145 m.Return(m.ChangeInt32ToInt64(
1146 m.Load(MachineType::Int32(), m.Parameter(0), m.Parameter(1))));
1147 Stream s = m.Build();
1148 ASSERT_EQ(2U, s.size());
1149 EXPECT_EQ(kMips64Lw, s[1]->arch_opcode());
1150 EXPECT_EQ(kMode_MRI, s[1]->addressing_mode());
1151 EXPECT_EQ(2U, s[1]->InputCount());
1152 EXPECT_EQ(1U, s[1]->OutputCount());
1153 }
1154 }
1155
1156 using InstructionSelectorElidedChangeUint32ToUint64Test =
1157 InstructionSelectorTestWithParam<MachInst2>;
1158
TEST_P(InstructionSelectorElidedChangeUint32ToUint64Test,Parameter)1159 TEST_P(InstructionSelectorElidedChangeUint32ToUint64Test, Parameter) {
1160 const MachInst2 binop = GetParam();
1161 StreamBuilder m(this, MachineType::Uint64(), binop.machine_type,
1162 binop.machine_type);
1163 m.Return(m.ChangeUint32ToUint64(
1164 (m.*binop.constructor)(m.Parameter(0), m.Parameter(1))));
1165 Stream s = m.Build();
1166 // Make sure the `ChangeUint32ToUint64` node turned into a no-op.
1167 if (FLAG_debug_code && binop.arch_opcode == kMips64Cmp) {
1168 ASSERT_EQ(6U, s.size());
1169 EXPECT_EQ(kMips64Cmp, s[0]->arch_opcode());
1170 EXPECT_EQ(kMips64Dshl, s[1]->arch_opcode());
1171 EXPECT_EQ(kMips64Dshl, s[2]->arch_opcode());
1172 EXPECT_EQ(kMips64Cmp, s[3]->arch_opcode());
1173 EXPECT_EQ(kMips64AssertEqual, s[4]->arch_opcode());
1174 EXPECT_EQ(kMips64Cmp, s[5]->arch_opcode());
1175 EXPECT_EQ(2U, s[5]->InputCount());
1176 EXPECT_EQ(1U, s[5]->OutputCount());
1177 } else {
1178 ASSERT_EQ(1U, s.size());
1179 EXPECT_EQ(binop.arch_opcode, s[0]->arch_opcode());
1180 EXPECT_EQ(2U, s[0]->InputCount());
1181 EXPECT_EQ(1U, s[0]->OutputCount());
1182 }
1183 }
1184
1185 INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest,
1186 InstructionSelectorElidedChangeUint32ToUint64Test,
1187 ::testing::ValuesIn(kCanElideChangeUint32ToUint64));
1188
TEST_F(InstructionSelectorTest,ChangeUint32ToUint64AfterLoad)1189 TEST_F(InstructionSelectorTest, ChangeUint32ToUint64AfterLoad) {
1190 // For each case, make sure the `ChangeUint32ToUint64` node turned into a
1191 // no-op.
1192
1193 // Lbu
1194 {
1195 StreamBuilder m(this, MachineType::Uint64(), MachineType::Pointer(),
1196 MachineType::Int32());
1197 m.Return(m.ChangeUint32ToUint64(
1198 m.Load(MachineType::Uint8(), m.Parameter(0), m.Parameter(1))));
1199 Stream s = m.Build();
1200 ASSERT_EQ(2U, s.size());
1201 EXPECT_EQ(kMips64Dadd, s[0]->arch_opcode());
1202 EXPECT_EQ(kMode_None, s[0]->addressing_mode());
1203 EXPECT_EQ(2U, s[0]->InputCount());
1204 EXPECT_EQ(1U, s[0]->OutputCount());
1205 EXPECT_EQ(kMips64Lbu, s[1]->arch_opcode());
1206 EXPECT_EQ(kMode_MRI, s[1]->addressing_mode());
1207 EXPECT_EQ(2U, s[1]->InputCount());
1208 EXPECT_EQ(1U, s[1]->OutputCount());
1209 }
1210 // Lhu
1211 {
1212 StreamBuilder m(this, MachineType::Uint64(), MachineType::Pointer(),
1213 MachineType::Int32());
1214 m.Return(m.ChangeUint32ToUint64(
1215 m.Load(MachineType::Uint16(), m.Parameter(0), m.Parameter(1))));
1216 Stream s = m.Build();
1217 ASSERT_EQ(2U, s.size());
1218 EXPECT_EQ(kMips64Dadd, s[0]->arch_opcode());
1219 EXPECT_EQ(kMode_None, s[0]->addressing_mode());
1220 EXPECT_EQ(2U, s[0]->InputCount());
1221 EXPECT_EQ(1U, s[0]->OutputCount());
1222 EXPECT_EQ(kMips64Lhu, s[1]->arch_opcode());
1223 EXPECT_EQ(kMode_MRI, s[1]->addressing_mode());
1224 EXPECT_EQ(2U, s[1]->InputCount());
1225 EXPECT_EQ(1U, s[1]->OutputCount());
1226 }
1227 // Lwu
1228 {
1229 StreamBuilder m(this, MachineType::Uint64(), MachineType::Pointer(),
1230 MachineType::Int32());
1231 m.Return(m.ChangeUint32ToUint64(
1232 m.Load(MachineType::Uint32(), m.Parameter(0), m.Parameter(1))));
1233 Stream s = m.Build();
1234 ASSERT_EQ(2U, s.size());
1235 EXPECT_EQ(kMips64Dadd, s[0]->arch_opcode());
1236 EXPECT_EQ(kMode_None, s[0]->addressing_mode());
1237 EXPECT_EQ(2U, s[0]->InputCount());
1238 EXPECT_EQ(1U, s[0]->OutputCount());
1239 EXPECT_EQ(kMips64Lwu, s[1]->arch_opcode());
1240 EXPECT_EQ(kMode_MRI, s[1]->addressing_mode());
1241 EXPECT_EQ(2U, s[1]->InputCount());
1242 EXPECT_EQ(1U, s[1]->OutputCount());
1243 }
1244 }
1245
1246 // ----------------------------------------------------------------------------
1247 // Loads and stores.
1248 // ----------------------------------------------------------------------------
1249
1250
1251 namespace {
1252
1253 struct MemoryAccess {
1254 MachineType type;
1255 ArchOpcode load_opcode;
1256 ArchOpcode store_opcode;
1257 };
1258
1259 static const MemoryAccess kMemoryAccesses[] = {
1260 {MachineType::Int8(), kMips64Lb, kMips64Sb},
1261 {MachineType::Uint8(), kMips64Lbu, kMips64Sb},
1262 {MachineType::Int16(), kMips64Lh, kMips64Sh},
1263 {MachineType::Uint16(), kMips64Lhu, kMips64Sh},
1264 {MachineType::Int32(), kMips64Lw, kMips64Sw},
1265 {MachineType::Float32(), kMips64Lwc1, kMips64Swc1},
1266 {MachineType::Float64(), kMips64Ldc1, kMips64Sdc1},
1267 {MachineType::Int64(), kMips64Ld, kMips64Sd}};
1268
1269
1270 struct MemoryAccessImm {
1271 MachineType type;
1272 ArchOpcode load_opcode;
1273 ArchOpcode store_opcode;
1274 bool (InstructionSelectorTest::Stream::*val_predicate)(
1275 const InstructionOperand*) const;
1276 const int32_t immediates[40];
1277 };
1278
1279
operator <<(std::ostream & os,const MemoryAccessImm & acc)1280 std::ostream& operator<<(std::ostream& os, const MemoryAccessImm& acc) {
1281 return os << acc.type;
1282 }
1283
1284
1285 struct MemoryAccessImm1 {
1286 MachineType type;
1287 ArchOpcode load_opcode;
1288 ArchOpcode store_opcode;
1289 bool (InstructionSelectorTest::Stream::*val_predicate)(
1290 const InstructionOperand*) const;
1291 const int32_t immediates[5];
1292 };
1293
1294
operator <<(std::ostream & os,const MemoryAccessImm1 & acc)1295 std::ostream& operator<<(std::ostream& os, const MemoryAccessImm1& acc) {
1296 return os << acc.type;
1297 }
1298
1299 struct MemoryAccessImm2 {
1300 MachineType type;
1301 ArchOpcode store_opcode;
1302 ArchOpcode store_opcode_unaligned;
1303 bool (InstructionSelectorTest::Stream::*val_predicate)(
1304 const InstructionOperand*) const;
1305 const int32_t immediates[40];
1306 };
1307
operator <<(std::ostream & os,const MemoryAccessImm2 & acc)1308 std::ostream& operator<<(std::ostream& os, const MemoryAccessImm2& acc) {
1309 return os << acc.type;
1310 }
1311
1312 // ----------------------------------------------------------------------------
1313 // Loads and stores immediate values
1314 // ----------------------------------------------------------------------------
1315
1316
1317 const MemoryAccessImm kMemoryAccessesImm[] = {
1318 {MachineType::Int8(),
1319 kMips64Lb,
1320 kMips64Sb,
1321 &InstructionSelectorTest::Stream::IsInteger,
1322 {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
1323 -87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
1324 115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
1325 {MachineType::Uint8(),
1326 kMips64Lbu,
1327 kMips64Sb,
1328 &InstructionSelectorTest::Stream::IsInteger,
1329 {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
1330 -87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
1331 115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
1332 {MachineType::Int16(),
1333 kMips64Lh,
1334 kMips64Sh,
1335 &InstructionSelectorTest::Stream::IsInteger,
1336 {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
1337 -87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
1338 115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
1339 {MachineType::Uint16(),
1340 kMips64Lhu,
1341 kMips64Sh,
1342 &InstructionSelectorTest::Stream::IsInteger,
1343 {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
1344 -87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
1345 115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
1346 {MachineType::Int32(),
1347 kMips64Lw,
1348 kMips64Sw,
1349 &InstructionSelectorTest::Stream::IsInteger,
1350 {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
1351 -87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
1352 115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
1353 {MachineType::Float32(),
1354 kMips64Lwc1,
1355 kMips64Swc1,
1356 &InstructionSelectorTest::Stream::IsDouble,
1357 {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
1358 -87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
1359 115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
1360 {MachineType::Float64(),
1361 kMips64Ldc1,
1362 kMips64Sdc1,
1363 &InstructionSelectorTest::Stream::IsDouble,
1364 {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
1365 -87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
1366 115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
1367 {MachineType::Int64(),
1368 kMips64Ld,
1369 kMips64Sd,
1370 &InstructionSelectorTest::Stream::IsInteger,
1371 {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
1372 -87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
1373 115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}}};
1374
1375 const MemoryAccessImm1 kMemoryAccessImmMoreThan16bit[] = {
1376 {MachineType::Int8(),
1377 kMips64Lb,
1378 kMips64Sb,
1379 &InstructionSelectorTest::Stream::IsInteger,
1380 {-65000, -55000, 32777, 55000, 65000}},
1381 {MachineType::Uint8(),
1382 kMips64Lbu,
1383 kMips64Sb,
1384 &InstructionSelectorTest::Stream::IsInteger,
1385 {-65000, -55000, 32777, 55000, 65000}},
1386 {MachineType::Int16(),
1387 kMips64Lh,
1388 kMips64Sh,
1389 &InstructionSelectorTest::Stream::IsInteger,
1390 {-65000, -55000, 32777, 55000, 65000}},
1391 {MachineType::Uint16(),
1392 kMips64Lhu,
1393 kMips64Sh,
1394 &InstructionSelectorTest::Stream::IsInteger,
1395 {-65000, -55000, 32777, 55000, 65000}},
1396 {MachineType::Int32(),
1397 kMips64Lw,
1398 kMips64Sw,
1399 &InstructionSelectorTest::Stream::IsInteger,
1400 {-65000, -55000, 32777, 55000, 65000}},
1401 {MachineType::Float32(),
1402 kMips64Lwc1,
1403 kMips64Swc1,
1404 &InstructionSelectorTest::Stream::IsDouble,
1405 {-65000, -55000, 32777, 55000, 65000}},
1406 {MachineType::Float64(),
1407 kMips64Ldc1,
1408 kMips64Sdc1,
1409 &InstructionSelectorTest::Stream::IsDouble,
1410 {-65000, -55000, 32777, 55000, 65000}},
1411 {MachineType::Int64(),
1412 kMips64Ld,
1413 kMips64Sd,
1414 &InstructionSelectorTest::Stream::IsInteger,
1415 {-65000, -55000, 32777, 55000, 65000}}};
1416
1417 const MemoryAccessImm2 kMemoryAccessesImmUnaligned[] = {
1418 {MachineType::Int16(),
1419 kMips64Ush,
1420 kMips64Sh,
1421 &InstructionSelectorTest::Stream::IsInteger,
1422 {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91,
1423 -89, -87, -86, -82, -44, -23, -3, 0, 7, 10,
1424 39, 52, 69, 71, 91, 92, 107, 109, 115, 124,
1425 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
1426 {MachineType::Int32(),
1427 kMips64Usw,
1428 kMips64Sw,
1429 &InstructionSelectorTest::Stream::IsInteger,
1430 {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91,
1431 -89, -87, -86, -82, -44, -23, -3, 0, 7, 10,
1432 39, 52, 69, 71, 91, 92, 107, 109, 115, 124,
1433 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
1434 {MachineType::Int64(),
1435 kMips64Usd,
1436 kMips64Sd,
1437 &InstructionSelectorTest::Stream::IsInteger,
1438 {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91,
1439 -89, -87, -86, -82, -44, -23, -3, 0, 7, 10,
1440 39, 52, 69, 71, 91, 92, 107, 109, 115, 124,
1441 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
1442 {MachineType::Float32(),
1443 kMips64Uswc1,
1444 kMips64Swc1,
1445 &InstructionSelectorTest::Stream::IsDouble,
1446 {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91,
1447 -89, -87, -86, -82, -44, -23, -3, 0, 7, 10,
1448 39, 52, 69, 71, 91, 92, 107, 109, 115, 124,
1449 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
1450 {MachineType::Float64(),
1451 kMips64Usdc1,
1452 kMips64Sdc1,
1453 &InstructionSelectorTest::Stream::IsDouble,
1454 {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91,
1455 -89, -87, -86, -82, -44, -23, -3, 0, 7, 10,
1456 39, 52, 69, 71, 91, 92, 107, 109, 115, 124,
1457 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}}};
1458
1459 } // namespace
1460
1461 using InstructionSelectorMemoryAccessTest =
1462 InstructionSelectorTestWithParam<MemoryAccess>;
1463
TEST_P(InstructionSelectorMemoryAccessTest,LoadWithParameters)1464 TEST_P(InstructionSelectorMemoryAccessTest, LoadWithParameters) {
1465 const MemoryAccess memacc = GetParam();
1466 StreamBuilder m(this, memacc.type, MachineType::Pointer(),
1467 MachineType::Int32());
1468 m.Return(m.Load(memacc.type, m.Parameter(0)));
1469 Stream s = m.Build();
1470 ASSERT_EQ(1U, s.size());
1471 EXPECT_EQ(memacc.load_opcode, s[0]->arch_opcode());
1472 EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
1473 }
1474
1475
TEST_P(InstructionSelectorMemoryAccessTest,StoreWithParameters)1476 TEST_P(InstructionSelectorMemoryAccessTest, StoreWithParameters) {
1477 const MemoryAccess memacc = GetParam();
1478 StreamBuilder m(this, MachineType::Int32(), MachineType::Pointer(),
1479 MachineType::Int32(), memacc.type);
1480 m.Store(memacc.type.representation(), m.Parameter(0), m.Parameter(1),
1481 kNoWriteBarrier);
1482 m.Return(m.Int32Constant(0));
1483 Stream s = m.Build();
1484 ASSERT_EQ(1U, s.size());
1485 EXPECT_EQ(memacc.store_opcode, s[0]->arch_opcode());
1486 EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
1487 }
1488
1489 INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest,
1490 InstructionSelectorMemoryAccessTest,
1491 ::testing::ValuesIn(kMemoryAccesses));
1492
1493 // ----------------------------------------------------------------------------
1494 // Load immediate.
1495 // ----------------------------------------------------------------------------
1496
1497 using InstructionSelectorMemoryAccessImmTest =
1498 InstructionSelectorTestWithParam<MemoryAccessImm>;
1499
TEST_P(InstructionSelectorMemoryAccessImmTest,LoadWithImmediateIndex)1500 TEST_P(InstructionSelectorMemoryAccessImmTest, LoadWithImmediateIndex) {
1501 const MemoryAccessImm memacc = GetParam();
1502 TRACED_FOREACH(int32_t, index, memacc.immediates) {
1503 StreamBuilder m(this, memacc.type, MachineType::Pointer());
1504 m.Return(m.Load(memacc.type, m.Parameter(0), m.Int32Constant(index)));
1505 Stream s = m.Build();
1506 ASSERT_EQ(1U, s.size());
1507 EXPECT_EQ(memacc.load_opcode, s[0]->arch_opcode());
1508 EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
1509 ASSERT_EQ(2U, s[0]->InputCount());
1510 ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
1511 EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
1512 ASSERT_EQ(1U, s[0]->OutputCount());
1513 EXPECT_TRUE((s.*memacc.val_predicate)(s[0]->Output()));
1514 }
1515 }
1516
1517
1518 // ----------------------------------------------------------------------------
1519 // Store immediate.
1520 // ----------------------------------------------------------------------------
1521
1522
TEST_P(InstructionSelectorMemoryAccessImmTest,StoreWithImmediateIndex)1523 TEST_P(InstructionSelectorMemoryAccessImmTest, StoreWithImmediateIndex) {
1524 const MemoryAccessImm memacc = GetParam();
1525 TRACED_FOREACH(int32_t, index, memacc.immediates) {
1526 StreamBuilder m(this, MachineType::Int32(), MachineType::Pointer(),
1527 memacc.type);
1528 m.Store(memacc.type.representation(), m.Parameter(0),
1529 m.Int32Constant(index), m.Parameter(1), kNoWriteBarrier);
1530 m.Return(m.Int32Constant(0));
1531 Stream s = m.Build();
1532 ASSERT_EQ(1U, s.size());
1533 EXPECT_EQ(memacc.store_opcode, s[0]->arch_opcode());
1534 EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
1535 ASSERT_EQ(3U, s[0]->InputCount());
1536 ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
1537 EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
1538 EXPECT_EQ(0U, s[0]->OutputCount());
1539 }
1540 }
1541
TEST_P(InstructionSelectorMemoryAccessImmTest,StoreZero)1542 TEST_P(InstructionSelectorMemoryAccessImmTest, StoreZero) {
1543 const MemoryAccessImm memacc = GetParam();
1544 TRACED_FOREACH(int32_t, index, memacc.immediates) {
1545 StreamBuilder m(this, MachineType::Int32(), MachineType::Pointer());
1546 m.Store(memacc.type.representation(), m.Parameter(0),
1547 m.Int32Constant(index), m.Int32Constant(0), kNoWriteBarrier);
1548 m.Return(m.Int32Constant(0));
1549 Stream s = m.Build();
1550 ASSERT_EQ(1U, s.size());
1551 EXPECT_EQ(memacc.store_opcode, s[0]->arch_opcode());
1552 EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
1553 ASSERT_EQ(3U, s[0]->InputCount());
1554 ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
1555 EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
1556 ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(2)->kind());
1557 EXPECT_EQ(0, s.ToInt64(s[0]->InputAt(2)));
1558 EXPECT_EQ(0U, s[0]->OutputCount());
1559 }
1560 }
1561
1562 INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest,
1563 InstructionSelectorMemoryAccessImmTest,
1564 ::testing::ValuesIn(kMemoryAccessesImm));
1565
1566 using InstructionSelectorMemoryAccessUnalignedImmTest =
1567 InstructionSelectorTestWithParam<MemoryAccessImm2>;
1568
TEST_P(InstructionSelectorMemoryAccessUnalignedImmTest,StoreZero)1569 TEST_P(InstructionSelectorMemoryAccessUnalignedImmTest, StoreZero) {
1570 const MemoryAccessImm2 memacc = GetParam();
1571 TRACED_FOREACH(int32_t, index, memacc.immediates) {
1572 StreamBuilder m(this, MachineType::Int32(), MachineType::Pointer());
1573 bool unaligned_store_supported =
1574 m.machine()->UnalignedStoreSupported(memacc.type.representation());
1575 m.UnalignedStore(memacc.type.representation(), m.Parameter(0),
1576 m.Int32Constant(index), m.Int32Constant(0));
1577 m.Return(m.Int32Constant(0));
1578 Stream s = m.Build();
1579 ASSERT_EQ(1U, s.size());
1580 EXPECT_EQ(unaligned_store_supported ? memacc.store_opcode_unaligned
1581 : memacc.store_opcode,
1582 s[0]->arch_opcode());
1583 EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
1584 ASSERT_EQ(3U, s[0]->InputCount());
1585 ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
1586 EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
1587 ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(2)->kind());
1588 EXPECT_EQ(0, s.ToInt64(s[0]->InputAt(2)));
1589 EXPECT_EQ(0U, s[0]->OutputCount());
1590 }
1591 }
1592
1593 INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest,
1594 InstructionSelectorMemoryAccessUnalignedImmTest,
1595 ::testing::ValuesIn(kMemoryAccessesImmUnaligned));
1596
1597 // ----------------------------------------------------------------------------
1598 // Load/store offsets more than 16 bits.
1599 // ----------------------------------------------------------------------------
1600
1601 using InstructionSelectorMemoryAccessImmMoreThan16bitTest =
1602 InstructionSelectorTestWithParam<MemoryAccessImm1>;
1603
TEST_P(InstructionSelectorMemoryAccessImmMoreThan16bitTest,LoadWithImmediateIndex)1604 TEST_P(InstructionSelectorMemoryAccessImmMoreThan16bitTest,
1605 LoadWithImmediateIndex) {
1606 const MemoryAccessImm1 memacc = GetParam();
1607 TRACED_FOREACH(int32_t, index, memacc.immediates) {
1608 StreamBuilder m(this, memacc.type, MachineType::Pointer());
1609 m.Return(m.Load(memacc.type, m.Parameter(0), m.Int32Constant(index)));
1610 Stream s = m.Build();
1611 ASSERT_EQ(1U, s.size());
1612 EXPECT_EQ(memacc.load_opcode, s[0]->arch_opcode());
1613 EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
1614 EXPECT_EQ(2U, s[0]->InputCount());
1615 EXPECT_EQ(1U, s[0]->OutputCount());
1616 }
1617 }
1618
TEST_P(InstructionSelectorMemoryAccessImmMoreThan16bitTest,StoreWithImmediateIndex)1619 TEST_P(InstructionSelectorMemoryAccessImmMoreThan16bitTest,
1620 StoreWithImmediateIndex) {
1621 const MemoryAccessImm1 memacc = GetParam();
1622 TRACED_FOREACH(int32_t, index, memacc.immediates) {
1623 StreamBuilder m(this, MachineType::Int32(), MachineType::Pointer(),
1624 memacc.type);
1625 m.Store(memacc.type.representation(), m.Parameter(0),
1626 m.Int32Constant(index), m.Parameter(1), kNoWriteBarrier);
1627 m.Return(m.Int32Constant(0));
1628 Stream s = m.Build();
1629 ASSERT_EQ(1U, s.size());
1630 EXPECT_EQ(memacc.store_opcode, s[0]->arch_opcode());
1631 EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
1632 EXPECT_EQ(3U, s[0]->InputCount());
1633 EXPECT_EQ(0U, s[0]->OutputCount());
1634 }
1635 }
1636
1637 INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest,
1638 InstructionSelectorMemoryAccessImmMoreThan16bitTest,
1639 ::testing::ValuesIn(kMemoryAccessImmMoreThan16bit));
1640
1641 // ----------------------------------------------------------------------------
1642 // kMips64Cmp with zero testing.
1643 // ----------------------------------------------------------------------------
1644
1645
TEST_F(InstructionSelectorTest,Word32EqualWithZero)1646 TEST_F(InstructionSelectorTest, Word32EqualWithZero) {
1647 {
1648 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
1649 m.Return(m.Word32Equal(m.Parameter(0), m.Int32Constant(0)));
1650 Stream s = m.Build();
1651 ASSERT_EQ(1U, s.size());
1652 EXPECT_EQ(kMips64Cmp, s[0]->arch_opcode());
1653 EXPECT_EQ(kMode_None, s[0]->addressing_mode());
1654 ASSERT_EQ(2U, s[0]->InputCount());
1655 EXPECT_EQ(1U, s[0]->OutputCount());
1656 EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1657 EXPECT_EQ(kEqual, s[0]->flags_condition());
1658 }
1659 {
1660 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
1661 m.Return(m.Word32Equal(m.Int32Constant(0), m.Parameter(0)));
1662 Stream s = m.Build();
1663 ASSERT_EQ(1U, s.size());
1664 EXPECT_EQ(kMips64Cmp, s[0]->arch_opcode());
1665 EXPECT_EQ(kMode_None, s[0]->addressing_mode());
1666 ASSERT_EQ(2U, s[0]->InputCount());
1667 EXPECT_EQ(1U, s[0]->OutputCount());
1668 EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1669 EXPECT_EQ(kEqual, s[0]->flags_condition());
1670 }
1671 }
1672
1673
TEST_F(InstructionSelectorTest,Word64EqualWithZero)1674 TEST_F(InstructionSelectorTest, Word64EqualWithZero) {
1675 {
1676 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64());
1677 m.Return(m.Word64Equal(m.Parameter(0), m.Int64Constant(0)));
1678 Stream s = m.Build();
1679 ASSERT_EQ(1U, s.size());
1680 EXPECT_EQ(kMips64Cmp, s[0]->arch_opcode());
1681 EXPECT_EQ(kMode_None, s[0]->addressing_mode());
1682 ASSERT_EQ(2U, s[0]->InputCount());
1683 EXPECT_EQ(1U, s[0]->OutputCount());
1684 EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1685 EXPECT_EQ(kEqual, s[0]->flags_condition());
1686 }
1687 {
1688 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64());
1689 m.Return(m.Word64Equal(m.Int32Constant(0), m.Parameter(0)));
1690 Stream s = m.Build();
1691 ASSERT_EQ(1U, s.size());
1692 EXPECT_EQ(kMips64Cmp, s[0]->arch_opcode());
1693 EXPECT_EQ(kMode_None, s[0]->addressing_mode());
1694 ASSERT_EQ(2U, s[0]->InputCount());
1695 EXPECT_EQ(1U, s[0]->OutputCount());
1696 EXPECT_EQ(kFlags_set, s[0]->flags_mode());
1697 EXPECT_EQ(kEqual, s[0]->flags_condition());
1698 }
1699 }
1700
1701
TEST_F(InstructionSelectorTest,Word32Clz)1702 TEST_F(InstructionSelectorTest, Word32Clz) {
1703 StreamBuilder m(this, MachineType::Uint32(), MachineType::Uint32());
1704 Node* const p0 = m.Parameter(0);
1705 Node* const n = m.Word32Clz(p0);
1706 m.Return(n);
1707 Stream s = m.Build();
1708 ASSERT_EQ(1U, s.size());
1709 EXPECT_EQ(kMips64Clz, s[0]->arch_opcode());
1710 ASSERT_EQ(1U, s[0]->InputCount());
1711 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1712 ASSERT_EQ(1U, s[0]->OutputCount());
1713 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
1714 }
1715
1716
TEST_F(InstructionSelectorTest,Word64Clz)1717 TEST_F(InstructionSelectorTest, Word64Clz) {
1718 StreamBuilder m(this, MachineType::Uint64(), MachineType::Uint64());
1719 Node* const p0 = m.Parameter(0);
1720 Node* const n = m.Word64Clz(p0);
1721 m.Return(n);
1722 Stream s = m.Build();
1723 ASSERT_EQ(1U, s.size());
1724 EXPECT_EQ(kMips64Dclz, s[0]->arch_opcode());
1725 ASSERT_EQ(1U, s[0]->InputCount());
1726 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1727 ASSERT_EQ(1U, s[0]->OutputCount());
1728 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
1729 }
1730
1731
TEST_F(InstructionSelectorTest,Float32Abs)1732 TEST_F(InstructionSelectorTest, Float32Abs) {
1733 StreamBuilder m(this, MachineType::Float32(), MachineType::Float32());
1734 Node* const p0 = m.Parameter(0);
1735 Node* const n = m.Float32Abs(p0);
1736 m.Return(n);
1737 Stream s = m.Build();
1738 ASSERT_EQ(1U, s.size());
1739 EXPECT_EQ(kMips64AbsS, s[0]->arch_opcode());
1740 ASSERT_EQ(1U, s[0]->InputCount());
1741 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1742 ASSERT_EQ(1U, s[0]->OutputCount());
1743 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
1744 }
1745
1746
TEST_F(InstructionSelectorTest,Float64Abs)1747 TEST_F(InstructionSelectorTest, Float64Abs) {
1748 StreamBuilder m(this, MachineType::Float64(), MachineType::Float64());
1749 Node* const p0 = m.Parameter(0);
1750 Node* const n = m.Float64Abs(p0);
1751 m.Return(n);
1752 Stream s = m.Build();
1753 ASSERT_EQ(1U, s.size());
1754 EXPECT_EQ(kMips64AbsD, s[0]->arch_opcode());
1755 ASSERT_EQ(1U, s[0]->InputCount());
1756 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1757 ASSERT_EQ(1U, s[0]->OutputCount());
1758 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
1759 }
1760
1761
TEST_F(InstructionSelectorTest,Float64Max)1762 TEST_F(InstructionSelectorTest, Float64Max) {
1763 StreamBuilder m(this, MachineType::Float64(), MachineType::Float64(),
1764 MachineType::Float64());
1765 Node* const p0 = m.Parameter(0);
1766 Node* const p1 = m.Parameter(1);
1767 Node* const n = m.Float64Max(p0, p1);
1768 m.Return(n);
1769 Stream s = m.Build();
1770 ASSERT_EQ(1U, s.size());
1771 EXPECT_EQ(kMips64Float64Max, s[0]->arch_opcode());
1772 ASSERT_EQ(2U, s[0]->InputCount());
1773 ASSERT_EQ(1U, s[0]->OutputCount());
1774 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
1775 }
1776
1777
TEST_F(InstructionSelectorTest,Float64Min)1778 TEST_F(InstructionSelectorTest, Float64Min) {
1779 StreamBuilder m(this, MachineType::Float64(), MachineType::Float64(),
1780 MachineType::Float64());
1781 Node* const p0 = m.Parameter(0);
1782 Node* const p1 = m.Parameter(1);
1783 Node* const n = m.Float64Min(p0, p1);
1784 m.Return(n);
1785 Stream s = m.Build();
1786 ASSERT_EQ(1U, s.size());
1787 EXPECT_EQ(kMips64Float64Min, s[0]->arch_opcode());
1788 ASSERT_EQ(2U, s[0]->InputCount());
1789 ASSERT_EQ(1U, s[0]->OutputCount());
1790 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
1791 }
1792
TEST_F(InstructionSelectorTest,LoadAndShiftRight)1793 TEST_F(InstructionSelectorTest, LoadAndShiftRight) {
1794 {
1795 int32_t immediates[] = {-256, -255, -3, -2, -1, 0, 1,
1796 2, 3, 255, 256, 260, 4096, 4100,
1797 8192, 8196, 3276, 3280, 16376, 16380};
1798 TRACED_FOREACH(int32_t, index, immediates) {
1799 StreamBuilder m(this, MachineType::Uint64(), MachineType::Pointer());
1800 Node* const load =
1801 m.Load(MachineType::Uint64(), m.Parameter(0), m.Int32Constant(index));
1802 Node* const sar = m.Word64Sar(load, m.Int32Constant(32));
1803 // Make sure we don't fold the shift into the following add:
1804 m.Return(m.Int64Add(sar, m.Parameter(0)));
1805 Stream s = m.Build();
1806 ASSERT_EQ(2U, s.size());
1807 EXPECT_EQ(kMips64Lw, s[0]->arch_opcode());
1808 EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
1809 EXPECT_EQ(2U, s[0]->InputCount());
1810 EXPECT_EQ(s.ToVreg(m.Parameter(0)), s.ToVreg(s[0]->InputAt(0)));
1811 ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
1812 #if defined(V8_TARGET_LITTLE_ENDIAN)
1813 EXPECT_EQ(index + 4, s.ToInt32(s[0]->InputAt(1)));
1814 #elif defined(V8_TARGET_BIG_ENDIAN)
1815 EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
1816 #endif
1817
1818 ASSERT_EQ(1U, s[0]->OutputCount());
1819 }
1820 }
1821 }
1822
TEST_F(InstructionSelectorTest,Word32ReverseBytes)1823 TEST_F(InstructionSelectorTest, Word32ReverseBytes) {
1824 {
1825 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
1826 m.Return(m.Word32ReverseBytes(m.Parameter(0)));
1827 Stream s = m.Build();
1828 ASSERT_EQ(1U, s.size());
1829 EXPECT_EQ(kMips64ByteSwap32, s[0]->arch_opcode());
1830 EXPECT_EQ(1U, s[0]->InputCount());
1831 EXPECT_EQ(1U, s[0]->OutputCount());
1832 }
1833 }
1834
TEST_F(InstructionSelectorTest,Word64ReverseBytes)1835 TEST_F(InstructionSelectorTest, Word64ReverseBytes) {
1836 {
1837 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64());
1838 m.Return(m.Word64ReverseBytes(m.Parameter(0)));
1839 Stream s = m.Build();
1840 ASSERT_EQ(1U, s.size());
1841 EXPECT_EQ(kMips64ByteSwap64, s[0]->arch_opcode());
1842 EXPECT_EQ(1U, s[0]->InputCount());
1843 EXPECT_EQ(1U, s[0]->OutputCount());
1844 }
1845 }
1846
1847 } // namespace compiler
1848 } // namespace internal
1849 } // namespace v8
1850