OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "test/unittests/compiler/instruction-selector-unittest.h" | 5 #include "test/unittests/compiler/instruction-selector-unittest.h" |
6 | 6 |
7 #include "src/compiler/node-matchers.h" | 7 #include "src/compiler/node-matchers.h" |
8 | 8 |
9 namespace v8 { | 9 namespace v8 { |
10 namespace internal { | 10 namespace internal { |
(...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
242 | 242 |
243 // ----------------------------------------------------------------------------- | 243 // ----------------------------------------------------------------------------- |
244 // Addition. | 244 // Addition. |
245 | 245 |
246 | 246 |
247 TEST_F(InstructionSelectorTest, Int32AddWithInt32ParametersLea) { | 247 TEST_F(InstructionSelectorTest, Int32AddWithInt32ParametersLea) { |
248 StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32); | 248 StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32); |
249 Node* const p0 = m.Parameter(0); | 249 Node* const p0 = m.Parameter(0); |
250 Node* const p1 = m.Parameter(1); | 250 Node* const p1 = m.Parameter(1); |
251 Node* const a0 = m.Int32Add(p0, p1); | 251 Node* const a0 = m.Int32Add(p0, p1); |
252 USE(a0); | |
253 // Additional uses of input to add chooses lea | 252 // Additional uses of input to add chooses lea |
254 Node* const a1 = m.Int32Add(p0, p1); | 253 Node* const a1 = m.Int32Div(p0, p1); |
255 m.Return(m.Int32Add(a0, a1)); | 254 m.Return(m.Int32Div(a0, a1)); |
256 Stream s = m.Build(); | 255 Stream s = m.Build(); |
257 ASSERT_EQ(3U, s.size()); | 256 ASSERT_EQ(3U, s.size()); |
258 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); | 257 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); |
259 ASSERT_EQ(2U, s[0]->InputCount()); | 258 ASSERT_EQ(2U, s[0]->InputCount()); |
260 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); | 259 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); |
261 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); | 260 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); |
262 } | 261 } |
263 | 262 |
264 | 263 |
265 TEST_F(InstructionSelectorTest, Int32AddConstantAsLeaSingle) { | 264 TEST_F(InstructionSelectorTest, Int32AddConstantAsLeaSingle) { |
266 StreamBuilder m(this, kMachInt32, kMachInt32); | 265 StreamBuilder m(this, kMachInt32, kMachInt32); |
267 Node* const p0 = m.Parameter(0); | 266 Node* const p0 = m.Parameter(0); |
268 Node* const c0 = m.Int32Constant(15); | 267 Node* const c0 = m.Int32Constant(15); |
269 // If there is only a single use of an add's input, still use lea and not add, | 268 // If there is only a single use of an add's input, use an "addl" not a |
270 // it is faster. | 269 // "leal", it is faster. |
271 m.Return(m.Int32Add(p0, c0)); | 270 Node* const v0 = m.Int32Add(p0, c0); |
| 271 m.Return(v0); |
272 Stream s = m.Build(); | 272 Stream s = m.Build(); |
273 ASSERT_EQ(1U, s.size()); | 273 ASSERT_EQ(1U, s.size()); |
274 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); | 274 EXPECT_EQ(kX64Add32, s[0]->arch_opcode()); |
275 EXPECT_EQ(kMode_MRI, s[0]->addressing_mode()); | 275 EXPECT_EQ(kMode_None, s[0]->addressing_mode()); |
276 ASSERT_EQ(2U, s[0]->InputCount()); | 276 ASSERT_EQ(2U, s[0]->InputCount()); |
277 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); | 277 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); |
278 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate()); | 278 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate()); |
279 } | 279 } |
280 | 280 |
281 | 281 |
282 TEST_F(InstructionSelectorTest, Int32AddConstantAsInc) { | 282 TEST_F(InstructionSelectorTest, Int32AddConstantAsAdd) { |
283 StreamBuilder m(this, kMachInt32, kMachInt32); | 283 StreamBuilder m(this, kMachInt32, kMachInt32); |
284 Node* const p0 = m.Parameter(0); | 284 Node* const p0 = m.Parameter(0); |
285 Node* const c0 = m.Int32Constant(1); | 285 Node* const c0 = m.Int32Constant(1); |
286 // If there is only a single use of an add's input and the immediate constant | 286 // If there is only a single use of an add's input and the immediate constant |
287 // for the add is 1, use inc. | 287 // for the add is 1, use inc. |
288 m.Return(m.Int32Add(p0, c0)); | 288 m.Return(m.Int32Add(p0, c0)); |
289 Stream s = m.Build(); | 289 Stream s = m.Build(); |
290 ASSERT_EQ(1U, s.size()); | 290 ASSERT_EQ(1U, s.size()); |
291 EXPECT_EQ(kX64Inc32, s[0]->arch_opcode()); | 291 EXPECT_EQ(kX64Add32, s[0]->arch_opcode()); |
292 EXPECT_EQ(kMode_None, s[0]->addressing_mode()); | 292 EXPECT_EQ(kMode_None, s[0]->addressing_mode()); |
293 ASSERT_EQ(1U, s[0]->InputCount()); | 293 ASSERT_EQ(2U, s[0]->InputCount()); |
294 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); | 294 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); |
| 295 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate()); |
295 } | 296 } |
296 | 297 |
297 | 298 |
298 TEST_F(InstructionSelectorTest, Int32AddConstantAsDec) { | |
299 StreamBuilder m(this, kMachInt32, kMachInt32); | |
300 Node* const p0 = m.Parameter(0); | |
301 Node* const c0 = m.Int32Constant(-1); | |
302 // If there is only a single use of an add's input and the immediate constant | |
303 // for the add is -11, use dec. | |
304 m.Return(m.Int32Add(p0, c0)); | |
305 Stream s = m.Build(); | |
306 ASSERT_EQ(1U, s.size()); | |
307 EXPECT_EQ(kX64Dec32, s[0]->arch_opcode()); | |
308 EXPECT_EQ(kMode_None, s[0]->addressing_mode()); | |
309 ASSERT_EQ(1U, s[0]->InputCount()); | |
310 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); | |
311 } | |
312 | |
313 | |
314 TEST_F(InstructionSelectorTest, Int32AddConstantAsLeaDouble) { | 299 TEST_F(InstructionSelectorTest, Int32AddConstantAsLeaDouble) { |
315 StreamBuilder m(this, kMachInt32, kMachInt32); | 300 StreamBuilder m(this, kMachInt32, kMachInt32); |
316 Node* const p0 = m.Parameter(0); | 301 Node* const p0 = m.Parameter(0); |
317 Node* const c0 = m.Int32Constant(15); | 302 Node* const c0 = m.Int32Constant(15); |
318 // A second use of an add's input uses lea | 303 // A second use of an add's input uses lea |
319 Node* const a0 = m.Int32Add(p0, c0); | 304 Node* const a0 = m.Int32Add(p0, c0); |
320 USE(a0); | 305 m.Return(m.Int32Div(a0, p0)); |
321 m.Return(m.Int32Add(p0, c0)); | |
322 Stream s = m.Build(); | 306 Stream s = m.Build(); |
323 ASSERT_EQ(1U, s.size()); | 307 ASSERT_EQ(2U, s.size()); |
324 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); | 308 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); |
325 EXPECT_EQ(kMode_MRI, s[0]->addressing_mode()); | 309 EXPECT_EQ(kMode_MRI, s[0]->addressing_mode()); |
326 ASSERT_EQ(2U, s[0]->InputCount()); | 310 ASSERT_EQ(2U, s[0]->InputCount()); |
327 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); | 311 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); |
328 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate()); | 312 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate()); |
329 } | 313 } |
330 | 314 |
331 | 315 |
332 TEST_F(InstructionSelectorTest, Int32AddCommutedConstantAsLeaSingle) { | 316 TEST_F(InstructionSelectorTest, Int32AddCommutedConstantAsLeaSingle) { |
333 StreamBuilder m(this, kMachInt32, kMachInt32); | 317 StreamBuilder m(this, kMachInt32, kMachInt32); |
334 Node* const p0 = m.Parameter(0); | 318 Node* const p0 = m.Parameter(0); |
335 Node* const c0 = m.Int32Constant(15); | 319 Node* const c0 = m.Int32Constant(15); |
336 // If there is only a single use of an add's input, still use lea... it's | 320 // If there is only a single use of an add's input, use "addl" |
337 // generally faster than the add to reduce register pressure. | |
338 m.Return(m.Int32Add(c0, p0)); | 321 m.Return(m.Int32Add(c0, p0)); |
339 Stream s = m.Build(); | 322 Stream s = m.Build(); |
340 ASSERT_EQ(1U, s.size()); | 323 ASSERT_EQ(1U, s.size()); |
341 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); | 324 EXPECT_EQ(kX64Add32, s[0]->arch_opcode()); |
342 EXPECT_EQ(kMode_MRI, s[0]->addressing_mode()); | 325 EXPECT_EQ(kMode_None, s[0]->addressing_mode()); |
343 ASSERT_EQ(2U, s[0]->InputCount()); | 326 ASSERT_EQ(2U, s[0]->InputCount()); |
344 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); | 327 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); |
345 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate()); | 328 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate()); |
346 } | 329 } |
347 | 330 |
348 | 331 |
349 TEST_F(InstructionSelectorTest, Int32AddCommutedConstantAsLeaDouble) { | 332 TEST_F(InstructionSelectorTest, Int32AddCommutedConstantAsLeaDouble) { |
350 StreamBuilder m(this, kMachInt32, kMachInt32); | 333 StreamBuilder m(this, kMachInt32, kMachInt32); |
351 Node* const p0 = m.Parameter(0); | 334 Node* const p0 = m.Parameter(0); |
352 Node* const c0 = m.Int32Constant(15); | 335 Node* const c0 = m.Int32Constant(15); |
353 // A second use of an add's input uses lea | 336 // A second use of an add's input uses lea |
354 Node* const a0 = m.Int32Add(c0, p0); | 337 Node* const a0 = m.Int32Add(c0, p0); |
355 USE(a0); | 338 USE(a0); |
356 m.Return(m.Int32Add(c0, p0)); | 339 m.Return(m.Int32Div(a0, p0)); |
357 Stream s = m.Build(); | 340 Stream s = m.Build(); |
358 ASSERT_EQ(1U, s.size()); | 341 ASSERT_EQ(2U, s.size()); |
359 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); | 342 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); |
360 EXPECT_EQ(kMode_MRI, s[0]->addressing_mode()); | 343 EXPECT_EQ(kMode_MRI, s[0]->addressing_mode()); |
361 ASSERT_EQ(2U, s[0]->InputCount()); | 344 ASSERT_EQ(2U, s[0]->InputCount()); |
362 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); | 345 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); |
363 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate()); | 346 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate()); |
364 } | 347 } |
365 | 348 |
366 | 349 |
| 350 TEST_F(InstructionSelectorTest, Int32AddSimpleAsAdd) { |
| 351 StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32); |
| 352 Node* const p0 = m.Parameter(0); |
| 353 Node* const p1 = m.Parameter(1); |
| 354 // If one of the add's operands is only used once, use an "addl". |
| 355 m.Return(m.Int32Add(p0, p1)); |
| 356 Stream s = m.Build(); |
| 357 ASSERT_EQ(1U, s.size()); |
| 358 EXPECT_EQ(kX64Add32, s[0]->arch_opcode()); |
| 359 EXPECT_EQ(kMode_None, s[0]->addressing_mode()); |
| 360 ASSERT_EQ(2U, s[0]->InputCount()); |
| 361 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); |
| 362 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); |
| 363 } |
| 364 |
| 365 |
| 366 TEST_F(InstructionSelectorTest, Int32AddSimpleAsLea) { |
| 367 StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32); |
| 368 Node* const p0 = m.Parameter(0); |
| 369 Node* const p1 = m.Parameter(1); |
| 370 // If all of of the add's operands are used multiple times, use an "leal". |
| 371 Node* const v1 = m.Int32Add(p0, p1); |
| 372 m.Return(m.Int32Add(m.Int32Add(v1, p1), p0)); |
| 373 Stream s = m.Build(); |
| 374 ASSERT_EQ(3U, s.size()); |
| 375 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); |
| 376 EXPECT_EQ(kMode_MR1, s[0]->addressing_mode()); |
| 377 ASSERT_EQ(2U, s[0]->InputCount()); |
| 378 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); |
| 379 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); |
| 380 } |
| 381 |
| 382 |
367 TEST_F(InstructionSelectorTest, Int32AddScaled2Mul) { | 383 TEST_F(InstructionSelectorTest, Int32AddScaled2Mul) { |
368 StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32); | 384 StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32); |
369 Node* const p0 = m.Parameter(0); | 385 Node* const p0 = m.Parameter(0); |
370 Node* const p1 = m.Parameter(1); | 386 Node* const p1 = m.Parameter(1); |
371 Node* const s0 = m.Int32Mul(p1, m.Int32Constant(2)); | 387 Node* const s0 = m.Int32Mul(p1, m.Int32Constant(2)); |
372 m.Return(m.Int32Add(p0, s0)); | 388 m.Return(m.Int32Add(p0, s0)); |
373 Stream s = m.Build(); | 389 Stream s = m.Build(); |
374 ASSERT_EQ(1U, s.size()); | 390 ASSERT_EQ(1U, s.size()); |
375 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); | 391 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); |
376 EXPECT_EQ(kMode_MR2, s[0]->addressing_mode()); | 392 EXPECT_EQ(kMode_MR2, s[0]->addressing_mode()); |
(...skipping 306 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
683 ASSERT_EQ(1U, s.size()); | 699 ASSERT_EQ(1U, s.size()); |
684 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); | 700 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); |
685 EXPECT_EQ(kMode_MR8I, s[0]->addressing_mode()); | 701 EXPECT_EQ(kMode_MR8I, s[0]->addressing_mode()); |
686 ASSERT_EQ(3U, s[0]->InputCount()); | 702 ASSERT_EQ(3U, s[0]->InputCount()); |
687 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); | 703 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); |
688 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); | 704 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); |
689 EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate()); | 705 EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate()); |
690 } | 706 } |
691 | 707 |
692 | 708 |
693 TEST_F(InstructionSelectorTest, Int32SubConstantAsInc) { | 709 TEST_F(InstructionSelectorTest, Int32SubConstantAsSub) { |
694 StreamBuilder m(this, kMachInt32, kMachInt32); | 710 StreamBuilder m(this, kMachInt32, kMachInt32); |
695 Node* const p0 = m.Parameter(0); | 711 Node* const p0 = m.Parameter(0); |
696 Node* const c0 = m.Int32Constant(-1); | 712 Node* const c0 = m.Int32Constant(-1); |
697 // If there is only a single use of an add's input and the immediate constant | 713 // If there is only a single use of on of the sub's non-constant input, use a |
698 // for the add is 1, use inc. | 714 // "subl" instruction. |
699 m.Return(m.Int32Sub(p0, c0)); | 715 m.Return(m.Int32Sub(p0, c0)); |
700 Stream s = m.Build(); | 716 Stream s = m.Build(); |
701 ASSERT_EQ(1U, s.size()); | 717 ASSERT_EQ(1U, s.size()); |
702 EXPECT_EQ(kX64Inc32, s[0]->arch_opcode()); | 718 EXPECT_EQ(kX64Sub32, s[0]->arch_opcode()); |
703 EXPECT_EQ(kMode_None, s[0]->addressing_mode()); | 719 EXPECT_EQ(kMode_None, s[0]->addressing_mode()); |
704 ASSERT_EQ(1U, s[0]->InputCount()); | 720 ASSERT_EQ(2U, s[0]->InputCount()); |
705 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); | 721 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); |
| 722 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate()); |
706 } | 723 } |
707 | 724 |
708 | 725 |
709 TEST_F(InstructionSelectorTest, Int32SubConstantAsDec) { | 726 TEST_F(InstructionSelectorTest, Int32SubConstantAsLea) { |
710 StreamBuilder m(this, kMachInt32, kMachInt32); | 727 StreamBuilder m(this, kMachInt32, kMachInt32); |
711 Node* const p0 = m.Parameter(0); | 728 Node* const p0 = m.Parameter(0); |
712 Node* const c0 = m.Int32Constant(1); | 729 Node* const c0 = m.Int32Constant(-1); |
713 // If there is only a single use of an sub's input and the immediate constant | 730 // If there are multiple uses of on of the sub's non-constant input, use a |
714 // for the add is 1, use dec. | 731 // "leal" instruction. |
715 m.Return(m.Int32Sub(p0, c0)); | 732 Node* const v0 = m.Int32Sub(p0, c0); |
| 733 m.Return(m.Int32Div(p0, v0)); |
716 Stream s = m.Build(); | 734 Stream s = m.Build(); |
717 ASSERT_EQ(1U, s.size()); | 735 ASSERT_EQ(2U, s.size()); |
718 EXPECT_EQ(kX64Dec32, s[0]->arch_opcode()); | 736 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); |
719 EXPECT_EQ(kMode_None, s[0]->addressing_mode()); | 737 EXPECT_EQ(kMode_MRI, s[0]->addressing_mode()); |
720 ASSERT_EQ(1U, s[0]->InputCount()); | 738 ASSERT_EQ(2U, s[0]->InputCount()); |
721 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); | 739 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); |
| 740 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate()); |
722 } | 741 } |
723 | 742 |
724 | 743 |
725 // ----------------------------------------------------------------------------- | 744 // ----------------------------------------------------------------------------- |
726 // Multiplication. | 745 // Multiplication. |
727 | 746 |
728 | 747 |
729 TEST_F(InstructionSelectorTest, Int32MulWithInt32MulWithParameters) { | 748 TEST_F(InstructionSelectorTest, Int32MulWithInt32MulWithParameters) { |
730 StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32); | 749 StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32); |
731 Node* const p0 = m.Parameter(0); | 750 Node* const p0 = m.Parameter(0); |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
824 EXPECT_EQ(x, s.ToInt32(s[0]->InputAt(1))); | 843 EXPECT_EQ(x, s.ToInt32(s[0]->InputAt(1))); |
825 ASSERT_EQ(1U, s[0]->OutputCount()); | 844 ASSERT_EQ(1U, s[0]->OutputCount()); |
826 EXPECT_TRUE(s.IsSameAsFirst(s[0]->Output())); | 845 EXPECT_TRUE(s.IsSameAsFirst(s[0]->Output())); |
827 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); | 846 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); |
828 } | 847 } |
829 } | 848 } |
830 | 849 |
831 } // namespace compiler | 850 } // namespace compiler |
832 } // namespace internal | 851 } // namespace internal |
833 } // namespace v8 | 852 } // namespace v8 |
OLD | NEW |