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 <limits>
6
7 #include "src/common/globals.h"
8 #include "src/compiler/machine-operator.h"
9 #include "src/compiler/node-matchers.h"
10 #include "src/objects/objects-inl.h"
11 #include "test/unittests/compiler/backend/instruction-selector-unittest.h"
12
13 #if V8_ENABLE_WEBASSEMBLY
14 #include "src/wasm/simd-shuffle.h"
15 #endif // V8_ENABLE_WEBASSEMBLY
16
17 namespace v8 {
18 namespace internal {
19 namespace compiler {
20
21 // -----------------------------------------------------------------------------
22 // Conversions.
23
24
TEST_F(InstructionSelectorTest,ChangeFloat32ToFloat64WithParameter)25 TEST_F(InstructionSelectorTest, ChangeFloat32ToFloat64WithParameter) {
26 StreamBuilder m(this, MachineType::Float32(), MachineType::Float64());
27 m.Return(m.ChangeFloat32ToFloat64(m.Parameter(0)));
28 Stream s = m.Build();
29 ASSERT_EQ(1U, s.size());
30 EXPECT_EQ(kSSEFloat32ToFloat64, s[0]->arch_opcode());
31 EXPECT_EQ(1U, s[0]->InputCount());
32 EXPECT_EQ(1U, s[0]->OutputCount());
33 }
34
35
TEST_F(InstructionSelectorTest,ChangeInt32ToInt64WithParameter)36 TEST_F(InstructionSelectorTest, ChangeInt32ToInt64WithParameter) {
37 StreamBuilder m(this, MachineType::Int64(), MachineType::Int32());
38 m.Return(m.ChangeInt32ToInt64(m.Parameter(0)));
39 Stream s = m.Build();
40 ASSERT_EQ(1U, s.size());
41 EXPECT_EQ(kX64Movsxlq, s[0]->arch_opcode());
42 }
43
TEST_F(InstructionSelectorTest,ChangeUint32ToFloat64WithParameter)44 TEST_F(InstructionSelectorTest, ChangeUint32ToFloat64WithParameter) {
45 StreamBuilder m(this, MachineType::Float64(), MachineType::Uint32());
46 m.Return(m.ChangeUint32ToFloat64(m.Parameter(0)));
47 Stream s = m.Build();
48 ASSERT_EQ(1U, s.size());
49 EXPECT_EQ(kSSEUint32ToFloat64, s[0]->arch_opcode());
50 }
51
52
TEST_F(InstructionSelectorTest,ChangeUint32ToUint64WithParameter)53 TEST_F(InstructionSelectorTest, ChangeUint32ToUint64WithParameter) {
54 StreamBuilder m(this, MachineType::Uint64(), MachineType::Uint32());
55 m.Return(m.ChangeUint32ToUint64(m.Parameter(0)));
56 Stream s = m.Build();
57 ASSERT_EQ(1U, s.size());
58 EXPECT_EQ(kX64Movl, s[0]->arch_opcode());
59 }
60
61
TEST_F(InstructionSelectorTest,TruncateFloat64ToFloat32WithParameter)62 TEST_F(InstructionSelectorTest, TruncateFloat64ToFloat32WithParameter) {
63 StreamBuilder m(this, MachineType::Float64(), MachineType::Float32());
64 m.Return(m.TruncateFloat64ToFloat32(m.Parameter(0)));
65 Stream s = m.Build();
66 ASSERT_EQ(1U, s.size());
67 EXPECT_EQ(kSSEFloat64ToFloat32, s[0]->arch_opcode());
68 EXPECT_EQ(1U, s[0]->InputCount());
69 EXPECT_EQ(1U, s[0]->OutputCount());
70 }
71
72
TEST_F(InstructionSelectorTest,TruncateInt64ToInt32WithParameter)73 TEST_F(InstructionSelectorTest, TruncateInt64ToInt32WithParameter) {
74 StreamBuilder m(this, MachineType::Int32(), MachineType::Int64());
75 m.Return(m.TruncateInt64ToInt32(m.Parameter(0)));
76 Stream s = m.Build();
77 ASSERT_EQ(1U, s.size());
78 EXPECT_EQ(kX64Movl, s[0]->arch_opcode());
79 }
80
TEST_F(InstructionSelectorTest,SelectWord32)81 TEST_F(InstructionSelectorTest, SelectWord32) {
82 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
83 MachineType::Int32());
84 Node* cond = m.Int32Constant(1);
85 m.Return(m.Word32Select(cond, m.Parameter(0), m.Parameter(1)));
86 Stream s = m.Build();
87 EXPECT_EQ(kX64Cmp32, s[0]->arch_opcode());
88 EXPECT_EQ(4U, s[0]->InputCount());
89 EXPECT_EQ(1U, s[0]->OutputCount());
90 EXPECT_EQ(kFlags_select, s[0]->flags_mode());
91 EXPECT_EQ(kNotEqual, s[0]->flags_condition());
92 EXPECT_TRUE(s.IsSameAsInput(s[0]->Output(), 2));
93 }
94
TEST_F(InstructionSelectorTest,SelectWord64)95 TEST_F(InstructionSelectorTest, SelectWord64) {
96 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64(),
97 MachineType::Int64());
98 Node* cond = m.Int32Constant(1);
99 m.Return(m.Word64Select(cond, m.Parameter(0), m.Parameter(1)));
100 Stream s = m.Build();
101 EXPECT_EQ(kX64Cmp32, s[0]->arch_opcode());
102 EXPECT_EQ(4U, s[0]->InputCount());
103 EXPECT_EQ(1U, s[0]->OutputCount());
104 EXPECT_EQ(kFlags_select, s[0]->flags_mode());
105 EXPECT_EQ(kNotEqual, s[0]->flags_condition());
106 EXPECT_TRUE(s.IsSameAsInput(s[0]->Output(), 2));
107 }
108
109 namespace {
110 struct LoadWithToInt64Extension {
111 MachineType type;
112 ArchOpcode expected_opcode;
113 };
114
operator <<(std::ostream & os,const LoadWithToInt64Extension & i32toi64)115 std::ostream& operator<<(std::ostream& os,
116 const LoadWithToInt64Extension& i32toi64) {
117 return os << i32toi64.type;
118 }
119
120 static const LoadWithToInt64Extension kLoadWithToInt64Extensions[] = {
121 {MachineType::Int8(), kX64Movsxbq},
122 {MachineType::Uint8(), kX64Movzxbq},
123 {MachineType::Int16(), kX64Movsxwq},
124 {MachineType::Uint16(), kX64Movzxwq},
125 {MachineType::Int32(), kX64Movsxlq}};
126
127 // The parameterized test that use the following type are intentionally part
128 // of the anonymous namespace. The issue here is that the type parameter is
129 // using a type that is in the anonymous namespace, but the class generated by
130 // TEST_P is not. This will cause GCC to generate a -Wsubobject-linkage warning.
131 //
132 // In this case there will only be single translation unit and the warning
133 // about subobject-linkage can be avoided by placing the class generated
134 // by TEST_P in the anoynmous namespace as well.
135 using InstructionSelectorChangeInt32ToInt64Test =
136 InstructionSelectorTestWithParam<LoadWithToInt64Extension>;
137
TEST_P(InstructionSelectorChangeInt32ToInt64Test,ChangeInt32ToInt64WithLoad)138 TEST_P(InstructionSelectorChangeInt32ToInt64Test, ChangeInt32ToInt64WithLoad) {
139 const LoadWithToInt64Extension extension = GetParam();
140 StreamBuilder m(this, MachineType::Int64(), MachineType::Pointer());
141 m.Return(m.ChangeInt32ToInt64(m.Load(extension.type, m.Parameter(0))));
142 Stream s = m.Build();
143 ASSERT_EQ(1U, s.size());
144 EXPECT_EQ(extension.expected_opcode, s[0]->arch_opcode());
145 }
146
147 } // namespace
148
149 INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest,
150 InstructionSelectorChangeInt32ToInt64Test,
151 ::testing::ValuesIn(kLoadWithToInt64Extensions));
152
153 // -----------------------------------------------------------------------------
154 // Loads and stores
155
156
157 namespace {
158
159 struct MemoryAccess {
160 MachineType type;
161 ArchOpcode load_opcode;
162 ArchOpcode store_opcode;
163 };
164
165
operator <<(std::ostream & os,const MemoryAccess & memacc)166 std::ostream& operator<<(std::ostream& os, const MemoryAccess& memacc) {
167 return os << memacc.type;
168 }
169
170
171 static const MemoryAccess kMemoryAccesses[] = {
172 {MachineType::Int8(), kX64Movsxbl, kX64Movb},
173 {MachineType::Uint8(), kX64Movzxbl, kX64Movb},
174 {MachineType::Int16(), kX64Movsxwl, kX64Movw},
175 {MachineType::Uint16(), kX64Movzxwl, kX64Movw},
176 {MachineType::Int32(), kX64Movl, kX64Movl},
177 {MachineType::Uint32(), kX64Movl, kX64Movl},
178 {MachineType::Int64(), kX64Movq, kX64Movq},
179 {MachineType::Uint64(), kX64Movq, kX64Movq},
180 {MachineType::Float32(), kX64Movss, kX64Movss},
181 {MachineType::Float64(), kX64Movsd, kX64Movsd}};
182
183 // The parameterized test that use the following type are intentionally part
184 // of the anonymous namespace. The issue here is that the type parameter is
185 // using a type that is in the anonymous namespace, but the class generated by
186 // TEST_P is not. This will cause GCC to generate a -Wsubobject-linkage warning.
187 //
188 // In this case there will only be single translation unit and the warning
189 // about subobject-linkage can be avoided by placing the class generated
190 // by TEST_P in the anoynmous namespace as well.
191 using InstructionSelectorMemoryAccessTest =
192 InstructionSelectorTestWithParam<MemoryAccess>;
193
TEST_P(InstructionSelectorMemoryAccessTest,LoadWithParameters)194 TEST_P(InstructionSelectorMemoryAccessTest, LoadWithParameters) {
195 const MemoryAccess memacc = GetParam();
196 StreamBuilder m(this, memacc.type, MachineType::Pointer(),
197 MachineType::Int32());
198 m.Return(m.Load(memacc.type, m.Parameter(0), m.Parameter(1)));
199 Stream s = m.Build();
200 ASSERT_EQ(1U, s.size());
201 EXPECT_EQ(memacc.load_opcode, s[0]->arch_opcode());
202 EXPECT_EQ(2U, s[0]->InputCount());
203 EXPECT_EQ(1U, s[0]->OutputCount());
204 }
205
206
TEST_P(InstructionSelectorMemoryAccessTest,StoreWithParameters)207 TEST_P(InstructionSelectorMemoryAccessTest, StoreWithParameters) {
208 const MemoryAccess memacc = GetParam();
209 StreamBuilder m(this, MachineType::Int32(), MachineType::Pointer(),
210 MachineType::Int32(), memacc.type);
211 m.Store(memacc.type.representation(), m.Parameter(0), m.Parameter(1),
212 m.Parameter(2), kNoWriteBarrier);
213 m.Return(m.Int32Constant(0));
214 Stream s = m.Build();
215 ASSERT_EQ(1U, s.size());
216 EXPECT_EQ(memacc.store_opcode, s[0]->arch_opcode());
217 EXPECT_EQ(3U, s[0]->InputCount());
218 EXPECT_EQ(0U, s[0]->OutputCount());
219 }
220
221 } // namespace
222
223 INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest,
224 InstructionSelectorMemoryAccessTest,
225 ::testing::ValuesIn(kMemoryAccesses));
226
227 // -----------------------------------------------------------------------------
228 // ChangeUint32ToUint64.
229
230
231 namespace {
232
233 using Constructor = Node* (RawMachineAssembler::*)(Node*, Node*);
234
235 struct BinaryOperation {
236 Constructor constructor;
237 const char* constructor_name;
238 };
239
240
operator <<(std::ostream & os,const BinaryOperation & bop)241 std::ostream& operator<<(std::ostream& os, const BinaryOperation& bop) {
242 return os << bop.constructor_name;
243 }
244
245
246 const BinaryOperation kWord32BinaryOperations[] = {
247 {&RawMachineAssembler::Word32And, "Word32And"},
248 {&RawMachineAssembler::Word32Or, "Word32Or"},
249 {&RawMachineAssembler::Word32Xor, "Word32Xor"},
250 {&RawMachineAssembler::Word32Shl, "Word32Shl"},
251 {&RawMachineAssembler::Word32Shr, "Word32Shr"},
252 {&RawMachineAssembler::Word32Sar, "Word32Sar"},
253 {&RawMachineAssembler::Word32Ror, "Word32Ror"},
254 {&RawMachineAssembler::Word32Equal, "Word32Equal"},
255 {&RawMachineAssembler::Int32Add, "Int32Add"},
256 {&RawMachineAssembler::Int32Sub, "Int32Sub"},
257 {&RawMachineAssembler::Int32Mul, "Int32Mul"},
258 {&RawMachineAssembler::Int32MulHigh, "Int32MulHigh"},
259 {&RawMachineAssembler::Int32Div, "Int32Div"},
260 {&RawMachineAssembler::Int32LessThan, "Int32LessThan"},
261 {&RawMachineAssembler::Int32LessThanOrEqual, "Int32LessThanOrEqual"},
262 {&RawMachineAssembler::Int32Mod, "Int32Mod"},
263 {&RawMachineAssembler::Uint32Div, "Uint32Div"},
264 {&RawMachineAssembler::Uint32LessThan, "Uint32LessThan"},
265 {&RawMachineAssembler::Uint32LessThanOrEqual, "Uint32LessThanOrEqual"},
266 {&RawMachineAssembler::Uint32Mod, "Uint32Mod"}};
267
268 // The parameterized test that use the following type are intentionally part
269 // of the anonymous namespace. The issue here is that the type parameter is
270 // using a type that is in the anonymous namespace, but the class generated by
271 // TEST_P is not. This will cause GCC to generate a -Wsubobject-linkage warning.
272 //
273 // In this case there will only be single translation unit and the warning
274 // about subobject-linkage can be avoided by placing the class generated
275 // by TEST_P in the anoynmous namespace as well.
276 using InstructionSelectorChangeUint32ToUint64Test =
277 InstructionSelectorTestWithParam<BinaryOperation>;
278
TEST_P(InstructionSelectorChangeUint32ToUint64Test,ChangeUint32ToUint64)279 TEST_P(InstructionSelectorChangeUint32ToUint64Test, ChangeUint32ToUint64) {
280 const BinaryOperation& bop = GetParam();
281 StreamBuilder m(this, MachineType::Uint64(), MachineType::Int32(),
282 MachineType::Int32());
283 Node* const p0 = m.Parameter(0);
284 Node* const p1 = m.Parameter(1);
285 m.Return(m.ChangeUint32ToUint64((m.*bop.constructor)(p0, p1)));
286 Stream s = m.Build();
287 ASSERT_EQ(1U, s.size());
288 }
289
290 } // namespace
291
292 INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest,
293 InstructionSelectorChangeUint32ToUint64Test,
294 ::testing::ValuesIn(kWord32BinaryOperations));
295
296 // -----------------------------------------------------------------------------
297 // CanElideChangeUint32ToUint64
298
299 namespace {
300
301 template <typename T>
302 struct MachInst {
303 T constructor;
304 const char* constructor_name;
305 ArchOpcode arch_opcode;
306 MachineType machine_type;
307 };
308
309 using MachInst2 = MachInst<Node* (RawMachineAssembler::*)(Node*, Node*)>;
310
311 // X64 instructions that clear the top 32 bits of the destination.
312 const MachInst2 kCanElideChangeUint32ToUint64[] = {
313 {&RawMachineAssembler::Word32And, "Word32And", kX64And32,
314 MachineType::Uint32()},
315 {&RawMachineAssembler::Word32Or, "Word32Or", kX64Or32,
316 MachineType::Uint32()},
317 {&RawMachineAssembler::Word32Xor, "Word32Xor", kX64Xor32,
318 MachineType::Uint32()},
319 {&RawMachineAssembler::Word32Shl, "Word32Shl", kX64Shl32,
320 MachineType::Uint32()},
321 {&RawMachineAssembler::Word32Shr, "Word32Shr", kX64Shr32,
322 MachineType::Uint32()},
323 {&RawMachineAssembler::Word32Sar, "Word32Sar", kX64Sar32,
324 MachineType::Uint32()},
325 {&RawMachineAssembler::Word32Ror, "Word32Ror", kX64Ror32,
326 MachineType::Uint32()},
327 {&RawMachineAssembler::Word32Equal, "Word32Equal", kX64Cmp32,
328 MachineType::Uint32()},
329 {&RawMachineAssembler::Int32Add, "Int32Add", kX64Lea32,
330 MachineType::Int32()},
331 {&RawMachineAssembler::Int32Sub, "Int32Sub", kX64Sub32,
332 MachineType::Int32()},
333 {&RawMachineAssembler::Int32Mul, "Int32Mul", kX64Imul32,
334 MachineType::Int32()},
335 {&RawMachineAssembler::Int32MulHigh, "Int32MulHigh", kX64ImulHigh32,
336 MachineType::Int32()},
337 {&RawMachineAssembler::Int32Div, "Int32Div", kX64Idiv32,
338 MachineType::Int32()},
339 {&RawMachineAssembler::Int32LessThan, "Int32LessThan", kX64Cmp32,
340 MachineType::Int32()},
341 {&RawMachineAssembler::Int32LessThanOrEqual, "Int32LessThanOrEqual",
342 kX64Cmp32, MachineType::Int32()},
343 {&RawMachineAssembler::Int32Mod, "Int32Mod", kX64Idiv32,
344 MachineType::Int32()},
345 {&RawMachineAssembler::Uint32Div, "Uint32Div", kX64Udiv32,
346 MachineType::Uint32()},
347 {&RawMachineAssembler::Uint32LessThan, "Uint32LessThan", kX64Cmp32,
348 MachineType::Uint32()},
349 {&RawMachineAssembler::Uint32LessThanOrEqual, "Uint32LessThanOrEqual",
350 kX64Cmp32, MachineType::Uint32()},
351 {&RawMachineAssembler::Uint32Mod, "Uint32Mod", kX64Udiv32,
352 MachineType::Uint32()},
353 };
354
355 // The parameterized test that use the following type are intentionally part
356 // of the anonymous namespace. The issue here is that the type parameter is
357 // using a type that is in the anonymous namespace, but the class generated by
358 // TEST_P is not. This will cause GCC to generate a -Wsubobject-linkage warning.
359 //
360 // In this case there will only be single translation unit and the warning
361 // about subobject-linkage can be avoided by placing the class generated
362 // by TEST_P in the anoynmous namespace as well.
363 using InstructionSelectorElidedChangeUint32ToUint64Test =
364 InstructionSelectorTestWithParam<MachInst2>;
365
TEST_P(InstructionSelectorElidedChangeUint32ToUint64Test,Parameter)366 TEST_P(InstructionSelectorElidedChangeUint32ToUint64Test, Parameter) {
367 const MachInst2 binop = GetParam();
368 StreamBuilder m(this, MachineType::Uint64(), binop.machine_type,
369 binop.machine_type);
370 m.Return(m.ChangeUint32ToUint64(
371 (m.*binop.constructor)(m.Parameter(0), m.Parameter(1))));
372 Stream s = m.Build();
373 // Make sure the `ChangeUint32ToUint64` node turned into a no-op.
374 ASSERT_EQ(1U, s.size());
375 EXPECT_EQ(binop.arch_opcode, s[0]->arch_opcode());
376 EXPECT_EQ(2U, s[0]->InputCount());
377 EXPECT_EQ(1U, s[0]->OutputCount());
378 }
379
380 } // namespace
381
382 INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest,
383 InstructionSelectorElidedChangeUint32ToUint64Test,
384 ::testing::ValuesIn(kCanElideChangeUint32ToUint64));
385
386 // ChangeUint32ToUint64AfterLoad
TEST_F(InstructionSelectorTest,ChangeUint32ToUint64AfterLoad)387 TEST_F(InstructionSelectorTest, ChangeUint32ToUint64AfterLoad) {
388 // For each case, make sure the `ChangeUint32ToUint64` node turned into a
389 // no-op.
390
391 // movzxbl
392 {
393 StreamBuilder m(this, MachineType::Uint64(), MachineType::Pointer(),
394 MachineType::Int32());
395 m.Return(m.ChangeUint32ToUint64(
396 m.Load(MachineType::Uint8(), m.Parameter(0), m.Parameter(1))));
397 Stream s = m.Build();
398 ASSERT_EQ(1U, s.size());
399 EXPECT_EQ(kX64Movzxbl, s[0]->arch_opcode());
400 EXPECT_EQ(kMode_MR1, s[0]->addressing_mode());
401 EXPECT_EQ(2U, s[0]->InputCount());
402 EXPECT_EQ(1U, s[0]->OutputCount());
403 }
404 // movsxbl
405 {
406 StreamBuilder m(this, MachineType::Uint64(), MachineType::Pointer(),
407 MachineType::Int32());
408 m.Return(m.ChangeUint32ToUint64(
409 m.Load(MachineType::Int8(), m.Parameter(0), m.Parameter(1))));
410 Stream s = m.Build();
411 ASSERT_EQ(1U, s.size());
412 EXPECT_EQ(kX64Movsxbl, s[0]->arch_opcode());
413 EXPECT_EQ(kMode_MR1, s[0]->addressing_mode());
414 EXPECT_EQ(2U, s[0]->InputCount());
415 EXPECT_EQ(1U, s[0]->OutputCount());
416 }
417 // movzxwl
418 {
419 StreamBuilder m(this, MachineType::Uint64(), MachineType::Pointer(),
420 MachineType::Int32());
421 m.Return(m.ChangeUint32ToUint64(
422 m.Load(MachineType::Uint16(), m.Parameter(0), m.Parameter(1))));
423 Stream s = m.Build();
424 ASSERT_EQ(1U, s.size());
425 EXPECT_EQ(kX64Movzxwl, s[0]->arch_opcode());
426 EXPECT_EQ(kMode_MR1, s[0]->addressing_mode());
427 EXPECT_EQ(2U, s[0]->InputCount());
428 EXPECT_EQ(1U, s[0]->OutputCount());
429 }
430 // movsxwl
431 {
432 StreamBuilder m(this, MachineType::Uint64(), MachineType::Pointer(),
433 MachineType::Int32());
434 m.Return(m.ChangeUint32ToUint64(
435 m.Load(MachineType::Int16(), m.Parameter(0), m.Parameter(1))));
436 Stream s = m.Build();
437 ASSERT_EQ(1U, s.size());
438 EXPECT_EQ(kX64Movsxwl, s[0]->arch_opcode());
439 EXPECT_EQ(kMode_MR1, s[0]->addressing_mode());
440 EXPECT_EQ(2U, s[0]->InputCount());
441 EXPECT_EQ(1U, s[0]->OutputCount());
442 }
443 }
444
445 // -----------------------------------------------------------------------------
446 // TruncateInt64ToInt32.
447
448
TEST_F(InstructionSelectorTest,TruncateInt64ToInt32WithWord64Sar)449 TEST_F(InstructionSelectorTest, TruncateInt64ToInt32WithWord64Sar) {
450 StreamBuilder m(this, MachineType::Int32(), MachineType::Int64());
451 Node* const p = m.Parameter(0);
452 Node* const t = m.TruncateInt64ToInt32(m.Word64Sar(p, m.Int64Constant(32)));
453 m.Return(t);
454 Stream s = m.Build();
455 ASSERT_EQ(1U, s.size());
456 EXPECT_EQ(kX64Shr, s[0]->arch_opcode());
457 ASSERT_EQ(2U, s[0]->InputCount());
458 EXPECT_EQ(s.ToVreg(p), s.ToVreg(s[0]->InputAt(0)));
459 EXPECT_EQ(32, s.ToInt32(s[0]->InputAt(1)));
460 ASSERT_EQ(1U, s[0]->OutputCount());
461 EXPECT_TRUE(s.IsSameAsFirst(s[0]->OutputAt(0)));
462 EXPECT_EQ(s.ToVreg(t), s.ToVreg(s[0]->OutputAt(0)));
463 }
464
465
TEST_F(InstructionSelectorTest,TruncateInt64ToInt32WithWord64Shr)466 TEST_F(InstructionSelectorTest, TruncateInt64ToInt32WithWord64Shr) {
467 StreamBuilder m(this, MachineType::Int32(), MachineType::Int64());
468 Node* const p = m.Parameter(0);
469 Node* const t = m.TruncateInt64ToInt32(m.Word64Shr(p, m.Int64Constant(32)));
470 m.Return(t);
471 Stream s = m.Build();
472 ASSERT_EQ(1U, s.size());
473 EXPECT_EQ(kX64Shr, s[0]->arch_opcode());
474 ASSERT_EQ(2U, s[0]->InputCount());
475 EXPECT_EQ(s.ToVreg(p), s.ToVreg(s[0]->InputAt(0)));
476 EXPECT_EQ(32, s.ToInt32(s[0]->InputAt(1)));
477 ASSERT_EQ(1U, s[0]->OutputCount());
478 EXPECT_TRUE(s.IsSameAsFirst(s[0]->OutputAt(0)));
479 EXPECT_EQ(s.ToVreg(t), s.ToVreg(s[0]->OutputAt(0)));
480 }
481
482
483 // -----------------------------------------------------------------------------
484 // Addition.
485
486
TEST_F(InstructionSelectorTest,Int32AddWithInt32ParametersLea)487 TEST_F(InstructionSelectorTest, Int32AddWithInt32ParametersLea) {
488 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
489 MachineType::Int32());
490 Node* const p0 = m.Parameter(0);
491 Node* const p1 = m.Parameter(1);
492 Node* const a0 = m.Int32Add(p0, p1);
493 // Additional uses of input to add chooses lea
494 Node* const a1 = m.Int32Div(p0, p1);
495 m.Return(m.Int32Div(a0, a1));
496 Stream s = m.Build();
497 ASSERT_EQ(3U, s.size());
498 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
499 ASSERT_EQ(2U, s[0]->InputCount());
500 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
501 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
502 }
503
504
TEST_F(InstructionSelectorTest,Int32AddConstantAsLeaSingle)505 TEST_F(InstructionSelectorTest, Int32AddConstantAsLeaSingle) {
506 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
507 Node* const p0 = m.Parameter(0);
508 Node* const c0 = m.Int32Constant(15);
509 // If one of the add's operands is only used once, use an "leal", even though
510 // an "addl" could be used. The "leal" has proven faster--out best guess is
511 // that it gives the register allocation more freedom and it doesn't set
512 // flags, reducing pressure in the CPU's pipeline. If we're lucky with
513 // register allocation, then code generation will select an "addl" later for
514 // the cases that have been measured to be faster.
515 Node* const v0 = m.Int32Add(p0, c0);
516 m.Return(v0);
517 Stream s = m.Build();
518 ASSERT_EQ(1U, s.size());
519 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
520 EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
521 ASSERT_EQ(2U, s[0]->InputCount());
522 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
523 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
524 }
525
526
TEST_F(InstructionSelectorTest,Int32AddConstantAsAdd)527 TEST_F(InstructionSelectorTest, Int32AddConstantAsAdd) {
528 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
529 Node* const p0 = m.Parameter(0);
530 Node* const c0 = m.Int32Constant(1);
531 // If there is only a single use of an add's input and the immediate constant
532 // for the add is 1, don't use an inc. It is much slower on modern Intel
533 // architectures.
534 m.Return(m.Int32Add(p0, c0));
535 Stream s = m.Build();
536 ASSERT_EQ(1U, s.size());
537 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
538 EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
539 ASSERT_EQ(2U, s[0]->InputCount());
540 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
541 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
542 }
543
544
TEST_F(InstructionSelectorTest,Int32AddConstantAsLeaDouble)545 TEST_F(InstructionSelectorTest, Int32AddConstantAsLeaDouble) {
546 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
547 Node* const p0 = m.Parameter(0);
548 Node* const c0 = m.Int32Constant(15);
549 // A second use of an add's input uses lea
550 Node* const a0 = m.Int32Add(p0, c0);
551 m.Return(m.Int32Div(a0, p0));
552 Stream s = m.Build();
553 ASSERT_EQ(2U, s.size());
554 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
555 EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
556 ASSERT_EQ(2U, s[0]->InputCount());
557 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
558 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
559 }
560
561
TEST_F(InstructionSelectorTest,Int32AddCommutedConstantAsLeaSingle)562 TEST_F(InstructionSelectorTest, Int32AddCommutedConstantAsLeaSingle) {
563 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
564 Node* const p0 = m.Parameter(0);
565 Node* const c0 = m.Int32Constant(15);
566 // If one of the add's operands is only used once, use an "leal", even though
567 // an "addl" could be used. The "leal" has proven faster--out best guess is
568 // that it gives the register allocation more freedom and it doesn't set
569 // flags, reducing pressure in the CPU's pipeline. If we're lucky with
570 // register allocation, then code generation will select an "addl" later for
571 // the cases that have been measured to be faster.
572 m.Return(m.Int32Add(c0, p0));
573 Stream s = m.Build();
574 ASSERT_EQ(1U, s.size());
575 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
576 EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
577 ASSERT_EQ(2U, s[0]->InputCount());
578 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
579 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
580 }
581
582
TEST_F(InstructionSelectorTest,Int32AddCommutedConstantAsLeaDouble)583 TEST_F(InstructionSelectorTest, Int32AddCommutedConstantAsLeaDouble) {
584 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
585 Node* const p0 = m.Parameter(0);
586 Node* const c0 = m.Int32Constant(15);
587 // A second use of an add's input uses lea
588 Node* const a0 = m.Int32Add(c0, p0);
589 USE(a0);
590 m.Return(m.Int32Div(a0, p0));
591 Stream s = m.Build();
592 ASSERT_EQ(2U, s.size());
593 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
594 EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
595 ASSERT_EQ(2U, s[0]->InputCount());
596 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
597 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
598 }
599
600
TEST_F(InstructionSelectorTest,Int32AddSimpleAsAdd)601 TEST_F(InstructionSelectorTest, Int32AddSimpleAsAdd) {
602 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
603 MachineType::Int32());
604 Node* const p0 = m.Parameter(0);
605 Node* const p1 = m.Parameter(1);
606 // If one of the add's operands is only used once, use an "leal", even though
607 // an "addl" could be used. The "leal" has proven faster--out best guess is
608 // that it gives the register allocation more freedom and it doesn't set
609 // flags, reducing pressure in the CPU's pipeline. If we're lucky with
610 // register allocation, then code generation will select an "addl" later for
611 // the cases that have been measured to be faster.
612 m.Return(m.Int32Add(p0, p1));
613 Stream s = m.Build();
614 ASSERT_EQ(1U, s.size());
615 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
616 EXPECT_EQ(kMode_MR1, s[0]->addressing_mode());
617 ASSERT_EQ(2U, s[0]->InputCount());
618 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
619 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
620 }
621
622
TEST_F(InstructionSelectorTest,Int32AddSimpleAsLea)623 TEST_F(InstructionSelectorTest, Int32AddSimpleAsLea) {
624 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
625 MachineType::Int32());
626 Node* const p0 = m.Parameter(0);
627 Node* const p1 = m.Parameter(1);
628 // If all of of the add's operands are used multiple times, use an "leal".
629 Node* const v1 = m.Int32Add(p0, p1);
630 m.Return(m.Int32Add(m.Int32Add(v1, p1), p0));
631 Stream s = m.Build();
632 ASSERT_EQ(3U, s.size());
633 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
634 EXPECT_EQ(kMode_MR1, s[0]->addressing_mode());
635 ASSERT_EQ(2U, s[0]->InputCount());
636 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
637 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
638 }
639
640
TEST_F(InstructionSelectorTest,Int32AddScaled2Mul)641 TEST_F(InstructionSelectorTest, Int32AddScaled2Mul) {
642 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
643 MachineType::Int32());
644 Node* const p0 = m.Parameter(0);
645 Node* const p1 = m.Parameter(1);
646 Node* const s0 = m.Int32Mul(p1, m.Int32Constant(2));
647 m.Return(m.Int32Add(p0, s0));
648 Stream s = m.Build();
649 ASSERT_EQ(1U, s.size());
650 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
651 EXPECT_EQ(kMode_MR2, s[0]->addressing_mode());
652 ASSERT_EQ(2U, s[0]->InputCount());
653 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
654 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
655 }
656
657
TEST_F(InstructionSelectorTest,Int32AddCommutedScaled2Mul)658 TEST_F(InstructionSelectorTest, Int32AddCommutedScaled2Mul) {
659 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
660 MachineType::Int32());
661 Node* const p0 = m.Parameter(0);
662 Node* const p1 = m.Parameter(1);
663 Node* const s0 = m.Int32Mul(p1, m.Int32Constant(2));
664 m.Return(m.Int32Add(s0, p0));
665 Stream s = m.Build();
666 ASSERT_EQ(1U, s.size());
667 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
668 EXPECT_EQ(kMode_MR2, s[0]->addressing_mode());
669 ASSERT_EQ(2U, s[0]->InputCount());
670 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
671 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
672 }
673
674
TEST_F(InstructionSelectorTest,Int32AddScaled2Shl)675 TEST_F(InstructionSelectorTest, Int32AddScaled2Shl) {
676 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
677 MachineType::Int32());
678 Node* const p0 = m.Parameter(0);
679 Node* const p1 = m.Parameter(1);
680 Node* const s0 = m.Word32Shl(p1, m.Int32Constant(1));
681 m.Return(m.Int32Add(p0, s0));
682 Stream s = m.Build();
683 ASSERT_EQ(1U, s.size());
684 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
685 EXPECT_EQ(kMode_MR2, s[0]->addressing_mode());
686 ASSERT_EQ(2U, s[0]->InputCount());
687 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
688 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
689 }
690
691
TEST_F(InstructionSelectorTest,Int32AddCommutedScaled2Shl)692 TEST_F(InstructionSelectorTest, Int32AddCommutedScaled2Shl) {
693 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
694 MachineType::Int32());
695 Node* const p0 = m.Parameter(0);
696 Node* const p1 = m.Parameter(1);
697 Node* const s0 = m.Word32Shl(p1, m.Int32Constant(1));
698 m.Return(m.Int32Add(s0, p0));
699 Stream s = m.Build();
700 ASSERT_EQ(1U, s.size());
701 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
702 EXPECT_EQ(kMode_MR2, s[0]->addressing_mode());
703 ASSERT_EQ(2U, s[0]->InputCount());
704 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
705 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
706 }
707
708
TEST_F(InstructionSelectorTest,Int32AddScaled4Mul)709 TEST_F(InstructionSelectorTest, Int32AddScaled4Mul) {
710 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
711 MachineType::Int32());
712 Node* const p0 = m.Parameter(0);
713 Node* const p1 = m.Parameter(1);
714 Node* const s0 = m.Int32Mul(p1, m.Int32Constant(4));
715 m.Return(m.Int32Add(p0, s0));
716 Stream s = m.Build();
717 ASSERT_EQ(1U, s.size());
718 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
719 EXPECT_EQ(kMode_MR4, s[0]->addressing_mode());
720 ASSERT_EQ(2U, s[0]->InputCount());
721 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
722 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
723 }
724
725
TEST_F(InstructionSelectorTest,Int32AddScaled4Shl)726 TEST_F(InstructionSelectorTest, Int32AddScaled4Shl) {
727 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
728 MachineType::Int32());
729 Node* const p0 = m.Parameter(0);
730 Node* const p1 = m.Parameter(1);
731 Node* const s0 = m.Word32Shl(p1, m.Int32Constant(2));
732 m.Return(m.Int32Add(p0, s0));
733 Stream s = m.Build();
734 ASSERT_EQ(1U, s.size());
735 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
736 EXPECT_EQ(kMode_MR4, s[0]->addressing_mode());
737 ASSERT_EQ(2U, s[0]->InputCount());
738 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
739 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
740 }
741
742
TEST_F(InstructionSelectorTest,Int32AddScaled8Mul)743 TEST_F(InstructionSelectorTest, Int32AddScaled8Mul) {
744 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
745 MachineType::Int32());
746 Node* const p0 = m.Parameter(0);
747 Node* const p1 = m.Parameter(1);
748 Node* const s0 = m.Int32Mul(p1, m.Int32Constant(8));
749 m.Return(m.Int32Add(p0, s0));
750 Stream s = m.Build();
751 ASSERT_EQ(1U, s.size());
752 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
753 EXPECT_EQ(kMode_MR8, s[0]->addressing_mode());
754 ASSERT_EQ(2U, s[0]->InputCount());
755 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
756 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
757 }
758
759
TEST_F(InstructionSelectorTest,Int32AddScaled8Shl)760 TEST_F(InstructionSelectorTest, Int32AddScaled8Shl) {
761 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
762 MachineType::Int32());
763 Node* const p0 = m.Parameter(0);
764 Node* const p1 = m.Parameter(1);
765 Node* const s0 = m.Word32Shl(p1, m.Int32Constant(3));
766 m.Return(m.Int32Add(p0, s0));
767 Stream s = m.Build();
768 ASSERT_EQ(1U, s.size());
769 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
770 EXPECT_EQ(kMode_MR8, s[0]->addressing_mode());
771 ASSERT_EQ(2U, s[0]->InputCount());
772 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
773 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
774 }
775
776
TEST_F(InstructionSelectorTest,Int32AddScaled2MulWithConstant)777 TEST_F(InstructionSelectorTest, Int32AddScaled2MulWithConstant) {
778 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
779 MachineType::Int32());
780 Node* const p0 = m.Parameter(0);
781 Node* const p1 = m.Parameter(1);
782 Node* const s0 = m.Int32Mul(p1, m.Int32Constant(2));
783 Node* const c0 = m.Int32Constant(15);
784 m.Return(m.Int32Add(c0, m.Int32Add(p0, s0)));
785 Stream s = m.Build();
786 ASSERT_EQ(1U, s.size());
787 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
788 EXPECT_EQ(kMode_MR2I, s[0]->addressing_mode());
789 ASSERT_EQ(3U, s[0]->InputCount());
790 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
791 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
792 EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
793 }
794
795
TEST_F(InstructionSelectorTest,Int32AddScaled2MulWithConstantShuffle1)796 TEST_F(InstructionSelectorTest, Int32AddScaled2MulWithConstantShuffle1) {
797 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
798 MachineType::Int32());
799 Node* const p0 = m.Parameter(0);
800 Node* const p1 = m.Parameter(1);
801 Node* const s0 = m.Int32Mul(p1, m.Int32Constant(2));
802 Node* const c0 = m.Int32Constant(15);
803 m.Return(m.Int32Add(p0, m.Int32Add(s0, c0)));
804 Stream s = m.Build();
805 ASSERT_EQ(1U, s.size());
806 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
807 EXPECT_EQ(kMode_MR2I, s[0]->addressing_mode());
808 ASSERT_EQ(3U, s[0]->InputCount());
809 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
810 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
811 EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
812 }
813
814
TEST_F(InstructionSelectorTest,Int32AddScaled2MulWithConstantShuffle2)815 TEST_F(InstructionSelectorTest, Int32AddScaled2MulWithConstantShuffle2) {
816 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
817 MachineType::Int32());
818 Node* const p0 = m.Parameter(0);
819 Node* const p1 = m.Parameter(1);
820 Node* const s0 = m.Int32Mul(p1, m.Int32Constant(2));
821 Node* const c0 = m.Int32Constant(15);
822 m.Return(m.Int32Add(s0, m.Int32Add(c0, p0)));
823 Stream s = m.Build();
824 ASSERT_EQ(1U, s.size());
825 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
826 EXPECT_EQ(kMode_MR2I, s[0]->addressing_mode());
827 ASSERT_EQ(3U, s[0]->InputCount());
828 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
829 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
830 EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
831 }
832
833
TEST_F(InstructionSelectorTest,Int32AddScaled2MulWithConstantShuffle3)834 TEST_F(InstructionSelectorTest, Int32AddScaled2MulWithConstantShuffle3) {
835 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
836 MachineType::Int32());
837 Node* const p0 = m.Parameter(0);
838 Node* const p1 = m.Parameter(1);
839 Node* const s0 = m.Int32Mul(p1, m.Int32Constant(2));
840 Node* const c0 = m.Int32Constant(15);
841 m.Return(m.Int32Add(m.Int32Add(s0, c0), p0));
842 Stream s = m.Build();
843 ASSERT_EQ(1U, s.size());
844 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
845 EXPECT_EQ(kMode_MR2I, s[0]->addressing_mode());
846 ASSERT_EQ(3U, s[0]->InputCount());
847 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
848 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
849 EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
850 }
851
852
TEST_F(InstructionSelectorTest,Int32AddScaled2MulWithConstantShuffle4)853 TEST_F(InstructionSelectorTest, Int32AddScaled2MulWithConstantShuffle4) {
854 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
855 MachineType::Int32());
856 Node* const p0 = m.Parameter(0);
857 Node* const p1 = m.Parameter(1);
858 Node* const s0 = m.Int32Mul(p1, m.Int32Constant(2));
859 Node* const c0 = m.Int32Constant(15);
860 m.Return(m.Int32Add(m.Int32Add(c0, p0), s0));
861 Stream s = m.Build();
862 ASSERT_EQ(1U, s.size());
863 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
864 EXPECT_EQ(kMode_MR2I, s[0]->addressing_mode());
865 ASSERT_EQ(3U, s[0]->InputCount());
866 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
867 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
868 EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
869 }
870
871
TEST_F(InstructionSelectorTest,Int32AddScaled2MulWithConstantShuffle5)872 TEST_F(InstructionSelectorTest, Int32AddScaled2MulWithConstantShuffle5) {
873 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
874 MachineType::Int32());
875 Node* const p0 = m.Parameter(0);
876 Node* const p1 = m.Parameter(1);
877 Node* const s0 = m.Int32Mul(p1, m.Int32Constant(2));
878 Node* const c0 = m.Int32Constant(15);
879 m.Return(m.Int32Add(m.Int32Add(p0, s0), c0));
880 Stream s = m.Build();
881 ASSERT_EQ(1U, s.size());
882 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
883 EXPECT_EQ(kMode_MR2I, s[0]->addressing_mode());
884 ASSERT_EQ(3U, s[0]->InputCount());
885 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
886 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
887 EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
888 }
889
890
TEST_F(InstructionSelectorTest,Int32AddScaled2ShlWithConstant)891 TEST_F(InstructionSelectorTest, Int32AddScaled2ShlWithConstant) {
892 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
893 MachineType::Int32());
894 Node* const p0 = m.Parameter(0);
895 Node* const p1 = m.Parameter(1);
896 Node* const s0 = m.Word32Shl(p1, m.Int32Constant(1));
897 Node* const c0 = m.Int32Constant(15);
898 m.Return(m.Int32Add(c0, m.Int32Add(p0, s0)));
899 Stream s = m.Build();
900 ASSERT_EQ(1U, s.size());
901 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
902 EXPECT_EQ(kMode_MR2I, s[0]->addressing_mode());
903 ASSERT_EQ(3U, s[0]->InputCount());
904 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
905 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
906 EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
907 }
908
909
TEST_F(InstructionSelectorTest,Int32AddScaled4MulWithConstant)910 TEST_F(InstructionSelectorTest, Int32AddScaled4MulWithConstant) {
911 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
912 MachineType::Int32());
913 Node* const p0 = m.Parameter(0);
914 Node* const p1 = m.Parameter(1);
915 Node* const s0 = m.Int32Mul(p1, m.Int32Constant(4));
916 Node* const c0 = m.Int32Constant(15);
917 m.Return(m.Int32Add(c0, m.Int32Add(p0, s0)));
918 Stream s = m.Build();
919 ASSERT_EQ(1U, s.size());
920 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
921 EXPECT_EQ(kMode_MR4I, s[0]->addressing_mode());
922 ASSERT_EQ(3U, s[0]->InputCount());
923 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
924 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
925 EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
926 }
927
928
TEST_F(InstructionSelectorTest,Int32AddScaled4ShlWithConstant)929 TEST_F(InstructionSelectorTest, Int32AddScaled4ShlWithConstant) {
930 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
931 MachineType::Int32());
932 Node* const p0 = m.Parameter(0);
933 Node* const p1 = m.Parameter(1);
934 Node* const s0 = m.Word32Shl(p1, m.Int32Constant(2));
935 Node* const c0 = m.Int32Constant(15);
936 m.Return(m.Int32Add(c0, m.Int32Add(p0, s0)));
937 Stream s = m.Build();
938 ASSERT_EQ(1U, s.size());
939 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
940 EXPECT_EQ(kMode_MR4I, s[0]->addressing_mode());
941 ASSERT_EQ(3U, s[0]->InputCount());
942 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
943 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
944 EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
945 }
946
947
TEST_F(InstructionSelectorTest,Int32AddScaled8MulWithConstant)948 TEST_F(InstructionSelectorTest, Int32AddScaled8MulWithConstant) {
949 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
950 MachineType::Int32());
951 Node* const p0 = m.Parameter(0);
952 Node* const p1 = m.Parameter(1);
953 Node* const s0 = m.Int32Mul(p1, m.Int32Constant(8));
954 Node* const c0 = m.Int32Constant(15);
955 m.Return(m.Int32Add(c0, m.Int32Add(p0, s0)));
956 Stream s = m.Build();
957 ASSERT_EQ(1U, s.size());
958 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
959 EXPECT_EQ(kMode_MR8I, s[0]->addressing_mode());
960 ASSERT_EQ(3U, s[0]->InputCount());
961 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
962 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
963 EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
964 }
965
966
TEST_F(InstructionSelectorTest,Int32AddScaled8ShlWithConstant)967 TEST_F(InstructionSelectorTest, Int32AddScaled8ShlWithConstant) {
968 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
969 MachineType::Int32());
970 Node* const p0 = m.Parameter(0);
971 Node* const p1 = m.Parameter(1);
972 Node* const s0 = m.Word32Shl(p1, m.Int32Constant(3));
973 Node* const c0 = m.Int32Constant(15);
974 m.Return(m.Int32Add(c0, m.Int32Add(p0, s0)));
975 Stream s = m.Build();
976 ASSERT_EQ(1U, s.size());
977 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
978 EXPECT_EQ(kMode_MR8I, s[0]->addressing_mode());
979 ASSERT_EQ(3U, s[0]->InputCount());
980 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
981 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
982 EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
983 }
984
985
TEST_F(InstructionSelectorTest,Int32SubConstantAsSub)986 TEST_F(InstructionSelectorTest, Int32SubConstantAsSub) {
987 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
988 Node* const p0 = m.Parameter(0);
989 Node* const c0 = m.Int32Constant(-1);
990 // If there is only a single use of on of the sub's non-constant input, use a
991 // "subl" instruction.
992 m.Return(m.Int32Sub(p0, c0));
993 Stream s = m.Build();
994 ASSERT_EQ(1U, s.size());
995 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
996 EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
997 ASSERT_EQ(2U, s[0]->InputCount());
998 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
999 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
1000 }
1001
1002
TEST_F(InstructionSelectorTest,Int32SubConstantAsLea)1003 TEST_F(InstructionSelectorTest, Int32SubConstantAsLea) {
1004 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
1005 Node* const p0 = m.Parameter(0);
1006 Node* const c0 = m.Int32Constant(-1);
1007 // If there are multiple uses of on of the sub's non-constant input, use a
1008 // "leal" instruction.
1009 Node* const v0 = m.Int32Sub(p0, c0);
1010 m.Return(m.Int32Div(p0, v0));
1011 Stream s = m.Build();
1012 ASSERT_EQ(2U, s.size());
1013 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
1014 EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
1015 ASSERT_EQ(2U, s[0]->InputCount());
1016 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1017 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
1018 }
1019
1020
TEST_F(InstructionSelectorTest,Int32AddScaled2Other)1021 TEST_F(InstructionSelectorTest, Int32AddScaled2Other) {
1022 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
1023 MachineType::Int32(), MachineType::Int32());
1024 Node* const p0 = m.Parameter(0);
1025 Node* const p1 = m.Parameter(1);
1026 Node* const p2 = m.Parameter(2);
1027 Node* const s0 = m.Int32Mul(p1, m.Int32Constant(2));
1028 Node* const a0 = m.Int32Add(s0, p2);
1029 Node* const a1 = m.Int32Add(p0, a0);
1030 m.Return(a1);
1031 Stream s = m.Build();
1032 ASSERT_EQ(2U, s.size());
1033 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
1034 EXPECT_EQ(kMode_MR2, s[0]->addressing_mode());
1035 ASSERT_EQ(2U, s[0]->InputCount());
1036 EXPECT_EQ(s.ToVreg(p2), s.ToVreg(s[0]->InputAt(0)));
1037 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
1038 EXPECT_EQ(s.ToVreg(a0), s.ToVreg(s[0]->OutputAt(0)));
1039 ASSERT_EQ(2U, s[1]->InputCount());
1040 EXPECT_EQ(kX64Lea32, s[1]->arch_opcode());
1041 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[1]->InputAt(0)));
1042 EXPECT_EQ(s.ToVreg(a0), s.ToVreg(s[1]->InputAt(1)));
1043 EXPECT_EQ(s.ToVreg(a1), s.ToVreg(s[1]->OutputAt(0)));
1044 }
1045
TEST_F(InstructionSelectorTest,Int32AddMinNegativeDisplacement)1046 TEST_F(InstructionSelectorTest, Int32AddMinNegativeDisplacement) {
1047 // This test case is simplified from a Wasm fuzz test in
1048 // https://crbug.com/1091892. The key here is that we match on a
1049 // sequence like: Int32Add(Int32Sub(-524288, -2147483648), -26048), which
1050 // matches on an EmitLea, with -2147483648 as the displacement. Since we
1051 // have a Int32Sub node, it sets kNegativeDisplacement, and later we try to
1052 // negate -2147483648, which overflows.
1053 StreamBuilder m(this, MachineType::Int32());
1054 Node* const c0 = m.Int32Constant(-524288);
1055 Node* const c1 = m.Int32Constant(std::numeric_limits<int32_t>::min());
1056 Node* const c2 = m.Int32Constant(-26048);
1057 Node* const a0 = m.Int32Sub(c0, c1);
1058 Node* const a1 = m.Int32Add(a0, c2);
1059 m.Return(a1);
1060 Stream s = m.Build();
1061 ASSERT_EQ(2U, s.size());
1062
1063 EXPECT_EQ(kX64Sub32, s[0]->arch_opcode());
1064 ASSERT_EQ(2U, s[0]->InputCount());
1065 EXPECT_EQ(kMode_None, s[0]->addressing_mode());
1066 EXPECT_EQ(s.ToVreg(c0), s.ToVreg(s[0]->InputAt(0)));
1067 EXPECT_EQ(s.ToVreg(c1), s.ToVreg(s[0]->InputAt(1)));
1068 EXPECT_EQ(s.ToVreg(a0), s.ToVreg(s[0]->OutputAt(0)));
1069
1070 EXPECT_EQ(kX64Add32, s[1]->arch_opcode());
1071 ASSERT_EQ(2U, s[1]->InputCount());
1072 EXPECT_EQ(kMode_None, s[1]->addressing_mode());
1073 EXPECT_EQ(s.ToVreg(a0), s.ToVreg(s[1]->InputAt(0)));
1074 EXPECT_TRUE(s[1]->InputAt(1)->IsImmediate());
1075 EXPECT_EQ(s.ToVreg(a1), s.ToVreg(s[1]->OutputAt(0)));
1076 }
1077
1078 // -----------------------------------------------------------------------------
1079 // Multiplication.
1080
1081
TEST_F(InstructionSelectorTest,Int32MulWithInt32MulWithParameters)1082 TEST_F(InstructionSelectorTest, Int32MulWithInt32MulWithParameters) {
1083 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
1084 MachineType::Int32());
1085 Node* const p0 = m.Parameter(0);
1086 Node* const p1 = m.Parameter(1);
1087 Node* const m0 = m.Int32Mul(p0, p1);
1088 m.Return(m.Int32Mul(m0, p0));
1089 Stream s = m.Build();
1090 ASSERT_EQ(2U, s.size());
1091 EXPECT_EQ(kX64Imul32, s[0]->arch_opcode());
1092 ASSERT_EQ(2U, s[0]->InputCount());
1093 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(0)));
1094 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
1095 ASSERT_EQ(1U, s[0]->OutputCount());
1096 EXPECT_EQ(s.ToVreg(m0), s.ToVreg(s[0]->OutputAt(0)));
1097 EXPECT_EQ(kX64Imul32, s[1]->arch_opcode());
1098 ASSERT_EQ(2U, s[1]->InputCount());
1099 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[1]->InputAt(0)));
1100 EXPECT_EQ(s.ToVreg(m0), s.ToVreg(s[1]->InputAt(1)));
1101 }
1102
1103
TEST_F(InstructionSelectorTest,Int32MulHigh)1104 TEST_F(InstructionSelectorTest, Int32MulHigh) {
1105 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
1106 MachineType::Int32());
1107 Node* const p0 = m.Parameter(0);
1108 Node* const p1 = m.Parameter(1);
1109 Node* const n = m.Int32MulHigh(p0, p1);
1110 m.Return(n);
1111 Stream s = m.Build();
1112 ASSERT_EQ(1U, s.size());
1113 EXPECT_EQ(kX64ImulHigh32, s[0]->arch_opcode());
1114 ASSERT_EQ(2U, s[0]->InputCount());
1115 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1116 EXPECT_TRUE(s.IsFixed(s[0]->InputAt(0), rax));
1117 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
1118 EXPECT_TRUE(!s.IsUsedAtStart(s[0]->InputAt(1)));
1119 ASSERT_LE(1U, s[0]->OutputCount());
1120 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
1121 EXPECT_TRUE(s.IsFixed(s[0]->OutputAt(0), rdx));
1122 }
1123
1124
TEST_F(InstructionSelectorTest,Uint32MulHigh)1125 TEST_F(InstructionSelectorTest, Uint32MulHigh) {
1126 StreamBuilder m(this, MachineType::Uint32(), MachineType::Uint32(),
1127 MachineType::Uint32());
1128 Node* const p0 = m.Parameter(0);
1129 Node* const p1 = m.Parameter(1);
1130 Node* const n = m.Uint32MulHigh(p0, p1);
1131 m.Return(n);
1132 Stream s = m.Build();
1133 ASSERT_EQ(1U, s.size());
1134 EXPECT_EQ(kX64UmulHigh32, s[0]->arch_opcode());
1135 ASSERT_EQ(2U, s[0]->InputCount());
1136 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1137 EXPECT_TRUE(s.IsFixed(s[0]->InputAt(0), rax));
1138 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
1139 EXPECT_TRUE(!s.IsUsedAtStart(s[0]->InputAt(1)));
1140 ASSERT_LE(1U, s[0]->OutputCount());
1141 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
1142 EXPECT_TRUE(s.IsFixed(s[0]->OutputAt(0), rdx));
1143 }
1144
1145
TEST_F(InstructionSelectorTest,Int32Mul2BecomesLea)1146 TEST_F(InstructionSelectorTest, Int32Mul2BecomesLea) {
1147 StreamBuilder m(this, MachineType::Uint32(), MachineType::Uint32(),
1148 MachineType::Uint32());
1149 Node* const p0 = m.Parameter(0);
1150 Node* const c1 = m.Int32Constant(2);
1151 Node* const n = m.Int32Mul(p0, c1);
1152 m.Return(n);
1153 Stream s = m.Build();
1154 ASSERT_EQ(1U, s.size());
1155 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
1156 EXPECT_EQ(kMode_MR1, s[0]->addressing_mode());
1157 ASSERT_EQ(2U, s[0]->InputCount());
1158 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1159 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
1160 }
1161
1162
TEST_F(InstructionSelectorTest,Int32Mul3BecomesLea)1163 TEST_F(InstructionSelectorTest, Int32Mul3BecomesLea) {
1164 StreamBuilder m(this, MachineType::Uint32(), MachineType::Uint32(),
1165 MachineType::Uint32());
1166 Node* const p0 = m.Parameter(0);
1167 Node* const c1 = m.Int32Constant(3);
1168 Node* const n = m.Int32Mul(p0, c1);
1169 m.Return(n);
1170 Stream s = m.Build();
1171 ASSERT_EQ(1U, s.size());
1172 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
1173 EXPECT_EQ(kMode_MR2, s[0]->addressing_mode());
1174 ASSERT_EQ(2U, s[0]->InputCount());
1175 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1176 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
1177 }
1178
1179
TEST_F(InstructionSelectorTest,Int32Mul4BecomesLea)1180 TEST_F(InstructionSelectorTest, Int32Mul4BecomesLea) {
1181 StreamBuilder m(this, MachineType::Uint32(), MachineType::Uint32(),
1182 MachineType::Uint32());
1183 Node* const p0 = m.Parameter(0);
1184 Node* const c1 = m.Int32Constant(4);
1185 Node* const n = m.Int32Mul(p0, c1);
1186 m.Return(n);
1187 Stream s = m.Build();
1188 ASSERT_EQ(1U, s.size());
1189 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
1190 EXPECT_EQ(kMode_M4, s[0]->addressing_mode());
1191 ASSERT_EQ(1U, s[0]->InputCount());
1192 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1193 }
1194
1195
TEST_F(InstructionSelectorTest,Int32Mul5BecomesLea)1196 TEST_F(InstructionSelectorTest, Int32Mul5BecomesLea) {
1197 StreamBuilder m(this, MachineType::Uint32(), MachineType::Uint32(),
1198 MachineType::Uint32());
1199 Node* const p0 = m.Parameter(0);
1200 Node* const c1 = m.Int32Constant(5);
1201 Node* const n = m.Int32Mul(p0, c1);
1202 m.Return(n);
1203 Stream s = m.Build();
1204 ASSERT_EQ(1U, s.size());
1205 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
1206 EXPECT_EQ(kMode_MR4, s[0]->addressing_mode());
1207 ASSERT_EQ(2U, s[0]->InputCount());
1208 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1209 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
1210 }
1211
1212
TEST_F(InstructionSelectorTest,Int32Mul8BecomesLea)1213 TEST_F(InstructionSelectorTest, Int32Mul8BecomesLea) {
1214 StreamBuilder m(this, MachineType::Uint32(), MachineType::Uint32(),
1215 MachineType::Uint32());
1216 Node* const p0 = m.Parameter(0);
1217 Node* const c1 = m.Int32Constant(8);
1218 Node* const n = m.Int32Mul(p0, c1);
1219 m.Return(n);
1220 Stream s = m.Build();
1221 ASSERT_EQ(1U, s.size());
1222 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
1223 EXPECT_EQ(kMode_M8, s[0]->addressing_mode());
1224 ASSERT_EQ(1U, s[0]->InputCount());
1225 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1226 }
1227
1228
TEST_F(InstructionSelectorTest,Int32Mul9BecomesLea)1229 TEST_F(InstructionSelectorTest, Int32Mul9BecomesLea) {
1230 StreamBuilder m(this, MachineType::Uint32(), MachineType::Uint32(),
1231 MachineType::Uint32());
1232 Node* const p0 = m.Parameter(0);
1233 Node* const c1 = m.Int32Constant(9);
1234 Node* const n = m.Int32Mul(p0, c1);
1235 m.Return(n);
1236 Stream s = m.Build();
1237 ASSERT_EQ(1U, s.size());
1238 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
1239 EXPECT_EQ(kMode_MR8, s[0]->addressing_mode());
1240 ASSERT_EQ(2U, s[0]->InputCount());
1241 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1242 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
1243 }
1244
1245
1246 // -----------------------------------------------------------------------------
1247 // Word32Shl.
1248
1249
TEST_F(InstructionSelectorTest,Int32Shl1BecomesLea)1250 TEST_F(InstructionSelectorTest, Int32Shl1BecomesLea) {
1251 StreamBuilder m(this, MachineType::Uint32(), MachineType::Uint32(),
1252 MachineType::Uint32());
1253 Node* const p0 = m.Parameter(0);
1254 Node* const c1 = m.Int32Constant(1);
1255 Node* const n = m.Word32Shl(p0, c1);
1256 m.Return(n);
1257 Stream s = m.Build();
1258 ASSERT_EQ(1U, s.size());
1259 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
1260 EXPECT_EQ(kMode_MR1, s[0]->addressing_mode());
1261 ASSERT_EQ(2U, s[0]->InputCount());
1262 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1263 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
1264 }
1265
1266
TEST_F(InstructionSelectorTest,Int32Shl2BecomesLea)1267 TEST_F(InstructionSelectorTest, Int32Shl2BecomesLea) {
1268 StreamBuilder m(this, MachineType::Uint32(), MachineType::Uint32(),
1269 MachineType::Uint32());
1270 Node* const p0 = m.Parameter(0);
1271 Node* const c1 = m.Int32Constant(2);
1272 Node* const n = m.Word32Shl(p0, c1);
1273 m.Return(n);
1274 Stream s = m.Build();
1275 ASSERT_EQ(1U, s.size());
1276 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
1277 EXPECT_EQ(kMode_M4, s[0]->addressing_mode());
1278 ASSERT_EQ(1U, s[0]->InputCount());
1279 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1280 }
1281
1282
TEST_F(InstructionSelectorTest,Int32Shl4BecomesLea)1283 TEST_F(InstructionSelectorTest, Int32Shl4BecomesLea) {
1284 StreamBuilder m(this, MachineType::Uint32(), MachineType::Uint32(),
1285 MachineType::Uint32());
1286 Node* const p0 = m.Parameter(0);
1287 Node* const c1 = m.Int32Constant(3);
1288 Node* const n = m.Word32Shl(p0, c1);
1289 m.Return(n);
1290 Stream s = m.Build();
1291 ASSERT_EQ(1U, s.size());
1292 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
1293 EXPECT_EQ(kMode_M8, s[0]->addressing_mode());
1294 ASSERT_EQ(1U, s[0]->InputCount());
1295 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1296 }
1297
1298 // -----------------------------------------------------------------------------
1299 // Binops with a memory operand.
1300
TEST_F(InstructionSelectorTest,LoadCmp32)1301 TEST_F(InstructionSelectorTest, LoadCmp32) {
1302 {
1303 // Word32Equal(Load[Int8](p0, p1), Int32Constant(0)) -> cmpb [p0,p1], 0
1304 StreamBuilder m(this, MachineType::Int32(), MachineType::Int64(),
1305 MachineType::Int64());
1306 Node* const p0 = m.Parameter(0);
1307 Node* const p1 = m.Parameter(1);
1308 m.Return(
1309 m.Word32Equal(m.Load(MachineType::Int8(), p0, p1), m.Int32Constant(0)));
1310 Stream s = m.Build();
1311 ASSERT_EQ(1U, s.size());
1312 EXPECT_EQ(kX64Cmp8, s[0]->arch_opcode());
1313 EXPECT_EQ(kMode_MR1, s[0]->addressing_mode());
1314 ASSERT_EQ(3U, s[0]->InputCount());
1315 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1316 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
1317 EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
1318 }
1319 {
1320 // Word32Equal(LoadImmutable[Int8](p0, p1), Int32Constant(0)) ->
1321 // cmpb [p0,p1], 0
1322 StreamBuilder m(this, MachineType::Int32(), MachineType::Int64(),
1323 MachineType::Int64());
1324 Node* const p0 = m.Parameter(0);
1325 Node* const p1 = m.Parameter(1);
1326 m.Return(m.Word32Equal(m.LoadImmutable(MachineType::Int8(), p0, p1),
1327 m.Int32Constant(0)));
1328 Stream s = m.Build();
1329 ASSERT_EQ(1U, s.size());
1330 EXPECT_EQ(kX64Cmp8, s[0]->arch_opcode());
1331 EXPECT_EQ(kMode_MR1, s[0]->addressing_mode());
1332 ASSERT_EQ(3U, s[0]->InputCount());
1333 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1334 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
1335 EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
1336 }
1337 {
1338 // Word32Equal(Load[Uint8](p0, p1), Int32Constant(0)) -> cmpb [p0,p1], 0
1339 StreamBuilder m(this, MachineType::Int32(), MachineType::Int64(),
1340 MachineType::Int64());
1341 Node* const p0 = m.Parameter(0);
1342 Node* const p1 = m.Parameter(1);
1343 m.Return(m.Word32Equal(m.Load(MachineType::Uint8(), p0, p1),
1344 m.Int32Constant(0)));
1345 Stream s = m.Build();
1346 ASSERT_EQ(1U, s.size());
1347 EXPECT_EQ(kX64Cmp8, s[0]->arch_opcode());
1348 EXPECT_EQ(kMode_MR1, s[0]->addressing_mode());
1349 ASSERT_EQ(3U, s[0]->InputCount());
1350 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1351 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
1352 EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
1353 }
1354 {
1355 // Word32Equal(Load[Int16](p0, p1), Int32Constant(0)) -> cmpw [p0,p1], 0
1356 StreamBuilder m(this, MachineType::Int32(), MachineType::Int64(),
1357 MachineType::Int64());
1358 Node* const p0 = m.Parameter(0);
1359 Node* const p1 = m.Parameter(1);
1360 m.Return(m.Word32Equal(m.Load(MachineType::Int16(), p0, p1),
1361 m.Int32Constant(0)));
1362 Stream s = m.Build();
1363 ASSERT_EQ(1U, s.size());
1364 EXPECT_EQ(kX64Cmp16, s[0]->arch_opcode());
1365 EXPECT_EQ(kMode_MR1, s[0]->addressing_mode());
1366 ASSERT_EQ(3U, s[0]->InputCount());
1367 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1368 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
1369 EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
1370 }
1371 {
1372 // Word32Equal(Load[Uint16](p0, p1), Int32Constant(0)) -> cmpw [p0,p1], 0
1373 StreamBuilder m(this, MachineType::Int32(), MachineType::Int64(),
1374 MachineType::Int64());
1375 Node* const p0 = m.Parameter(0);
1376 Node* const p1 = m.Parameter(1);
1377 m.Return(m.Word32Equal(m.Load(MachineType::Uint16(), p0, p1),
1378 m.Int32Constant(0)));
1379 Stream s = m.Build();
1380 ASSERT_EQ(1U, s.size());
1381 EXPECT_EQ(kX64Cmp16, s[0]->arch_opcode());
1382 EXPECT_EQ(kMode_MR1, s[0]->addressing_mode());
1383 ASSERT_EQ(3U, s[0]->InputCount());
1384 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1385 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
1386 EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
1387 }
1388 {
1389 // Word32Equal(Load[Int32](p0, p1), Int32Constant(0)) -> cmpl [p0,p1], 0
1390 StreamBuilder m(this, MachineType::Int32(), MachineType::Int64(),
1391 MachineType::Int64());
1392 Node* const p0 = m.Parameter(0);
1393 Node* const p1 = m.Parameter(1);
1394 m.Return(m.Word32Equal(m.Load(MachineType::Int32(), p0, p1),
1395 m.Int32Constant(0)));
1396 Stream s = m.Build();
1397 ASSERT_EQ(1U, s.size());
1398 EXPECT_EQ(kX64Cmp32, s[0]->arch_opcode());
1399 EXPECT_EQ(kMode_MR1, s[0]->addressing_mode());
1400 ASSERT_EQ(3U, s[0]->InputCount());
1401 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1402 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
1403 EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
1404 }
1405 {
1406 // Word32Equal(Load[Uint32](p0, p1), Int32Constant(0)) -> cmpl [p0,p1], 0
1407 StreamBuilder m(this, MachineType::Int32(), MachineType::Int64(),
1408 MachineType::Int64());
1409 Node* const p0 = m.Parameter(0);
1410 Node* const p1 = m.Parameter(1);
1411 m.Return(m.Word32Equal(m.Load(MachineType::Uint32(), p0, p1),
1412 m.Int32Constant(0)));
1413 Stream s = m.Build();
1414 ASSERT_EQ(1U, s.size());
1415 EXPECT_EQ(kX64Cmp32, s[0]->arch_opcode());
1416 EXPECT_EQ(kMode_MR1, s[0]->addressing_mode());
1417 ASSERT_EQ(3U, s[0]->InputCount());
1418 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1419 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
1420 EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
1421 }
1422 }
1423
TEST_F(InstructionSelectorTest,LoadAnd32)1424 TEST_F(InstructionSelectorTest, LoadAnd32) {
1425 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
1426 MachineType::Int32());
1427 Node* const p0 = m.Parameter(0);
1428 Node* const p1 = m.Parameter(1);
1429 m.Return(
1430 m.Word32And(p0, m.Load(MachineType::Int32(), p1, m.Int32Constant(127))));
1431 Stream s = m.Build();
1432 ASSERT_EQ(1U, s.size());
1433 EXPECT_EQ(kX64And32, s[0]->arch_opcode());
1434 ASSERT_EQ(3U, s[0]->InputCount());
1435 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1436 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
1437 }
1438
TEST_F(InstructionSelectorTest,LoadOr32)1439 TEST_F(InstructionSelectorTest, LoadOr32) {
1440 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
1441 MachineType::Int32());
1442 Node* const p0 = m.Parameter(0);
1443 Node* const p1 = m.Parameter(1);
1444 m.Return(
1445 m.Word32Or(p0, m.Load(MachineType::Int32(), p1, m.Int32Constant(127))));
1446 Stream s = m.Build();
1447 ASSERT_EQ(1U, s.size());
1448 EXPECT_EQ(kX64Or32, s[0]->arch_opcode());
1449 ASSERT_EQ(3U, s[0]->InputCount());
1450 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1451 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
1452 }
1453
TEST_F(InstructionSelectorTest,LoadXor32)1454 TEST_F(InstructionSelectorTest, LoadXor32) {
1455 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
1456 MachineType::Int32());
1457 Node* const p0 = m.Parameter(0);
1458 Node* const p1 = m.Parameter(1);
1459 m.Return(
1460 m.Word32Xor(p0, m.Load(MachineType::Int32(), p1, m.Int32Constant(127))));
1461 Stream s = m.Build();
1462 ASSERT_EQ(1U, s.size());
1463 EXPECT_EQ(kX64Xor32, s[0]->arch_opcode());
1464 ASSERT_EQ(3U, s[0]->InputCount());
1465 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1466 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
1467 }
1468
TEST_F(InstructionSelectorTest,LoadAdd32)1469 TEST_F(InstructionSelectorTest, LoadAdd32) {
1470 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
1471 MachineType::Int32());
1472 Node* const p0 = m.Parameter(0);
1473 Node* const p1 = m.Parameter(1);
1474 m.Return(
1475 m.Int32Add(p0, m.Load(MachineType::Int32(), p1, m.Int32Constant(127))));
1476 Stream s = m.Build();
1477 // Use lea instead of add, so memory operand is invalid.
1478 ASSERT_EQ(2U, s.size());
1479 EXPECT_EQ(kX64Movl, s[0]->arch_opcode());
1480 EXPECT_EQ(kX64Lea32, s[1]->arch_opcode());
1481 }
1482
TEST_F(InstructionSelectorTest,LoadSub32)1483 TEST_F(InstructionSelectorTest, LoadSub32) {
1484 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
1485 MachineType::Int32());
1486 Node* const p0 = m.Parameter(0);
1487 Node* const p1 = m.Parameter(1);
1488 m.Return(
1489 m.Int32Sub(p0, m.Load(MachineType::Int32(), p1, m.Int32Constant(127))));
1490 Stream s = m.Build();
1491 ASSERT_EQ(1U, s.size());
1492 EXPECT_EQ(kX64Sub32, s[0]->arch_opcode());
1493 ASSERT_EQ(3U, s[0]->InputCount());
1494 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1495 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
1496 }
1497
TEST_F(InstructionSelectorTest,LoadAnd64)1498 TEST_F(InstructionSelectorTest, LoadAnd64) {
1499 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64(),
1500 MachineType::Int64());
1501 Node* const p0 = m.Parameter(0);
1502 Node* const p1 = m.Parameter(1);
1503 m.Return(
1504 m.Word64And(p0, m.Load(MachineType::Int64(), p1, m.Int32Constant(127))));
1505 Stream s = m.Build();
1506 ASSERT_EQ(1U, s.size());
1507 EXPECT_EQ(kX64And, s[0]->arch_opcode());
1508 ASSERT_EQ(3U, s[0]->InputCount());
1509 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1510 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
1511 }
1512
TEST_F(InstructionSelectorTest,LoadOr64)1513 TEST_F(InstructionSelectorTest, LoadOr64) {
1514 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64(),
1515 MachineType::Int64());
1516 Node* const p0 = m.Parameter(0);
1517 Node* const p1 = m.Parameter(1);
1518 m.Return(
1519 m.Word64Or(p0, m.Load(MachineType::Int64(), p1, m.Int32Constant(127))));
1520 Stream s = m.Build();
1521 ASSERT_EQ(1U, s.size());
1522 EXPECT_EQ(kX64Or, s[0]->arch_opcode());
1523 ASSERT_EQ(3U, s[0]->InputCount());
1524 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1525 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
1526 }
1527
TEST_F(InstructionSelectorTest,LoadXor64)1528 TEST_F(InstructionSelectorTest, LoadXor64) {
1529 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64(),
1530 MachineType::Int64());
1531 Node* const p0 = m.Parameter(0);
1532 Node* const p1 = m.Parameter(1);
1533 m.Return(
1534 m.Word64Xor(p0, m.Load(MachineType::Int64(), p1, m.Int32Constant(127))));
1535 Stream s = m.Build();
1536 ASSERT_EQ(1U, s.size());
1537 EXPECT_EQ(kX64Xor, s[0]->arch_opcode());
1538 ASSERT_EQ(3U, s[0]->InputCount());
1539 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1540 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
1541 }
1542
TEST_F(InstructionSelectorTest,LoadAdd64)1543 TEST_F(InstructionSelectorTest, LoadAdd64) {
1544 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64(),
1545 MachineType::Int64());
1546 Node* const p0 = m.Parameter(0);
1547 Node* const p1 = m.Parameter(1);
1548 m.Return(
1549 m.Int64Add(p0, m.Load(MachineType::Int64(), p1, m.Int32Constant(127))));
1550 Stream s = m.Build();
1551 // Use lea instead of add, so memory operand is invalid.
1552 ASSERT_EQ(2U, s.size());
1553 EXPECT_EQ(kX64Movq, s[0]->arch_opcode());
1554 EXPECT_EQ(kX64Lea, s[1]->arch_opcode());
1555 }
1556
TEST_F(InstructionSelectorTest,LoadSub64)1557 TEST_F(InstructionSelectorTest, LoadSub64) {
1558 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64(),
1559 MachineType::Int64());
1560 Node* const p0 = m.Parameter(0);
1561 Node* const p1 = m.Parameter(1);
1562 m.Return(
1563 m.Int64Sub(p0, m.Load(MachineType::Int64(), p1, m.Int32Constant(127))));
1564 Stream s = m.Build();
1565 ASSERT_EQ(1U, s.size());
1566 EXPECT_EQ(kX64Sub, s[0]->arch_opcode());
1567 ASSERT_EQ(3U, s[0]->InputCount());
1568 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1569 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
1570 }
1571
1572 // -----------------------------------------------------------------------------
1573 // Floating point operations.
1574
TEST_F(InstructionSelectorTest,Float32Abs)1575 TEST_F(InstructionSelectorTest, Float32Abs) {
1576 {
1577 StreamBuilder m(this, MachineType::Float32(), MachineType::Float32());
1578 Node* const p0 = m.Parameter(0);
1579 Node* const n = m.Float32Abs(p0);
1580 m.Return(n);
1581 Stream s = m.Build();
1582 ASSERT_EQ(1U, s.size());
1583 EXPECT_EQ(kX64Float32Abs, s[0]->arch_opcode());
1584 ASSERT_EQ(1U, s[0]->InputCount());
1585 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1586 ASSERT_EQ(1U, s[0]->OutputCount());
1587 EXPECT_TRUE(s.IsSameAsFirst(s[0]->Output()));
1588 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
1589 EXPECT_EQ(kFlags_none, s[0]->flags_mode());
1590 }
1591 {
1592 StreamBuilder m(this, MachineType::Float32(), MachineType::Float32());
1593 Node* const p0 = m.Parameter(0);
1594 Node* const n = m.Float32Abs(p0);
1595 m.Return(n);
1596 Stream s = m.Build(AVX);
1597 ASSERT_EQ(1U, s.size());
1598 EXPECT_EQ(kX64Float32Abs, s[0]->arch_opcode());
1599 ASSERT_EQ(1U, s[0]->InputCount());
1600 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1601 ASSERT_EQ(1U, s[0]->OutputCount());
1602 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
1603 EXPECT_EQ(kFlags_none, s[0]->flags_mode());
1604 }
1605 }
1606
1607
TEST_F(InstructionSelectorTest,Float64Abs)1608 TEST_F(InstructionSelectorTest, Float64Abs) {
1609 {
1610 StreamBuilder m(this, MachineType::Float64(), MachineType::Float64());
1611 Node* const p0 = m.Parameter(0);
1612 Node* const n = m.Float64Abs(p0);
1613 m.Return(n);
1614 Stream s = m.Build();
1615 ASSERT_EQ(1U, s.size());
1616 EXPECT_EQ(kX64Float64Abs, s[0]->arch_opcode());
1617 ASSERT_EQ(1U, s[0]->InputCount());
1618 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1619 ASSERT_EQ(1U, s[0]->OutputCount());
1620 EXPECT_TRUE(s.IsSameAsFirst(s[0]->Output()));
1621 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
1622 EXPECT_EQ(kFlags_none, s[0]->flags_mode());
1623 }
1624 {
1625 StreamBuilder m(this, MachineType::Float64(), MachineType::Float64());
1626 Node* const p0 = m.Parameter(0);
1627 Node* const n = m.Float64Abs(p0);
1628 m.Return(n);
1629 Stream s = m.Build(AVX);
1630 ASSERT_EQ(1U, s.size());
1631 EXPECT_EQ(kX64Float64Abs, s[0]->arch_opcode());
1632 ASSERT_EQ(1U, s[0]->InputCount());
1633 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1634 ASSERT_EQ(1U, s[0]->OutputCount());
1635 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
1636 EXPECT_EQ(kFlags_none, s[0]->flags_mode());
1637 }
1638 }
1639
1640
TEST_F(InstructionSelectorTest,Float64BinopArithmetic)1641 TEST_F(InstructionSelectorTest, Float64BinopArithmetic) {
1642 {
1643 StreamBuilder m(this, MachineType::Float64(), MachineType::Float64(),
1644 MachineType::Float64());
1645 Node* add = m.Float64Add(m.Parameter(0), m.Parameter(1));
1646 Node* mul = m.Float64Mul(add, m.Parameter(1));
1647 Node* sub = m.Float64Sub(mul, add);
1648 Node* ret = m.Float64Div(mul, sub);
1649 m.Return(ret);
1650 Stream s = m.Build(AVX);
1651 ASSERT_EQ(4U, s.size());
1652 EXPECT_EQ(kAVXFloat64Add, s[0]->arch_opcode());
1653 EXPECT_EQ(kAVXFloat64Mul, s[1]->arch_opcode());
1654 EXPECT_EQ(kAVXFloat64Sub, s[2]->arch_opcode());
1655 EXPECT_EQ(kAVXFloat64Div, s[3]->arch_opcode());
1656 }
1657 {
1658 StreamBuilder m(this, MachineType::Float64(), MachineType::Float64(),
1659 MachineType::Float64());
1660 Node* add = m.Float64Add(m.Parameter(0), m.Parameter(1));
1661 Node* mul = m.Float64Mul(add, m.Parameter(1));
1662 Node* sub = m.Float64Sub(mul, add);
1663 Node* ret = m.Float64Div(mul, sub);
1664 m.Return(ret);
1665 Stream s = m.Build();
1666 ASSERT_EQ(4U, s.size());
1667 EXPECT_EQ(kSSEFloat64Add, s[0]->arch_opcode());
1668 EXPECT_EQ(kSSEFloat64Mul, s[1]->arch_opcode());
1669 EXPECT_EQ(kSSEFloat64Sub, s[2]->arch_opcode());
1670 EXPECT_EQ(kSSEFloat64Div, s[3]->arch_opcode());
1671 }
1672 }
1673
TEST_F(InstructionSelectorTest,Float32BinopArithmeticWithLoad)1674 TEST_F(InstructionSelectorTest, Float32BinopArithmeticWithLoad) {
1675 {
1676 StreamBuilder m(this, MachineType::Float32(), MachineType::Float32(),
1677 MachineType::Int64(), MachineType::Int64());
1678 Node* const p0 = m.Parameter(0);
1679 Node* const p1 = m.Parameter(1);
1680 Node* const p2 = m.Parameter(2);
1681 Node* add = m.Float32Add(
1682 p0, m.Load(MachineType::Float32(), p1, m.Int32Constant(127)));
1683 Node* sub = m.Float32Sub(
1684 add, m.Load(MachineType::Float32(), p1, m.Int32Constant(127)));
1685 Node* ret = m.Float32Mul(
1686 m.Load(MachineType::Float32(), p2, m.Int32Constant(127)), sub);
1687 m.Return(ret);
1688 Stream s = m.Build(AVX);
1689 ASSERT_EQ(3U, s.size());
1690 EXPECT_EQ(kAVXFloat32Add, s[0]->arch_opcode());
1691 ASSERT_EQ(3U, s[0]->InputCount());
1692 EXPECT_EQ(kAVXFloat32Sub, s[1]->arch_opcode());
1693 ASSERT_EQ(3U, s[1]->InputCount());
1694 EXPECT_EQ(kAVXFloat32Mul, s[2]->arch_opcode());
1695 ASSERT_EQ(3U, s[2]->InputCount());
1696 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1697 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
1698 EXPECT_EQ(s.ToVreg(p2), s.ToVreg(s[2]->InputAt(1)));
1699 }
1700 {
1701 StreamBuilder m(this, MachineType::Float32(), MachineType::Float32(),
1702 MachineType::Int64(), MachineType::Int64());
1703 Node* const p0 = m.Parameter(0);
1704 Node* const p1 = m.Parameter(1);
1705 Node* const p2 = m.Parameter(2);
1706 Node* add = m.Float32Add(
1707 p0, m.Load(MachineType::Float32(), p1, m.Int32Constant(127)));
1708 Node* sub = m.Float32Sub(
1709 add, m.Load(MachineType::Float32(), p1, m.Int32Constant(127)));
1710 Node* ret = m.Float32Mul(
1711 m.Load(MachineType::Float32(), p2, m.Int32Constant(127)), sub);
1712 m.Return(ret);
1713 Stream s = m.Build();
1714 ASSERT_EQ(3U, s.size());
1715 EXPECT_EQ(kSSEFloat32Add, s[0]->arch_opcode());
1716 ASSERT_EQ(3U, s[0]->InputCount());
1717 EXPECT_EQ(kSSEFloat32Sub, s[1]->arch_opcode());
1718 ASSERT_EQ(3U, s[1]->InputCount());
1719 EXPECT_EQ(kSSEFloat32Mul, s[2]->arch_opcode());
1720 ASSERT_EQ(3U, s[2]->InputCount());
1721 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1722 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
1723 EXPECT_EQ(s.ToVreg(p2), s.ToVreg(s[2]->InputAt(1)));
1724 }
1725 }
1726
TEST_F(InstructionSelectorTest,Float64BinopArithmeticWithLoad)1727 TEST_F(InstructionSelectorTest, Float64BinopArithmeticWithLoad) {
1728 {
1729 StreamBuilder m(this, MachineType::Float64(), MachineType::Float64(),
1730 MachineType::Int64(), MachineType::Int64());
1731 Node* const p0 = m.Parameter(0);
1732 Node* const p1 = m.Parameter(1);
1733 Node* const p2 = m.Parameter(2);
1734 Node* add = m.Float64Add(
1735 p0, m.Load(MachineType::Float64(), p1, m.Int32Constant(127)));
1736 Node* sub = m.Float64Sub(
1737 add, m.Load(MachineType::Float64(), p1, m.Int32Constant(127)));
1738 Node* ret = m.Float64Mul(
1739 m.Load(MachineType::Float64(), p2, m.Int32Constant(127)), sub);
1740 m.Return(ret);
1741 Stream s = m.Build(AVX);
1742 ASSERT_EQ(3U, s.size());
1743 EXPECT_EQ(kAVXFloat64Add, s[0]->arch_opcode());
1744 ASSERT_EQ(3U, s[0]->InputCount());
1745 EXPECT_EQ(kAVXFloat64Sub, s[1]->arch_opcode());
1746 ASSERT_EQ(3U, s[1]->InputCount());
1747 EXPECT_EQ(kAVXFloat64Mul, s[2]->arch_opcode());
1748 ASSERT_EQ(3U, s[2]->InputCount());
1749 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1750 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
1751 EXPECT_EQ(s.ToVreg(p2), s.ToVreg(s[2]->InputAt(1)));
1752 }
1753 {
1754 StreamBuilder m(this, MachineType::Float64(), MachineType::Float64(),
1755 MachineType::Int64(), MachineType::Int64());
1756 Node* const p0 = m.Parameter(0);
1757 Node* const p1 = m.Parameter(1);
1758 Node* const p2 = m.Parameter(2);
1759 Node* add = m.Float64Add(
1760 p0, m.Load(MachineType::Float64(), p1, m.Int32Constant(127)));
1761 Node* sub = m.Float64Sub(
1762 add, m.Load(MachineType::Float64(), p1, m.Int32Constant(127)));
1763 Node* ret = m.Float64Mul(
1764 m.Load(MachineType::Float64(), p2, m.Int32Constant(127)), sub);
1765 m.Return(ret);
1766 Stream s = m.Build();
1767 ASSERT_EQ(3U, s.size());
1768 EXPECT_EQ(kSSEFloat64Add, s[0]->arch_opcode());
1769 ASSERT_EQ(3U, s[0]->InputCount());
1770 EXPECT_EQ(kSSEFloat64Sub, s[1]->arch_opcode());
1771 ASSERT_EQ(3U, s[1]->InputCount());
1772 EXPECT_EQ(kSSEFloat64Mul, s[2]->arch_opcode());
1773 ASSERT_EQ(3U, s[2]->InputCount());
1774 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1775 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
1776 EXPECT_EQ(s.ToVreg(p2), s.ToVreg(s[2]->InputAt(1)));
1777 }
1778 }
1779
1780 // -----------------------------------------------------------------------------
1781 // Miscellaneous.
1782
1783
TEST_F(InstructionSelectorTest,Word64ShlWithChangeInt32ToInt64)1784 TEST_F(InstructionSelectorTest, Word64ShlWithChangeInt32ToInt64) {
1785 TRACED_FORRANGE(int64_t, x, 32, 63) {
1786 StreamBuilder m(this, MachineType::Int64(), MachineType::Int32());
1787 Node* const p0 = m.Parameter(0);
1788 Node* const n = m.Word64Shl(m.ChangeInt32ToInt64(p0), m.Int64Constant(x));
1789 m.Return(n);
1790 Stream s = m.Build();
1791 ASSERT_EQ(1U, s.size());
1792 EXPECT_EQ(kX64Shl, s[0]->arch_opcode());
1793 ASSERT_EQ(2U, s[0]->InputCount());
1794 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1795 EXPECT_EQ(x, s.ToInt32(s[0]->InputAt(1)));
1796 ASSERT_EQ(1U, s[0]->OutputCount());
1797 EXPECT_TRUE(s.IsSameAsFirst(s[0]->Output()));
1798 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
1799 }
1800 }
1801
1802
TEST_F(InstructionSelectorTest,Word64ShlWithChangeUint32ToUint64)1803 TEST_F(InstructionSelectorTest, Word64ShlWithChangeUint32ToUint64) {
1804 TRACED_FORRANGE(int64_t, x, 32, 63) {
1805 StreamBuilder m(this, MachineType::Int64(), MachineType::Uint32());
1806 Node* const p0 = m.Parameter(0);
1807 Node* const n = m.Word64Shl(m.ChangeUint32ToUint64(p0), m.Int64Constant(x));
1808 m.Return(n);
1809 Stream s = m.Build();
1810 ASSERT_EQ(1U, s.size());
1811 EXPECT_EQ(kX64Shl, s[0]->arch_opcode());
1812 ASSERT_EQ(2U, s[0]->InputCount());
1813 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1814 EXPECT_EQ(x, s.ToInt32(s[0]->InputAt(1)));
1815 ASSERT_EQ(1U, s[0]->OutputCount());
1816 EXPECT_TRUE(s.IsSameAsFirst(s[0]->Output()));
1817 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
1818 }
1819 }
1820
TEST_F(InstructionSelectorTest,Word32AndWith0xFF)1821 TEST_F(InstructionSelectorTest, Word32AndWith0xFF) {
1822 {
1823 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
1824 Node* const p0 = m.Parameter(0);
1825 Node* const n = m.Word32And(p0, m.Int32Constant(0xFF));
1826 m.Return(n);
1827 Stream s = m.Build();
1828 ASSERT_EQ(1U, s.size());
1829 EXPECT_EQ(kX64Movzxbl, s[0]->arch_opcode());
1830 ASSERT_EQ(1U, s[0]->InputCount());
1831 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1832 ASSERT_EQ(1U, s[0]->OutputCount());
1833 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
1834 }
1835 {
1836 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
1837 Node* const p0 = m.Parameter(0);
1838 Node* const n = m.Word32And(m.Int32Constant(0xFF), p0);
1839 m.Return(n);
1840 Stream s = m.Build();
1841 ASSERT_EQ(1U, s.size());
1842 EXPECT_EQ(kX64Movzxbl, s[0]->arch_opcode());
1843 ASSERT_EQ(1U, s[0]->InputCount());
1844 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1845 ASSERT_EQ(1U, s[0]->OutputCount());
1846 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
1847 }
1848 }
1849
TEST_F(InstructionSelectorTest,Word32AndWith0xFFFF)1850 TEST_F(InstructionSelectorTest, Word32AndWith0xFFFF) {
1851 {
1852 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
1853 Node* const p0 = m.Parameter(0);
1854 Node* const n = m.Word32And(p0, m.Int32Constant(0xFFFF));
1855 m.Return(n);
1856 Stream s = m.Build();
1857 ASSERT_EQ(1U, s.size());
1858 EXPECT_EQ(kX64Movzxwl, s[0]->arch_opcode());
1859 ASSERT_EQ(1U, s[0]->InputCount());
1860 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1861 ASSERT_EQ(1U, s[0]->OutputCount());
1862 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
1863 }
1864 {
1865 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
1866 Node* const p0 = m.Parameter(0);
1867 Node* const n = m.Word32And(m.Int32Constant(0xFFFF), p0);
1868 m.Return(n);
1869 Stream s = m.Build();
1870 ASSERT_EQ(1U, s.size());
1871 EXPECT_EQ(kX64Movzxwl, s[0]->arch_opcode());
1872 ASSERT_EQ(1U, s[0]->InputCount());
1873 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1874 ASSERT_EQ(1U, s[0]->OutputCount());
1875 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
1876 }
1877 }
1878
1879
TEST_F(InstructionSelectorTest,Word32Clz)1880 TEST_F(InstructionSelectorTest, Word32Clz) {
1881 StreamBuilder m(this, MachineType::Uint32(), MachineType::Uint32());
1882 Node* const p0 = m.Parameter(0);
1883 Node* const n = m.Word32Clz(p0);
1884 m.Return(n);
1885 Stream s = m.Build();
1886 ASSERT_EQ(1U, s.size());
1887 EXPECT_EQ(kX64Lzcnt32, s[0]->arch_opcode());
1888 ASSERT_EQ(1U, s[0]->InputCount());
1889 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1890 ASSERT_EQ(1U, s[0]->OutputCount());
1891 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
1892 }
1893
TEST_F(InstructionSelectorTest,LoadAndWord64ShiftRight32)1894 TEST_F(InstructionSelectorTest, LoadAndWord64ShiftRight32) {
1895 {
1896 StreamBuilder m(this, MachineType::Uint64(), MachineType::Uint32());
1897 Node* const p0 = m.Parameter(0);
1898 Node* const load = m.Load(MachineType::Uint64(), p0);
1899 Node* const shift = m.Word64Shr(load, m.Int32Constant(32));
1900 m.Return(shift);
1901 Stream s = m.Build();
1902 ASSERT_EQ(1U, s.size());
1903 EXPECT_EQ(kX64Movl, s[0]->arch_opcode());
1904 ASSERT_EQ(2U, s[0]->InputCount());
1905 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1906 EXPECT_EQ(4, s.ToInt32(s[0]->InputAt(1)));
1907 ASSERT_EQ(1U, s[0]->OutputCount());
1908 EXPECT_EQ(s.ToVreg(shift), s.ToVreg(s[0]->Output()));
1909 }
1910 {
1911 StreamBuilder m(this, MachineType::Int64(), MachineType::Int32());
1912 Node* const p0 = m.Parameter(0);
1913 Node* const load = m.Load(MachineType::Int64(), p0);
1914 Node* const shift = m.Word64Sar(load, m.Int32Constant(32));
1915 m.Return(shift);
1916 Stream s = m.Build();
1917 ASSERT_EQ(1U, s.size());
1918 EXPECT_EQ(kX64Movsxlq, s[0]->arch_opcode());
1919 ASSERT_EQ(2U, s[0]->InputCount());
1920 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1921 EXPECT_EQ(4, s.ToInt32(s[0]->InputAt(1)));
1922 ASSERT_EQ(1U, s[0]->OutputCount());
1923 EXPECT_EQ(s.ToVreg(shift), s.ToVreg(s[0]->Output()));
1924 }
1925 {
1926 StreamBuilder m(this, MachineType::Int64(), MachineType::Int32());
1927 Node* const p0 = m.Parameter(0);
1928 Node* const load = m.Load(MachineType::Int64(), p0);
1929 Node* const shift = m.Word64Sar(load, m.Int32Constant(32));
1930 Node* const truncate = m.TruncateInt64ToInt32(shift);
1931 m.Return(truncate);
1932 Stream s = m.Build();
1933 ASSERT_EQ(1U, s.size());
1934 EXPECT_EQ(kX64Movl, s[0]->arch_opcode());
1935 ASSERT_EQ(2U, s[0]->InputCount());
1936 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1937 EXPECT_EQ(4, s.ToInt32(s[0]->InputAt(1)));
1938 ASSERT_EQ(1U, s[0]->OutputCount());
1939 EXPECT_EQ(s.ToVreg(shift), s.ToVreg(s[0]->Output()));
1940 }
1941 }
1942
1943 // -----------------------------------------------------------------------------
1944 // SIMD.
1945
TEST_F(InstructionSelectorTest,SIMDSplatZero)1946 TEST_F(InstructionSelectorTest, SIMDSplatZero) {
1947 // Test optimization for splat of contant 0.
1948 // {i8x16,i16x8,i32x4,i64x2}.splat(const(0)) -> v128.zero().
1949 // Optimizations for f32x4.splat and f64x2.splat not implemented since it
1950 // doesn't improve the codegen as much (same number of instructions).
1951 {
1952 StreamBuilder m(this, MachineType::Simd128());
1953 Node* const splat = m.I64x2Splat(m.Int64Constant(0));
1954 m.Return(splat);
1955 Stream s = m.Build();
1956 ASSERT_EQ(1U, s.size());
1957 EXPECT_EQ(kX64S128Zero, s[0]->arch_opcode());
1958 ASSERT_EQ(0U, s[0]->InputCount());
1959 EXPECT_EQ(1U, s[0]->OutputCount());
1960 }
1961 {
1962 StreamBuilder m(this, MachineType::Simd128());
1963 Node* const splat = m.I32x4Splat(m.Int32Constant(0));
1964 m.Return(splat);
1965 Stream s = m.Build();
1966 ASSERT_EQ(1U, s.size());
1967 EXPECT_EQ(kX64S128Zero, s[0]->arch_opcode());
1968 ASSERT_EQ(0U, s[0]->InputCount());
1969 EXPECT_EQ(1U, s[0]->OutputCount());
1970 }
1971 {
1972 StreamBuilder m(this, MachineType::Simd128());
1973 Node* const splat = m.I16x8Splat(m.Int32Constant(0));
1974 m.Return(splat);
1975 Stream s = m.Build();
1976 ASSERT_EQ(1U, s.size());
1977 EXPECT_EQ(kX64S128Zero, s[0]->arch_opcode());
1978 ASSERT_EQ(0U, s[0]->InputCount());
1979 EXPECT_EQ(1U, s[0]->OutputCount());
1980 }
1981 {
1982 StreamBuilder m(this, MachineType::Simd128());
1983 Node* const splat = m.I8x16Splat(m.Int32Constant(0));
1984 m.Return(splat);
1985 Stream s = m.Build();
1986 ASSERT_EQ(1U, s.size());
1987 EXPECT_EQ(kX64S128Zero, s[0]->arch_opcode());
1988 ASSERT_EQ(0U, s[0]->InputCount());
1989 EXPECT_EQ(1U, s[0]->OutputCount());
1990 }
1991 }
1992
1993 #if V8_ENABLE_WEBASSEMBLY
1994 struct ArchShuffle {
1995 uint8_t shuffle[kSimd128Size];
1996 ArchOpcode arch_opcode;
1997 size_t input_count;
1998 };
1999
2000 static constexpr ArchShuffle kArchShuffles[] = {
2001 // These are architecture specific shuffles defined in
2002 // instruction-selecor-x64.cc arch_shuffles.
2003 {
2004 {0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 23},
2005 kX64S64x2UnpackLow,
2006 2,
2007 },
2008 {
2009 {8, 9, 10, 11, 12, 13, 14, 15, 24, 25, 26, 27, 28, 29, 30, 31},
2010 kX64S64x2UnpackHigh,
2011 2,
2012 },
2013 {
2014 {0, 1, 2, 3, 16, 17, 18, 19, 4, 5, 6, 7, 20, 21, 22, 23},
2015 kX64S32x4UnpackLow,
2016 2,
2017 },
2018 {
2019 {8, 9, 10, 11, 24, 25, 26, 27, 12, 13, 14, 15, 28, 29, 30, 31},
2020 kX64S32x4UnpackHigh,
2021 2,
2022 },
2023 {
2024 {0, 1, 16, 17, 2, 3, 18, 19, 4, 5, 20, 21, 6, 7, 22, 23},
2025 kX64S16x8UnpackLow,
2026 2,
2027 },
2028 {
2029 {8, 9, 24, 25, 10, 11, 26, 27, 12, 13, 28, 29, 14, 15, 30, 31},
2030 kX64S16x8UnpackHigh,
2031 2,
2032 },
2033 {
2034 {0, 16, 1, 17, 2, 18, 3, 19, 4, 20, 5, 21, 6, 22, 7, 23},
2035 kX64S8x16UnpackLow,
2036 2,
2037 },
2038 {
2039 {8, 24, 9, 25, 10, 26, 11, 27, 12, 28, 13, 29, 14, 30, 15, 31},
2040 kX64S8x16UnpackHigh,
2041 2,
2042 },
2043 {
2044 {0, 1, 4, 5, 8, 9, 12, 13, 16, 17, 20, 21, 24, 25, 28, 29},
2045 kX64S16x8UnzipLow,
2046 2,
2047 },
2048 {
2049 {2, 3, 6, 7, 10, 11, 14, 15, 18, 19, 22, 23, 26, 27, 30, 31},
2050 kX64S16x8UnzipHigh,
2051 2,
2052 },
2053 {
2054 {0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30},
2055 kX64S8x16UnzipLow,
2056 2,
2057 },
2058 {
2059 {1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31},
2060 kX64S8x16UnzipHigh,
2061 2,
2062 },
2063 {
2064 {0, 16, 2, 18, 4, 20, 6, 22, 8, 24, 10, 26, 12, 28, 14, 30},
2065 kX64S8x16TransposeLow,
2066 2,
2067 },
2068 {
2069 {1, 17, 3, 19, 5, 21, 7, 23, 9, 25, 11, 27, 13, 29, 15, 31},
2070 kX64S8x16TransposeHigh,
2071 2,
2072 },
2073 {
2074 {7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8},
2075 kX64S8x8Reverse,
2076 1,
2077 },
2078 {
2079 {3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12},
2080 kX64S8x4Reverse,
2081 1,
2082 },
2083 {
2084 {1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14},
2085 kX64S8x2Reverse,
2086 1,
2087 },
2088 // These are matched by TryMatchConcat && TryMatch32x4Rotate.
2089 {
2090 {4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3},
2091 kX64S32x4Rotate,
2092 2,
2093 },
2094 {
2095 {8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7},
2096 kX64S32x4Rotate,
2097 2,
2098 },
2099 {
2100 {12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11},
2101 kX64S32x4Rotate,
2102 2,
2103 },
2104 // These are matched by TryMatchConcat && !TryMatch32x4Rotate.
2105 {
2106 {3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2},
2107 kX64S8x16Alignr,
2108 3,
2109 },
2110 {
2111 {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1},
2112 kX64S8x16Alignr,
2113 3,
2114 },
2115 {
2116 {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17},
2117 kX64S8x16Alignr,
2118 3,
2119 },
2120 // These are matched by TryMatch32x4Shuffle && is_swizzle.
2121 {
2122 {0, 1, 2, 3, 8, 9, 10, 11, 4, 5, 6, 7, 12, 13, 14, 15},
2123 kX64S32x4Swizzle,
2124 2,
2125 },
2126 {
2127 {0, 1, 2, 3, 4, 5, 6, 7, 12, 13, 14, 15, 8, 9, 10, 11},
2128 kX64S32x4Swizzle,
2129 2,
2130 },
2131 // These are matched by TryMatch32x4Shuffle && !is_swizzle && TryMatchBlend.
2132 {
2133 {0, 1, 2, 3, 20, 21, 22, 23, 8, 9, 10, 11, 28, 29, 30, 31},
2134 kX64S16x8Blend,
2135 3,
2136 },
2137 {
2138 {16, 17, 18, 19, 4, 5, 6, 7, 24, 25, 26, 27, 12, 13, 14, 15},
2139 kX64S16x8Blend,
2140 3,
2141 },
2142 // These are matched by TryMatch32x4Shuffle && !is_swizzle &&
2143 // TryMatchShufps.
2144 {
2145 {0, 1, 2, 3, 8, 9, 10, 11, 28, 29, 30, 31, 28, 29, 30, 31},
2146 kX64Shufps,
2147 3,
2148 },
2149 {
2150 {8, 9, 10, 11, 0, 1, 2, 3, 28, 29, 30, 31, 28, 29, 30, 31},
2151 kX64Shufps,
2152 3,
2153 },
2154 // These are matched by TryMatch32x4Shuffle && !is_swizzle.
2155 {
2156 {28, 29, 30, 31, 0, 1, 2, 3, 28, 29, 30, 31, 28, 29, 30, 31},
2157 kX64S32x4Shuffle,
2158 4,
2159 },
2160 // These are matched by TryMatch16x8Shuffle && TryMatchBlend.
2161 {
2162 {16, 17, 2, 3, 4, 5, 6, 7, 24, 25, 26, 27, 12, 13, 14, 15},
2163 kX64S16x8Blend,
2164 3,
2165 },
2166 // These are matched by TryMatch16x8Shuffle && TryMatchSplat<8>.
2167 {
2168 {2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3},
2169 kX64S16x8Dup,
2170 2,
2171 },
2172 // These are matched by TryMatch16x8Shuffle && TryMatch16x8HalfShuffle.
2173 {
2174 {6, 7, 4, 5, 2, 3, 0, 1, 14, 15, 12, 13, 10, 11, 8, 9},
2175 kX64S16x8HalfShuffle1,
2176 3,
2177 },
2178 {
2179 {6, 7, 4, 5, 2, 3, 0, 1, 30, 31, 28, 29, 26, 27, 24, 25},
2180 kX64S16x8HalfShuffle2,
2181 5,
2182 },
2183 // These are matched by TryMatchSplat<16>.
2184 {
2185 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
2186 kX64S8x16Dup,
2187 2,
2188 },
2189 // Generic shuffle that only uses 1 input.
2190 {
2191 {1, 15, 2, 14, 3, 13, 4, 12, 5, 11, 6, 10, 7, 9, 8},
2192 kX64I8x16Shuffle,
2193 5,
2194 },
2195 // Generic shuffle that uses both input.
2196 {
2197 {1, 31, 2, 14, 3, 13, 4, 12, 5, 11, 6, 10, 7, 9, 8},
2198 kX64I8x16Shuffle,
2199 6,
2200 },
2201 };
2202
2203 using InstructionSelectorSIMDArchShuffleTest =
2204 InstructionSelectorTestWithParam<ArchShuffle>;
2205
TEST_P(InstructionSelectorSIMDArchShuffleTest,SIMDArchShuffle)2206 TEST_P(InstructionSelectorSIMDArchShuffleTest, SIMDArchShuffle) {
2207 MachineType type = MachineType::Simd128();
2208 {
2209 // Tests various shuffle optimizations
2210 StreamBuilder m(this, type, type, type);
2211 auto param = GetParam();
2212 auto shuffle = param.shuffle;
2213 const Operator* op = m.machine()->I8x16Shuffle(shuffle);
2214 Node* n = m.AddNode(op, m.Parameter(0), m.Parameter(1));
2215 m.Return(n);
2216 Stream s = m.Build();
2217 ASSERT_EQ(1U, s.size());
2218 EXPECT_EQ(param.arch_opcode, s[0]->arch_opcode());
2219 ASSERT_EQ(param.input_count, s[0]->InputCount());
2220 EXPECT_EQ(1U, s[0]->OutputCount());
2221 }
2222 }
2223
2224 INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest,
2225 InstructionSelectorSIMDArchShuffleTest,
2226 ::testing::ValuesIn(kArchShuffles));
2227 #endif // V8_ENABLE_WEBASSEMBLY
2228
2229 struct SwizzleConstants {
2230 uint8_t shuffle[kSimd128Size];
2231 bool omit_add;
2232 };
2233
2234 static constexpr SwizzleConstants kSwizzleConstants[] = {
2235 {
2236 // all lanes < kSimd128Size
2237 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
2238 true,
2239 },
2240 {
2241 // lanes that are >= kSimd128Size have top bit set
2242 {12, 13, 14, 15, 0x90, 0x91, 0x92, 0x93, 0xA0, 0xA1, 0xA2, 0xA3, 0xFC,
2243 0xFD, 0xFE, 0xFF},
2244 true,
2245 },
2246 {
2247 {12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27},
2248 false,
2249 },
2250 };
2251
2252 using InstructionSelectorSIMDSwizzleConstantTest =
2253 InstructionSelectorTestWithParam<SwizzleConstants>;
2254
TEST_P(InstructionSelectorSIMDSwizzleConstantTest,SimdSwizzleConstant)2255 TEST_P(InstructionSelectorSIMDSwizzleConstantTest, SimdSwizzleConstant) {
2256 // Test optimization of swizzle with constant indices.
2257 auto param = GetParam();
2258 StreamBuilder m(this, MachineType::Simd128(), MachineType::Simd128());
2259 Node* const c = m.S128Const(param.shuffle);
2260 Node* swizzle = m.AddNode(m.machine()->I8x16Swizzle(), m.Parameter(0), c);
2261 m.Return(swizzle);
2262 Stream s = m.Build();
2263 ASSERT_EQ(2U, s.size());
2264 ASSERT_EQ(kX64I8x16Swizzle, s[1]->arch_opcode());
2265 ASSERT_EQ(param.omit_add, s[1]->misc());
2266 ASSERT_EQ(1U, s[0]->OutputCount());
2267 }
2268
2269 INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest,
2270 InstructionSelectorSIMDSwizzleConstantTest,
2271 ::testing::ValuesIn(kSwizzleConstants));
2272
TEST_F(InstructionSelectorTest,F64x2PromoteLowF32x4WithS128Load64Zero)2273 TEST_F(InstructionSelectorTest, F64x2PromoteLowF32x4WithS128Load64Zero) {
2274 StreamBuilder m(this, MachineType::Simd128(), MachineType::Int32());
2275 Node* const load =
2276 m.AddNode(m.machine()->LoadTransform(MemoryAccessKind::kProtected,
2277 LoadTransformation::kS128Load64Zero),
2278 m.Int32Constant(2), m.Parameter(0));
2279 Node* const promote = m.AddNode(m.machine()->F64x2PromoteLowF32x4(), load);
2280 m.Return(promote);
2281 Stream s = m.Build();
2282 ASSERT_EQ(1U, s.size());
2283 ASSERT_EQ(kX64F64x2PromoteLowF32x4, s[0]->arch_opcode());
2284 ASSERT_EQ(kMode_MRI, s[0]->addressing_mode());
2285 EXPECT_EQ(2U, s[0]->InputCount());
2286 EXPECT_EQ(1U, s[0]->OutputCount());
2287 }
2288
2289 } // namespace compiler
2290 } // namespace internal
2291 } // namespace v8
2292