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 namespace v8 { | 7 namespace v8 { |
8 namespace internal { | 8 namespace internal { |
9 namespace compiler { | 9 namespace compiler { |
10 | 10 |
(...skipping 1074 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1085 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { | 1085 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { |
1086 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); | 1086 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); |
1087 RawMachineLabel a, b; | 1087 RawMachineLabel a, b; |
1088 m.Branch(m.Int32Sub(m.Parameter(0), m.Int32Constant(imm)), &a, &b); | 1088 m.Branch(m.Int32Sub(m.Parameter(0), m.Int32Constant(imm)), &a, &b); |
1089 m.Bind(&a); | 1089 m.Bind(&a); |
1090 m.Return(m.Int32Constant(1)); | 1090 m.Return(m.Int32Constant(1)); |
1091 m.Bind(&b); | 1091 m.Bind(&b); |
1092 m.Return(m.Int32Constant(0)); | 1092 m.Return(m.Int32Constant(0)); |
1093 Stream s = m.Build(); | 1093 Stream s = m.Build(); |
1094 ASSERT_EQ(1U, s.size()); | 1094 ASSERT_EQ(1U, s.size()); |
1095 EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode()); | 1095 EXPECT_EQ((imm == 0) ? kArm64CompareAndBranch32 : kArm64Cmp32, |
| 1096 s[0]->arch_opcode()); |
1096 EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); | 1097 EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); |
1097 EXPECT_EQ(kNotEqual, s[0]->flags_condition()); | 1098 EXPECT_EQ(kNotEqual, s[0]->flags_condition()); |
1098 } | 1099 } |
1099 } | 1100 } |
1100 | 1101 |
1101 | 1102 |
1102 TEST_F(InstructionSelectorTest, Word32AndBranchWithImmediateOnLeft) { | 1103 TEST_F(InstructionSelectorTest, Word32AndBranchWithImmediateOnLeft) { |
1103 TRACED_FOREACH(int32_t, imm, kLogical32Immediates) { | 1104 TRACED_FOREACH(int32_t, imm, kLogical32Immediates) { |
1104 // Skip the cases where the instruction selector would use tbz/tbnz. | 1105 // Skip the cases where the instruction selector would use tbz/tbnz. |
1105 if (base::bits::CountPopulation32(imm) == 1) continue; | 1106 if (base::bits::CountPopulation32(imm) == 1) continue; |
(...skipping 2104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3210 } | 3211 } |
3211 } | 3212 } |
3212 } | 3213 } |
3213 | 3214 |
3214 TEST_F(InstructionSelectorTest, CmpWithImmediateOnLeft) { | 3215 TEST_F(InstructionSelectorTest, CmpWithImmediateOnLeft) { |
3215 TRACED_FOREACH(IntegerCmp, cmp, kIntegerCmpInstructions) { | 3216 TRACED_FOREACH(IntegerCmp, cmp, kIntegerCmpInstructions) { |
3216 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { | 3217 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { |
3217 // kEqual and kNotEqual trigger the cbz/cbnz optimization, which | 3218 // kEqual and kNotEqual trigger the cbz/cbnz optimization, which |
3218 // is tested elsewhere. | 3219 // is tested elsewhere. |
3219 if (cmp.cond == kEqual || cmp.cond == kNotEqual) continue; | 3220 if (cmp.cond == kEqual || cmp.cond == kNotEqual) continue; |
| 3221 // For signed less than or equal to zero, we generate TBNZ. |
| 3222 if (cmp.cond == kSignedLessThanOrEqual && imm == 0) continue; |
3220 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); | 3223 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); |
3221 Node* const p0 = m.Parameter(0); | 3224 Node* const p0 = m.Parameter(0); |
3222 RawMachineLabel a, b; | 3225 m.Return((m.*cmp.mi.constructor)(m.Int32Constant(imm), p0)); |
3223 m.Branch((m.*cmp.mi.constructor)(m.Int32Constant(imm), p0), &a, &b); | |
3224 m.Bind(&a); | |
3225 m.Return(m.Int32Constant(1)); | |
3226 m.Bind(&b); | |
3227 m.Return(m.Int32Constant(0)); | |
3228 Stream s = m.Build(); | 3226 Stream s = m.Build(); |
3229 ASSERT_EQ(1U, s.size()); | 3227 ASSERT_EQ(1U, s.size()); |
3230 EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode()); | 3228 EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode()); |
3231 ASSERT_LE(2U, s[0]->InputCount()); | 3229 ASSERT_LE(2U, s[0]->InputCount()); |
3232 EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); | 3230 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); |
3233 EXPECT_EQ(cmp.commuted_cond, s[0]->flags_condition()); | 3231 EXPECT_EQ(cmp.commuted_cond, s[0]->flags_condition()); |
3234 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); | 3232 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); |
3235 } | 3233 } |
3236 } | 3234 } |
3237 } | 3235 } |
3238 | 3236 |
3239 TEST_F(InstructionSelectorTest, CmnWithImmediateOnLeft) { | 3237 TEST_F(InstructionSelectorTest, CmnWithImmediateOnLeft) { |
3240 TRACED_FOREACH(IntegerCmp, cmp, kIntegerCmpEqualityInstructions) { | 3238 TRACED_FOREACH(IntegerCmp, cmp, kIntegerCmpEqualityInstructions) { |
3241 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { | 3239 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { |
3242 // kEqual and kNotEqual trigger the cbz/cbnz optimization, which | 3240 // kEqual and kNotEqual trigger the cbz/cbnz optimization, which |
3243 // is tested elsewhere. | 3241 // is tested elsewhere. |
3244 if (cmp.cond == kEqual || cmp.cond == kNotEqual) continue; | 3242 if (cmp.cond == kEqual || cmp.cond == kNotEqual) continue; |
3245 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); | 3243 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); |
3246 Node* sub = m.Int32Sub(m.Int32Constant(0), m.Parameter(0)); | 3244 Node* sub = m.Int32Sub(m.Int32Constant(0), m.Parameter(0)); |
3247 RawMachineLabel a, b; | 3245 m.Return((m.*cmp.mi.constructor)(m.Int32Constant(imm), sub)); |
3248 m.Branch((m.*cmp.mi.constructor)(m.Int32Constant(imm), sub), &a, &b); | |
3249 m.Bind(&a); | |
3250 m.Return(m.Int32Constant(1)); | |
3251 m.Bind(&b); | |
3252 m.Return(m.Int32Constant(0)); | |
3253 Stream s = m.Build(); | 3246 Stream s = m.Build(); |
3254 ASSERT_EQ(1U, s.size()); | 3247 ASSERT_EQ(1U, s.size()); |
3255 EXPECT_EQ(kArm64Cmn32, s[0]->arch_opcode()); | 3248 EXPECT_EQ(kArm64Cmn32, s[0]->arch_opcode()); |
3256 ASSERT_LE(2U, s[0]->InputCount()); | 3249 ASSERT_LE(2U, s[0]->InputCount()); |
3257 EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); | 3250 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); |
3258 EXPECT_EQ(cmp.cond, s[0]->flags_condition()); | 3251 EXPECT_EQ(cmp.cond, s[0]->flags_condition()); |
3259 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); | 3252 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); |
3260 } | 3253 } |
3261 } | 3254 } |
3262 } | 3255 } |
3263 | 3256 |
3264 TEST_F(InstructionSelectorTest, CmpSignedExtendByteOnLeft) { | 3257 TEST_F(InstructionSelectorTest, CmpSignedExtendByteOnLeft) { |
3265 TRACED_FOREACH(IntegerCmp, cmp, kIntegerCmpInstructions) { | 3258 TRACED_FOREACH(IntegerCmp, cmp, kIntegerCmpInstructions) { |
3266 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), | 3259 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), |
3267 MachineType::Int32()); | 3260 MachineType::Int32()); |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3435 | 3428 |
3436 typedef InstructionSelectorTestWithParam<FlagSettingInst> | 3429 typedef InstructionSelectorTestWithParam<FlagSettingInst> |
3437 InstructionSelectorFlagSettingTest; | 3430 InstructionSelectorFlagSettingTest; |
3438 | 3431 |
3439 TEST_P(InstructionSelectorFlagSettingTest, CmpZeroRight) { | 3432 TEST_P(InstructionSelectorFlagSettingTest, CmpZeroRight) { |
3440 const FlagSettingInst inst = GetParam(); | 3433 const FlagSettingInst inst = GetParam(); |
3441 // Add with single user : a cmp instruction. | 3434 // Add with single user : a cmp instruction. |
3442 TRACED_FOREACH(IntegerCmp, cmp, kBinopCmpZeroRightInstructions) { | 3435 TRACED_FOREACH(IntegerCmp, cmp, kBinopCmpZeroRightInstructions) { |
3443 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), | 3436 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), |
3444 MachineType::Int32()); | 3437 MachineType::Int32()); |
3445 RawMachineLabel a, b; | |
3446 Node* binop = (m.*inst.mi.constructor)(m.Parameter(0), m.Parameter(1)); | 3438 Node* binop = (m.*inst.mi.constructor)(m.Parameter(0), m.Parameter(1)); |
3447 Node* comp = (m.*cmp.mi.constructor)(binop, m.Int32Constant(0)); | 3439 m.Return((m.*cmp.mi.constructor)(binop, m.Int32Constant(0))); |
3448 m.Branch(comp, &a, &b); | |
3449 m.Bind(&a); | |
3450 m.Return(m.Int32Constant(1)); | |
3451 m.Bind(&b); | |
3452 m.Return(m.Int32Constant(0)); | |
3453 Stream s = m.Build(); | 3440 Stream s = m.Build(); |
3454 ASSERT_EQ(1U, s.size()); | 3441 ASSERT_EQ(1U, s.size()); |
3455 ASSERT_EQ(4U, s[0]->InputCount()); // The labels are also inputs. | 3442 ASSERT_EQ(2U, s[0]->InputCount()); |
3456 EXPECT_EQ(inst.no_output_opcode, s[0]->arch_opcode()); | 3443 EXPECT_EQ(inst.no_output_opcode, s[0]->arch_opcode()); |
3457 EXPECT_EQ(s.ToVreg(m.Parameter(0)), s.ToVreg(s[0]->InputAt(0))); | 3444 EXPECT_EQ(s.ToVreg(m.Parameter(0)), s.ToVreg(s[0]->InputAt(0))); |
3458 EXPECT_EQ(s.ToVreg(m.Parameter(1)), s.ToVreg(s[0]->InputAt(1))); | 3445 EXPECT_EQ(s.ToVreg(m.Parameter(1)), s.ToVreg(s[0]->InputAt(1))); |
3459 EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); | 3446 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); |
3460 EXPECT_EQ(cmp.cond, s[0]->flags_condition()); | 3447 EXPECT_EQ(cmp.cond, s[0]->flags_condition()); |
3461 } | 3448 } |
3462 } | 3449 } |
3463 | 3450 |
3464 TEST_P(InstructionSelectorFlagSettingTest, CmpZeroLeft) { | 3451 TEST_P(InstructionSelectorFlagSettingTest, CmpZeroLeft) { |
3465 const FlagSettingInst inst = GetParam(); | 3452 const FlagSettingInst inst = GetParam(); |
3466 // Test a cmp with zero on the left-hand side. | 3453 // Test a cmp with zero on the left-hand side. |
3467 TRACED_FOREACH(IntegerCmp, cmp, kBinopCmpZeroLeftInstructions) { | 3454 TRACED_FOREACH(IntegerCmp, cmp, kBinopCmpZeroLeftInstructions) { |
3468 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), | 3455 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), |
3469 MachineType::Int32()); | 3456 MachineType::Int32()); |
3470 RawMachineLabel a, b; | |
3471 Node* binop = (m.*inst.mi.constructor)(m.Parameter(0), m.Parameter(1)); | 3457 Node* binop = (m.*inst.mi.constructor)(m.Parameter(0), m.Parameter(1)); |
3472 Node* comp = (m.*cmp.mi.constructor)(m.Int32Constant(0), binop); | 3458 m.Return((m.*cmp.mi.constructor)(m.Int32Constant(0), binop)); |
3473 m.Branch(comp, &a, &b); | |
3474 m.Bind(&a); | |
3475 m.Return(m.Int32Constant(1)); | |
3476 m.Bind(&b); | |
3477 m.Return(m.Int32Constant(0)); | |
3478 Stream s = m.Build(); | 3459 Stream s = m.Build(); |
3479 ASSERT_EQ(1U, s.size()); | 3460 ASSERT_EQ(1U, s.size()); |
3480 ASSERT_EQ(4U, s[0]->InputCount()); // The labels are also inputs. | 3461 ASSERT_EQ(2U, s[0]->InputCount()); |
3481 EXPECT_EQ(inst.no_output_opcode, s[0]->arch_opcode()); | 3462 EXPECT_EQ(inst.no_output_opcode, s[0]->arch_opcode()); |
3482 EXPECT_EQ(s.ToVreg(m.Parameter(0)), s.ToVreg(s[0]->InputAt(0))); | 3463 EXPECT_EQ(s.ToVreg(m.Parameter(0)), s.ToVreg(s[0]->InputAt(0))); |
3483 EXPECT_EQ(s.ToVreg(m.Parameter(1)), s.ToVreg(s[0]->InputAt(1))); | 3464 EXPECT_EQ(s.ToVreg(m.Parameter(1)), s.ToVreg(s[0]->InputAt(1))); |
3484 EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); | 3465 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); |
3485 EXPECT_EQ(cmp.cond, s[0]->flags_condition()); | 3466 EXPECT_EQ(cmp.cond, s[0]->flags_condition()); |
3486 } | 3467 } |
3487 } | 3468 } |
3488 | 3469 |
3489 TEST_P(InstructionSelectorFlagSettingTest, CmpZeroOnlyUserInBasicBlock) { | 3470 TEST_P(InstructionSelectorFlagSettingTest, CmpZeroOnlyUserInBasicBlock) { |
3490 const FlagSettingInst inst = GetParam(); | 3471 const FlagSettingInst inst = GetParam(); |
3491 // Binop with additional users, but in a different basic block. | 3472 // Binop with additional users, but in a different basic block. |
3492 TRACED_FOREACH(IntegerCmp, cmp, kBinopCmpZeroRightInstructions) { | 3473 TRACED_FOREACH(IntegerCmp, cmp, kBinopCmpZeroRightInstructions) { |
3493 // For kEqual and kNotEqual, we generate a cbz or cbnz. | |
3494 if (cmp.cond == kEqual || cmp.cond == kNotEqual) continue; | |
3495 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), | 3474 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), |
3496 MachineType::Int32()); | 3475 MachineType::Int32()); |
3497 RawMachineLabel a, b; | 3476 RawMachineLabel a, b; |
3498 Node* binop = (m.*inst.mi.constructor)(m.Parameter(0), m.Parameter(1)); | 3477 Node* binop = (m.*inst.mi.constructor)(m.Parameter(0), m.Parameter(1)); |
3499 Node* comp = (m.*cmp.mi.constructor)(binop, m.Int32Constant(0)); | 3478 Node* comp = (m.*cmp.mi.constructor)(binop, m.Int32Constant(0)); |
3500 m.Branch(comp, &a, &b); | 3479 m.Branch(m.Parameter(0), &a, &b); |
3501 m.Bind(&a); | 3480 m.Bind(&a); |
3502 m.Return(binop); | 3481 m.Return(binop); |
3503 m.Bind(&b); | 3482 m.Bind(&b); |
3504 m.Return(m.Int32Constant(0)); | 3483 m.Return(comp); |
3505 Stream s = m.Build(); | 3484 Stream s = m.Build(); |
3506 ASSERT_EQ(1U, s.size()); | 3485 ASSERT_EQ(2U, s.size()); // Flag-setting instruction and branch. |
3507 ASSERT_EQ(4U, s[0]->InputCount()); // The labels are also inputs. | 3486 ASSERT_EQ(2U, s[0]->InputCount()); |
3508 EXPECT_EQ(inst.mi.arch_opcode, s[0]->arch_opcode()); | 3487 EXPECT_EQ(inst.mi.arch_opcode, s[0]->arch_opcode()); |
3509 EXPECT_EQ(s.ToVreg(m.Parameter(0)), s.ToVreg(s[0]->InputAt(0))); | 3488 EXPECT_EQ(s.ToVreg(m.Parameter(0)), s.ToVreg(s[0]->InputAt(0))); |
3510 EXPECT_EQ(s.ToVreg(m.Parameter(1)), s.ToVreg(s[0]->InputAt(1))); | 3489 EXPECT_EQ(s.ToVreg(m.Parameter(1)), s.ToVreg(s[0]->InputAt(1))); |
3511 EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); | 3490 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); |
3512 EXPECT_EQ(cmp.cond, s[0]->flags_condition()); | 3491 EXPECT_EQ(cmp.cond, s[0]->flags_condition()); |
3513 } | 3492 } |
3514 } | 3493 } |
3515 | 3494 |
3516 TEST_P(InstructionSelectorFlagSettingTest, ShiftedOperand) { | 3495 TEST_P(InstructionSelectorFlagSettingTest, ShiftedOperand) { |
3517 const FlagSettingInst inst = GetParam(); | 3496 const FlagSettingInst inst = GetParam(); |
3518 // Like the test above, but with a shifted input to the binary operator. | 3497 // Like the test above, but with a shifted input to the binary operator. |
3519 TRACED_FOREACH(IntegerCmp, cmp, kBinopCmpZeroRightInstructions) { | 3498 TRACED_FOREACH(IntegerCmp, cmp, kBinopCmpZeroRightInstructions) { |
3520 // For kEqual and kNotEqual, we generate a cbz or cbnz. | |
3521 if (cmp.cond == kEqual || cmp.cond == kNotEqual) continue; | |
3522 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), | 3499 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), |
3523 MachineType::Int32()); | 3500 MachineType::Int32()); |
3524 RawMachineLabel a, b; | 3501 RawMachineLabel a, b; |
3525 Node* imm = m.Int32Constant(5); | 3502 Node* imm = m.Int32Constant(5); |
3526 Node* shift = m.Word32Shl(m.Parameter(1), imm); | 3503 Node* shift = m.Word32Shl(m.Parameter(1), imm); |
3527 Node* binop = (m.*inst.mi.constructor)(m.Parameter(0), shift); | 3504 Node* binop = (m.*inst.mi.constructor)(m.Parameter(0), shift); |
3528 Node* comp = (m.*cmp.mi.constructor)(binop, m.Int32Constant(0)); | 3505 Node* comp = (m.*cmp.mi.constructor)(binop, m.Int32Constant(0)); |
3529 m.Branch(comp, &a, &b); | 3506 m.Branch(m.Parameter(0), &a, &b); |
3530 m.Bind(&a); | 3507 m.Bind(&a); |
3531 m.Return(binop); | 3508 m.Return(binop); |
3532 m.Bind(&b); | 3509 m.Bind(&b); |
3533 m.Return(m.Int32Constant(0)); | 3510 m.Return(comp); |
3534 Stream s = m.Build(); | 3511 Stream s = m.Build(); |
3535 ASSERT_EQ(1U, s.size()); | 3512 ASSERT_EQ(2U, s.size()); // Flag-setting instruction and branch. |
3536 ASSERT_EQ(5U, s[0]->InputCount()); // The labels are also inputs. | 3513 ASSERT_EQ(3U, s[0]->InputCount()); |
3537 EXPECT_EQ(inst.mi.arch_opcode, s[0]->arch_opcode()); | 3514 EXPECT_EQ(inst.mi.arch_opcode, s[0]->arch_opcode()); |
3538 EXPECT_EQ(s.ToVreg(m.Parameter(0)), s.ToVreg(s[0]->InputAt(0))); | 3515 EXPECT_EQ(s.ToVreg(m.Parameter(0)), s.ToVreg(s[0]->InputAt(0))); |
3539 EXPECT_EQ(s.ToVreg(m.Parameter(1)), s.ToVreg(s[0]->InputAt(1))); | 3516 EXPECT_EQ(s.ToVreg(m.Parameter(1)), s.ToVreg(s[0]->InputAt(1))); |
3540 EXPECT_EQ(5, s.ToInt32(s[0]->InputAt(2))); | 3517 EXPECT_EQ(5, s.ToInt32(s[0]->InputAt(2))); |
3541 EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode()); | 3518 EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode()); |
3542 EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); | 3519 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); |
3543 EXPECT_EQ(cmp.cond, s[0]->flags_condition()); | 3520 EXPECT_EQ(cmp.cond, s[0]->flags_condition()); |
3544 } | 3521 } |
3545 } | 3522 } |
3546 | 3523 |
3547 TEST_P(InstructionSelectorFlagSettingTest, UsersInSameBasicBlock) { | 3524 TEST_P(InstructionSelectorFlagSettingTest, UsersInSameBasicBlock) { |
3548 const FlagSettingInst inst = GetParam(); | 3525 const FlagSettingInst inst = GetParam(); |
3549 // Binop with additional users, in the same basic block. We need to make sure | 3526 // Binop with additional users, in the same basic block. We need to make sure |
3550 // we don't try to optimise this case. | 3527 // we don't try to optimise this case. |
3551 TRACED_FOREACH(IntegerCmp, cmp, kIntegerCmpInstructions) { | 3528 TRACED_FOREACH(IntegerCmp, cmp, kIntegerCmpInstructions) { |
3552 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), | 3529 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), |
3553 MachineType::Int32()); | 3530 MachineType::Int32()); |
3554 RawMachineLabel a, b; | 3531 RawMachineLabel a, b; |
3555 Node* binop = (m.*inst.mi.constructor)(m.Parameter(0), m.Parameter(1)); | 3532 Node* binop = (m.*inst.mi.constructor)(m.Parameter(0), m.Parameter(1)); |
3556 Node* mul = m.Int32Mul(m.Parameter(0), binop); | 3533 Node* mul = m.Int32Mul(m.Parameter(0), binop); |
3557 Node* comp = (m.*cmp.mi.constructor)(binop, m.Int32Constant(0)); | 3534 Node* comp = (m.*cmp.mi.constructor)(binop, m.Int32Constant(0)); |
3558 m.Branch(comp, &a, &b); | 3535 m.Branch(m.Parameter(0), &a, &b); |
3559 m.Bind(&a); | 3536 m.Bind(&a); |
3560 m.Return(mul); | 3537 m.Return(mul); |
3561 m.Bind(&b); | 3538 m.Bind(&b); |
3562 m.Return(m.Int32Constant(0)); | 3539 m.Return(comp); |
3563 Stream s = m.Build(); | 3540 Stream s = m.Build(); |
3564 ASSERT_EQ(3U, s.size()); | 3541 ASSERT_EQ(4U, s.size()); // Includes the compare and branch instruction. |
3565 EXPECT_EQ(inst.mi.arch_opcode, s[0]->arch_opcode()); | 3542 EXPECT_EQ(inst.mi.arch_opcode, s[0]->arch_opcode()); |
3566 EXPECT_NE(kFlags_branch, s[0]->flags_mode()); | 3543 EXPECT_EQ(kFlags_none, s[0]->flags_mode()); |
3567 EXPECT_EQ(kArm64Mul32, s[1]->arch_opcode()); | 3544 EXPECT_EQ(kArm64Mul32, s[1]->arch_opcode()); |
3568 EXPECT_EQ(cmp.cond == kEqual ? kArm64CompareAndBranch32 : kArm64Cmp32, | 3545 EXPECT_EQ(kArm64Cmp32, s[2]->arch_opcode()); |
3569 s[2]->arch_opcode()); | 3546 EXPECT_EQ(kFlags_set, s[2]->flags_mode()); |
3570 EXPECT_EQ(kFlags_branch, s[2]->flags_mode()); | |
3571 EXPECT_EQ(cmp.cond, s[2]->flags_condition()); | 3547 EXPECT_EQ(cmp.cond, s[2]->flags_condition()); |
3572 } | 3548 } |
3573 } | 3549 } |
3574 | 3550 |
3575 TEST_P(InstructionSelectorFlagSettingTest, CommuteImmediate) { | 3551 TEST_P(InstructionSelectorFlagSettingTest, CommuteImmediate) { |
3576 const FlagSettingInst inst = GetParam(); | 3552 const FlagSettingInst inst = GetParam(); |
3577 // Immediate on left hand side of the binary operator. | 3553 // Immediate on left hand side of the binary operator. |
3578 TRACED_FOREACH(IntegerCmp, cmp, kBinopCmpZeroRightInstructions) { | 3554 TRACED_FOREACH(IntegerCmp, cmp, kBinopCmpZeroRightInstructions) { |
3579 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); | 3555 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); |
3580 RawMachineLabel a, b; | |
3581 // 3 can be an immediate on both arithmetic and logical instructions. | 3556 // 3 can be an immediate on both arithmetic and logical instructions. |
3582 Node* imm = m.Int32Constant(3); | 3557 Node* imm = m.Int32Constant(3); |
3583 Node* binop = (m.*inst.mi.constructor)(imm, m.Parameter(0)); | 3558 Node* binop = (m.*inst.mi.constructor)(imm, m.Parameter(0)); |
3584 Node* comp = (m.*cmp.mi.constructor)(binop, m.Int32Constant(0)); | 3559 Node* comp = (m.*cmp.mi.constructor)(binop, m.Int32Constant(0)); |
3585 m.Branch(comp, &a, &b); | 3560 m.Return(comp); |
3586 m.Bind(&a); | |
3587 m.Return(m.Int32Constant(1)); | |
3588 m.Bind(&b); | |
3589 m.Return(m.Int32Constant(0)); | |
3590 Stream s = m.Build(); | 3561 Stream s = m.Build(); |
3591 ASSERT_EQ(1U, s.size()); | 3562 ASSERT_EQ(1U, s.size()); |
3592 ASSERT_EQ(4U, s[0]->InputCount()); // The labels are also inputs. | 3563 ASSERT_EQ(2U, s[0]->InputCount()); |
3593 EXPECT_EQ(inst.no_output_opcode, s[0]->arch_opcode()); | 3564 EXPECT_EQ(inst.no_output_opcode, s[0]->arch_opcode()); |
3594 EXPECT_EQ(s.ToVreg(m.Parameter(0)), s.ToVreg(s[0]->InputAt(0))); | 3565 EXPECT_EQ(s.ToVreg(m.Parameter(0)), s.ToVreg(s[0]->InputAt(0))); |
3595 EXPECT_EQ(3, s.ToInt32(s[0]->InputAt(1))); | 3566 EXPECT_EQ(3, s.ToInt32(s[0]->InputAt(1))); |
3596 EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); | 3567 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); |
3597 EXPECT_EQ(cmp.cond, s[0]->flags_condition()); | 3568 EXPECT_EQ(cmp.cond, s[0]->flags_condition()); |
3598 } | 3569 } |
3599 } | 3570 } |
3600 | 3571 |
3601 TEST_P(InstructionSelectorFlagSettingTest, CommuteShift) { | 3572 TEST_P(InstructionSelectorFlagSettingTest, CommuteShift) { |
3602 const FlagSettingInst inst = GetParam(); | 3573 const FlagSettingInst inst = GetParam(); |
3603 // Left-hand side operand shifted by immediate. | 3574 // Left-hand side operand shifted by immediate. |
3604 TRACED_FOREACH(IntegerCmp, cmp, kBinopCmpZeroRightInstructions) { | 3575 TRACED_FOREACH(IntegerCmp, cmp, kBinopCmpZeroRightInstructions) { |
3605 TRACED_FOREACH(Shift, shift, kShiftInstructions) { | 3576 TRACED_FOREACH(Shift, shift, kShiftInstructions) { |
3606 // Only test relevant shifted operands. | 3577 // Only test relevant shifted operands. |
(...skipping 26 matching lines...) Expand all Loading... |
3633 } | 3604 } |
3634 | 3605 |
3635 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, | 3606 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, |
3636 InstructionSelectorFlagSettingTest, | 3607 InstructionSelectorFlagSettingTest, |
3637 ::testing::ValuesIn(kFlagSettingInstructions)); | 3608 ::testing::ValuesIn(kFlagSettingInstructions)); |
3638 | 3609 |
3639 TEST_F(InstructionSelectorTest, TstInvalidImmediate) { | 3610 TEST_F(InstructionSelectorTest, TstInvalidImmediate) { |
3640 // Make sure we do not generate an invalid immediate for TST. | 3611 // Make sure we do not generate an invalid immediate for TST. |
3641 TRACED_FOREACH(IntegerCmp, cmp, kBinopCmpZeroRightInstructions) { | 3612 TRACED_FOREACH(IntegerCmp, cmp, kBinopCmpZeroRightInstructions) { |
3642 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); | 3613 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); |
3643 RawMachineLabel a, b; | |
3644 // 5 is not a valid constant for TST. | 3614 // 5 is not a valid constant for TST. |
3645 Node* imm = m.Int32Constant(5); | 3615 Node* imm = m.Int32Constant(5); |
3646 Node* binop = m.Word32And(imm, m.Parameter(0)); | 3616 Node* binop = m.Word32And(imm, m.Parameter(0)); |
3647 Node* comp = (m.*cmp.mi.constructor)(binop, m.Int32Constant(0)); | 3617 Node* comp = (m.*cmp.mi.constructor)(binop, m.Int32Constant(0)); |
3648 m.Branch(comp, &a, &b); | 3618 m.Return(comp); |
3649 m.Bind(&a); | |
3650 m.Return(m.Int32Constant(1)); | |
3651 m.Bind(&b); | |
3652 m.Return(m.Int32Constant(0)); | |
3653 Stream s = m.Build(); | 3619 Stream s = m.Build(); |
3654 ASSERT_EQ(1U, s.size()); | 3620 ASSERT_EQ(1U, s.size()); |
3655 ASSERT_EQ(4U, s[0]->InputCount()); // The labels are also inputs. | 3621 ASSERT_EQ(2U, s[0]->InputCount()); |
3656 EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode()); | 3622 EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode()); |
3657 EXPECT_NE(InstructionOperand::IMMEDIATE, s[0]->InputAt(0)->kind()); | 3623 EXPECT_NE(InstructionOperand::IMMEDIATE, s[0]->InputAt(0)->kind()); |
3658 EXPECT_NE(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind()); | 3624 EXPECT_NE(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind()); |
3659 EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); | 3625 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); |
3660 EXPECT_EQ(cmp.cond, s[0]->flags_condition()); | 3626 EXPECT_EQ(cmp.cond, s[0]->flags_condition()); |
3661 } | 3627 } |
3662 } | 3628 } |
3663 | 3629 |
3664 TEST_F(InstructionSelectorTest, CommuteAddsExtend) { | 3630 TEST_F(InstructionSelectorTest, CommuteAddsExtend) { |
3665 // Extended left-hand side operand. | 3631 // Extended left-hand side operand. |
3666 TRACED_FOREACH(IntegerCmp, cmp, kBinopCmpZeroRightInstructions) { | 3632 TRACED_FOREACH(IntegerCmp, cmp, kBinopCmpZeroRightInstructions) { |
3667 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), | 3633 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), |
3668 MachineType::Int32()); | 3634 MachineType::Int32()); |
3669 Node* extend = m.Word32Sar(m.Word32Shl(m.Parameter(0), m.Int32Constant(24)), | 3635 Node* extend = m.Word32Sar(m.Word32Shl(m.Parameter(0), m.Int32Constant(24)), |
(...skipping 668 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4338 EXPECT_EQ(kMode_MRI, s[0]->addressing_mode()); | 4304 EXPECT_EQ(kMode_MRI, s[0]->addressing_mode()); |
4339 EXPECT_EQ(2U, s[0]->InputCount()); | 4305 EXPECT_EQ(2U, s[0]->InputCount()); |
4340 EXPECT_EQ(s.ToVreg(m.Parameter(0)), s.ToVreg(s[0]->InputAt(0))); | 4306 EXPECT_EQ(s.ToVreg(m.Parameter(0)), s.ToVreg(s[0]->InputAt(0))); |
4341 ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind()); | 4307 ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind()); |
4342 EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1))); | 4308 EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1))); |
4343 ASSERT_EQ(1U, s[0]->OutputCount()); | 4309 ASSERT_EQ(1U, s[0]->OutputCount()); |
4344 } | 4310 } |
4345 } | 4311 } |
4346 } | 4312 } |
4347 | 4313 |
| 4314 TEST_F(InstructionSelectorTest, CompareAgainstZero32) { |
| 4315 TRACED_FOREACH(IntegerCmp, cmp, kBinopCmpZeroRightInstructions) { |
| 4316 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); |
| 4317 Node* const param = m.Parameter(0); |
| 4318 RawMachineLabel a, b; |
| 4319 m.Branch((m.*cmp.mi.constructor)(param, m.Int32Constant(0)), &a, &b); |
| 4320 m.Bind(&a); |
| 4321 m.Return(m.Int32Constant(1)); |
| 4322 m.Bind(&b); |
| 4323 m.Return(m.Int32Constant(0)); |
| 4324 Stream s = m.Build(); |
| 4325 ASSERT_EQ(1U, s.size()); |
| 4326 EXPECT_EQ(s.ToVreg(param), s.ToVreg(s[0]->InputAt(0))); |
| 4327 if (cmp.cond == kNegative || cmp.cond == kPositiveOrZero) { |
| 4328 EXPECT_EQ(kArm64TestAndBranch32, s[0]->arch_opcode()); |
| 4329 EXPECT_EQ(4U, s[0]->InputCount()); // The labels are also inputs. |
| 4330 EXPECT_EQ((cmp.cond == kNegative) ? kNotEqual : kEqual, |
| 4331 s[0]->flags_condition()); |
| 4332 EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind()); |
| 4333 EXPECT_EQ(31, s.ToInt32(s[0]->InputAt(1))); |
| 4334 } else { |
| 4335 EXPECT_EQ(kArm64CompareAndBranch32, s[0]->arch_opcode()); |
| 4336 EXPECT_EQ(3U, s[0]->InputCount()); // The labels are also inputs. |
| 4337 EXPECT_EQ(cmp.cond, s[0]->flags_condition()); |
| 4338 } |
| 4339 } |
| 4340 } |
| 4341 |
| 4342 TEST_F(InstructionSelectorTest, CompareFloat64HighLessThanZero64) { |
| 4343 StreamBuilder m(this, MachineType::Int32(), MachineType::Float64()); |
| 4344 Node* const param = m.Parameter(0); |
| 4345 Node* const high = m.Float64ExtractHighWord32(param); |
| 4346 RawMachineLabel a, b; |
| 4347 m.Branch(m.Int32LessThan(high, m.Int32Constant(0)), &a, &b); |
| 4348 m.Bind(&a); |
| 4349 m.Return(m.Int32Constant(1)); |
| 4350 m.Bind(&b); |
| 4351 m.Return(m.Int32Constant(0)); |
| 4352 Stream s = m.Build(); |
| 4353 ASSERT_EQ(2U, s.size()); |
| 4354 EXPECT_EQ(kArm64U64MoveFloat64, s[0]->arch_opcode()); |
| 4355 EXPECT_EQ(kArm64TestAndBranch, s[1]->arch_opcode()); |
| 4356 EXPECT_EQ(kNotEqual, s[1]->flags_condition()); |
| 4357 EXPECT_EQ(4U, s[1]->InputCount()); |
| 4358 EXPECT_EQ(InstructionOperand::IMMEDIATE, s[1]->InputAt(1)->kind()); |
| 4359 EXPECT_EQ(63, s.ToInt32(s[1]->InputAt(1))); |
| 4360 } |
| 4361 |
| 4362 TEST_F(InstructionSelectorTest, CompareFloat64HighGreaterThanOrEqualZero64) { |
| 4363 StreamBuilder m(this, MachineType::Int32(), MachineType::Float64()); |
| 4364 Node* const param = m.Parameter(0); |
| 4365 Node* const high = m.Float64ExtractHighWord32(param); |
| 4366 RawMachineLabel a, b; |
| 4367 m.Branch(m.Int32GreaterThanOrEqual(high, m.Int32Constant(0)), &a, &b); |
| 4368 m.Bind(&a); |
| 4369 m.Return(m.Int32Constant(1)); |
| 4370 m.Bind(&b); |
| 4371 m.Return(m.Int32Constant(0)); |
| 4372 Stream s = m.Build(); |
| 4373 ASSERT_EQ(2U, s.size()); |
| 4374 EXPECT_EQ(kArm64U64MoveFloat64, s[0]->arch_opcode()); |
| 4375 EXPECT_EQ(kArm64TestAndBranch, s[1]->arch_opcode()); |
| 4376 EXPECT_EQ(kEqual, s[1]->flags_condition()); |
| 4377 EXPECT_EQ(4U, s[1]->InputCount()); |
| 4378 EXPECT_EQ(InstructionOperand::IMMEDIATE, s[1]->InputAt(1)->kind()); |
| 4379 EXPECT_EQ(63, s.ToInt32(s[1]->InputAt(1))); |
| 4380 } |
| 4381 |
4348 } // namespace compiler | 4382 } // namespace compiler |
4349 } // namespace internal | 4383 } // namespace internal |
4350 } // namespace v8 | 4384 } // namespace v8 |
OLD | NEW |