Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(12)

Side by Side Diff: test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc

Issue 2359723004: [arm64] Check sign with TBZ/TBNZ. (Closed)
Patch Set: Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/compiler/arm64/instruction-selector-arm64.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/compiler/arm64/instruction-selector-arm64.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698