| 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 |