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