Line data Source code
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/compiler/node-matchers.h"
8 : #include "src/objects-inl.h"
9 :
10 : namespace v8 {
11 : namespace internal {
12 : namespace compiler {
13 :
14 : // -----------------------------------------------------------------------------
15 : // Conversions.
16 :
17 :
18 15128 : TEST_F(InstructionSelectorTest, ChangeFloat32ToFloat64WithParameter) {
19 1 : StreamBuilder m(this, MachineType::Float32(), MachineType::Float64());
20 1 : m.Return(m.ChangeFloat32ToFloat64(m.Parameter(0)));
21 1 : Stream s = m.Build();
22 3 : ASSERT_EQ(1U, s.size());
23 3 : EXPECT_EQ(kSSEFloat32ToFloat64, s[0]->arch_opcode());
24 3 : EXPECT_EQ(1U, s[0]->InputCount());
25 3 : EXPECT_EQ(1U, s[0]->OutputCount());
26 : }
27 :
28 :
29 15128 : TEST_F(InstructionSelectorTest, ChangeInt32ToInt64WithParameter) {
30 1 : StreamBuilder m(this, MachineType::Int64(), MachineType::Int32());
31 1 : m.Return(m.ChangeInt32ToInt64(m.Parameter(0)));
32 1 : Stream s = m.Build();
33 3 : ASSERT_EQ(1U, s.size());
34 3 : EXPECT_EQ(kX64Movsxlq, s[0]->arch_opcode());
35 : }
36 :
37 15128 : TEST_F(InstructionSelectorTest, ChangeUint32ToFloat64WithParameter) {
38 1 : StreamBuilder m(this, MachineType::Float64(), MachineType::Uint32());
39 1 : m.Return(m.ChangeUint32ToFloat64(m.Parameter(0)));
40 1 : Stream s = m.Build();
41 3 : ASSERT_EQ(1U, s.size());
42 3 : EXPECT_EQ(kSSEUint32ToFloat64, s[0]->arch_opcode());
43 : }
44 :
45 :
46 15128 : TEST_F(InstructionSelectorTest, ChangeUint32ToUint64WithParameter) {
47 1 : StreamBuilder m(this, MachineType::Uint64(), MachineType::Uint32());
48 1 : m.Return(m.ChangeUint32ToUint64(m.Parameter(0)));
49 1 : Stream s = m.Build();
50 3 : ASSERT_EQ(1U, s.size());
51 3 : EXPECT_EQ(kX64Movl, s[0]->arch_opcode());
52 : }
53 :
54 :
55 15128 : TEST_F(InstructionSelectorTest, TruncateFloat64ToFloat32WithParameter) {
56 1 : StreamBuilder m(this, MachineType::Float64(), MachineType::Float32());
57 1 : m.Return(m.TruncateFloat64ToFloat32(m.Parameter(0)));
58 1 : Stream s = m.Build();
59 3 : ASSERT_EQ(1U, s.size());
60 3 : EXPECT_EQ(kSSEFloat64ToFloat32, s[0]->arch_opcode());
61 3 : EXPECT_EQ(1U, s[0]->InputCount());
62 3 : EXPECT_EQ(1U, s[0]->OutputCount());
63 : }
64 :
65 :
66 15128 : TEST_F(InstructionSelectorTest, TruncateInt64ToInt32WithParameter) {
67 1 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int64());
68 1 : m.Return(m.TruncateInt64ToInt32(m.Parameter(0)));
69 1 : Stream s = m.Build();
70 3 : ASSERT_EQ(1U, s.size());
71 3 : EXPECT_EQ(kX64Movl, s[0]->arch_opcode());
72 : }
73 :
74 : namespace {
75 : struct LoadWithToInt64Extension {
76 : MachineType type;
77 : ArchOpcode expected_opcode;
78 : };
79 :
80 : std::ostream& operator<<(std::ostream& os,
81 : const LoadWithToInt64Extension& i32toi64) {
82 15125 : return os << i32toi64.type;
83 : }
84 :
85 : static const LoadWithToInt64Extension kLoadWithToInt64Extensions[] = {
86 : {MachineType::Int8(), kX64Movsxbq},
87 : {MachineType::Uint8(), kX64Movzxbq},
88 : {MachineType::Int16(), kX64Movsxwq},
89 : {MachineType::Uint16(), kX64Movzxwq},
90 : {MachineType::Int32(), kX64Movsxlq}};
91 :
92 : } // namespace
93 :
94 : typedef InstructionSelectorTestWithParam<LoadWithToInt64Extension>
95 : InstructionSelectorChangeInt32ToInt64Test;
96 :
97 18170 : TEST_P(InstructionSelectorChangeInt32ToInt64Test, ChangeInt32ToInt64WithLoad) {
98 5 : const LoadWithToInt64Extension extension = GetParam();
99 5 : StreamBuilder m(this, MachineType::Int64(), MachineType::Pointer());
100 5 : m.Return(m.ChangeInt32ToInt64(m.Load(extension.type, m.Parameter(0))));
101 5 : Stream s = m.Build();
102 15 : ASSERT_EQ(1U, s.size());
103 15 : EXPECT_EQ(extension.expected_opcode, s[0]->arch_opcode());
104 : }
105 :
106 36300 : INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
107 : InstructionSelectorChangeInt32ToInt64Test,
108 : ::testing::ValuesIn(kLoadWithToInt64Extensions));
109 :
110 : // -----------------------------------------------------------------------------
111 : // Loads and stores
112 :
113 :
114 : namespace {
115 :
116 : struct MemoryAccess {
117 : MachineType type;
118 : ArchOpcode load_opcode;
119 : ArchOpcode store_opcode;
120 : };
121 :
122 :
123 : std::ostream& operator<<(std::ostream& os, const MemoryAccess& memacc) {
124 60500 : return os << memacc.type;
125 : }
126 :
127 :
128 : static const MemoryAccess kMemoryAccesses[] = {
129 : {MachineType::Int8(), kX64Movsxbl, kX64Movb},
130 : {MachineType::Uint8(), kX64Movzxbl, kX64Movb},
131 : {MachineType::Int16(), kX64Movsxwl, kX64Movw},
132 : {MachineType::Uint16(), kX64Movzxwl, kX64Movw},
133 : {MachineType::Int32(), kX64Movl, kX64Movl},
134 : {MachineType::Uint32(), kX64Movl, kX64Movl},
135 : {MachineType::Int64(), kX64Movq, kX64Movq},
136 : {MachineType::Uint64(), kX64Movq, kX64Movq},
137 : {MachineType::Float32(), kX64Movss, kX64Movss},
138 : {MachineType::Float64(), kX64Movsd, kX64Movsd}};
139 :
140 : } // namespace
141 :
142 :
143 : typedef InstructionSelectorTestWithParam<MemoryAccess>
144 : InstructionSelectorMemoryAccessTest;
145 :
146 :
147 18190 : TEST_P(InstructionSelectorMemoryAccessTest, LoadWithParameters) {
148 10 : const MemoryAccess memacc = GetParam();
149 : StreamBuilder m(this, memacc.type, MachineType::Pointer(),
150 10 : MachineType::Int32());
151 10 : m.Return(m.Load(memacc.type, m.Parameter(0), m.Parameter(1)));
152 10 : Stream s = m.Build();
153 30 : ASSERT_EQ(1U, s.size());
154 30 : EXPECT_EQ(memacc.load_opcode, s[0]->arch_opcode());
155 30 : EXPECT_EQ(2U, s[0]->InputCount());
156 30 : EXPECT_EQ(1U, s[0]->OutputCount());
157 : }
158 :
159 :
160 18190 : TEST_P(InstructionSelectorMemoryAccessTest, StoreWithParameters) {
161 10 : const MemoryAccess memacc = GetParam();
162 : StreamBuilder m(this, MachineType::Int32(), MachineType::Pointer(),
163 10 : MachineType::Int32(), memacc.type);
164 : m.Store(memacc.type.representation(), m.Parameter(0), m.Parameter(1),
165 10 : m.Parameter(2), kNoWriteBarrier);
166 10 : m.Return(m.Int32Constant(0));
167 10 : Stream s = m.Build();
168 30 : ASSERT_EQ(1U, s.size());
169 30 : EXPECT_EQ(memacc.store_opcode, s[0]->arch_opcode());
170 30 : EXPECT_EQ(3U, s[0]->InputCount());
171 30 : EXPECT_EQ(0U, s[0]->OutputCount());
172 : }
173 :
174 :
175 87725 : INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
176 : InstructionSelectorMemoryAccessTest,
177 : ::testing::ValuesIn(kMemoryAccesses));
178 :
179 :
180 : // -----------------------------------------------------------------------------
181 : // ChangeUint32ToUint64.
182 :
183 :
184 : namespace {
185 :
186 : typedef Node* (RawMachineAssembler::*Constructor)(Node*, Node*);
187 :
188 :
189 : struct BinaryOperation {
190 : Constructor constructor;
191 : const char* constructor_name;
192 : };
193 :
194 :
195 : std::ostream& operator<<(std::ostream& os, const BinaryOperation& bop) {
196 60500 : return os << bop.constructor_name;
197 : }
198 :
199 :
200 : const BinaryOperation kWord32BinaryOperations[] = {
201 : {&RawMachineAssembler::Word32And, "Word32And"},
202 : {&RawMachineAssembler::Word32Or, "Word32Or"},
203 : {&RawMachineAssembler::Word32Xor, "Word32Xor"},
204 : {&RawMachineAssembler::Word32Shl, "Word32Shl"},
205 : {&RawMachineAssembler::Word32Shr, "Word32Shr"},
206 : {&RawMachineAssembler::Word32Sar, "Word32Sar"},
207 : {&RawMachineAssembler::Word32Ror, "Word32Ror"},
208 : {&RawMachineAssembler::Word32Equal, "Word32Equal"},
209 : {&RawMachineAssembler::Int32Add, "Int32Add"},
210 : {&RawMachineAssembler::Int32Sub, "Int32Sub"},
211 : {&RawMachineAssembler::Int32Mul, "Int32Mul"},
212 : {&RawMachineAssembler::Int32MulHigh, "Int32MulHigh"},
213 : {&RawMachineAssembler::Int32Div, "Int32Div"},
214 : {&RawMachineAssembler::Int32LessThan, "Int32LessThan"},
215 : {&RawMachineAssembler::Int32LessThanOrEqual, "Int32LessThanOrEqual"},
216 : {&RawMachineAssembler::Int32Mod, "Int32Mod"},
217 : {&RawMachineAssembler::Uint32Div, "Uint32Div"},
218 : {&RawMachineAssembler::Uint32LessThan, "Uint32LessThan"},
219 : {&RawMachineAssembler::Uint32LessThanOrEqual, "Uint32LessThanOrEqual"},
220 : {&RawMachineAssembler::Uint32Mod, "Uint32Mod"}};
221 :
222 : } // namespace
223 :
224 :
225 : typedef InstructionSelectorTestWithParam<BinaryOperation>
226 : InstructionSelectorChangeUint32ToUint64Test;
227 :
228 :
229 18230 : TEST_P(InstructionSelectorChangeUint32ToUint64Test, ChangeUint32ToUint64) {
230 20 : const BinaryOperation& bop = GetParam();
231 : StreamBuilder m(this, MachineType::Uint64(), MachineType::Int32(),
232 20 : MachineType::Int32());
233 20 : Node* const p0 = m.Parameter(0);
234 20 : Node* const p1 = m.Parameter(1);
235 20 : m.Return(m.ChangeUint32ToUint64((m.*bop.constructor)(p0, p1)));
236 20 : Stream s = m.Build();
237 60 : ASSERT_EQ(1U, s.size());
238 : }
239 :
240 :
241 81675 : INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
242 : InstructionSelectorChangeUint32ToUint64Test,
243 : ::testing::ValuesIn(kWord32BinaryOperations));
244 :
245 : // -----------------------------------------------------------------------------
246 : // CanElideChangeUint32ToUint64
247 :
248 : namespace {
249 :
250 : template <typename T>
251 : struct MachInst {
252 : T constructor;
253 : const char* constructor_name;
254 : ArchOpcode arch_opcode;
255 : MachineType machine_type;
256 : };
257 :
258 : typedef MachInst<Node* (RawMachineAssembler::*)(Node*, Node*)> MachInst2;
259 :
260 : // X64 instructions that clear the top 32 bits of the destination.
261 : const MachInst2 kCanElideChangeUint32ToUint64[] = {
262 : {&RawMachineAssembler::Word32And, "Word32And", kX64And32,
263 : MachineType::Uint32()},
264 : {&RawMachineAssembler::Word32Or, "Word32Or", kX64Or32,
265 : MachineType::Uint32()},
266 : {&RawMachineAssembler::Word32Xor, "Word32Xor", kX64Xor32,
267 : MachineType::Uint32()},
268 : {&RawMachineAssembler::Word32Shl, "Word32Shl", kX64Shl32,
269 : MachineType::Uint32()},
270 : {&RawMachineAssembler::Word32Shr, "Word32Shr", kX64Shr32,
271 : MachineType::Uint32()},
272 : {&RawMachineAssembler::Word32Sar, "Word32Sar", kX64Sar32,
273 : MachineType::Uint32()},
274 : {&RawMachineAssembler::Word32Ror, "Word32Ror", kX64Ror32,
275 : MachineType::Uint32()},
276 : {&RawMachineAssembler::Word32Equal, "Word32Equal", kX64Cmp32,
277 : MachineType::Uint32()},
278 : {&RawMachineAssembler::Int32Add, "Int32Add", kX64Lea32,
279 : MachineType::Int32()},
280 : {&RawMachineAssembler::Int32Sub, "Int32Sub", kX64Sub32,
281 : MachineType::Int32()},
282 : {&RawMachineAssembler::Int32Mul, "Int32Mul", kX64Imul32,
283 : MachineType::Int32()},
284 : {&RawMachineAssembler::Int32MulHigh, "Int32MulHigh", kX64ImulHigh32,
285 : MachineType::Int32()},
286 : {&RawMachineAssembler::Int32Div, "Int32Div", kX64Idiv32,
287 : MachineType::Int32()},
288 : {&RawMachineAssembler::Int32LessThan, "Int32LessThan", kX64Cmp32,
289 : MachineType::Int32()},
290 : {&RawMachineAssembler::Int32LessThanOrEqual, "Int32LessThanOrEqual",
291 : kX64Cmp32, MachineType::Int32()},
292 : {&RawMachineAssembler::Int32Mod, "Int32Mod", kX64Idiv32,
293 : MachineType::Int32()},
294 : {&RawMachineAssembler::Uint32Div, "Uint32Div", kX64Udiv32,
295 : MachineType::Uint32()},
296 : {&RawMachineAssembler::Uint32LessThan, "Uint32LessThan", kX64Cmp32,
297 : MachineType::Uint32()},
298 : {&RawMachineAssembler::Uint32LessThanOrEqual, "Uint32LessThanOrEqual",
299 : kX64Cmp32, MachineType::Uint32()},
300 : {&RawMachineAssembler::Uint32Mod, "Uint32Mod", kX64Udiv32,
301 : MachineType::Uint32()},
302 : };
303 :
304 : } // namespace
305 :
306 : typedef InstructionSelectorTestWithParam<MachInst2>
307 : InstructionSelectorElidedChangeUint32ToUint64Test;
308 :
309 18230 : TEST_P(InstructionSelectorElidedChangeUint32ToUint64Test, Parameter) {
310 20 : const MachInst2 binop = GetParam();
311 : StreamBuilder m(this, MachineType::Uint64(), binop.machine_type,
312 20 : binop.machine_type);
313 : m.Return(m.ChangeUint32ToUint64(
314 20 : (m.*binop.constructor)(m.Parameter(0), m.Parameter(1))));
315 20 : Stream s = m.Build();
316 : // Make sure the `ChangeUint32ToUint64` node turned into a no-op.
317 60 : ASSERT_EQ(1U, s.size());
318 60 : EXPECT_EQ(binop.arch_opcode, s[0]->arch_opcode());
319 60 : EXPECT_EQ(2U, s[0]->InputCount());
320 60 : EXPECT_EQ(1U, s[0]->OutputCount());
321 : }
322 :
323 81675 : INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
324 : InstructionSelectorElidedChangeUint32ToUint64Test,
325 : ::testing::ValuesIn(kCanElideChangeUint32ToUint64));
326 :
327 : // ChangeUint32ToUint64AfterLoad
328 15128 : TEST_F(InstructionSelectorTest, ChangeUint32ToUint64AfterLoad) {
329 : // For each case, make sure the `ChangeUint32ToUint64` node turned into a
330 : // no-op.
331 :
332 : // movzxbl
333 : {
334 : StreamBuilder m(this, MachineType::Uint64(), MachineType::Pointer(),
335 1 : MachineType::Int32());
336 : m.Return(m.ChangeUint32ToUint64(
337 1 : m.Load(MachineType::Uint8(), m.Parameter(0), m.Parameter(1))));
338 1 : Stream s = m.Build();
339 2 : ASSERT_EQ(1U, s.size());
340 3 : EXPECT_EQ(kX64Movzxbl, s[0]->arch_opcode());
341 3 : EXPECT_EQ(kMode_MR1, s[0]->addressing_mode());
342 3 : EXPECT_EQ(2U, s[0]->InputCount());
343 3 : EXPECT_EQ(1U, s[0]->OutputCount());
344 : }
345 : // movsxbl
346 : {
347 : StreamBuilder m(this, MachineType::Uint64(), MachineType::Pointer(),
348 1 : MachineType::Int32());
349 : m.Return(m.ChangeUint32ToUint64(
350 1 : m.Load(MachineType::Int8(), m.Parameter(0), m.Parameter(1))));
351 1 : Stream s = m.Build();
352 2 : ASSERT_EQ(1U, s.size());
353 3 : EXPECT_EQ(kX64Movsxbl, s[0]->arch_opcode());
354 3 : EXPECT_EQ(kMode_MR1, s[0]->addressing_mode());
355 3 : EXPECT_EQ(2U, s[0]->InputCount());
356 3 : EXPECT_EQ(1U, s[0]->OutputCount());
357 : }
358 : // movzxwl
359 : {
360 : StreamBuilder m(this, MachineType::Uint64(), MachineType::Pointer(),
361 1 : MachineType::Int32());
362 : m.Return(m.ChangeUint32ToUint64(
363 1 : m.Load(MachineType::Uint16(), m.Parameter(0), m.Parameter(1))));
364 1 : Stream s = m.Build();
365 2 : ASSERT_EQ(1U, s.size());
366 3 : EXPECT_EQ(kX64Movzxwl, s[0]->arch_opcode());
367 3 : EXPECT_EQ(kMode_MR1, s[0]->addressing_mode());
368 3 : EXPECT_EQ(2U, s[0]->InputCount());
369 2 : EXPECT_EQ(1U, s[0]->OutputCount());
370 : }
371 : // movsxwl
372 : {
373 : StreamBuilder m(this, MachineType::Uint64(), MachineType::Pointer(),
374 1 : MachineType::Int32());
375 : m.Return(m.ChangeUint32ToUint64(
376 1 : m.Load(MachineType::Int16(), m.Parameter(0), m.Parameter(1))));
377 1 : Stream s = m.Build();
378 2 : ASSERT_EQ(1U, s.size());
379 3 : EXPECT_EQ(kX64Movsxwl, s[0]->arch_opcode());
380 3 : EXPECT_EQ(kMode_MR1, s[0]->addressing_mode());
381 3 : EXPECT_EQ(2U, s[0]->InputCount());
382 3 : EXPECT_EQ(1U, s[0]->OutputCount());
383 : }
384 : }
385 :
386 : // -----------------------------------------------------------------------------
387 : // TruncateInt64ToInt32.
388 :
389 :
390 15128 : TEST_F(InstructionSelectorTest, TruncateInt64ToInt32WithWord64Sar) {
391 1 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int64());
392 1 : Node* const p = m.Parameter(0);
393 1 : Node* const t = m.TruncateInt64ToInt32(m.Word64Sar(p, m.Int64Constant(32)));
394 1 : m.Return(t);
395 1 : Stream s = m.Build();
396 2 : ASSERT_EQ(1U, s.size());
397 3 : EXPECT_EQ(kX64Shr, s[0]->arch_opcode());
398 3 : ASSERT_EQ(2U, s[0]->InputCount());
399 3 : EXPECT_EQ(s.ToVreg(p), s.ToVreg(s[0]->InputAt(0)));
400 4 : EXPECT_EQ(32, s.ToInt32(s[0]->InputAt(1)));
401 3 : ASSERT_EQ(1U, s[0]->OutputCount());
402 2 : EXPECT_TRUE(s.IsSameAsFirst(s[0]->OutputAt(0)));
403 2 : EXPECT_EQ(s.ToVreg(t), s.ToVreg(s[0]->OutputAt(0)));
404 : }
405 :
406 :
407 15128 : TEST_F(InstructionSelectorTest, TruncateInt64ToInt32WithWord64Shr) {
408 1 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int64());
409 1 : Node* const p = m.Parameter(0);
410 1 : Node* const t = m.TruncateInt64ToInt32(m.Word64Shr(p, m.Int64Constant(32)));
411 1 : m.Return(t);
412 1 : Stream s = m.Build();
413 2 : ASSERT_EQ(1U, s.size());
414 3 : EXPECT_EQ(kX64Shr, s[0]->arch_opcode());
415 3 : ASSERT_EQ(2U, s[0]->InputCount());
416 3 : EXPECT_EQ(s.ToVreg(p), s.ToVreg(s[0]->InputAt(0)));
417 4 : EXPECT_EQ(32, s.ToInt32(s[0]->InputAt(1)));
418 3 : ASSERT_EQ(1U, s[0]->OutputCount());
419 2 : EXPECT_TRUE(s.IsSameAsFirst(s[0]->OutputAt(0)));
420 2 : EXPECT_EQ(s.ToVreg(t), s.ToVreg(s[0]->OutputAt(0)));
421 : }
422 :
423 :
424 : // -----------------------------------------------------------------------------
425 : // Addition.
426 :
427 :
428 15128 : TEST_F(InstructionSelectorTest, Int32AddWithInt32ParametersLea) {
429 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
430 1 : MachineType::Int32());
431 1 : Node* const p0 = m.Parameter(0);
432 1 : Node* const p1 = m.Parameter(1);
433 1 : Node* const a0 = m.Int32Add(p0, p1);
434 : // Additional uses of input to add chooses lea
435 1 : Node* const a1 = m.Int32Div(p0, p1);
436 1 : m.Return(m.Int32Div(a0, a1));
437 1 : Stream s = m.Build();
438 2 : ASSERT_EQ(3U, s.size());
439 3 : EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
440 3 : ASSERT_EQ(2U, s[0]->InputCount());
441 3 : EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
442 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
443 : }
444 :
445 :
446 15128 : TEST_F(InstructionSelectorTest, Int32AddConstantAsLeaSingle) {
447 1 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
448 1 : Node* const p0 = m.Parameter(0);
449 1 : Node* const c0 = m.Int32Constant(15);
450 : // If one of the add's operands is only used once, use an "leal", even though
451 : // an "addl" could be used. The "leal" has proven faster--out best guess is
452 : // that it gives the register allocation more freedom and it doesn't set
453 : // flags, reducing pressure in the CPU's pipeline. If we're lucky with
454 : // register allocation, then code generation will select an "addl" later for
455 : // the cases that have been measured to be faster.
456 1 : Node* const v0 = m.Int32Add(p0, c0);
457 1 : m.Return(v0);
458 1 : Stream s = m.Build();
459 2 : ASSERT_EQ(1U, s.size());
460 3 : EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
461 3 : EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
462 3 : ASSERT_EQ(2U, s[0]->InputCount());
463 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
464 3 : EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
465 : }
466 :
467 :
468 15128 : TEST_F(InstructionSelectorTest, Int32AddConstantAsAdd) {
469 1 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
470 1 : Node* const p0 = m.Parameter(0);
471 1 : Node* const c0 = m.Int32Constant(1);
472 : // If there is only a single use of an add's input and the immediate constant
473 : // for the add is 1, don't use an inc. It is much slower on modern Intel
474 : // architectures.
475 1 : m.Return(m.Int32Add(p0, c0));
476 1 : Stream s = m.Build();
477 2 : ASSERT_EQ(1U, s.size());
478 3 : EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
479 3 : EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
480 3 : ASSERT_EQ(2U, s[0]->InputCount());
481 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
482 3 : EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
483 : }
484 :
485 :
486 15128 : TEST_F(InstructionSelectorTest, Int32AddConstantAsLeaDouble) {
487 1 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
488 1 : Node* const p0 = m.Parameter(0);
489 1 : Node* const c0 = m.Int32Constant(15);
490 : // A second use of an add's input uses lea
491 1 : Node* const a0 = m.Int32Add(p0, c0);
492 1 : m.Return(m.Int32Div(a0, p0));
493 1 : Stream s = m.Build();
494 2 : ASSERT_EQ(2U, s.size());
495 3 : EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
496 3 : EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
497 3 : ASSERT_EQ(2U, s[0]->InputCount());
498 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
499 3 : EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
500 : }
501 :
502 :
503 15128 : TEST_F(InstructionSelectorTest, Int32AddCommutedConstantAsLeaSingle) {
504 1 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
505 1 : Node* const p0 = m.Parameter(0);
506 1 : Node* const c0 = m.Int32Constant(15);
507 : // If one of the add's operands is only used once, use an "leal", even though
508 : // an "addl" could be used. The "leal" has proven faster--out best guess is
509 : // that it gives the register allocation more freedom and it doesn't set
510 : // flags, reducing pressure in the CPU's pipeline. If we're lucky with
511 : // register allocation, then code generation will select an "addl" later for
512 : // the cases that have been measured to be faster.
513 1 : m.Return(m.Int32Add(c0, p0));
514 1 : Stream s = m.Build();
515 2 : ASSERT_EQ(1U, s.size());
516 3 : EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
517 3 : EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
518 3 : ASSERT_EQ(2U, s[0]->InputCount());
519 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
520 3 : EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
521 : }
522 :
523 :
524 15128 : TEST_F(InstructionSelectorTest, Int32AddCommutedConstantAsLeaDouble) {
525 1 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
526 1 : Node* const p0 = m.Parameter(0);
527 1 : Node* const c0 = m.Int32Constant(15);
528 : // A second use of an add's input uses lea
529 1 : Node* const a0 = m.Int32Add(c0, p0);
530 : USE(a0);
531 1 : m.Return(m.Int32Div(a0, p0));
532 1 : Stream s = m.Build();
533 2 : ASSERT_EQ(2U, s.size());
534 3 : EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
535 3 : EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
536 3 : ASSERT_EQ(2U, s[0]->InputCount());
537 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
538 3 : EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
539 : }
540 :
541 :
542 15128 : TEST_F(InstructionSelectorTest, Int32AddSimpleAsAdd) {
543 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
544 1 : MachineType::Int32());
545 1 : Node* const p0 = m.Parameter(0);
546 1 : Node* const p1 = m.Parameter(1);
547 : // If one of the add's operands is only used once, use an "leal", even though
548 : // an "addl" could be used. The "leal" has proven faster--out best guess is
549 : // that it gives the register allocation more freedom and it doesn't set
550 : // flags, reducing pressure in the CPU's pipeline. If we're lucky with
551 : // register allocation, then code generation will select an "addl" later for
552 : // the cases that have been measured to be faster.
553 1 : m.Return(m.Int32Add(p0, p1));
554 1 : Stream s = m.Build();
555 2 : ASSERT_EQ(1U, s.size());
556 3 : EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
557 3 : EXPECT_EQ(kMode_MR1, s[0]->addressing_mode());
558 3 : ASSERT_EQ(2U, s[0]->InputCount());
559 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
560 3 : EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
561 : }
562 :
563 :
564 15128 : TEST_F(InstructionSelectorTest, Int32AddSimpleAsLea) {
565 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
566 1 : MachineType::Int32());
567 1 : Node* const p0 = m.Parameter(0);
568 1 : Node* const p1 = m.Parameter(1);
569 : // If all of of the add's operands are used multiple times, use an "leal".
570 1 : Node* const v1 = m.Int32Add(p0, p1);
571 1 : m.Return(m.Int32Add(m.Int32Add(v1, p1), p0));
572 1 : Stream s = m.Build();
573 2 : ASSERT_EQ(3U, s.size());
574 3 : EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
575 3 : EXPECT_EQ(kMode_MR1, s[0]->addressing_mode());
576 3 : ASSERT_EQ(2U, s[0]->InputCount());
577 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
578 3 : EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
579 : }
580 :
581 :
582 15128 : TEST_F(InstructionSelectorTest, Int32AddScaled2Mul) {
583 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
584 1 : MachineType::Int32());
585 1 : Node* const p0 = m.Parameter(0);
586 1 : Node* const p1 = m.Parameter(1);
587 1 : Node* const s0 = m.Int32Mul(p1, m.Int32Constant(2));
588 1 : m.Return(m.Int32Add(p0, s0));
589 1 : Stream s = m.Build();
590 2 : ASSERT_EQ(1U, s.size());
591 3 : EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
592 3 : EXPECT_EQ(kMode_MR2, s[0]->addressing_mode());
593 3 : ASSERT_EQ(2U, s[0]->InputCount());
594 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
595 3 : EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
596 : }
597 :
598 :
599 15128 : TEST_F(InstructionSelectorTest, Int32AddCommutedScaled2Mul) {
600 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
601 1 : MachineType::Int32());
602 1 : Node* const p0 = m.Parameter(0);
603 1 : Node* const p1 = m.Parameter(1);
604 1 : Node* const s0 = m.Int32Mul(p1, m.Int32Constant(2));
605 1 : m.Return(m.Int32Add(s0, p0));
606 1 : Stream s = m.Build();
607 2 : ASSERT_EQ(1U, s.size());
608 3 : EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
609 3 : EXPECT_EQ(kMode_MR2, s[0]->addressing_mode());
610 3 : ASSERT_EQ(2U, s[0]->InputCount());
611 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
612 3 : EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
613 : }
614 :
615 :
616 15128 : TEST_F(InstructionSelectorTest, Int32AddScaled2Shl) {
617 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
618 1 : MachineType::Int32());
619 1 : Node* const p0 = m.Parameter(0);
620 1 : Node* const p1 = m.Parameter(1);
621 1 : Node* const s0 = m.Word32Shl(p1, m.Int32Constant(1));
622 1 : m.Return(m.Int32Add(p0, s0));
623 1 : Stream s = m.Build();
624 2 : ASSERT_EQ(1U, s.size());
625 3 : EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
626 3 : EXPECT_EQ(kMode_MR2, s[0]->addressing_mode());
627 3 : ASSERT_EQ(2U, s[0]->InputCount());
628 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
629 3 : EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
630 : }
631 :
632 :
633 15128 : TEST_F(InstructionSelectorTest, Int32AddCommutedScaled2Shl) {
634 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
635 1 : MachineType::Int32());
636 1 : Node* const p0 = m.Parameter(0);
637 1 : Node* const p1 = m.Parameter(1);
638 1 : Node* const s0 = m.Word32Shl(p1, m.Int32Constant(1));
639 1 : m.Return(m.Int32Add(s0, p0));
640 1 : Stream s = m.Build();
641 2 : ASSERT_EQ(1U, s.size());
642 3 : EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
643 3 : EXPECT_EQ(kMode_MR2, s[0]->addressing_mode());
644 3 : ASSERT_EQ(2U, s[0]->InputCount());
645 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
646 3 : EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
647 : }
648 :
649 :
650 15128 : TEST_F(InstructionSelectorTest, Int32AddScaled4Mul) {
651 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
652 1 : MachineType::Int32());
653 1 : Node* const p0 = m.Parameter(0);
654 1 : Node* const p1 = m.Parameter(1);
655 1 : Node* const s0 = m.Int32Mul(p1, m.Int32Constant(4));
656 1 : m.Return(m.Int32Add(p0, s0));
657 1 : Stream s = m.Build();
658 2 : ASSERT_EQ(1U, s.size());
659 3 : EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
660 3 : EXPECT_EQ(kMode_MR4, s[0]->addressing_mode());
661 3 : ASSERT_EQ(2U, s[0]->InputCount());
662 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
663 3 : EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
664 : }
665 :
666 :
667 15128 : TEST_F(InstructionSelectorTest, Int32AddScaled4Shl) {
668 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
669 1 : MachineType::Int32());
670 1 : Node* const p0 = m.Parameter(0);
671 1 : Node* const p1 = m.Parameter(1);
672 1 : Node* const s0 = m.Word32Shl(p1, m.Int32Constant(2));
673 1 : m.Return(m.Int32Add(p0, s0));
674 1 : Stream s = m.Build();
675 2 : ASSERT_EQ(1U, s.size());
676 3 : EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
677 3 : EXPECT_EQ(kMode_MR4, s[0]->addressing_mode());
678 3 : ASSERT_EQ(2U, s[0]->InputCount());
679 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
680 3 : EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
681 : }
682 :
683 :
684 15128 : TEST_F(InstructionSelectorTest, Int32AddScaled8Mul) {
685 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
686 1 : MachineType::Int32());
687 1 : Node* const p0 = m.Parameter(0);
688 1 : Node* const p1 = m.Parameter(1);
689 1 : Node* const s0 = m.Int32Mul(p1, m.Int32Constant(8));
690 1 : m.Return(m.Int32Add(p0, s0));
691 1 : Stream s = m.Build();
692 2 : ASSERT_EQ(1U, s.size());
693 3 : EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
694 3 : EXPECT_EQ(kMode_MR8, s[0]->addressing_mode());
695 3 : ASSERT_EQ(2U, s[0]->InputCount());
696 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
697 3 : EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
698 : }
699 :
700 :
701 15128 : TEST_F(InstructionSelectorTest, Int32AddScaled8Shl) {
702 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
703 1 : MachineType::Int32());
704 1 : Node* const p0 = m.Parameter(0);
705 1 : Node* const p1 = m.Parameter(1);
706 1 : Node* const s0 = m.Word32Shl(p1, m.Int32Constant(3));
707 1 : m.Return(m.Int32Add(p0, s0));
708 1 : Stream s = m.Build();
709 2 : ASSERT_EQ(1U, s.size());
710 3 : EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
711 3 : EXPECT_EQ(kMode_MR8, s[0]->addressing_mode());
712 3 : ASSERT_EQ(2U, s[0]->InputCount());
713 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
714 3 : EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
715 : }
716 :
717 :
718 15128 : TEST_F(InstructionSelectorTest, Int32AddScaled2MulWithConstant) {
719 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
720 1 : MachineType::Int32());
721 1 : Node* const p0 = m.Parameter(0);
722 1 : Node* const p1 = m.Parameter(1);
723 1 : Node* const s0 = m.Int32Mul(p1, m.Int32Constant(2));
724 1 : Node* const c0 = m.Int32Constant(15);
725 1 : m.Return(m.Int32Add(c0, m.Int32Add(p0, s0)));
726 1 : Stream s = m.Build();
727 2 : ASSERT_EQ(1U, s.size());
728 3 : EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
729 3 : EXPECT_EQ(kMode_MR2I, s[0]->addressing_mode());
730 3 : ASSERT_EQ(3U, s[0]->InputCount());
731 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
732 3 : EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
733 3 : EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
734 : }
735 :
736 :
737 15128 : TEST_F(InstructionSelectorTest, Int32AddScaled2MulWithConstantShuffle1) {
738 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
739 1 : MachineType::Int32());
740 1 : Node* const p0 = m.Parameter(0);
741 1 : Node* const p1 = m.Parameter(1);
742 1 : Node* const s0 = m.Int32Mul(p1, m.Int32Constant(2));
743 1 : Node* const c0 = m.Int32Constant(15);
744 1 : m.Return(m.Int32Add(p0, m.Int32Add(s0, c0)));
745 1 : Stream s = m.Build();
746 2 : ASSERT_EQ(1U, s.size());
747 3 : EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
748 3 : EXPECT_EQ(kMode_MR2I, s[0]->addressing_mode());
749 3 : ASSERT_EQ(3U, s[0]->InputCount());
750 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
751 3 : EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
752 3 : EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
753 : }
754 :
755 :
756 15128 : TEST_F(InstructionSelectorTest, Int32AddScaled2MulWithConstantShuffle2) {
757 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
758 1 : MachineType::Int32());
759 1 : Node* const p0 = m.Parameter(0);
760 1 : Node* const p1 = m.Parameter(1);
761 1 : Node* const s0 = m.Int32Mul(p1, m.Int32Constant(2));
762 1 : Node* const c0 = m.Int32Constant(15);
763 1 : m.Return(m.Int32Add(s0, m.Int32Add(c0, p0)));
764 1 : Stream s = m.Build();
765 2 : ASSERT_EQ(1U, s.size());
766 3 : EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
767 3 : EXPECT_EQ(kMode_MR2I, s[0]->addressing_mode());
768 3 : ASSERT_EQ(3U, s[0]->InputCount());
769 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
770 3 : EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
771 3 : EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
772 : }
773 :
774 :
775 15128 : TEST_F(InstructionSelectorTest, Int32AddScaled2MulWithConstantShuffle3) {
776 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
777 1 : MachineType::Int32());
778 1 : Node* const p0 = m.Parameter(0);
779 1 : Node* const p1 = m.Parameter(1);
780 1 : Node* const s0 = m.Int32Mul(p1, m.Int32Constant(2));
781 1 : Node* const c0 = m.Int32Constant(15);
782 1 : m.Return(m.Int32Add(m.Int32Add(s0, c0), p0));
783 1 : Stream s = m.Build();
784 2 : ASSERT_EQ(1U, s.size());
785 3 : EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
786 3 : EXPECT_EQ(kMode_MR2I, s[0]->addressing_mode());
787 3 : ASSERT_EQ(3U, s[0]->InputCount());
788 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
789 3 : EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
790 3 : EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
791 : }
792 :
793 :
794 15128 : TEST_F(InstructionSelectorTest, Int32AddScaled2MulWithConstantShuffle4) {
795 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
796 1 : MachineType::Int32());
797 1 : Node* const p0 = m.Parameter(0);
798 1 : Node* const p1 = m.Parameter(1);
799 1 : Node* const s0 = m.Int32Mul(p1, m.Int32Constant(2));
800 1 : Node* const c0 = m.Int32Constant(15);
801 1 : m.Return(m.Int32Add(m.Int32Add(c0, p0), s0));
802 1 : Stream s = m.Build();
803 2 : ASSERT_EQ(1U, s.size());
804 3 : EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
805 3 : EXPECT_EQ(kMode_MR2I, s[0]->addressing_mode());
806 3 : ASSERT_EQ(3U, s[0]->InputCount());
807 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
808 3 : EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
809 3 : EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
810 : }
811 :
812 :
813 15128 : TEST_F(InstructionSelectorTest, Int32AddScaled2MulWithConstantShuffle5) {
814 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
815 1 : MachineType::Int32());
816 1 : Node* const p0 = m.Parameter(0);
817 1 : Node* const p1 = m.Parameter(1);
818 1 : Node* const s0 = m.Int32Mul(p1, m.Int32Constant(2));
819 1 : Node* const c0 = m.Int32Constant(15);
820 1 : m.Return(m.Int32Add(m.Int32Add(p0, s0), c0));
821 1 : Stream s = m.Build();
822 2 : ASSERT_EQ(1U, s.size());
823 3 : EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
824 3 : EXPECT_EQ(kMode_MR2I, s[0]->addressing_mode());
825 3 : ASSERT_EQ(3U, s[0]->InputCount());
826 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
827 3 : EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
828 3 : EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
829 : }
830 :
831 :
832 15128 : TEST_F(InstructionSelectorTest, Int32AddScaled2ShlWithConstant) {
833 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
834 1 : MachineType::Int32());
835 1 : Node* const p0 = m.Parameter(0);
836 1 : Node* const p1 = m.Parameter(1);
837 1 : Node* const s0 = m.Word32Shl(p1, m.Int32Constant(1));
838 1 : Node* const c0 = m.Int32Constant(15);
839 1 : m.Return(m.Int32Add(c0, m.Int32Add(p0, s0)));
840 1 : Stream s = m.Build();
841 2 : ASSERT_EQ(1U, s.size());
842 3 : EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
843 3 : EXPECT_EQ(kMode_MR2I, s[0]->addressing_mode());
844 3 : ASSERT_EQ(3U, s[0]->InputCount());
845 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
846 3 : EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
847 3 : EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
848 : }
849 :
850 :
851 15128 : TEST_F(InstructionSelectorTest, Int32AddScaled4MulWithConstant) {
852 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
853 1 : MachineType::Int32());
854 1 : Node* const p0 = m.Parameter(0);
855 1 : Node* const p1 = m.Parameter(1);
856 1 : Node* const s0 = m.Int32Mul(p1, m.Int32Constant(4));
857 1 : Node* const c0 = m.Int32Constant(15);
858 1 : m.Return(m.Int32Add(c0, m.Int32Add(p0, s0)));
859 1 : Stream s = m.Build();
860 2 : ASSERT_EQ(1U, s.size());
861 3 : EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
862 3 : EXPECT_EQ(kMode_MR4I, s[0]->addressing_mode());
863 3 : ASSERT_EQ(3U, s[0]->InputCount());
864 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
865 3 : EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
866 3 : EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
867 : }
868 :
869 :
870 15128 : TEST_F(InstructionSelectorTest, Int32AddScaled4ShlWithConstant) {
871 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
872 1 : MachineType::Int32());
873 1 : Node* const p0 = m.Parameter(0);
874 1 : Node* const p1 = m.Parameter(1);
875 1 : Node* const s0 = m.Word32Shl(p1, m.Int32Constant(2));
876 1 : Node* const c0 = m.Int32Constant(15);
877 1 : m.Return(m.Int32Add(c0, m.Int32Add(p0, s0)));
878 1 : Stream s = m.Build();
879 2 : ASSERT_EQ(1U, s.size());
880 3 : EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
881 3 : EXPECT_EQ(kMode_MR4I, s[0]->addressing_mode());
882 3 : ASSERT_EQ(3U, s[0]->InputCount());
883 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
884 3 : EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
885 3 : EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
886 : }
887 :
888 :
889 15128 : TEST_F(InstructionSelectorTest, Int32AddScaled8MulWithConstant) {
890 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
891 1 : MachineType::Int32());
892 1 : Node* const p0 = m.Parameter(0);
893 1 : Node* const p1 = m.Parameter(1);
894 1 : Node* const s0 = m.Int32Mul(p1, m.Int32Constant(8));
895 1 : Node* const c0 = m.Int32Constant(15);
896 1 : m.Return(m.Int32Add(c0, m.Int32Add(p0, s0)));
897 1 : Stream s = m.Build();
898 2 : ASSERT_EQ(1U, s.size());
899 3 : EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
900 3 : EXPECT_EQ(kMode_MR8I, s[0]->addressing_mode());
901 3 : ASSERT_EQ(3U, s[0]->InputCount());
902 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
903 3 : EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
904 3 : EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
905 : }
906 :
907 :
908 15128 : TEST_F(InstructionSelectorTest, Int32AddScaled8ShlWithConstant) {
909 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
910 1 : MachineType::Int32());
911 1 : Node* const p0 = m.Parameter(0);
912 1 : Node* const p1 = m.Parameter(1);
913 1 : Node* const s0 = m.Word32Shl(p1, m.Int32Constant(3));
914 1 : Node* const c0 = m.Int32Constant(15);
915 1 : m.Return(m.Int32Add(c0, m.Int32Add(p0, s0)));
916 1 : Stream s = m.Build();
917 2 : ASSERT_EQ(1U, s.size());
918 3 : EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
919 3 : EXPECT_EQ(kMode_MR8I, s[0]->addressing_mode());
920 3 : ASSERT_EQ(3U, s[0]->InputCount());
921 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
922 3 : EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
923 3 : EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
924 : }
925 :
926 :
927 15128 : TEST_F(InstructionSelectorTest, Int32SubConstantAsSub) {
928 1 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
929 1 : Node* const p0 = m.Parameter(0);
930 1 : Node* const c0 = m.Int32Constant(-1);
931 : // If there is only a single use of on of the sub's non-constant input, use a
932 : // "subl" instruction.
933 1 : m.Return(m.Int32Sub(p0, c0));
934 1 : Stream s = m.Build();
935 2 : ASSERT_EQ(1U, s.size());
936 3 : EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
937 3 : EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
938 3 : ASSERT_EQ(2U, s[0]->InputCount());
939 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
940 3 : EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
941 : }
942 :
943 :
944 15128 : TEST_F(InstructionSelectorTest, Int32SubConstantAsLea) {
945 1 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
946 1 : Node* const p0 = m.Parameter(0);
947 1 : Node* const c0 = m.Int32Constant(-1);
948 : // If there are multiple uses of on of the sub's non-constant input, use a
949 : // "leal" instruction.
950 1 : Node* const v0 = m.Int32Sub(p0, c0);
951 1 : m.Return(m.Int32Div(p0, v0));
952 1 : Stream s = m.Build();
953 2 : ASSERT_EQ(2U, s.size());
954 3 : EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
955 3 : EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
956 3 : ASSERT_EQ(2U, s[0]->InputCount());
957 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
958 3 : EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
959 : }
960 :
961 :
962 15128 : TEST_F(InstructionSelectorTest, Int32AddScaled2Other) {
963 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
964 1 : MachineType::Int32(), MachineType::Int32());
965 1 : Node* const p0 = m.Parameter(0);
966 1 : Node* const p1 = m.Parameter(1);
967 1 : Node* const p2 = m.Parameter(2);
968 1 : Node* const s0 = m.Int32Mul(p1, m.Int32Constant(2));
969 1 : Node* const a0 = m.Int32Add(s0, p2);
970 1 : Node* const a1 = m.Int32Add(p0, a0);
971 1 : m.Return(a1);
972 1 : Stream s = m.Build();
973 2 : ASSERT_EQ(2U, s.size());
974 3 : EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
975 3 : EXPECT_EQ(kMode_MR2, s[0]->addressing_mode());
976 3 : ASSERT_EQ(2U, s[0]->InputCount());
977 3 : EXPECT_EQ(s.ToVreg(p2), s.ToVreg(s[0]->InputAt(0)));
978 3 : EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
979 2 : EXPECT_EQ(s.ToVreg(a0), s.ToVreg(s[0]->OutputAt(0)));
980 3 : ASSERT_EQ(2U, s[1]->InputCount());
981 3 : EXPECT_EQ(kX64Lea32, s[1]->arch_opcode());
982 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[1]->InputAt(0)));
983 3 : EXPECT_EQ(s.ToVreg(a0), s.ToVreg(s[1]->InputAt(1)));
984 2 : EXPECT_EQ(s.ToVreg(a1), s.ToVreg(s[1]->OutputAt(0)));
985 : }
986 :
987 :
988 : // -----------------------------------------------------------------------------
989 : // Multiplication.
990 :
991 :
992 15128 : TEST_F(InstructionSelectorTest, Int32MulWithInt32MulWithParameters) {
993 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
994 1 : MachineType::Int32());
995 1 : Node* const p0 = m.Parameter(0);
996 1 : Node* const p1 = m.Parameter(1);
997 1 : Node* const m0 = m.Int32Mul(p0, p1);
998 1 : m.Return(m.Int32Mul(m0, p0));
999 1 : Stream s = m.Build();
1000 2 : ASSERT_EQ(2U, s.size());
1001 3 : EXPECT_EQ(kX64Imul32, s[0]->arch_opcode());
1002 3 : ASSERT_EQ(2U, s[0]->InputCount());
1003 3 : EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(0)));
1004 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
1005 3 : ASSERT_EQ(1U, s[0]->OutputCount());
1006 2 : EXPECT_EQ(s.ToVreg(m0), s.ToVreg(s[0]->OutputAt(0)));
1007 3 : EXPECT_EQ(kX64Imul32, s[1]->arch_opcode());
1008 3 : ASSERT_EQ(2U, s[1]->InputCount());
1009 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[1]->InputAt(0)));
1010 3 : EXPECT_EQ(s.ToVreg(m0), s.ToVreg(s[1]->InputAt(1)));
1011 : }
1012 :
1013 :
1014 15128 : TEST_F(InstructionSelectorTest, Int32MulHigh) {
1015 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
1016 1 : MachineType::Int32());
1017 1 : Node* const p0 = m.Parameter(0);
1018 1 : Node* const p1 = m.Parameter(1);
1019 1 : Node* const n = m.Int32MulHigh(p0, p1);
1020 1 : m.Return(n);
1021 1 : Stream s = m.Build();
1022 2 : ASSERT_EQ(1U, s.size());
1023 3 : EXPECT_EQ(kX64ImulHigh32, s[0]->arch_opcode());
1024 3 : ASSERT_EQ(2U, s[0]->InputCount());
1025 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1026 3 : EXPECT_TRUE(s.IsFixed(s[0]->InputAt(0), rax));
1027 3 : EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
1028 3 : EXPECT_TRUE(!s.IsUsedAtStart(s[0]->InputAt(1)));
1029 2 : ASSERT_LE(1U, s[0]->OutputCount());
1030 2 : EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
1031 2 : EXPECT_TRUE(s.IsFixed(s[0]->OutputAt(0), rdx));
1032 : }
1033 :
1034 :
1035 15128 : TEST_F(InstructionSelectorTest, Uint32MulHigh) {
1036 : StreamBuilder m(this, MachineType::Uint32(), MachineType::Uint32(),
1037 1 : MachineType::Uint32());
1038 1 : Node* const p0 = m.Parameter(0);
1039 1 : Node* const p1 = m.Parameter(1);
1040 1 : Node* const n = m.Uint32MulHigh(p0, p1);
1041 1 : m.Return(n);
1042 1 : Stream s = m.Build();
1043 2 : ASSERT_EQ(1U, s.size());
1044 3 : EXPECT_EQ(kX64UmulHigh32, s[0]->arch_opcode());
1045 3 : ASSERT_EQ(2U, s[0]->InputCount());
1046 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1047 3 : EXPECT_TRUE(s.IsFixed(s[0]->InputAt(0), rax));
1048 3 : EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
1049 3 : EXPECT_TRUE(!s.IsUsedAtStart(s[0]->InputAt(1)));
1050 2 : ASSERT_LE(1U, s[0]->OutputCount());
1051 2 : EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
1052 2 : EXPECT_TRUE(s.IsFixed(s[0]->OutputAt(0), rdx));
1053 : }
1054 :
1055 :
1056 15128 : TEST_F(InstructionSelectorTest, Int32Mul2BecomesLea) {
1057 : StreamBuilder m(this, MachineType::Uint32(), MachineType::Uint32(),
1058 1 : MachineType::Uint32());
1059 1 : Node* const p0 = m.Parameter(0);
1060 1 : Node* const c1 = m.Int32Constant(2);
1061 1 : Node* const n = m.Int32Mul(p0, c1);
1062 1 : m.Return(n);
1063 1 : Stream s = m.Build();
1064 2 : ASSERT_EQ(1U, s.size());
1065 3 : EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
1066 3 : EXPECT_EQ(kMode_MR1, s[0]->addressing_mode());
1067 3 : ASSERT_EQ(2U, s[0]->InputCount());
1068 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1069 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
1070 : }
1071 :
1072 :
1073 15128 : TEST_F(InstructionSelectorTest, Int32Mul3BecomesLea) {
1074 : StreamBuilder m(this, MachineType::Uint32(), MachineType::Uint32(),
1075 1 : MachineType::Uint32());
1076 1 : Node* const p0 = m.Parameter(0);
1077 1 : Node* const c1 = m.Int32Constant(3);
1078 1 : Node* const n = m.Int32Mul(p0, c1);
1079 1 : m.Return(n);
1080 1 : Stream s = m.Build();
1081 2 : ASSERT_EQ(1U, s.size());
1082 3 : EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
1083 3 : EXPECT_EQ(kMode_MR2, s[0]->addressing_mode());
1084 3 : ASSERT_EQ(2U, s[0]->InputCount());
1085 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1086 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
1087 : }
1088 :
1089 :
1090 15128 : TEST_F(InstructionSelectorTest, Int32Mul4BecomesLea) {
1091 : StreamBuilder m(this, MachineType::Uint32(), MachineType::Uint32(),
1092 1 : MachineType::Uint32());
1093 1 : Node* const p0 = m.Parameter(0);
1094 1 : Node* const c1 = m.Int32Constant(4);
1095 1 : Node* const n = m.Int32Mul(p0, c1);
1096 1 : m.Return(n);
1097 1 : Stream s = m.Build();
1098 2 : ASSERT_EQ(1U, s.size());
1099 3 : EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
1100 3 : EXPECT_EQ(kMode_M4, s[0]->addressing_mode());
1101 3 : ASSERT_EQ(1U, s[0]->InputCount());
1102 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1103 : }
1104 :
1105 :
1106 15128 : TEST_F(InstructionSelectorTest, Int32Mul5BecomesLea) {
1107 : StreamBuilder m(this, MachineType::Uint32(), MachineType::Uint32(),
1108 1 : MachineType::Uint32());
1109 1 : Node* const p0 = m.Parameter(0);
1110 1 : Node* const c1 = m.Int32Constant(5);
1111 1 : Node* const n = m.Int32Mul(p0, c1);
1112 1 : m.Return(n);
1113 1 : Stream s = m.Build();
1114 2 : ASSERT_EQ(1U, s.size());
1115 3 : EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
1116 3 : EXPECT_EQ(kMode_MR4, s[0]->addressing_mode());
1117 3 : ASSERT_EQ(2U, s[0]->InputCount());
1118 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1119 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
1120 : }
1121 :
1122 :
1123 15128 : TEST_F(InstructionSelectorTest, Int32Mul8BecomesLea) {
1124 : StreamBuilder m(this, MachineType::Uint32(), MachineType::Uint32(),
1125 1 : MachineType::Uint32());
1126 1 : Node* const p0 = m.Parameter(0);
1127 1 : Node* const c1 = m.Int32Constant(8);
1128 1 : Node* const n = m.Int32Mul(p0, c1);
1129 1 : m.Return(n);
1130 1 : Stream s = m.Build();
1131 2 : ASSERT_EQ(1U, s.size());
1132 3 : EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
1133 3 : EXPECT_EQ(kMode_M8, s[0]->addressing_mode());
1134 3 : ASSERT_EQ(1U, s[0]->InputCount());
1135 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1136 : }
1137 :
1138 :
1139 15128 : TEST_F(InstructionSelectorTest, Int32Mul9BecomesLea) {
1140 : StreamBuilder m(this, MachineType::Uint32(), MachineType::Uint32(),
1141 1 : MachineType::Uint32());
1142 1 : Node* const p0 = m.Parameter(0);
1143 1 : Node* const c1 = m.Int32Constant(9);
1144 1 : Node* const n = m.Int32Mul(p0, c1);
1145 1 : m.Return(n);
1146 1 : Stream s = m.Build();
1147 2 : ASSERT_EQ(1U, s.size());
1148 3 : EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
1149 3 : EXPECT_EQ(kMode_MR8, s[0]->addressing_mode());
1150 3 : ASSERT_EQ(2U, s[0]->InputCount());
1151 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1152 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
1153 : }
1154 :
1155 :
1156 : // -----------------------------------------------------------------------------
1157 : // Word32Shl.
1158 :
1159 :
1160 15128 : TEST_F(InstructionSelectorTest, Int32Shl1BecomesLea) {
1161 : StreamBuilder m(this, MachineType::Uint32(), MachineType::Uint32(),
1162 1 : MachineType::Uint32());
1163 1 : Node* const p0 = m.Parameter(0);
1164 1 : Node* const c1 = m.Int32Constant(1);
1165 1 : Node* const n = m.Word32Shl(p0, c1);
1166 1 : m.Return(n);
1167 1 : Stream s = m.Build();
1168 2 : ASSERT_EQ(1U, s.size());
1169 3 : EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
1170 3 : EXPECT_EQ(kMode_MR1, s[0]->addressing_mode());
1171 3 : ASSERT_EQ(2U, s[0]->InputCount());
1172 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1173 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
1174 : }
1175 :
1176 :
1177 15128 : TEST_F(InstructionSelectorTest, Int32Shl2BecomesLea) {
1178 : StreamBuilder m(this, MachineType::Uint32(), MachineType::Uint32(),
1179 1 : MachineType::Uint32());
1180 1 : Node* const p0 = m.Parameter(0);
1181 1 : Node* const c1 = m.Int32Constant(2);
1182 1 : Node* const n = m.Word32Shl(p0, c1);
1183 1 : m.Return(n);
1184 1 : Stream s = m.Build();
1185 2 : ASSERT_EQ(1U, s.size());
1186 3 : EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
1187 3 : EXPECT_EQ(kMode_M4, s[0]->addressing_mode());
1188 3 : ASSERT_EQ(1U, s[0]->InputCount());
1189 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1190 : }
1191 :
1192 :
1193 15128 : TEST_F(InstructionSelectorTest, Int32Shl4BecomesLea) {
1194 : StreamBuilder m(this, MachineType::Uint32(), MachineType::Uint32(),
1195 1 : MachineType::Uint32());
1196 1 : Node* const p0 = m.Parameter(0);
1197 1 : Node* const c1 = m.Int32Constant(3);
1198 1 : Node* const n = m.Word32Shl(p0, c1);
1199 1 : m.Return(n);
1200 1 : Stream s = m.Build();
1201 2 : ASSERT_EQ(1U, s.size());
1202 3 : EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
1203 3 : EXPECT_EQ(kMode_M8, s[0]->addressing_mode());
1204 3 : ASSERT_EQ(1U, s[0]->InputCount());
1205 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1206 : }
1207 :
1208 : // -----------------------------------------------------------------------------
1209 : // Binops with a memory operand.
1210 :
1211 15128 : TEST_F(InstructionSelectorTest, LoadCmp32) {
1212 : {
1213 : // Word32Equal(Load[Int8](p0, p1), Int32Constant(0)) -> cmpb [p0,p1], 0
1214 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int64(),
1215 1 : MachineType::Int64());
1216 1 : Node* const p0 = m.Parameter(0);
1217 1 : Node* const p1 = m.Parameter(1);
1218 : m.Return(
1219 1 : m.Word32Equal(m.Load(MachineType::Int8(), p0, p1), m.Int32Constant(0)));
1220 1 : Stream s = m.Build();
1221 2 : ASSERT_EQ(1U, s.size());
1222 3 : EXPECT_EQ(kX64Cmp8, s[0]->arch_opcode());
1223 3 : EXPECT_EQ(kMode_MR1, s[0]->addressing_mode());
1224 3 : ASSERT_EQ(3U, s[0]->InputCount());
1225 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1226 3 : EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
1227 3 : EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
1228 : }
1229 : {
1230 : // Word32Equal(Load[Uint8](p0, p1), Int32Constant(0)) -> cmpb [p0,p1], 0
1231 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int64(),
1232 1 : MachineType::Int64());
1233 1 : Node* const p0 = m.Parameter(0);
1234 1 : Node* const p1 = m.Parameter(1);
1235 : m.Return(m.Word32Equal(m.Load(MachineType::Uint8(), p0, p1),
1236 1 : m.Int32Constant(0)));
1237 1 : Stream s = m.Build();
1238 2 : ASSERT_EQ(1U, s.size());
1239 3 : EXPECT_EQ(kX64Cmp8, s[0]->arch_opcode());
1240 3 : EXPECT_EQ(kMode_MR1, s[0]->addressing_mode());
1241 3 : ASSERT_EQ(3U, s[0]->InputCount());
1242 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1243 3 : EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
1244 3 : EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
1245 : }
1246 : {
1247 : // Word32Equal(Load[Int16](p0, p1), Int32Constant(0)) -> cmpw [p0,p1], 0
1248 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int64(),
1249 1 : MachineType::Int64());
1250 1 : Node* const p0 = m.Parameter(0);
1251 1 : Node* const p1 = m.Parameter(1);
1252 : m.Return(m.Word32Equal(m.Load(MachineType::Int16(), p0, p1),
1253 1 : m.Int32Constant(0)));
1254 1 : Stream s = m.Build();
1255 2 : ASSERT_EQ(1U, s.size());
1256 3 : EXPECT_EQ(kX64Cmp16, s[0]->arch_opcode());
1257 3 : EXPECT_EQ(kMode_MR1, s[0]->addressing_mode());
1258 3 : ASSERT_EQ(3U, s[0]->InputCount());
1259 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1260 3 : EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
1261 3 : EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
1262 : }
1263 : {
1264 : // Word32Equal(Load[Uint16](p0, p1), Int32Constant(0)) -> cmpw [p0,p1], 0
1265 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int64(),
1266 1 : MachineType::Int64());
1267 1 : Node* const p0 = m.Parameter(0);
1268 1 : Node* const p1 = m.Parameter(1);
1269 : m.Return(m.Word32Equal(m.Load(MachineType::Uint16(), p0, p1),
1270 1 : m.Int32Constant(0)));
1271 1 : Stream s = m.Build();
1272 2 : ASSERT_EQ(1U, s.size());
1273 3 : EXPECT_EQ(kX64Cmp16, s[0]->arch_opcode());
1274 3 : EXPECT_EQ(kMode_MR1, s[0]->addressing_mode());
1275 3 : ASSERT_EQ(3U, s[0]->InputCount());
1276 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1277 3 : EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
1278 3 : EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
1279 : }
1280 : {
1281 : // Word32Equal(Load[Int32](p0, p1), Int32Constant(0)) -> cmpl [p0,p1], 0
1282 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int64(),
1283 1 : MachineType::Int64());
1284 1 : Node* const p0 = m.Parameter(0);
1285 1 : Node* const p1 = m.Parameter(1);
1286 : m.Return(m.Word32Equal(m.Load(MachineType::Int32(), p0, p1),
1287 1 : m.Int32Constant(0)));
1288 1 : Stream s = m.Build();
1289 2 : ASSERT_EQ(1U, s.size());
1290 3 : EXPECT_EQ(kX64Cmp32, s[0]->arch_opcode());
1291 3 : EXPECT_EQ(kMode_MR1, s[0]->addressing_mode());
1292 3 : ASSERT_EQ(3U, s[0]->InputCount());
1293 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1294 3 : EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
1295 3 : EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
1296 : }
1297 : {
1298 : // Word32Equal(Load[Uint32](p0, p1), Int32Constant(0)) -> cmpl [p0,p1], 0
1299 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int64(),
1300 1 : MachineType::Int64());
1301 1 : Node* const p0 = m.Parameter(0);
1302 1 : Node* const p1 = m.Parameter(1);
1303 : m.Return(m.Word32Equal(m.Load(MachineType::Uint32(), p0, p1),
1304 1 : m.Int32Constant(0)));
1305 1 : Stream s = m.Build();
1306 2 : ASSERT_EQ(1U, s.size());
1307 3 : EXPECT_EQ(kX64Cmp32, s[0]->arch_opcode());
1308 3 : EXPECT_EQ(kMode_MR1, s[0]->addressing_mode());
1309 3 : ASSERT_EQ(3U, s[0]->InputCount());
1310 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1311 3 : EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
1312 3 : EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
1313 : }
1314 : }
1315 :
1316 15128 : TEST_F(InstructionSelectorTest, LoadAnd32) {
1317 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
1318 1 : MachineType::Int32());
1319 1 : Node* const p0 = m.Parameter(0);
1320 1 : Node* const p1 = m.Parameter(1);
1321 : m.Return(
1322 1 : m.Word32And(p0, m.Load(MachineType::Int32(), p1, m.Int32Constant(127))));
1323 1 : Stream s = m.Build();
1324 2 : ASSERT_EQ(1U, s.size());
1325 3 : EXPECT_EQ(kX64And32, s[0]->arch_opcode());
1326 3 : ASSERT_EQ(3U, s[0]->InputCount());
1327 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1328 3 : EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
1329 : }
1330 :
1331 15128 : TEST_F(InstructionSelectorTest, LoadOr32) {
1332 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
1333 1 : MachineType::Int32());
1334 1 : Node* const p0 = m.Parameter(0);
1335 1 : Node* const p1 = m.Parameter(1);
1336 : m.Return(
1337 1 : m.Word32Or(p0, m.Load(MachineType::Int32(), p1, m.Int32Constant(127))));
1338 1 : Stream s = m.Build();
1339 2 : ASSERT_EQ(1U, s.size());
1340 3 : EXPECT_EQ(kX64Or32, s[0]->arch_opcode());
1341 3 : ASSERT_EQ(3U, s[0]->InputCount());
1342 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1343 3 : EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
1344 : }
1345 :
1346 15128 : TEST_F(InstructionSelectorTest, LoadXor32) {
1347 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
1348 1 : MachineType::Int32());
1349 1 : Node* const p0 = m.Parameter(0);
1350 1 : Node* const p1 = m.Parameter(1);
1351 : m.Return(
1352 1 : m.Word32Xor(p0, m.Load(MachineType::Int32(), p1, m.Int32Constant(127))));
1353 1 : Stream s = m.Build();
1354 2 : ASSERT_EQ(1U, s.size());
1355 3 : EXPECT_EQ(kX64Xor32, s[0]->arch_opcode());
1356 3 : ASSERT_EQ(3U, s[0]->InputCount());
1357 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1358 3 : EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
1359 : }
1360 :
1361 15128 : TEST_F(InstructionSelectorTest, LoadAdd32) {
1362 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
1363 1 : MachineType::Int32());
1364 1 : Node* const p0 = m.Parameter(0);
1365 1 : Node* const p1 = m.Parameter(1);
1366 : m.Return(
1367 1 : m.Int32Add(p0, m.Load(MachineType::Int32(), p1, m.Int32Constant(127))));
1368 1 : Stream s = m.Build();
1369 : // Use lea instead of add, so memory operand is invalid.
1370 3 : ASSERT_EQ(2U, s.size());
1371 3 : EXPECT_EQ(kX64Movl, s[0]->arch_opcode());
1372 3 : EXPECT_EQ(kX64Lea32, s[1]->arch_opcode());
1373 : }
1374 :
1375 15128 : TEST_F(InstructionSelectorTest, LoadSub32) {
1376 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(),
1377 1 : MachineType::Int32());
1378 1 : Node* const p0 = m.Parameter(0);
1379 1 : Node* const p1 = m.Parameter(1);
1380 : m.Return(
1381 1 : m.Int32Sub(p0, m.Load(MachineType::Int32(), p1, m.Int32Constant(127))));
1382 1 : Stream s = m.Build();
1383 2 : ASSERT_EQ(1U, s.size());
1384 3 : EXPECT_EQ(kX64Sub32, s[0]->arch_opcode());
1385 3 : ASSERT_EQ(3U, s[0]->InputCount());
1386 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1387 3 : EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
1388 : }
1389 :
1390 15128 : TEST_F(InstructionSelectorTest, LoadAnd64) {
1391 : StreamBuilder m(this, MachineType::Int64(), MachineType::Int64(),
1392 1 : MachineType::Int64());
1393 1 : Node* const p0 = m.Parameter(0);
1394 1 : Node* const p1 = m.Parameter(1);
1395 : m.Return(
1396 1 : m.Word64And(p0, m.Load(MachineType::Int64(), p1, m.Int32Constant(127))));
1397 1 : Stream s = m.Build();
1398 2 : ASSERT_EQ(1U, s.size());
1399 3 : EXPECT_EQ(kX64And, s[0]->arch_opcode());
1400 3 : ASSERT_EQ(3U, s[0]->InputCount());
1401 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1402 3 : EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
1403 : }
1404 :
1405 15128 : TEST_F(InstructionSelectorTest, LoadOr64) {
1406 : StreamBuilder m(this, MachineType::Int64(), MachineType::Int64(),
1407 1 : MachineType::Int64());
1408 1 : Node* const p0 = m.Parameter(0);
1409 1 : Node* const p1 = m.Parameter(1);
1410 : m.Return(
1411 1 : m.Word64Or(p0, m.Load(MachineType::Int64(), p1, m.Int32Constant(127))));
1412 1 : Stream s = m.Build();
1413 2 : ASSERT_EQ(1U, s.size());
1414 3 : EXPECT_EQ(kX64Or, s[0]->arch_opcode());
1415 3 : ASSERT_EQ(3U, s[0]->InputCount());
1416 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1417 3 : EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
1418 : }
1419 :
1420 15128 : TEST_F(InstructionSelectorTest, LoadXor64) {
1421 : StreamBuilder m(this, MachineType::Int64(), MachineType::Int64(),
1422 1 : MachineType::Int64());
1423 1 : Node* const p0 = m.Parameter(0);
1424 1 : Node* const p1 = m.Parameter(1);
1425 : m.Return(
1426 1 : m.Word64Xor(p0, m.Load(MachineType::Int64(), p1, m.Int32Constant(127))));
1427 1 : Stream s = m.Build();
1428 2 : ASSERT_EQ(1U, s.size());
1429 3 : EXPECT_EQ(kX64Xor, s[0]->arch_opcode());
1430 3 : ASSERT_EQ(3U, s[0]->InputCount());
1431 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1432 3 : EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
1433 : }
1434 :
1435 15128 : TEST_F(InstructionSelectorTest, LoadAdd64) {
1436 : StreamBuilder m(this, MachineType::Int64(), MachineType::Int64(),
1437 1 : MachineType::Int64());
1438 1 : Node* const p0 = m.Parameter(0);
1439 1 : Node* const p1 = m.Parameter(1);
1440 : m.Return(
1441 1 : m.Int64Add(p0, m.Load(MachineType::Int64(), p1, m.Int32Constant(127))));
1442 1 : Stream s = m.Build();
1443 : // Use lea instead of add, so memory operand is invalid.
1444 3 : ASSERT_EQ(2U, s.size());
1445 3 : EXPECT_EQ(kX64Movq, s[0]->arch_opcode());
1446 3 : EXPECT_EQ(kX64Lea, s[1]->arch_opcode());
1447 : }
1448 :
1449 15128 : TEST_F(InstructionSelectorTest, LoadSub64) {
1450 : StreamBuilder m(this, MachineType::Int64(), MachineType::Int64(),
1451 1 : MachineType::Int64());
1452 1 : Node* const p0 = m.Parameter(0);
1453 1 : Node* const p1 = m.Parameter(1);
1454 : m.Return(
1455 1 : m.Int64Sub(p0, m.Load(MachineType::Int64(), p1, m.Int32Constant(127))));
1456 1 : Stream s = m.Build();
1457 2 : ASSERT_EQ(1U, s.size());
1458 3 : EXPECT_EQ(kX64Sub, s[0]->arch_opcode());
1459 3 : ASSERT_EQ(3U, s[0]->InputCount());
1460 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1461 3 : EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
1462 : }
1463 :
1464 : // -----------------------------------------------------------------------------
1465 : // Floating point operations.
1466 :
1467 15128 : TEST_F(InstructionSelectorTest, Float32Abs) {
1468 : {
1469 1 : StreamBuilder m(this, MachineType::Float32(), MachineType::Float32());
1470 1 : Node* const p0 = m.Parameter(0);
1471 1 : Node* const n = m.Float32Abs(p0);
1472 1 : m.Return(n);
1473 1 : Stream s = m.Build();
1474 2 : ASSERT_EQ(1U, s.size());
1475 3 : EXPECT_EQ(kSSEFloat32Abs, s[0]->arch_opcode());
1476 3 : ASSERT_EQ(1U, s[0]->InputCount());
1477 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1478 3 : ASSERT_EQ(1U, s[0]->OutputCount());
1479 2 : EXPECT_TRUE(s.IsSameAsFirst(s[0]->Output()));
1480 2 : EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
1481 3 : EXPECT_EQ(kFlags_none, s[0]->flags_mode());
1482 : }
1483 : {
1484 1 : StreamBuilder m(this, MachineType::Float32(), MachineType::Float32());
1485 1 : Node* const p0 = m.Parameter(0);
1486 1 : Node* const n = m.Float32Abs(p0);
1487 1 : m.Return(n);
1488 1 : Stream s = m.Build(AVX);
1489 2 : ASSERT_EQ(1U, s.size());
1490 3 : EXPECT_EQ(kAVXFloat32Abs, s[0]->arch_opcode());
1491 3 : ASSERT_EQ(1U, s[0]->InputCount());
1492 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1493 3 : ASSERT_EQ(1U, s[0]->OutputCount());
1494 2 : EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
1495 3 : EXPECT_EQ(kFlags_none, s[0]->flags_mode());
1496 : }
1497 : }
1498 :
1499 :
1500 15128 : TEST_F(InstructionSelectorTest, Float64Abs) {
1501 : {
1502 1 : StreamBuilder m(this, MachineType::Float64(), MachineType::Float64());
1503 1 : Node* const p0 = m.Parameter(0);
1504 1 : Node* const n = m.Float64Abs(p0);
1505 1 : m.Return(n);
1506 1 : Stream s = m.Build();
1507 2 : ASSERT_EQ(1U, s.size());
1508 3 : EXPECT_EQ(kSSEFloat64Abs, s[0]->arch_opcode());
1509 3 : ASSERT_EQ(1U, s[0]->InputCount());
1510 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1511 3 : ASSERT_EQ(1U, s[0]->OutputCount());
1512 2 : EXPECT_TRUE(s.IsSameAsFirst(s[0]->Output()));
1513 2 : EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
1514 3 : EXPECT_EQ(kFlags_none, s[0]->flags_mode());
1515 : }
1516 : {
1517 1 : StreamBuilder m(this, MachineType::Float64(), MachineType::Float64());
1518 1 : Node* const p0 = m.Parameter(0);
1519 1 : Node* const n = m.Float64Abs(p0);
1520 1 : m.Return(n);
1521 1 : Stream s = m.Build(AVX);
1522 2 : ASSERT_EQ(1U, s.size());
1523 3 : EXPECT_EQ(kAVXFloat64Abs, s[0]->arch_opcode());
1524 3 : ASSERT_EQ(1U, s[0]->InputCount());
1525 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1526 3 : ASSERT_EQ(1U, s[0]->OutputCount());
1527 2 : EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
1528 3 : EXPECT_EQ(kFlags_none, s[0]->flags_mode());
1529 : }
1530 : }
1531 :
1532 :
1533 15128 : TEST_F(InstructionSelectorTest, Float64BinopArithmetic) {
1534 : {
1535 : StreamBuilder m(this, MachineType::Float64(), MachineType::Float64(),
1536 1 : MachineType::Float64());
1537 1 : Node* add = m.Float64Add(m.Parameter(0), m.Parameter(1));
1538 1 : Node* mul = m.Float64Mul(add, m.Parameter(1));
1539 1 : Node* sub = m.Float64Sub(mul, add);
1540 1 : Node* ret = m.Float64Div(mul, sub);
1541 1 : m.Return(ret);
1542 1 : Stream s = m.Build(AVX);
1543 2 : ASSERT_EQ(4U, s.size());
1544 3 : EXPECT_EQ(kAVXFloat64Add, s[0]->arch_opcode());
1545 3 : EXPECT_EQ(kAVXFloat64Mul, s[1]->arch_opcode());
1546 3 : EXPECT_EQ(kAVXFloat64Sub, s[2]->arch_opcode());
1547 3 : EXPECT_EQ(kAVXFloat64Div, s[3]->arch_opcode());
1548 : }
1549 : {
1550 : StreamBuilder m(this, MachineType::Float64(), MachineType::Float64(),
1551 1 : MachineType::Float64());
1552 1 : Node* add = m.Float64Add(m.Parameter(0), m.Parameter(1));
1553 1 : Node* mul = m.Float64Mul(add, m.Parameter(1));
1554 1 : Node* sub = m.Float64Sub(mul, add);
1555 1 : Node* ret = m.Float64Div(mul, sub);
1556 1 : m.Return(ret);
1557 1 : Stream s = m.Build();
1558 2 : ASSERT_EQ(4U, s.size());
1559 3 : EXPECT_EQ(kSSEFloat64Add, s[0]->arch_opcode());
1560 3 : EXPECT_EQ(kSSEFloat64Mul, s[1]->arch_opcode());
1561 3 : EXPECT_EQ(kSSEFloat64Sub, s[2]->arch_opcode());
1562 3 : EXPECT_EQ(kSSEFloat64Div, s[3]->arch_opcode());
1563 : }
1564 : }
1565 :
1566 : // -----------------------------------------------------------------------------
1567 : // Miscellaneous.
1568 :
1569 :
1570 15128 : TEST_F(InstructionSelectorTest, Word64ShlWithChangeInt32ToInt64) {
1571 225 : TRACED_FORRANGE(int64_t, x, 32, 63) {
1572 32 : StreamBuilder m(this, MachineType::Int64(), MachineType::Int32());
1573 32 : Node* const p0 = m.Parameter(0);
1574 32 : Node* const n = m.Word64Shl(m.ChangeInt32ToInt64(p0), m.Int64Constant(x));
1575 32 : m.Return(n);
1576 32 : Stream s = m.Build();
1577 64 : ASSERT_EQ(1U, s.size());
1578 96 : EXPECT_EQ(kX64Shl, s[0]->arch_opcode());
1579 96 : ASSERT_EQ(2U, s[0]->InputCount());
1580 96 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1581 128 : EXPECT_EQ(x, s.ToInt32(s[0]->InputAt(1)));
1582 96 : ASSERT_EQ(1U, s[0]->OutputCount());
1583 64 : EXPECT_TRUE(s.IsSameAsFirst(s[0]->Output()));
1584 64 : EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
1585 32 : }
1586 : }
1587 :
1588 :
1589 15128 : TEST_F(InstructionSelectorTest, Word64ShlWithChangeUint32ToUint64) {
1590 225 : TRACED_FORRANGE(int64_t, x, 32, 63) {
1591 32 : StreamBuilder m(this, MachineType::Int64(), MachineType::Uint32());
1592 32 : Node* const p0 = m.Parameter(0);
1593 32 : Node* const n = m.Word64Shl(m.ChangeUint32ToUint64(p0), m.Int64Constant(x));
1594 32 : m.Return(n);
1595 32 : Stream s = m.Build();
1596 64 : ASSERT_EQ(1U, s.size());
1597 96 : EXPECT_EQ(kX64Shl, s[0]->arch_opcode());
1598 96 : ASSERT_EQ(2U, s[0]->InputCount());
1599 96 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1600 128 : EXPECT_EQ(x, s.ToInt32(s[0]->InputAt(1)));
1601 96 : ASSERT_EQ(1U, s[0]->OutputCount());
1602 64 : EXPECT_TRUE(s.IsSameAsFirst(s[0]->Output()));
1603 64 : EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
1604 32 : }
1605 : }
1606 :
1607 15128 : TEST_F(InstructionSelectorTest, Word32AndWith0xFF) {
1608 : {
1609 1 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
1610 1 : Node* const p0 = m.Parameter(0);
1611 1 : Node* const n = m.Word32And(p0, m.Int32Constant(0xFF));
1612 1 : m.Return(n);
1613 1 : Stream s = m.Build();
1614 2 : ASSERT_EQ(1U, s.size());
1615 3 : EXPECT_EQ(kX64Movzxbl, s[0]->arch_opcode());
1616 3 : ASSERT_EQ(1U, s[0]->InputCount());
1617 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1618 3 : ASSERT_EQ(1U, s[0]->OutputCount());
1619 2 : EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
1620 : }
1621 : {
1622 1 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
1623 1 : Node* const p0 = m.Parameter(0);
1624 1 : Node* const n = m.Word32And(m.Int32Constant(0xFF), p0);
1625 1 : m.Return(n);
1626 1 : Stream s = m.Build();
1627 2 : ASSERT_EQ(1U, s.size());
1628 3 : EXPECT_EQ(kX64Movzxbl, s[0]->arch_opcode());
1629 3 : ASSERT_EQ(1U, s[0]->InputCount());
1630 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1631 3 : ASSERT_EQ(1U, s[0]->OutputCount());
1632 2 : EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
1633 : }
1634 : }
1635 :
1636 15128 : TEST_F(InstructionSelectorTest, Word32AndWith0xFFFF) {
1637 : {
1638 1 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
1639 1 : Node* const p0 = m.Parameter(0);
1640 1 : Node* const n = m.Word32And(p0, m.Int32Constant(0xFFFF));
1641 1 : m.Return(n);
1642 1 : Stream s = m.Build();
1643 2 : ASSERT_EQ(1U, s.size());
1644 3 : EXPECT_EQ(kX64Movzxwl, s[0]->arch_opcode());
1645 3 : ASSERT_EQ(1U, s[0]->InputCount());
1646 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1647 3 : ASSERT_EQ(1U, s[0]->OutputCount());
1648 2 : EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
1649 : }
1650 : {
1651 1 : StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
1652 1 : Node* const p0 = m.Parameter(0);
1653 1 : Node* const n = m.Word32And(m.Int32Constant(0xFFFF), p0);
1654 1 : m.Return(n);
1655 1 : Stream s = m.Build();
1656 2 : ASSERT_EQ(1U, s.size());
1657 3 : EXPECT_EQ(kX64Movzxwl, s[0]->arch_opcode());
1658 3 : ASSERT_EQ(1U, s[0]->InputCount());
1659 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1660 3 : ASSERT_EQ(1U, s[0]->OutputCount());
1661 2 : EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
1662 : }
1663 : }
1664 :
1665 :
1666 15128 : TEST_F(InstructionSelectorTest, Word32Clz) {
1667 1 : StreamBuilder m(this, MachineType::Uint32(), MachineType::Uint32());
1668 1 : Node* const p0 = m.Parameter(0);
1669 1 : Node* const n = m.Word32Clz(p0);
1670 1 : m.Return(n);
1671 1 : Stream s = m.Build();
1672 2 : ASSERT_EQ(1U, s.size());
1673 3 : EXPECT_EQ(kX64Lzcnt32, s[0]->arch_opcode());
1674 3 : ASSERT_EQ(1U, s[0]->InputCount());
1675 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1676 3 : ASSERT_EQ(1U, s[0]->OutputCount());
1677 2 : EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
1678 : }
1679 :
1680 15128 : TEST_F(InstructionSelectorTest, LoadAndWord64ShiftRight32) {
1681 : {
1682 1 : StreamBuilder m(this, MachineType::Uint64(), MachineType::Uint32());
1683 1 : Node* const p0 = m.Parameter(0);
1684 1 : Node* const load = m.Load(MachineType::Uint64(), p0);
1685 1 : Node* const shift = m.Word64Shr(load, m.Int32Constant(32));
1686 1 : m.Return(shift);
1687 1 : Stream s = m.Build();
1688 2 : ASSERT_EQ(1U, s.size());
1689 3 : EXPECT_EQ(kX64Movl, s[0]->arch_opcode());
1690 3 : ASSERT_EQ(2U, s[0]->InputCount());
1691 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1692 4 : EXPECT_EQ(4, s.ToInt32(s[0]->InputAt(1)));
1693 3 : ASSERT_EQ(1U, s[0]->OutputCount());
1694 2 : EXPECT_EQ(s.ToVreg(shift), s.ToVreg(s[0]->Output()));
1695 : }
1696 : {
1697 1 : StreamBuilder m(this, MachineType::Int64(), MachineType::Int32());
1698 1 : Node* const p0 = m.Parameter(0);
1699 1 : Node* const load = m.Load(MachineType::Int64(), p0);
1700 1 : Node* const shift = m.Word64Sar(load, m.Int32Constant(32));
1701 1 : m.Return(shift);
1702 1 : Stream s = m.Build();
1703 2 : ASSERT_EQ(1U, s.size());
1704 3 : EXPECT_EQ(kX64Movsxlq, s[0]->arch_opcode());
1705 3 : ASSERT_EQ(2U, s[0]->InputCount());
1706 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1707 4 : EXPECT_EQ(4, s.ToInt32(s[0]->InputAt(1)));
1708 3 : ASSERT_EQ(1U, s[0]->OutputCount());
1709 2 : EXPECT_EQ(s.ToVreg(shift), s.ToVreg(s[0]->Output()));
1710 : }
1711 : {
1712 1 : StreamBuilder m(this, MachineType::Int64(), MachineType::Int32());
1713 1 : Node* const p0 = m.Parameter(0);
1714 1 : Node* const load = m.Load(MachineType::Int64(), p0);
1715 1 : Node* const shift = m.Word64Sar(load, m.Int32Constant(32));
1716 1 : Node* const truncate = m.TruncateInt64ToInt32(shift);
1717 1 : m.Return(truncate);
1718 1 : Stream s = m.Build();
1719 2 : ASSERT_EQ(1U, s.size());
1720 3 : EXPECT_EQ(kX64Movl, s[0]->arch_opcode());
1721 3 : ASSERT_EQ(2U, s[0]->InputCount());
1722 3 : EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
1723 4 : EXPECT_EQ(4, s.ToInt32(s[0]->InputAt(1)));
1724 3 : ASSERT_EQ(1U, s[0]->OutputCount());
1725 2 : EXPECT_EQ(s.ToVreg(shift), s.ToVreg(s[0]->Output()));
1726 : }
1727 : }
1728 :
1729 15128 : TEST_F(InstructionSelectorTest, SpeculationFence) {
1730 1 : StreamBuilder m(this, MachineType::Int32());
1731 1 : m.SpeculationFence();
1732 1 : m.Return(m.Int32Constant(0));
1733 1 : Stream s = m.Build();
1734 3 : ASSERT_EQ(1U, s.size());
1735 3 : EXPECT_EQ(kLFence, s[0]->arch_opcode());
1736 : }
1737 :
1738 15128 : TEST_F(InstructionSelectorTest, StackCheck0) {
1739 : ExternalReference js_stack_limit =
1740 1 : ExternalReference::Create(isolate()->stack_guard()->address_of_jslimit());
1741 1 : StreamBuilder m(this, MachineType::Int32());
1742 1 : Node* const sp = m.LoadStackPointer();
1743 : Node* const stack_limit =
1744 1 : m.Load(MachineType::Pointer(), m.ExternalConstant(js_stack_limit));
1745 : Node* const interrupt = m.UintPtrLessThan(sp, stack_limit);
1746 :
1747 1 : RawMachineLabel if_true, if_false;
1748 1 : m.Branch(interrupt, &if_true, &if_false);
1749 :
1750 1 : m.Bind(&if_true);
1751 1 : m.Return(m.Int32Constant(1));
1752 :
1753 1 : m.Bind(&if_false);
1754 1 : m.Return(m.Int32Constant(0));
1755 :
1756 1 : Stream s = m.Build();
1757 :
1758 3 : ASSERT_EQ(1U, s.size());
1759 3 : EXPECT_EQ(kX64Cmp, s[0]->arch_opcode());
1760 3 : EXPECT_EQ(4U, s[0]->InputCount());
1761 3 : EXPECT_EQ(0U, s[0]->OutputCount());
1762 : }
1763 :
1764 15128 : TEST_F(InstructionSelectorTest, StackCheck1) {
1765 : ExternalReference js_stack_limit =
1766 1 : ExternalReference::Create(isolate()->stack_guard()->address_of_jslimit());
1767 1 : StreamBuilder m(this, MachineType::Int32());
1768 1 : Node* const sp = m.LoadStackPointer();
1769 : Node* const stack_limit =
1770 1 : m.Load(MachineType::Pointer(), m.ExternalConstant(js_stack_limit));
1771 : Node* const sp_within_limit = m.UintPtrLessThan(stack_limit, sp);
1772 :
1773 1 : RawMachineLabel if_true, if_false;
1774 1 : m.Branch(sp_within_limit, &if_true, &if_false);
1775 :
1776 1 : m.Bind(&if_true);
1777 1 : m.Return(m.Int32Constant(1));
1778 :
1779 1 : m.Bind(&if_false);
1780 1 : m.Return(m.Int32Constant(0));
1781 :
1782 1 : Stream s = m.Build();
1783 :
1784 3 : ASSERT_EQ(1U, s.size());
1785 3 : EXPECT_EQ(kX64StackCheck, s[0]->arch_opcode());
1786 3 : EXPECT_EQ(2U, s[0]->InputCount());
1787 3 : EXPECT_EQ(0U, s[0]->OutputCount());
1788 : }
1789 :
1790 : } // namespace compiler
1791 : } // namespace internal
1792 9075 : } // namespace v8
|