diff options
Diffstat (limited to 'deps/v8/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc')
-rw-r--r-- | deps/v8/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc | 218 |
1 files changed, 143 insertions, 75 deletions
diff --git a/deps/v8/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc b/deps/v8/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc index 6ca5e5e684..7892c4bbb9 100644 --- a/deps/v8/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc +++ b/deps/v8/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc @@ -402,7 +402,6 @@ TEST_P(InstructionSelectorLogicalTest, Parameter) { TEST_P(InstructionSelectorLogicalTest, Immediate) { const MachInst2 dpi = GetParam(); const MachineType type = dpi.machine_type; - // TODO(all): Add support for testing 64-bit immediates. if (type == MachineType::Int32()) { // Immediate on the right. TRACED_FOREACH(int32_t, imm, kLogical32Immediates) { @@ -429,6 +428,32 @@ TEST_P(InstructionSelectorLogicalTest, Immediate) { EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); EXPECT_EQ(1U, s[0]->OutputCount()); } + } else if (type == MachineType::Int64()) { + // Immediate on the right. + TRACED_FOREACH(int64_t, imm, kLogical64Immediates) { + StreamBuilder m(this, type, type); + m.Return((m.*dpi.constructor)(m.Parameter(0), m.Int64Constant(imm))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); + ASSERT_EQ(2U, s[0]->InputCount()); + EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate()); + EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1))); + EXPECT_EQ(1U, s[0]->OutputCount()); + } + + // Immediate on the left; all logical ops should commute. + TRACED_FOREACH(int64_t, imm, kLogical64Immediates) { + StreamBuilder m(this, type, type); + m.Return((m.*dpi.constructor)(m.Int64Constant(imm), m.Parameter(0))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); + ASSERT_EQ(2U, s[0]->InputCount()); + EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate()); + EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1))); + EXPECT_EQ(1U, s[0]->OutputCount()); + } } } @@ -1067,7 +1092,8 @@ TEST_F(InstructionSelectorTest, SubBranchWithImmediateOnRight) { m.Return(m.Int32Constant(0)); Stream s = m.Build(); ASSERT_EQ(1U, s.size()); - EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode()); + EXPECT_EQ((imm == 0) ? kArm64CompareAndBranch32 : kArm64Cmp32, + s[0]->arch_opcode()); EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); EXPECT_EQ(kNotEqual, s[0]->flags_condition()); } @@ -3142,11 +3168,20 @@ const IntegerCmp kIntegerCmpInstructions[] = { kUnsignedLessThanOrEqual, kUnsignedGreaterThanOrEqual}}; +const IntegerCmp kIntegerCmpEqualityInstructions[] = { + {{&RawMachineAssembler::Word32Equal, "Word32Equal", kArm64Cmp32, + MachineType::Int32()}, + kEqual, + kEqual}, + {{&RawMachineAssembler::Word32NotEqual, "Word32NotEqual", kArm64Cmp32, + MachineType::Int32()}, + kNotEqual, + kNotEqual}}; } // namespace TEST_F(InstructionSelectorTest, Word32CompareNegateWithWord32Shift) { - TRACED_FOREACH(IntegerCmp, cmp, kIntegerCmpInstructions) { + TRACED_FOREACH(IntegerCmp, cmp, kIntegerCmpEqualityInstructions) { TRACED_FOREACH(Shift, shift, kShiftInstructions) { // Test 32-bit operations. Ignore ROR shifts, as compare-negate does not // support them. @@ -3183,19 +3218,16 @@ TEST_F(InstructionSelectorTest, CmpWithImmediateOnLeft) { // kEqual and kNotEqual trigger the cbz/cbnz optimization, which // is tested elsewhere. if (cmp.cond == kEqual || cmp.cond == kNotEqual) continue; + // For signed less than or equal to zero, we generate TBNZ. + if (cmp.cond == kSignedLessThanOrEqual && imm == 0) continue; StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); Node* const p0 = m.Parameter(0); - RawMachineLabel a, b; - m.Branch((m.*cmp.mi.constructor)(m.Int32Constant(imm), p0), &a, &b); - m.Bind(&a); - m.Return(m.Int32Constant(1)); - m.Bind(&b); - m.Return(m.Int32Constant(0)); + m.Return((m.*cmp.mi.constructor)(m.Int32Constant(imm), p0)); Stream s = m.Build(); ASSERT_EQ(1U, s.size()); EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode()); ASSERT_LE(2U, s[0]->InputCount()); - EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); + EXPECT_EQ(kFlags_set, s[0]->flags_mode()); EXPECT_EQ(cmp.commuted_cond, s[0]->flags_condition()); EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); } @@ -3203,24 +3235,19 @@ TEST_F(InstructionSelectorTest, CmpWithImmediateOnLeft) { } TEST_F(InstructionSelectorTest, CmnWithImmediateOnLeft) { - TRACED_FOREACH(IntegerCmp, cmp, kIntegerCmpInstructions) { + TRACED_FOREACH(IntegerCmp, cmp, kIntegerCmpEqualityInstructions) { TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { // kEqual and kNotEqual trigger the cbz/cbnz optimization, which // is tested elsewhere. if (cmp.cond == kEqual || cmp.cond == kNotEqual) continue; StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); Node* sub = m.Int32Sub(m.Int32Constant(0), m.Parameter(0)); - RawMachineLabel a, b; - m.Branch((m.*cmp.mi.constructor)(m.Int32Constant(imm), sub), &a, &b); - m.Bind(&a); - m.Return(m.Int32Constant(1)); - m.Bind(&b); - m.Return(m.Int32Constant(0)); + m.Return((m.*cmp.mi.constructor)(m.Int32Constant(imm), sub)); Stream s = m.Build(); ASSERT_EQ(1U, s.size()); EXPECT_EQ(kArm64Cmn32, s[0]->arch_opcode()); ASSERT_LE(2U, s[0]->InputCount()); - EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); + EXPECT_EQ(kFlags_set, s[0]->flags_mode()); EXPECT_EQ(cmp.cond, s[0]->flags_condition()); EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); } @@ -3244,7 +3271,7 @@ TEST_F(InstructionSelectorTest, CmpSignedExtendByteOnLeft) { } TEST_F(InstructionSelectorTest, CmnSignedExtendByteOnLeft) { - TRACED_FOREACH(IntegerCmp, cmp, kIntegerCmpInstructions) { + TRACED_FOREACH(IntegerCmp, cmp, kIntegerCmpEqualityInstructions) { StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), MachineType::Int32()); Node* sub = m.Int32Sub(m.Int32Constant(0), m.Parameter(0)); @@ -3294,7 +3321,7 @@ TEST_F(InstructionSelectorTest, CmpShiftByImmediateOnLeft) { } TEST_F(InstructionSelectorTest, CmnShiftByImmediateOnLeft) { - TRACED_FOREACH(IntegerCmp, cmp, kIntegerCmpInstructions) { + TRACED_FOREACH(IntegerCmp, cmp, kIntegerCmpEqualityInstructions) { TRACED_FOREACH(Shift, shift, kShiftInstructions) { // Only test relevant shifted operands. if (shift.mi.machine_type != MachineType::Int32()) continue; @@ -3408,21 +3435,15 @@ TEST_P(InstructionSelectorFlagSettingTest, CmpZeroRight) { TRACED_FOREACH(IntegerCmp, cmp, kBinopCmpZeroRightInstructions) { StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), MachineType::Int32()); - RawMachineLabel a, b; Node* binop = (m.*inst.mi.constructor)(m.Parameter(0), m.Parameter(1)); - Node* comp = (m.*cmp.mi.constructor)(binop, m.Int32Constant(0)); - m.Branch(comp, &a, &b); - m.Bind(&a); - m.Return(m.Int32Constant(1)); - m.Bind(&b); - m.Return(m.Int32Constant(0)); + m.Return((m.*cmp.mi.constructor)(binop, m.Int32Constant(0))); Stream s = m.Build(); ASSERT_EQ(1U, s.size()); - ASSERT_EQ(4U, s[0]->InputCount()); // The labels are also inputs. + ASSERT_EQ(2U, s[0]->InputCount()); EXPECT_EQ(inst.no_output_opcode, s[0]->arch_opcode()); EXPECT_EQ(s.ToVreg(m.Parameter(0)), s.ToVreg(s[0]->InputAt(0))); EXPECT_EQ(s.ToVreg(m.Parameter(1)), s.ToVreg(s[0]->InputAt(1))); - EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); + EXPECT_EQ(kFlags_set, s[0]->flags_mode()); EXPECT_EQ(cmp.cond, s[0]->flags_condition()); } } @@ -3433,21 +3454,15 @@ TEST_P(InstructionSelectorFlagSettingTest, CmpZeroLeft) { TRACED_FOREACH(IntegerCmp, cmp, kBinopCmpZeroLeftInstructions) { StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), MachineType::Int32()); - RawMachineLabel a, b; Node* binop = (m.*inst.mi.constructor)(m.Parameter(0), m.Parameter(1)); - Node* comp = (m.*cmp.mi.constructor)(m.Int32Constant(0), binop); - m.Branch(comp, &a, &b); - m.Bind(&a); - m.Return(m.Int32Constant(1)); - m.Bind(&b); - m.Return(m.Int32Constant(0)); + m.Return((m.*cmp.mi.constructor)(m.Int32Constant(0), binop)); Stream s = m.Build(); ASSERT_EQ(1U, s.size()); - ASSERT_EQ(4U, s[0]->InputCount()); // The labels are also inputs. + ASSERT_EQ(2U, s[0]->InputCount()); EXPECT_EQ(inst.no_output_opcode, s[0]->arch_opcode()); EXPECT_EQ(s.ToVreg(m.Parameter(0)), s.ToVreg(s[0]->InputAt(0))); EXPECT_EQ(s.ToVreg(m.Parameter(1)), s.ToVreg(s[0]->InputAt(1))); - EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); + EXPECT_EQ(kFlags_set, s[0]->flags_mode()); EXPECT_EQ(cmp.cond, s[0]->flags_condition()); } } @@ -3456,25 +3471,23 @@ TEST_P(InstructionSelectorFlagSettingTest, CmpZeroOnlyUserInBasicBlock) { const FlagSettingInst inst = GetParam(); // Binop with additional users, but in a different basic block. TRACED_FOREACH(IntegerCmp, cmp, kBinopCmpZeroRightInstructions) { - // For kEqual and kNotEqual, we generate a cbz or cbnz. - if (cmp.cond == kEqual || cmp.cond == kNotEqual) continue; StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), MachineType::Int32()); RawMachineLabel a, b; Node* binop = (m.*inst.mi.constructor)(m.Parameter(0), m.Parameter(1)); Node* comp = (m.*cmp.mi.constructor)(binop, m.Int32Constant(0)); - m.Branch(comp, &a, &b); + m.Branch(m.Parameter(0), &a, &b); m.Bind(&a); m.Return(binop); m.Bind(&b); - m.Return(m.Int32Constant(0)); + m.Return(comp); Stream s = m.Build(); - ASSERT_EQ(1U, s.size()); - ASSERT_EQ(4U, s[0]->InputCount()); // The labels are also inputs. + ASSERT_EQ(2U, s.size()); // Flag-setting instruction and branch. + ASSERT_EQ(2U, s[0]->InputCount()); EXPECT_EQ(inst.mi.arch_opcode, s[0]->arch_opcode()); EXPECT_EQ(s.ToVreg(m.Parameter(0)), s.ToVreg(s[0]->InputAt(0))); EXPECT_EQ(s.ToVreg(m.Parameter(1)), s.ToVreg(s[0]->InputAt(1))); - EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); + EXPECT_EQ(kFlags_set, s[0]->flags_mode()); EXPECT_EQ(cmp.cond, s[0]->flags_condition()); } } @@ -3483,8 +3496,6 @@ TEST_P(InstructionSelectorFlagSettingTest, ShiftedOperand) { const FlagSettingInst inst = GetParam(); // Like the test above, but with a shifted input to the binary operator. TRACED_FOREACH(IntegerCmp, cmp, kBinopCmpZeroRightInstructions) { - // For kEqual and kNotEqual, we generate a cbz or cbnz. - if (cmp.cond == kEqual || cmp.cond == kNotEqual) continue; StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), MachineType::Int32()); RawMachineLabel a, b; @@ -3492,20 +3503,20 @@ TEST_P(InstructionSelectorFlagSettingTest, ShiftedOperand) { Node* shift = m.Word32Shl(m.Parameter(1), imm); Node* binop = (m.*inst.mi.constructor)(m.Parameter(0), shift); Node* comp = (m.*cmp.mi.constructor)(binop, m.Int32Constant(0)); - m.Branch(comp, &a, &b); + m.Branch(m.Parameter(0), &a, &b); m.Bind(&a); m.Return(binop); m.Bind(&b); - m.Return(m.Int32Constant(0)); + m.Return(comp); Stream s = m.Build(); - ASSERT_EQ(1U, s.size()); - ASSERT_EQ(5U, s[0]->InputCount()); // The labels are also inputs. + ASSERT_EQ(2U, s.size()); // Flag-setting instruction and branch. + ASSERT_EQ(3U, s[0]->InputCount()); EXPECT_EQ(inst.mi.arch_opcode, s[0]->arch_opcode()); EXPECT_EQ(s.ToVreg(m.Parameter(0)), s.ToVreg(s[0]->InputAt(0))); EXPECT_EQ(s.ToVreg(m.Parameter(1)), s.ToVreg(s[0]->InputAt(1))); EXPECT_EQ(5, s.ToInt32(s[0]->InputAt(2))); EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode()); - EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); + EXPECT_EQ(kFlags_set, s[0]->flags_mode()); EXPECT_EQ(cmp.cond, s[0]->flags_condition()); } } @@ -3521,19 +3532,18 @@ TEST_P(InstructionSelectorFlagSettingTest, UsersInSameBasicBlock) { Node* binop = (m.*inst.mi.constructor)(m.Parameter(0), m.Parameter(1)); Node* mul = m.Int32Mul(m.Parameter(0), binop); Node* comp = (m.*cmp.mi.constructor)(binop, m.Int32Constant(0)); - m.Branch(comp, &a, &b); + m.Branch(m.Parameter(0), &a, &b); m.Bind(&a); m.Return(mul); m.Bind(&b); - m.Return(m.Int32Constant(0)); + m.Return(comp); Stream s = m.Build(); - ASSERT_EQ(3U, s.size()); + ASSERT_EQ(4U, s.size()); // Includes the compare and branch instruction. EXPECT_EQ(inst.mi.arch_opcode, s[0]->arch_opcode()); - EXPECT_NE(kFlags_branch, s[0]->flags_mode()); + EXPECT_EQ(kFlags_none, s[0]->flags_mode()); EXPECT_EQ(kArm64Mul32, s[1]->arch_opcode()); - EXPECT_EQ(cmp.cond == kEqual ? kArm64CompareAndBranch32 : kArm64Cmp32, - s[2]->arch_opcode()); - EXPECT_EQ(kFlags_branch, s[2]->flags_mode()); + EXPECT_EQ(kArm64Cmp32, s[2]->arch_opcode()); + EXPECT_EQ(kFlags_set, s[2]->flags_mode()); EXPECT_EQ(cmp.cond, s[2]->flags_condition()); } } @@ -3543,23 +3553,18 @@ TEST_P(InstructionSelectorFlagSettingTest, CommuteImmediate) { // Immediate on left hand side of the binary operator. TRACED_FOREACH(IntegerCmp, cmp, kBinopCmpZeroRightInstructions) { StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); - RawMachineLabel a, b; // 3 can be an immediate on both arithmetic and logical instructions. Node* imm = m.Int32Constant(3); Node* binop = (m.*inst.mi.constructor)(imm, m.Parameter(0)); Node* comp = (m.*cmp.mi.constructor)(binop, m.Int32Constant(0)); - m.Branch(comp, &a, &b); - m.Bind(&a); - m.Return(m.Int32Constant(1)); - m.Bind(&b); - m.Return(m.Int32Constant(0)); + m.Return(comp); Stream s = m.Build(); ASSERT_EQ(1U, s.size()); - ASSERT_EQ(4U, s[0]->InputCount()); // The labels are also inputs. + ASSERT_EQ(2U, s[0]->InputCount()); EXPECT_EQ(inst.no_output_opcode, s[0]->arch_opcode()); EXPECT_EQ(s.ToVreg(m.Parameter(0)), s.ToVreg(s[0]->InputAt(0))); EXPECT_EQ(3, s.ToInt32(s[0]->InputAt(1))); - EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); + EXPECT_EQ(kFlags_set, s[0]->flags_mode()); EXPECT_EQ(cmp.cond, s[0]->flags_condition()); } } @@ -3606,23 +3611,18 @@ TEST_F(InstructionSelectorTest, TstInvalidImmediate) { // Make sure we do not generate an invalid immediate for TST. TRACED_FOREACH(IntegerCmp, cmp, kBinopCmpZeroRightInstructions) { StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); - RawMachineLabel a, b; // 5 is not a valid constant for TST. Node* imm = m.Int32Constant(5); Node* binop = m.Word32And(imm, m.Parameter(0)); Node* comp = (m.*cmp.mi.constructor)(binop, m.Int32Constant(0)); - m.Branch(comp, &a, &b); - m.Bind(&a); - m.Return(m.Int32Constant(1)); - m.Bind(&b); - m.Return(m.Int32Constant(0)); + m.Return(comp); Stream s = m.Build(); ASSERT_EQ(1U, s.size()); - ASSERT_EQ(4U, s[0]->InputCount()); // The labels are also inputs. + ASSERT_EQ(2U, s[0]->InputCount()); EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode()); EXPECT_NE(InstructionOperand::IMMEDIATE, s[0]->InputAt(0)->kind()); EXPECT_NE(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind()); - EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); + EXPECT_EQ(kFlags_set, s[0]->flags_mode()); EXPECT_EQ(cmp.cond, s[0]->flags_condition()); } } @@ -4311,6 +4311,74 @@ TEST_F(InstructionSelectorTest, LoadAndShiftRight) { } } +TEST_F(InstructionSelectorTest, CompareAgainstZero32) { + TRACED_FOREACH(IntegerCmp, cmp, kBinopCmpZeroRightInstructions) { + StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); + Node* const param = m.Parameter(0); + RawMachineLabel a, b; + m.Branch((m.*cmp.mi.constructor)(param, m.Int32Constant(0)), &a, &b); + m.Bind(&a); + m.Return(m.Int32Constant(1)); + m.Bind(&b); + m.Return(m.Int32Constant(0)); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(s.ToVreg(param), s.ToVreg(s[0]->InputAt(0))); + if (cmp.cond == kNegative || cmp.cond == kPositiveOrZero) { + EXPECT_EQ(kArm64TestAndBranch32, s[0]->arch_opcode()); + EXPECT_EQ(4U, s[0]->InputCount()); // The labels are also inputs. + EXPECT_EQ((cmp.cond == kNegative) ? kNotEqual : kEqual, + s[0]->flags_condition()); + EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind()); + EXPECT_EQ(31, s.ToInt32(s[0]->InputAt(1))); + } else { + EXPECT_EQ(kArm64CompareAndBranch32, s[0]->arch_opcode()); + EXPECT_EQ(3U, s[0]->InputCount()); // The labels are also inputs. + EXPECT_EQ(cmp.cond, s[0]->flags_condition()); + } + } +} + +TEST_F(InstructionSelectorTest, CompareFloat64HighLessThanZero64) { + StreamBuilder m(this, MachineType::Int32(), MachineType::Float64()); + Node* const param = m.Parameter(0); + Node* const high = m.Float64ExtractHighWord32(param); + RawMachineLabel a, b; + m.Branch(m.Int32LessThan(high, m.Int32Constant(0)), &a, &b); + m.Bind(&a); + m.Return(m.Int32Constant(1)); + m.Bind(&b); + m.Return(m.Int32Constant(0)); + Stream s = m.Build(); + ASSERT_EQ(2U, s.size()); + EXPECT_EQ(kArm64U64MoveFloat64, s[0]->arch_opcode()); + EXPECT_EQ(kArm64TestAndBranch, s[1]->arch_opcode()); + EXPECT_EQ(kNotEqual, s[1]->flags_condition()); + EXPECT_EQ(4U, s[1]->InputCount()); + EXPECT_EQ(InstructionOperand::IMMEDIATE, s[1]->InputAt(1)->kind()); + EXPECT_EQ(63, s.ToInt32(s[1]->InputAt(1))); +} + +TEST_F(InstructionSelectorTest, CompareFloat64HighGreaterThanOrEqualZero64) { + StreamBuilder m(this, MachineType::Int32(), MachineType::Float64()); + Node* const param = m.Parameter(0); + Node* const high = m.Float64ExtractHighWord32(param); + RawMachineLabel a, b; + m.Branch(m.Int32GreaterThanOrEqual(high, m.Int32Constant(0)), &a, &b); + m.Bind(&a); + m.Return(m.Int32Constant(1)); + m.Bind(&b); + m.Return(m.Int32Constant(0)); + Stream s = m.Build(); + ASSERT_EQ(2U, s.size()); + EXPECT_EQ(kArm64U64MoveFloat64, s[0]->arch_opcode()); + EXPECT_EQ(kArm64TestAndBranch, s[1]->arch_opcode()); + EXPECT_EQ(kEqual, s[1]->flags_condition()); + EXPECT_EQ(4U, s[1]->InputCount()); + EXPECT_EQ(InstructionOperand::IMMEDIATE, s[1]->InputAt(1)->kind()); + EXPECT_EQ(63, s.ToInt32(s[1]->InputAt(1))); +} + } // namespace compiler } // namespace internal } // namespace v8 |