diff options
author | Michaël Zasso <targos@protonmail.com> | 2016-12-23 16:30:57 +0100 |
---|---|---|
committer | Michaël Zasso <targos@protonmail.com> | 2017-01-26 22:46:17 +0100 |
commit | 2739185b790e040c3b044c577327f5d44bffad4a (patch) | |
tree | 29a466999212f4c85958379d9d400eec8a185ba5 /deps/v8/test/unittests/compiler | |
parent | a67a04d7654faaa04c8da00e42981ebc9fd0911c (diff) | |
download | node-new-2739185b790e040c3b044c577327f5d44bffad4a.tar.gz |
deps: update V8 to 5.5.372.40
PR-URL: https://github.com/nodejs/node/pull/9618
Reviewed-By: Ali Ijaz Sheikh <ofrobots@google.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Diffstat (limited to 'deps/v8/test/unittests/compiler')
24 files changed, 1618 insertions, 816 deletions
diff --git a/deps/v8/test/unittests/compiler/arm/instruction-selector-arm-unittest.cc b/deps/v8/test/unittests/compiler/arm/instruction-selector-arm-unittest.cc index 6317d91fa9..746624a691 100644 --- a/deps/v8/test/unittests/compiler/arm/instruction-selector-arm-unittest.cc +++ b/deps/v8/test/unittests/compiler/arm/instruction-selector-arm-unittest.cc @@ -2079,10 +2079,6 @@ TEST_P(InstructionSelectorFlagSettingTest, CmpZeroOnlyUserInBasicBlock) { const FlagSettingInst inst = GetParam(); // Binop with additional users, but in a different basic block. TRACED_FOREACH(Comparison, cmp, kBinopCmpZeroRightInstructions) { - // We don't optimise this case at the moment. - if (cmp.flags_condition == kEqual || cmp.flags_condition == kNotEqual) { - continue; - } StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), MachineType::Int32()); RawMachineLabel a, b; @@ -2108,10 +2104,6 @@ TEST_P(InstructionSelectorFlagSettingTest, ShiftedOperand) { const FlagSettingInst inst = GetParam(); // Like the test above, but with a shifted input to the binary operator. TRACED_FOREACH(Comparison, cmp, kBinopCmpZeroRightInstructions) { - // We don't optimise this case at the moment. - if (cmp.flags_condition == kEqual || cmp.flags_condition == kNotEqual) { - continue; - } StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), MachineType::Int32()); RawMachineLabel a, b; @@ -2158,8 +2150,7 @@ TEST_P(InstructionSelectorFlagSettingTest, UsersInSameBasicBlock) { EXPECT_EQ(inst.arch_opcode, s[0]->arch_opcode()); EXPECT_NE(kFlags_branch, s[0]->flags_mode()); EXPECT_EQ(kArmMul, s[1]->arch_opcode()); - EXPECT_EQ(cmp.flags_condition == kEqual ? kArmTst : kArmCmp, - s[2]->arch_opcode()); + EXPECT_EQ(kArmCmp, s[2]->arch_opcode()); EXPECT_EQ(kFlags_branch, s[2]->flags_mode()); EXPECT_EQ(cmp.flags_condition, s[2]->flags_condition()); } @@ -3059,10 +3050,11 @@ TEST_F(InstructionSelectorTest, Word32EqualWithZero) { m.Return(m.Word32Equal(m.Parameter(0), m.Int32Constant(0))); Stream s = m.Build(); ASSERT_EQ(1U, s.size()); - EXPECT_EQ(kArmTst, s[0]->arch_opcode()); - EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode()); + EXPECT_EQ(kArmCmp, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode()); ASSERT_EQ(2U, s[0]->InputCount()); - EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1))); + EXPECT_EQ(s.ToVreg(m.Parameter(0)), s.ToVreg(s[0]->InputAt(0))); + EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(1))); EXPECT_EQ(1U, s[0]->OutputCount()); EXPECT_EQ(kFlags_set, s[0]->flags_mode()); EXPECT_EQ(kEqual, s[0]->flags_condition()); @@ -3072,10 +3064,11 @@ TEST_F(InstructionSelectorTest, Word32EqualWithZero) { m.Return(m.Word32Equal(m.Int32Constant(0), m.Parameter(0))); Stream s = m.Build(); ASSERT_EQ(1U, s.size()); - EXPECT_EQ(kArmTst, s[0]->arch_opcode()); - EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode()); + EXPECT_EQ(kArmCmp, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode()); ASSERT_EQ(2U, s[0]->InputCount()); - EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1))); + EXPECT_EQ(s.ToVreg(m.Parameter(0)), s.ToVreg(s[0]->InputAt(0))); + EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(1))); EXPECT_EQ(1U, s[0]->OutputCount()); EXPECT_EQ(kFlags_set, s[0]->flags_mode()); EXPECT_EQ(kEqual, s[0]->flags_condition()); 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 diff --git a/deps/v8/test/unittests/compiler/branch-elimination-unittest.cc b/deps/v8/test/unittests/compiler/branch-elimination-unittest.cc index fcd702c428..9486d1fe6e 100644 --- a/deps/v8/test/unittests/compiler/branch-elimination-unittest.cc +++ b/deps/v8/test/unittests/compiler/branch-elimination-unittest.cc @@ -15,7 +15,7 @@ namespace v8 { namespace internal { namespace compiler { -class BranchEliminationTest : public TypedGraphTest { +class BranchEliminationTest : public GraphTest { public: BranchEliminationTest() : machine_(zone(), MachineType::PointerRepresentation(), diff --git a/deps/v8/test/unittests/compiler/common-operator-reducer-unittest.cc b/deps/v8/test/unittests/compiler/common-operator-reducer-unittest.cc index f51a54d074..d284772395 100644 --- a/deps/v8/test/unittests/compiler/common-operator-reducer-unittest.cc +++ b/deps/v8/test/unittests/compiler/common-operator-reducer-unittest.cc @@ -158,6 +158,26 @@ TEST_F(CommonOperatorReducerTest, BranchWithBooleanNot) { } } +TEST_F(CommonOperatorReducerTest, BranchWithSelect) { + Node* const value = Parameter(0); + TRACED_FOREACH(BranchHint, hint, kBranchHints) { + Node* const control = graph()->start(); + Node* const branch = graph()->NewNode( + common()->Branch(hint), + graph()->NewNode(common()->Select(MachineRepresentation::kTagged), + value, FalseConstant(), TrueConstant()), + control); + Node* const if_true = graph()->NewNode(common()->IfTrue(), branch); + Node* const if_false = graph()->NewNode(common()->IfFalse(), branch); + Reduction const r = Reduce(branch); + ASSERT_TRUE(r.Changed()); + EXPECT_EQ(branch, r.replacement()); + EXPECT_THAT(branch, IsBranch(value, control)); + EXPECT_THAT(if_false, IsIfTrue(branch)); + EXPECT_THAT(if_true, IsIfFalse(branch)); + EXPECT_EQ(NegateBranchHint(hint), BranchHintOf(branch->op())); + } +} // ----------------------------------------------------------------------------- // Merge diff --git a/deps/v8/test/unittests/compiler/control-equivalence-unittest.cc b/deps/v8/test/unittests/compiler/control-equivalence-unittest.cc index a87f760c82..6534e90ccc 100644 --- a/deps/v8/test/unittests/compiler/control-equivalence-unittest.cc +++ b/deps/v8/test/unittests/compiler/control-equivalence-unittest.cc @@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "src/bit-vector.h" #include "src/compiler/control-equivalence.h" +#include "src/bit-vector.h" #include "src/compiler/graph-visualizer.h" #include "src/compiler/node-properties.h" #include "src/compiler/source-position.h" -#include "src/zone-containers.h" +#include "src/zone/zone-containers.h" #include "test/unittests/compiler/graph-unittest.h" namespace v8 { diff --git a/deps/v8/test/unittests/compiler/effect-control-linearizer-unittest.cc b/deps/v8/test/unittests/compiler/effect-control-linearizer-unittest.cc index 71a8696d09..0a12ea371a 100644 --- a/deps/v8/test/unittests/compiler/effect-control-linearizer-unittest.cc +++ b/deps/v8/test/unittests/compiler/effect-control-linearizer-unittest.cc @@ -21,10 +21,10 @@ namespace compiler { using testing::Capture; -class EffectControlLinearizerTest : public TypedGraphTest { +class EffectControlLinearizerTest : public GraphTest { public: EffectControlLinearizerTest() - : TypedGraphTest(3), + : GraphTest(3), machine_(zone()), javascript_(zone()), simplified_(zone()), diff --git a/deps/v8/test/unittests/compiler/escape-analysis-unittest.cc b/deps/v8/test/unittests/compiler/escape-analysis-unittest.cc index 990b813947..3a233d6872 100644 --- a/deps/v8/test/unittests/compiler/escape-analysis-unittest.cc +++ b/deps/v8/test/unittests/compiler/escape-analysis-unittest.cc @@ -2,22 +2,22 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "src/bit-vector.h" #include "src/compiler/escape-analysis.h" +#include "src/bit-vector.h" #include "src/compiler/escape-analysis-reducer.h" #include "src/compiler/graph-visualizer.h" #include "src/compiler/js-graph.h" #include "src/compiler/node-properties.h" #include "src/compiler/simplified-operator.h" -#include "src/types.h" -#include "src/zone-containers.h" +#include "src/compiler/types.h" +#include "src/zone/zone-containers.h" #include "test/unittests/compiler/graph-unittest.h" namespace v8 { namespace internal { namespace compiler { -class EscapeAnalysisTest : public GraphTest { +class EscapeAnalysisTest : public TypedGraphTest { public: EscapeAnalysisTest() : simplified_(zone()), @@ -468,8 +468,7 @@ TEST_F(EscapeAnalysisTest, DeoptReplacement) { ASSERT_EQ(object1, NodeProperties::GetValueInput(object_state, 0)); } - -TEST_F(EscapeAnalysisTest, DeoptReplacementIdentity) { +TEST_F(EscapeAnalysisTest, DISABLED_DeoptReplacementIdentity) { Node* object1 = Constant(1); BeginRegion(); Node* allocation = Allocate(Constant(kPointerSize * 2)); diff --git a/deps/v8/test/unittests/compiler/instruction-selector-unittest.cc b/deps/v8/test/unittests/compiler/instruction-selector-unittest.cc index d2953159fc..18ccaaaea5 100644 --- a/deps/v8/test/unittests/compiler/instruction-selector-unittest.cc +++ b/deps/v8/test/unittests/compiler/instruction-selector-unittest.cc @@ -41,7 +41,8 @@ InstructionSelectorTest::Stream InstructionSelectorTest::StreamBuilder::Build( SourcePositionTable source_position_table(graph()); InstructionSelector selector(test_->zone(), node_count, &linkage, &sequence, schedule, &source_position_table, nullptr, - source_position_mode, features); + source_position_mode, features, + InstructionSelector::kDisableScheduling); selector.SelectInstructions(); if (FLAG_trace_turbo) { OFStream out(stdout); @@ -244,19 +245,13 @@ TARGET_TEST_F(InstructionSelectorTest, FinishRegion) { m.AddNode(m.common()->FinishRegion(), param, m.graph()->start()); m.Return(finish); Stream s = m.Build(kAllInstructions); - ASSERT_EQ(4U, s.size()); + ASSERT_EQ(3U, s.size()); EXPECT_EQ(kArchNop, s[0]->arch_opcode()); ASSERT_EQ(1U, s[0]->OutputCount()); ASSERT_TRUE(s[0]->Output()->IsUnallocated()); + EXPECT_EQ(kArchRet, s[1]->arch_opcode()); EXPECT_EQ(s.ToVreg(param), s.ToVreg(s[0]->Output())); - EXPECT_EQ(kArchNop, s[1]->arch_opcode()); - ASSERT_EQ(1U, s[1]->InputCount()); - ASSERT_TRUE(s[1]->InputAt(0)->IsUnallocated()); EXPECT_EQ(s.ToVreg(param), s.ToVreg(s[1]->InputAt(0))); - ASSERT_EQ(1U, s[1]->OutputCount()); - ASSERT_TRUE(s[1]->Output()->IsUnallocated()); - EXPECT_TRUE(UnallocatedOperand::cast(s[1]->Output())->HasSameAsInputPolicy()); - EXPECT_EQ(s.ToVreg(finish), s.ToVreg(s[1]->Output())); EXPECT_TRUE(s.IsReference(finish)); } diff --git a/deps/v8/test/unittests/compiler/js-builtin-reducer-unittest.cc b/deps/v8/test/unittests/compiler/js-builtin-reducer-unittest.cc index ed20e64194..48debc368c 100644 --- a/deps/v8/test/unittests/compiler/js-builtin-reducer-unittest.cc +++ b/deps/v8/test/unittests/compiler/js-builtin-reducer-unittest.cc @@ -38,6 +38,15 @@ class JSBuiltinReducerTest : public TypedGraphTest { return reducer.Reduce(node); } + Node* GlobalFunction(const char* name) { + Handle<JSFunction> f = Handle<JSFunction>::cast( + Object::GetProperty( + isolate()->global_object(), + isolate()->factory()->NewStringFromAsciiChecked(name)) + .ToHandleChecked()); + return HeapConstant(f); + } + Node* MathFunction(const char* name) { Handle<Object> m = JSObject::GetProperty(isolate()->global_object(), @@ -101,6 +110,91 @@ Type* const kNumberTypes[] = { // ----------------------------------------------------------------------------- +// isFinite + +TEST_F(JSBuiltinReducerTest, GlobalIsFiniteWithNumber) { + Node* function = GlobalFunction("isFinite"); + + Node* effect = graph()->start(); + Node* control = graph()->start(); + Node* context = UndefinedConstant(); + Node* frame_state = graph()->start(); + TRACED_FOREACH(Type*, t0, kNumberTypes) { + Node* p0 = Parameter(t0, 0); + Node* call = graph()->NewNode(javascript()->CallFunction(3), function, + UndefinedConstant(), p0, context, frame_state, + effect, control); + Reduction r = Reduce(call); + + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsNumberEqual(IsNumberSubtract(p0, p0), + IsNumberSubtract(p0, p0))); + } +} + +TEST_F(JSBuiltinReducerTest, GlobalIsFiniteWithPlainPrimitive) { + Node* function = GlobalFunction("isFinite"); + + Node* effect = graph()->start(); + Node* control = graph()->start(); + Node* context = UndefinedConstant(); + Node* frame_state = graph()->start(); + Node* p0 = Parameter(Type::PlainPrimitive(), 0); + Node* call = graph()->NewNode(javascript()->CallFunction(3), function, + UndefinedConstant(), p0, context, frame_state, + effect, control); + Reduction r = Reduce(call); + + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), + IsNumberEqual(IsNumberSubtract(IsPlainPrimitiveToNumber(p0), + IsPlainPrimitiveToNumber(p0)), + IsNumberSubtract(IsPlainPrimitiveToNumber(p0), + IsPlainPrimitiveToNumber(p0)))); +} + +// ----------------------------------------------------------------------------- +// isNaN + +TEST_F(JSBuiltinReducerTest, GlobalIsNaNWithNumber) { + Node* function = GlobalFunction("isNaN"); + + Node* effect = graph()->start(); + Node* control = graph()->start(); + Node* context = UndefinedConstant(); + Node* frame_state = graph()->start(); + TRACED_FOREACH(Type*, t0, kNumberTypes) { + Node* p0 = Parameter(t0, 0); + Node* call = graph()->NewNode(javascript()->CallFunction(3), function, + UndefinedConstant(), p0, context, frame_state, + effect, control); + Reduction r = Reduce(call); + + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsBooleanNot(IsNumberEqual(p0, p0))); + } +} + +TEST_F(JSBuiltinReducerTest, GlobalIsNaNWithPlainPrimitive) { + Node* function = GlobalFunction("isNaN"); + + Node* effect = graph()->start(); + Node* control = graph()->start(); + Node* context = UndefinedConstant(); + Node* frame_state = graph()->start(); + Node* p0 = Parameter(Type::PlainPrimitive(), 0); + Node* call = graph()->NewNode(javascript()->CallFunction(3), function, + UndefinedConstant(), p0, context, frame_state, + effect, control); + Reduction r = Reduce(call); + + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), + IsBooleanNot(IsNumberEqual(IsPlainPrimitiveToNumber(p0), + IsPlainPrimitiveToNumber(p0)))); +} + +// ----------------------------------------------------------------------------- // Math.abs TEST_F(JSBuiltinReducerTest, MathAbsWithNumber) { @@ -1315,6 +1409,97 @@ TEST_F(JSBuiltinReducerTest, MathTruncWithPlainPrimitive) { } // ----------------------------------------------------------------------------- +// Number.isFinite + +TEST_F(JSBuiltinReducerTest, NumberIsFiniteWithNumber) { + Node* function = NumberFunction("isFinite"); + + Node* effect = graph()->start(); + Node* control = graph()->start(); + Node* context = UndefinedConstant(); + Node* frame_state = graph()->start(); + TRACED_FOREACH(Type*, t0, kNumberTypes) { + Node* p0 = Parameter(t0, 0); + Node* call = graph()->NewNode(javascript()->CallFunction(3), function, + UndefinedConstant(), p0, context, frame_state, + effect, control); + Reduction r = Reduce(call); + + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsNumberEqual(IsNumberSubtract(p0, p0), + IsNumberSubtract(p0, p0))); + } +} + +// ----------------------------------------------------------------------------- +// Number.isInteger + +TEST_F(JSBuiltinReducerTest, NumberIsIntegerWithNumber) { + Node* function = NumberFunction("isInteger"); + + Node* effect = graph()->start(); + Node* control = graph()->start(); + Node* context = UndefinedConstant(); + Node* frame_state = graph()->start(); + TRACED_FOREACH(Type*, t0, kNumberTypes) { + Node* p0 = Parameter(t0, 0); + Node* call = graph()->NewNode(javascript()->CallFunction(3), function, + UndefinedConstant(), p0, context, frame_state, + effect, control); + Reduction r = Reduce(call); + + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), + IsNumberEqual(IsNumberSubtract(p0, IsNumberTrunc(p0)), + IsNumberConstant(0.0))); + } +} + +// ----------------------------------------------------------------------------- +// Number.isNaN + +TEST_F(JSBuiltinReducerTest, NumberIsNaNWithNumber) { + Node* function = NumberFunction("isNaN"); + + Node* effect = graph()->start(); + Node* control = graph()->start(); + Node* context = UndefinedConstant(); + Node* frame_state = graph()->start(); + TRACED_FOREACH(Type*, t0, kNumberTypes) { + Node* p0 = Parameter(t0, 0); + Node* call = graph()->NewNode(javascript()->CallFunction(3), function, + UndefinedConstant(), p0, context, frame_state, + effect, control); + Reduction r = Reduce(call); + + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsBooleanNot(IsNumberEqual(p0, p0))); + } +} + +// ----------------------------------------------------------------------------- +// Number.isSafeInteger + +TEST_F(JSBuiltinReducerTest, NumberIsSafeIntegerWithIntegral32) { + Node* function = NumberFunction("isSafeInteger"); + + Node* effect = graph()->start(); + Node* control = graph()->start(); + Node* context = UndefinedConstant(); + Node* frame_state = graph()->start(); + TRACED_FOREACH(Type*, t0, kIntegral32Types) { + Node* p0 = Parameter(t0, 0); + Node* call = graph()->NewNode(javascript()->CallFunction(3), function, + UndefinedConstant(), p0, context, frame_state, + effect, control); + Reduction r = Reduce(call); + + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsTrueConstant()); + } +} + +// ----------------------------------------------------------------------------- // Number.parseInt TEST_F(JSBuiltinReducerTest, NumberParseIntWithIntegral32) { diff --git a/deps/v8/test/unittests/compiler/js-create-lowering-unittest.cc b/deps/v8/test/unittests/compiler/js-create-lowering-unittest.cc index 9c001e9eb2..ebb1633401 100644 --- a/deps/v8/test/unittests/compiler/js-create-lowering-unittest.cc +++ b/deps/v8/test/unittests/compiler/js-create-lowering-unittest.cc @@ -40,7 +40,8 @@ class JSCreateLoweringTest : public TypedGraphTest { // TODO(titzer): mock the GraphReducer here for better unit testing. GraphReducer graph_reducer(zone(), graph()); JSCreateLowering reducer(&graph_reducer, &deps_, &jsgraph, - MaybeHandle<LiteralsArray>(), zone()); + MaybeHandle<LiteralsArray>(), + MaybeHandle<Context>(), zone()); return reducer.Reduce(node); } @@ -174,14 +175,15 @@ TEST_F(JSCreateLoweringTest, JSCreateFunctionContextViaInlinedAllocation) { // JSCreateWithContext TEST_F(JSCreateLoweringTest, JSCreateWithContext) { + Handle<ScopeInfo> scope_info(factory()->NewScopeInfo(1)); Node* const object = Parameter(Type::Receiver()); Node* const closure = Parameter(Type::Function()); Node* const context = Parameter(Type::Any()); Node* const effect = graph()->start(); Node* const control = graph()->start(); Reduction r = - Reduce(graph()->NewNode(javascript()->CreateWithContext(), object, - closure, context, effect, control)); + Reduce(graph()->NewNode(javascript()->CreateWithContext(scope_info), + object, closure, context, effect, control)); ASSERT_TRUE(r.Changed()); EXPECT_THAT(r.replacement(), IsFinishRegion(IsAllocate(IsNumberConstant(Context::SizeFor( @@ -195,14 +197,15 @@ TEST_F(JSCreateLoweringTest, JSCreateWithContext) { TEST_F(JSCreateLoweringTest, JSCreateCatchContext) { Handle<String> name = factory()->length_string(); + Handle<ScopeInfo> scope_info(factory()->NewScopeInfo(1)); Node* const exception = Parameter(Type::Receiver()); Node* const closure = Parameter(Type::Function()); Node* const context = Parameter(Type::Any()); Node* const effect = graph()->start(); Node* const control = graph()->start(); - Reduction r = - Reduce(graph()->NewNode(javascript()->CreateCatchContext(name), exception, - closure, context, effect, control)); + Reduction r = Reduce( + graph()->NewNode(javascript()->CreateCatchContext(name, scope_info), + exception, closure, context, effect, control)); ASSERT_TRUE(r.Changed()); EXPECT_THAT(r.replacement(), IsFinishRegion(IsAllocate(IsNumberConstant(Context::SizeFor( diff --git a/deps/v8/test/unittests/compiler/js-operator-unittest.cc b/deps/v8/test/unittests/compiler/js-operator-unittest.cc index 3b83d691f1..853249785e 100644 --- a/deps/v8/test/unittests/compiler/js-operator-unittest.cc +++ b/deps/v8/test/unittests/compiler/js-operator-unittest.cc @@ -46,7 +46,6 @@ const SharedOperator kSharedOperators[] = { SHARED(ToObject, Operator::kFoldable, 1, 1, 1, 1, 1, 1, 2), SHARED(Create, Operator::kEliminatable, 2, 1, 1, 0, 1, 1, 0), SHARED(TypeOf, Operator::kPure, 1, 0, 0, 0, 1, 0, 0), - SHARED(CreateWithContext, Operator::kNoProperties, 2, 0, 1, 1, 1, 1, 2), #undef SHARED }; diff --git a/deps/v8/test/unittests/compiler/js-type-feedback-unittest.cc b/deps/v8/test/unittests/compiler/js-type-feedback-unittest.cc deleted file mode 100644 index dece25def1..0000000000 --- a/deps/v8/test/unittests/compiler/js-type-feedback-unittest.cc +++ /dev/null @@ -1,336 +0,0 @@ -// Copyright 2015 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "src/compiler.h" - -#include "src/compiler/access-builder.h" -#include "src/compiler/js-graph.h" -#include "src/compiler/js-operator.h" -#include "src/compiler/js-type-feedback.h" -#include "src/compiler/machine-operator.h" -#include "src/compiler/node-matchers.h" -#include "src/compiler/node-properties.h" -#include "src/compiler/operator-properties.h" - -#include "test/unittests/compiler/compiler-test-utils.h" -#include "test/unittests/compiler/graph-unittest.h" -#include "test/unittests/compiler/node-test-utils.h" -#include "testing/gmock-support.h" - -using testing::Capture; - - -namespace v8 { -namespace internal { -namespace compiler { - -class JSTypeFeedbackTest : public TypedGraphTest { - public: - JSTypeFeedbackTest() - : TypedGraphTest(3), - javascript_(zone()), - dependencies_(isolate(), zone()) {} - ~JSTypeFeedbackTest() override { dependencies_.Rollback(); } - - protected: - Reduction Reduce(Node* node, - JSTypeFeedbackSpecializer::DeoptimizationMode mode) { - Handle<GlobalObject> global_object( - isolate()->native_context()->global_object(), isolate()); - - MachineOperatorBuilder machine(zone()); - SimplifiedOperatorBuilder simplified(zone()); - JSGraph jsgraph(isolate(), graph(), common(), javascript(), &simplified, - &machine); - JSTypeFeedbackTable table(zone()); - // TODO(titzer): mock the GraphReducer here for better unit testing. - GraphReducer graph_reducer(zone(), graph()); - JSTypeFeedbackSpecializer reducer(&graph_reducer, &jsgraph, &table, nullptr, - global_object, mode, &dependencies_); - return reducer.Reduce(node); - } - - Node* EmptyFrameState() { - MachineOperatorBuilder machine(zone()); - JSGraph jsgraph(isolate(), graph(), common(), javascript(), nullptr, - &machine); - return jsgraph.EmptyFrameState(); - } - - JSOperatorBuilder* javascript() { return &javascript_; } - - void SetGlobalProperty(const char* string, int value) { - SetGlobalProperty(string, Handle<Smi>(Smi::FromInt(value), isolate())); - } - - void SetGlobalProperty(const char* string, double value) { - SetGlobalProperty(string, isolate()->factory()->NewNumber(value)); - } - - void SetGlobalProperty(const char* string, Handle<Object> value) { - Handle<JSObject> global(isolate()->context()->global_object(), isolate()); - Handle<String> name = - isolate()->factory()->NewStringFromAsciiChecked(string); - MaybeHandle<Object> result = - JSReceiver::SetProperty(global, name, value, SLOPPY); - result.Assert(); - } - - Node* ReturnLoadNamedFromGlobal( - const char* string, Node* effect, Node* control, - JSTypeFeedbackSpecializer::DeoptimizationMode mode) { - VectorSlotPair feedback; - Node* vector = UndefinedConstant(); - Node* context = UndefinedConstant(); - - Handle<Name> name = isolate()->factory()->InternalizeUtf8String(string); - const Operator* op = javascript()->LoadGlobal(name, feedback); - Node* load = graph()->NewNode(op, vector, context, EmptyFrameState(), - EmptyFrameState(), effect, control); - Node* if_success = graph()->NewNode(common()->IfSuccess(), load); - return graph()->NewNode(common()->Return(), load, load, if_success); - } - - CompilationDependencies* dependencies() { return &dependencies_; } - - private: - JSOperatorBuilder javascript_; - CompilationDependencies dependencies_; -}; - - -TEST_F(JSTypeFeedbackTest, JSLoadNamedGlobalConstSmi) { - const int kValue = 111; - const char* kName = "banana"; - SetGlobalProperty(kName, kValue); - - Node* ret = ReturnLoadNamedFromGlobal( - kName, graph()->start(), graph()->start(), - JSTypeFeedbackSpecializer::kDeoptimizationDisabled); - graph()->SetEnd(graph()->NewNode(common()->End(1), ret)); - - Reduction r = Reduce(ret->InputAt(0), - JSTypeFeedbackSpecializer::kDeoptimizationDisabled); - EXPECT_FALSE(r.Changed()); - EXPECT_TRUE(dependencies()->IsEmpty()); -} - - -TEST_F(JSTypeFeedbackTest, JSLoadNamedGlobalConstSmiWithDeoptimization) { - const int kValue = 111; - const char* kName = "banana"; - SetGlobalProperty(kName, kValue); - - Node* ret = ReturnLoadNamedFromGlobal( - kName, graph()->start(), graph()->start(), - JSTypeFeedbackSpecializer::kDeoptimizationEnabled); - graph()->SetEnd(graph()->NewNode(common()->End(1), ret)); - - Reduction r = Reduce(ret->InputAt(0), - JSTypeFeedbackSpecializer::kDeoptimizationEnabled); - - // Check LoadNamed(global) => HeapConstant[kValue] - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsNumberConstant(kValue)); - - EXPECT_THAT(ret, IsReturn(IsNumberConstant(kValue), graph()->start(), - graph()->start())); - EXPECT_THAT(graph()->end(), IsEnd(ret)); - - EXPECT_FALSE(dependencies()->IsEmpty()); - dependencies()->Rollback(); -} - - -TEST_F(JSTypeFeedbackTest, JSLoadNamedGlobalConstNumber) { - const double kValue = -11.25; - const char* kName = "kiwi"; - SetGlobalProperty(kName, kValue); - - Node* ret = ReturnLoadNamedFromGlobal( - kName, graph()->start(), graph()->start(), - JSTypeFeedbackSpecializer::kDeoptimizationDisabled); - graph()->SetEnd(graph()->NewNode(common()->End(1), ret)); - - Reduction r = Reduce(ret->InputAt(0), - JSTypeFeedbackSpecializer::kDeoptimizationDisabled); - - EXPECT_FALSE(r.Changed()); - EXPECT_TRUE(dependencies()->IsEmpty()); -} - - -TEST_F(JSTypeFeedbackTest, JSLoadNamedGlobalConstNumberWithDeoptimization) { - const double kValue = -11.25; - const char* kName = "kiwi"; - SetGlobalProperty(kName, kValue); - - Node* ret = ReturnLoadNamedFromGlobal( - kName, graph()->start(), graph()->start(), - JSTypeFeedbackSpecializer::kDeoptimizationEnabled); - graph()->SetEnd(graph()->NewNode(common()->End(1), ret)); - - Reduction r = Reduce(ret->InputAt(0), - JSTypeFeedbackSpecializer::kDeoptimizationEnabled); - - // Check LoadNamed(global) => HeapConstant[kValue] - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsNumberConstant(kValue)); - - EXPECT_THAT(ret, IsReturn(IsNumberConstant(kValue), graph()->start(), - graph()->start())); - EXPECT_THAT(graph()->end(), IsEnd(ret)); - - EXPECT_FALSE(dependencies()->IsEmpty()); -} - - -TEST_F(JSTypeFeedbackTest, JSLoadNamedGlobalConstString) { - Handle<HeapObject> kValue = isolate()->factory()->undefined_string(); - const char* kName = "mango"; - SetGlobalProperty(kName, kValue); - - Node* ret = ReturnLoadNamedFromGlobal( - kName, graph()->start(), graph()->start(), - JSTypeFeedbackSpecializer::kDeoptimizationDisabled); - graph()->SetEnd(graph()->NewNode(common()->End(1), ret)); - - Reduction r = Reduce(ret->InputAt(0), - JSTypeFeedbackSpecializer::kDeoptimizationDisabled); - ASSERT_FALSE(r.Changed()); - EXPECT_TRUE(dependencies()->IsEmpty()); -} - - -TEST_F(JSTypeFeedbackTest, JSLoadNamedGlobalConstStringWithDeoptimization) { - Handle<HeapObject> kValue = isolate()->factory()->undefined_string(); - const char* kName = "mango"; - SetGlobalProperty(kName, kValue); - - Node* ret = ReturnLoadNamedFromGlobal( - kName, graph()->start(), graph()->start(), - JSTypeFeedbackSpecializer::kDeoptimizationEnabled); - graph()->SetEnd(graph()->NewNode(common()->End(1), ret)); - - Reduction r = Reduce(ret->InputAt(0), - JSTypeFeedbackSpecializer::kDeoptimizationEnabled); - - // Check LoadNamed(global) => HeapConstant[kValue] - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsHeapConstant(kValue)); - - EXPECT_THAT(ret, IsReturn(IsHeapConstant(kValue), graph()->start(), - graph()->start())); - EXPECT_THAT(graph()->end(), IsEnd(ret)); - - EXPECT_FALSE(dependencies()->IsEmpty()); - dependencies()->Rollback(); -} - - -TEST_F(JSTypeFeedbackTest, JSLoadNamedGlobalPropertyCellSmi) { - const char* kName = "melon"; - SetGlobalProperty(kName, 123); - SetGlobalProperty(kName, 124); - - Node* ret = ReturnLoadNamedFromGlobal( - kName, graph()->start(), graph()->start(), - JSTypeFeedbackSpecializer::kDeoptimizationDisabled); - graph()->SetEnd(graph()->NewNode(common()->End(1), ret)); - - Reduction r = Reduce(ret->InputAt(0), - JSTypeFeedbackSpecializer::kDeoptimizationDisabled); - ASSERT_FALSE(r.Changed()); - EXPECT_TRUE(dependencies()->IsEmpty()); -} - - -TEST_F(JSTypeFeedbackTest, JSLoadNamedGlobalPropertyCellSmiWithDeoptimization) { - const char* kName = "melon"; - SetGlobalProperty(kName, 123); - SetGlobalProperty(kName, 124); - - Node* ret = ReturnLoadNamedFromGlobal( - kName, graph()->start(), graph()->start(), - JSTypeFeedbackSpecializer::kDeoptimizationEnabled); - graph()->SetEnd(graph()->NewNode(common()->End(1), ret)); - - Reduction r = Reduce(ret->InputAt(0), - JSTypeFeedbackSpecializer::kDeoptimizationEnabled); - - // Check LoadNamed(global) => LoadField[PropertyCell::value](cell) - ASSERT_TRUE(r.Changed()); - FieldAccess access = AccessBuilder::ForPropertyCellValue(); - Capture<Node*> cell_capture; - Matcher<Node*> load_field_match = IsLoadField( - access, CaptureEq(&cell_capture), graph()->start(), graph()->start()); - EXPECT_THAT(r.replacement(), load_field_match); - - HeapObjectMatcher cell(cell_capture.value()); - EXPECT_TRUE(cell.HasValue()); - EXPECT_TRUE(cell.Value()->IsPropertyCell()); - - EXPECT_THAT(ret, - IsReturn(load_field_match, load_field_match, graph()->start())); - EXPECT_THAT(graph()->end(), IsEnd(ret)); - - EXPECT_FALSE(dependencies()->IsEmpty()); - dependencies()->Rollback(); -} - - -TEST_F(JSTypeFeedbackTest, JSLoadNamedGlobalPropertyCellString) { - const char* kName = "pineapple"; - SetGlobalProperty(kName, isolate()->factory()->undefined_string()); - SetGlobalProperty(kName, isolate()->factory()->undefined_value()); - - Node* ret = ReturnLoadNamedFromGlobal( - kName, graph()->start(), graph()->start(), - JSTypeFeedbackSpecializer::kDeoptimizationDisabled); - graph()->SetEnd(graph()->NewNode(common()->End(1), ret)); - - Reduction r = Reduce(ret->InputAt(0), - JSTypeFeedbackSpecializer::kDeoptimizationDisabled); - ASSERT_FALSE(r.Changed()); - EXPECT_TRUE(dependencies()->IsEmpty()); -} - - -TEST_F(JSTypeFeedbackTest, - JSLoadNamedGlobalPropertyCellStringWithDeoptimization) { - const char* kName = "pineapple"; - SetGlobalProperty(kName, isolate()->factory()->undefined_string()); - SetGlobalProperty(kName, isolate()->factory()->undefined_value()); - - Node* ret = ReturnLoadNamedFromGlobal( - kName, graph()->start(), graph()->start(), - JSTypeFeedbackSpecializer::kDeoptimizationEnabled); - graph()->SetEnd(graph()->NewNode(common()->End(1), ret)); - - Reduction r = Reduce(ret->InputAt(0), - JSTypeFeedbackSpecializer::kDeoptimizationEnabled); - - // Check LoadNamed(global) => LoadField[PropertyCell::value](cell) - ASSERT_TRUE(r.Changed()); - FieldAccess access = AccessBuilder::ForPropertyCellValue(); - Capture<Node*> cell_capture; - Matcher<Node*> load_field_match = IsLoadField( - access, CaptureEq(&cell_capture), graph()->start(), graph()->start()); - EXPECT_THAT(r.replacement(), load_field_match); - - HeapObjectMatcher cell(cell_capture.value()); - EXPECT_TRUE(cell.HasValue()); - EXPECT_TRUE(cell.Value()->IsPropertyCell()); - - EXPECT_THAT(ret, - IsReturn(load_field_match, load_field_match, graph()->start())); - EXPECT_THAT(graph()->end(), IsEnd(ret)); - - EXPECT_FALSE(dependencies()->IsEmpty()); - dependencies()->Rollback(); -} - -} // namespace compiler -} // namespace internal -} // namespace v8 diff --git a/deps/v8/test/unittests/compiler/js-typed-lowering-unittest.cc b/deps/v8/test/unittests/compiler/js-typed-lowering-unittest.cc index 72c582525e..ec1ff19880 100644 --- a/deps/v8/test/unittests/compiler/js-typed-lowering-unittest.cc +++ b/deps/v8/test/unittests/compiler/js-typed-lowering-unittest.cc @@ -33,36 +33,8 @@ const ExternalArrayType kExternalArrayTypes[] = { kExternalInt16Array, kExternalUint32Array, kExternalInt32Array, kExternalFloat32Array, kExternalFloat64Array}; - -const double kFloat64Values[] = { - -V8_INFINITY, -4.23878e+275, -5.82632e+265, -6.60355e+220, -6.26172e+212, - -2.56222e+211, -4.82408e+201, -1.84106e+157, -1.63662e+127, -1.55772e+100, - -1.67813e+72, -2.3382e+55, -3.179e+30, -1.441e+09, -1.0647e+09, - -7.99361e+08, -5.77375e+08, -2.20984e+08, -32757, -13171, -9970, -3984, - -107, -105, -92, -77, -61, -0.000208163, -1.86685e-06, -1.17296e-10, - -9.26358e-11, -5.08004e-60, -1.74753e-65, -1.06561e-71, -5.67879e-79, - -5.78459e-130, -2.90989e-171, -7.15489e-243, -3.76242e-252, -1.05639e-263, - -4.40497e-267, -2.19666e-273, -4.9998e-276, -5.59821e-278, -2.03855e-282, - -5.99335e-283, -7.17554e-284, -3.11744e-309, -0.0, 0.0, 2.22507e-308, - 1.30127e-270, 7.62898e-260, 4.00313e-249, 3.16829e-233, 1.85244e-228, - 2.03544e-129, 1.35126e-110, 1.01182e-106, 5.26333e-94, 1.35292e-90, - 2.85394e-83, 1.78323e-77, 5.4967e-57, 1.03207e-25, 4.57401e-25, 1.58738e-05, - 2, 125, 2310, 9636, 14802, 17168, 28945, 29305, 4.81336e+07, 1.41207e+08, - 4.65962e+08, 1.40499e+09, 2.12648e+09, 8.80006e+30, 1.4446e+45, 1.12164e+54, - 2.48188e+89, 6.71121e+102, 3.074e+112, 4.9699e+152, 5.58383e+166, - 4.30654e+172, 7.08824e+185, 9.6586e+214, 2.028e+223, 6.63277e+243, - 1.56192e+261, 1.23202e+269, 5.72883e+289, 8.5798e+290, 1.40256e+294, - 1.79769e+308, V8_INFINITY}; - - const size_t kIndices[] = {0, 1, 42, 100, 1024}; - -const double kIntegerValues[] = {-V8_INFINITY, INT_MIN, -1000.0, -42.0, - -1.0, 0.0, 1.0, 42.0, - 1000.0, INT_MAX, UINT_MAX, V8_INFINITY}; - - Type* const kJSTypes[] = {Type::Undefined(), Type::Null(), Type::Boolean(), Type::Number(), Type::String(), Type::Object()}; @@ -112,100 +84,6 @@ class JSTypedLoweringTest : public TypedGraphTest { // ----------------------------------------------------------------------------- -// Constant propagation - - -TEST_F(JSTypedLoweringTest, ParameterWithMinusZero) { - { - Reduction r = Reduce( - Parameter(Type::Constant(factory()->minus_zero_value(), zone()))); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsNumberConstant(-0.0)); - } - { - Reduction r = Reduce(Parameter(Type::MinusZero())); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsNumberConstant(-0.0)); - } - { - Reduction r = Reduce(Parameter( - Type::Union(Type::MinusZero(), - Type::Constant(factory()->NewNumber(0), zone()), zone()))); - EXPECT_FALSE(r.Changed()); - } -} - - -TEST_F(JSTypedLoweringTest, ParameterWithNull) { - Handle<HeapObject> null = factory()->null_value(); - { - Reduction r = Reduce(Parameter(Type::Constant(null, zone()))); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsHeapConstant(null)); - } - { - Reduction r = Reduce(Parameter(Type::Null())); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsHeapConstant(null)); - } -} - - -TEST_F(JSTypedLoweringTest, ParameterWithNaN) { - const double kNaNs[] = {-std::numeric_limits<double>::quiet_NaN(), - std::numeric_limits<double>::quiet_NaN(), - std::numeric_limits<double>::signaling_NaN()}; - TRACED_FOREACH(double, nan, kNaNs) { - Handle<Object> constant = factory()->NewNumber(nan); - Reduction r = Reduce(Parameter(Type::Constant(constant, zone()))); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsNumberConstant(IsNaN())); - } - { - Reduction r = - Reduce(Parameter(Type::Constant(factory()->nan_value(), zone()))); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsNumberConstant(IsNaN())); - } - { - Reduction r = Reduce(Parameter(Type::NaN())); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsNumberConstant(IsNaN())); - } -} - - -TEST_F(JSTypedLoweringTest, ParameterWithPlainNumber) { - TRACED_FOREACH(double, value, kFloat64Values) { - Handle<Object> constant = factory()->NewNumber(value); - Reduction r = Reduce(Parameter(Type::Constant(constant, zone()))); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsNumberConstant(value)); - } - TRACED_FOREACH(double, value, kIntegerValues) { - Reduction r = Reduce(Parameter(Type::Range(value, value, zone()))); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsNumberConstant(value)); - } -} - - -TEST_F(JSTypedLoweringTest, ParameterWithUndefined) { - Handle<HeapObject> undefined = factory()->undefined_value(); - { - Reduction r = Reduce(Parameter(Type::Undefined())); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsHeapConstant(undefined)); - } - { - Reduction r = Reduce(Parameter(Type::Constant(undefined, zone()))); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsHeapConstant(undefined)); - } -} - - -// ----------------------------------------------------------------------------- // JSToBoolean @@ -219,60 +97,6 @@ TEST_F(JSTypedLoweringTest, JSToBooleanWithBoolean) { } -TEST_F(JSTypedLoweringTest, JSToBooleanWithFalsish) { - Node* input = Parameter( - Type::Union( - Type::MinusZero(), - Type::Union( - Type::NaN(), - Type::Union( - Type::Null(), - Type::Union( - Type::Undefined(), - Type::Union( - Type::Undetectable(), - Type::Union( - Type::Constant(factory()->false_value(), zone()), - Type::Range(0.0, 0.0, zone()), zone()), - zone()), - zone()), - zone()), - zone()), - zone()), - 0); - Node* context = Parameter(Type::Any(), 1); - Reduction r = Reduce(graph()->NewNode( - javascript()->ToBoolean(ToBooleanHint::kAny), input, context)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsFalseConstant()); -} - - -TEST_F(JSTypedLoweringTest, JSToBooleanWithTruish) { - Node* input = Parameter( - Type::Union( - Type::Constant(factory()->true_value(), zone()), - Type::Union(Type::DetectableReceiver(), Type::Symbol(), zone()), - zone()), - 0); - Node* context = Parameter(Type::Any(), 1); - Reduction r = Reduce(graph()->NewNode( - javascript()->ToBoolean(ToBooleanHint::kAny), input, context)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsTrueConstant()); -} - - -TEST_F(JSTypedLoweringTest, JSToBooleanWithNonZeroPlainNumber) { - Node* input = Parameter(Type::Range(1, V8_INFINITY, zone()), 0); - Node* context = Parameter(Type::Any(), 1); - Reduction r = Reduce(graph()->NewNode( - javascript()->ToBoolean(ToBooleanHint::kAny), input, context)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsTrueConstant()); -} - - TEST_F(JSTypedLoweringTest, JSToBooleanWithOrderedNumber) { Node* input = Parameter(Type::OrderedNumber(), 0); Node* context = Parameter(Type::Any(), 1); @@ -289,24 +113,9 @@ TEST_F(JSTypedLoweringTest, JSToBooleanWithNumber) { Reduction r = Reduce(graph()->NewNode( javascript()->ToBoolean(ToBooleanHint::kAny), input, context)); ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), - IsNumberLessThan(IsNumberConstant(0.0), IsNumberAbs(input))); + EXPECT_THAT(r.replacement(), IsNumberToBoolean(input)); } -TEST_F(JSTypedLoweringTest, JSToBooleanWithString) { - Node* input = Parameter(Type::String(), 0); - Node* context = Parameter(Type::Any(), 1); - Reduction r = Reduce(graph()->NewNode( - javascript()->ToBoolean(ToBooleanHint::kAny), input, context)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT( - r.replacement(), - IsNumberLessThan(IsNumberConstant(0.0), - IsLoadField(AccessBuilder::ForStringLength(), input, - graph()->start(), graph()->start()))); -} - - TEST_F(JSTypedLoweringTest, JSToBooleanWithAny) { Node* input = Parameter(Type::Any(), 0); Node* context = Parameter(Type::Any(), 1); @@ -1022,68 +831,6 @@ TEST_F(JSTypedLoweringTest, JSSubtractSmis) { } // ----------------------------------------------------------------------------- -// JSInstanceOf -// Test that instanceOf is reduced if and only if the right-hand side is a -// function constant. Functional correctness is ensured elsewhere. - -TEST_F(JSTypedLoweringTest, JSInstanceOfSpecializationWithoutSmiCheck) { - Node* const context = Parameter(Type::Any()); - Node* const frame_state = EmptyFrameState(); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - - // Reduce if left-hand side is known to be an object. - Node* instanceOf = - graph()->NewNode(javascript()->InstanceOf(), Parameter(Type::Object(), 0), - HeapConstant(isolate()->object_function()), context, - frame_state, effect, control); - Node* dummy = graph()->NewNode(javascript()->ToObject(), instanceOf, context, - frame_state, effect, control); - Reduction r = Reduce(instanceOf); - ASSERT_TRUE(r.Changed()); - ASSERT_EQ(r.replacement(), dummy->InputAt(0)); - ASSERT_NE(instanceOf, dummy->InputAt(0)); -} - - -TEST_F(JSTypedLoweringTest, JSInstanceOfSpecializationWithSmiCheck) { - Node* const context = Parameter(Type::Any()); - Node* const frame_state = EmptyFrameState(); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - - // Reduce if left-hand side could be a Smi. - Node* instanceOf = - graph()->NewNode(javascript()->InstanceOf(), Parameter(Type::Any(), 0), - HeapConstant(isolate()->object_function()), context, - frame_state, effect, control); - Node* dummy = graph()->NewNode(javascript()->ToObject(), instanceOf, context, - frame_state, effect, control); - Reduction r = Reduce(instanceOf); - ASSERT_TRUE(r.Changed()); - ASSERT_EQ(r.replacement(), dummy->InputAt(0)); - ASSERT_NE(instanceOf, dummy->InputAt(0)); -} - - -TEST_F(JSTypedLoweringTest, JSInstanceOfNoSpecialization) { - Node* const context = Parameter(Type::Any()); - Node* const frame_state = EmptyFrameState(); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - - // Do not reduce if right-hand side is not a function constant. - Node* instanceOf = graph()->NewNode( - javascript()->InstanceOf(), Parameter(Type::Any(), 0), - Parameter(Type::Any()), context, frame_state, effect, control); - Node* dummy = graph()->NewNode(javascript()->ToObject(), instanceOf, context, - frame_state, effect, control); - Reduction r = Reduce(instanceOf); - ASSERT_FALSE(r.Changed()); - ASSERT_EQ(instanceOf, dummy->InputAt(0)); -} - -// ----------------------------------------------------------------------------- // JSBitwiseAnd TEST_F(JSTypedLoweringTest, JSBitwiseAndWithSignedSmallHint) { diff --git a/deps/v8/test/unittests/compiler/load-elimination-unittest.cc b/deps/v8/test/unittests/compiler/load-elimination-unittest.cc index ada99b5a7f..81393941bb 100644 --- a/deps/v8/test/unittests/compiler/load-elimination-unittest.cc +++ b/deps/v8/test/unittests/compiler/load-elimination-unittest.cc @@ -213,6 +213,269 @@ TEST_F(LoadEliminationTest, StoreFieldAndStoreElementAndLoadField) { EXPECT_EQ(value, r.replacement()); } +TEST_F(LoadEliminationTest, LoadElementOnTrueBranchOfDiamond) { + Node* object = Parameter(Type::Any(), 0); + Node* index = Parameter(Type::UnsignedSmall(), 1); + Node* check = Parameter(Type::Boolean(), 2); + Node* effect = graph()->start(); + Node* control = graph()->start(); + ElementAccess const access = {kTaggedBase, kPointerSize, Type::Any(), + MachineType::AnyTagged(), kNoWriteBarrier}; + + StrictMock<MockAdvancedReducerEditor> editor; + LoadElimination load_elimination(&editor, jsgraph(), zone()); + + load_elimination.Reduce(graph()->start()); + + Node* branch = graph()->NewNode(common()->Branch(), check, control); + + Node* if_true = graph()->NewNode(common()->IfTrue(), branch); + Node* etrue = graph()->NewNode(simplified()->LoadElement(access), object, + index, effect, if_true); + load_elimination.Reduce(etrue); + + Node* if_false = graph()->NewNode(common()->IfFalse(), branch); + Node* efalse = effect; + + control = graph()->NewNode(common()->Merge(2), if_true, if_false); + effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control); + load_elimination.Reduce(effect); + + Node* load = graph()->NewNode(simplified()->LoadElement(access), object, + index, effect, control); + Reduction r = load_elimination.Reduce(load); + ASSERT_TRUE(r.Changed()); + EXPECT_EQ(load, r.replacement()); +} + +TEST_F(LoadEliminationTest, LoadElementOnFalseBranchOfDiamond) { + Node* object = Parameter(Type::Any(), 0); + Node* index = Parameter(Type::UnsignedSmall(), 1); + Node* check = Parameter(Type::Boolean(), 2); + Node* effect = graph()->start(); + Node* control = graph()->start(); + ElementAccess const access = {kTaggedBase, kPointerSize, Type::Any(), + MachineType::AnyTagged(), kNoWriteBarrier}; + + StrictMock<MockAdvancedReducerEditor> editor; + LoadElimination load_elimination(&editor, jsgraph(), zone()); + + load_elimination.Reduce(graph()->start()); + + Node* branch = graph()->NewNode(common()->Branch(), check, control); + + Node* if_true = graph()->NewNode(common()->IfTrue(), branch); + Node* etrue = effect; + + Node* if_false = graph()->NewNode(common()->IfFalse(), branch); + Node* efalse = graph()->NewNode(simplified()->LoadElement(access), object, + index, effect, if_false); + load_elimination.Reduce(efalse); + + control = graph()->NewNode(common()->Merge(2), if_true, if_false); + effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control); + load_elimination.Reduce(effect); + + Node* load = graph()->NewNode(simplified()->LoadElement(access), object, + index, effect, control); + Reduction r = load_elimination.Reduce(load); + ASSERT_TRUE(r.Changed()); + EXPECT_EQ(load, r.replacement()); +} + +TEST_F(LoadEliminationTest, LoadFieldOnFalseBranchOfDiamond) { + Node* object = Parameter(Type::Any(), 0); + Node* check = Parameter(Type::Boolean(), 1); + Node* effect = graph()->start(); + Node* control = graph()->start(); + FieldAccess const access = {kTaggedBase, + kPointerSize, + MaybeHandle<Name>(), + Type::Any(), + MachineType::AnyTagged(), + kNoWriteBarrier}; + + StrictMock<MockAdvancedReducerEditor> editor; + LoadElimination load_elimination(&editor, jsgraph(), zone()); + + load_elimination.Reduce(graph()->start()); + + Node* branch = graph()->NewNode(common()->Branch(), check, control); + + Node* if_true = graph()->NewNode(common()->IfTrue(), branch); + Node* etrue = effect; + + Node* if_false = graph()->NewNode(common()->IfFalse(), branch); + Node* efalse = graph()->NewNode(simplified()->LoadField(access), object, + effect, if_false); + load_elimination.Reduce(efalse); + + control = graph()->NewNode(common()->Merge(2), if_true, if_false); + effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control); + load_elimination.Reduce(effect); + + Node* load = graph()->NewNode(simplified()->LoadField(access), object, effect, + control); + Reduction r = load_elimination.Reduce(load); + ASSERT_TRUE(r.Changed()); + EXPECT_EQ(load, r.replacement()); +} + +TEST_F(LoadEliminationTest, LoadFieldOnTrueBranchOfDiamond) { + Node* object = Parameter(Type::Any(), 0); + Node* check = Parameter(Type::Boolean(), 1); + Node* effect = graph()->start(); + Node* control = graph()->start(); + FieldAccess const access = {kTaggedBase, + kPointerSize, + MaybeHandle<Name>(), + Type::Any(), + MachineType::AnyTagged(), + kNoWriteBarrier}; + + StrictMock<MockAdvancedReducerEditor> editor; + LoadElimination load_elimination(&editor, jsgraph(), zone()); + + load_elimination.Reduce(graph()->start()); + + Node* branch = graph()->NewNode(common()->Branch(), check, control); + + Node* if_true = graph()->NewNode(common()->IfTrue(), branch); + Node* etrue = graph()->NewNode(simplified()->LoadField(access), object, + effect, if_true); + load_elimination.Reduce(etrue); + + Node* if_false = graph()->NewNode(common()->IfFalse(), branch); + Node* efalse = effect; + + control = graph()->NewNode(common()->Merge(2), if_true, if_false); + effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control); + load_elimination.Reduce(effect); + + Node* load = graph()->NewNode(simplified()->LoadField(access), object, effect, + control); + Reduction r = load_elimination.Reduce(load); + ASSERT_TRUE(r.Changed()); + EXPECT_EQ(load, r.replacement()); +} + +TEST_F(LoadEliminationTest, LoadFieldWithTypeMismatch) { + Node* object = Parameter(Type::Any(), 0); + Node* value = Parameter(Type::Signed32(), 1); + Node* effect = graph()->start(); + Node* control = graph()->start(); + FieldAccess const access = {kTaggedBase, + kPointerSize, + MaybeHandle<Name>(), + Type::Unsigned31(), + MachineType::AnyTagged(), + kNoWriteBarrier}; + + StrictMock<MockAdvancedReducerEditor> editor; + LoadElimination load_elimination(&editor, jsgraph(), zone()); + + load_elimination.Reduce(graph()->start()); + + Node* store = effect = graph()->NewNode(simplified()->StoreField(access), + object, value, effect, control); + load_elimination.Reduce(effect); + + Node* load = graph()->NewNode(simplified()->LoadField(access), object, effect, + control); + EXPECT_CALL(editor, + ReplaceWithValue(load, IsTypeGuard(value, control), store, _)); + Reduction r = load_elimination.Reduce(load); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsTypeGuard(value, control)); +} + +TEST_F(LoadEliminationTest, LoadElementWithTypeMismatch) { + Node* object = Parameter(Type::Any(), 0); + Node* index = Parameter(Type::UnsignedSmall(), 1); + Node* value = Parameter(Type::Signed32(), 2); + Node* effect = graph()->start(); + Node* control = graph()->start(); + ElementAccess const access = {kTaggedBase, kPointerSize, Type::Unsigned31(), + MachineType::AnyTagged(), kNoWriteBarrier}; + + StrictMock<MockAdvancedReducerEditor> editor; + LoadElimination load_elimination(&editor, jsgraph(), zone()); + + load_elimination.Reduce(graph()->start()); + + Node* store = effect = + graph()->NewNode(simplified()->StoreElement(access), object, index, value, + effect, control); + load_elimination.Reduce(effect); + + Node* load = graph()->NewNode(simplified()->LoadElement(access), object, + index, effect, control); + EXPECT_CALL(editor, + ReplaceWithValue(load, IsTypeGuard(value, control), store, _)); + Reduction r = load_elimination.Reduce(load); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsTypeGuard(value, control)); +} + +TEST_F(LoadEliminationTest, AliasAnalysisForFinishRegion) { + Node* value0 = Parameter(Type::Signed32(), 0); + Node* value1 = Parameter(Type::Signed32(), 1); + Node* effect = graph()->start(); + Node* control = graph()->start(); + FieldAccess const access = {kTaggedBase, + kPointerSize, + MaybeHandle<Name>(), + Type::Signed32(), + MachineType::AnyTagged(), + kNoWriteBarrier}; + + StrictMock<MockAdvancedReducerEditor> editor; + LoadElimination load_elimination(&editor, jsgraph(), zone()); + + load_elimination.Reduce(effect); + + effect = graph()->NewNode( + common()->BeginRegion(RegionObservability::kNotObservable), effect); + load_elimination.Reduce(effect); + + Node* object0 = effect = + graph()->NewNode(simplified()->Allocate(NOT_TENURED), + jsgraph()->Constant(16), effect, control); + load_elimination.Reduce(effect); + + Node* region0 = effect = + graph()->NewNode(common()->FinishRegion(), object0, effect); + load_elimination.Reduce(effect); + + effect = graph()->NewNode( + common()->BeginRegion(RegionObservability::kNotObservable), effect); + load_elimination.Reduce(effect); + + Node* object1 = effect = + graph()->NewNode(simplified()->Allocate(NOT_TENURED), + jsgraph()->Constant(16), effect, control); + load_elimination.Reduce(effect); + + Node* region1 = effect = + graph()->NewNode(common()->FinishRegion(), object1, effect); + load_elimination.Reduce(effect); + + effect = graph()->NewNode(simplified()->StoreField(access), region0, value0, + effect, control); + load_elimination.Reduce(effect); + + effect = graph()->NewNode(simplified()->StoreField(access), region1, value1, + effect, control); + load_elimination.Reduce(effect); + + Node* load = graph()->NewNode(simplified()->LoadField(access), region0, + effect, control); + EXPECT_CALL(editor, ReplaceWithValue(load, value0, effect, _)); + Reduction r = load_elimination.Reduce(load); + ASSERT_TRUE(r.Changed()); + EXPECT_EQ(value0, r.replacement()); +} + } // namespace compiler } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/compiler/machine-operator-reducer-unittest.cc b/deps/v8/test/unittests/compiler/machine-operator-reducer-unittest.cc index ed426be5d8..1d29d9733f 100644 --- a/deps/v8/test/unittests/compiler/machine-operator-reducer-unittest.cc +++ b/deps/v8/test/unittests/compiler/machine-operator-reducer-unittest.cc @@ -23,10 +23,10 @@ namespace v8 { namespace internal { namespace compiler { -class MachineOperatorReducerTest : public TypedGraphTest { +class MachineOperatorReducerTest : public GraphTest { public: explicit MachineOperatorReducerTest(int num_parameters = 2) - : TypedGraphTest(num_parameters), machine_(zone()) {} + : GraphTest(num_parameters), machine_(zone()) {} protected: Reduction Reduce(Node* node) { @@ -729,25 +729,52 @@ TEST_F(MachineOperatorReducerTest, ReduceToWord32RorWithParameters) { EXPECT_EQ(reduction2.replacement(), node2); EXPECT_THAT(reduction2.replacement(), IsWord32Ror(value, sub)); - // Testing rotate right. - Node* shl_r = graph()->NewNode(machine()->Word32Shl(), value, sub); - Node* shr_r = graph()->NewNode(machine()->Word32Shr(), value, shift); - - // (x << (32 - y)) | (x >>> y) => x ror y - Node* node3 = graph()->NewNode(machine()->Word32Or(), shl_r, shr_r); + // (x << y) ^ (x >>> (32 - y)) => x ror (32 - y) + Node* node3 = graph()->NewNode(machine()->Word32Xor(), shl_l, shr_l); Reduction reduction3 = Reduce(node3); EXPECT_TRUE(reduction3.Changed()); EXPECT_EQ(reduction3.replacement(), node3); - EXPECT_THAT(reduction3.replacement(), IsWord32Ror(value, shift)); + EXPECT_THAT(reduction3.replacement(), IsWord32Ror(value, sub)); - // (x >>> y) | (x << (32 - y)) => x ror y - Node* node4 = graph()->NewNode(machine()->Word32Or(), shr_r, shl_r); + // (x >>> (32 - y)) ^ (x << y) => x ror (32 - y) + Node* node4 = graph()->NewNode(machine()->Word32Xor(), shr_l, shl_l); Reduction reduction4 = Reduce(node4); EXPECT_TRUE(reduction4.Changed()); EXPECT_EQ(reduction4.replacement(), node4); - EXPECT_THAT(reduction4.replacement(), IsWord32Ror(value, shift)); -} + EXPECT_THAT(reduction4.replacement(), IsWord32Ror(value, sub)); + + // Testing rotate right. + Node* shl_r = graph()->NewNode(machine()->Word32Shl(), value, sub); + Node* shr_r = graph()->NewNode(machine()->Word32Shr(), value, shift); + + // (x << (32 - y)) | (x >>> y) => x ror y + Node* node5 = graph()->NewNode(machine()->Word32Or(), shl_r, shr_r); + Reduction reduction5 = Reduce(node5); + EXPECT_TRUE(reduction5.Changed()); + EXPECT_EQ(reduction5.replacement(), node5); + EXPECT_THAT(reduction5.replacement(), IsWord32Ror(value, shift)); + // (x >>> y) | (x << (32 - y)) => x ror y + Node* node6 = graph()->NewNode(machine()->Word32Or(), shr_r, shl_r); + Reduction reduction6 = Reduce(node6); + EXPECT_TRUE(reduction6.Changed()); + EXPECT_EQ(reduction6.replacement(), node6); + EXPECT_THAT(reduction6.replacement(), IsWord32Ror(value, shift)); + + // (x << (32 - y)) ^ (x >>> y) => x ror y + Node* node7 = graph()->NewNode(machine()->Word32Xor(), shl_r, shr_r); + Reduction reduction7 = Reduce(node7); + EXPECT_TRUE(reduction7.Changed()); + EXPECT_EQ(reduction7.replacement(), node7); + EXPECT_THAT(reduction7.replacement(), IsWord32Ror(value, shift)); + + // (x >>> y) ^ (x << (32 - y)) => x ror y + Node* node8 = graph()->NewNode(machine()->Word32Xor(), shr_r, shl_r); + Reduction reduction8 = Reduce(node8); + EXPECT_TRUE(reduction8.Changed()); + EXPECT_EQ(reduction8.replacement(), node8); + EXPECT_THAT(reduction8.replacement(), IsWord32Ror(value, shift)); +} TEST_F(MachineOperatorReducerTest, ReduceToWord32RorWithConstant) { Node* value = Parameter(0); @@ -1587,6 +1614,48 @@ TEST_F(MachineOperatorReducerTest, Float32SubMinusZeroMinusX) { } } +TEST_F(MachineOperatorReducerTest, Float64MulWithTwo) { + Node* const p0 = Parameter(0); + { + Reduction r = Reduce( + graph()->NewNode(machine()->Float64Mul(), Float64Constant(2.0), p0)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsFloat64Add(p0, p0)); + } + { + Reduction r = Reduce( + graph()->NewNode(machine()->Float64Mul(), p0, Float64Constant(2.0))); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsFloat64Add(p0, p0)); + } +} + +// ----------------------------------------------------------------------------- +// Float64Div + +TEST_F(MachineOperatorReducerTest, Float64DivWithMinusOne) { + Node* const p0 = Parameter(0); + { + Reduction r = Reduce( + graph()->NewNode(machine()->Float64Div(), p0, Float64Constant(-1.0))); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsFloat64Neg(p0)); + } +} + +TEST_F(MachineOperatorReducerTest, Float64DivWithPowerOfTwo) { + Node* const p0 = Parameter(0); + TRACED_FORRANGE(uint64_t, exponent, 1, 0x7fe) { + Double divisor = Double(exponent << Double::kPhysicalSignificandSize); + if (divisor.value() == 1.0) continue; // Skip x / 1.0 => x. + Reduction r = Reduce(graph()->NewNode(machine()->Float64Div(), p0, + Float64Constant(divisor.value()))); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), + IsFloat64Mul(p0, IsFloat64Constant(1.0 / divisor.value()))); + } +} + // ----------------------------------------------------------------------------- // Float64Acos @@ -1772,6 +1841,37 @@ TEST_F(MachineOperatorReducerTest, Float64Log1pWithConstant) { } // ----------------------------------------------------------------------------- +// Float64Pow + +TEST_F(MachineOperatorReducerTest, Float64PowWithConstant) { + TRACED_FOREACH(double, x, kFloat64Values) { + TRACED_FOREACH(double, y, kFloat64Values) { + Reduction const r = Reduce(graph()->NewNode( + machine()->Float64Pow(), Float64Constant(x), Float64Constant(y))); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), + IsFloat64Constant(NanSensitiveDoubleEq(Pow(x, y)))); + } + } +} + +TEST_F(MachineOperatorReducerTest, Float64PowWithZeroExponent) { + Node* const p0 = Parameter(0); + { + Reduction const r = Reduce( + graph()->NewNode(machine()->Float64Pow(), p0, Float64Constant(-0.0))); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsFloat64Constant(1.0)); + } + { + Reduction const r = Reduce( + graph()->NewNode(machine()->Float64Pow(), p0, Float64Constant(0.0))); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsFloat64Constant(1.0)); + } +} + +// ----------------------------------------------------------------------------- // Float64Sin TEST_F(MachineOperatorReducerTest, Float64SinWithConstant) { diff --git a/deps/v8/test/unittests/compiler/mips/instruction-selector-mips-unittest.cc b/deps/v8/test/unittests/compiler/mips/instruction-selector-mips-unittest.cc index 7b5c667261..dc14b85361 100644 --- a/deps/v8/test/unittests/compiler/mips/instruction-selector-mips-unittest.cc +++ b/deps/v8/test/unittests/compiler/mips/instruction-selector-mips-unittest.cc @@ -408,6 +408,36 @@ TEST_F(InstructionSelectorTest, Word32ShlWithWord32And) { } } +TEST_F(InstructionSelectorTest, Word32SarWithWord32Shl) { + { + StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); + Node* const p0 = m.Parameter(0); + Node* const r = + m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(24)), m.Int32Constant(24)); + m.Return(r); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kMipsSeb, s[0]->arch_opcode()); + ASSERT_EQ(1U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output())); + } + { + StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); + Node* const p0 = m.Parameter(0); + Node* const r = + m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(16)), m.Int32Constant(16)); + m.Return(r); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kMipsSeh, s[0]->arch_opcode()); + ASSERT_EQ(1U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output())); + } +} // ---------------------------------------------------------------------------- // Logical instructions. @@ -1149,6 +1179,219 @@ TEST_F(InstructionSelectorTest, Float64Abs) { EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); } +TEST_F(InstructionSelectorTest, Float32AddWithFloat32Mul) { + if (!IsMipsArchVariant(kMips32r2) && !IsMipsArchVariant(kMips32r6)) { + return; + } + { + StreamBuilder m(this, MachineType::Float32(), MachineType::Float32(), + MachineType::Float32(), MachineType::Float32()); + Node* const p0 = m.Parameter(0); + Node* const p1 = m.Parameter(1); + Node* const p2 = m.Parameter(2); + Node* const n = m.Float32Add(m.Float32Mul(p0, p1), p2); + m.Return(n); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + if (IsMipsArchVariant(kMips32r2)) { + EXPECT_EQ(kMipsMaddS, s[0]->arch_opcode()); + } else if (IsMipsArchVariant(kMips32r6)) { + EXPECT_EQ(kMipsMaddfS, s[0]->arch_opcode()); + } + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p2), s.ToVreg(s[0]->InputAt(0))); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1))); + EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(2))); + ASSERT_EQ(1U, s[0]->OutputCount()); + if (IsMipsArchVariant(kMips32r2)) { + EXPECT_FALSE( + UnallocatedOperand::cast(s[0]->Output())->HasSameAsInputPolicy()); + } else if (IsMipsArchVariant(kMips32r6)) { + EXPECT_TRUE( + UnallocatedOperand::cast(s[0]->Output())->HasSameAsInputPolicy()); + } + EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); + EXPECT_EQ(kFlags_none, s[0]->flags_mode()); + } + { + StreamBuilder m(this, MachineType::Float32(), MachineType::Float32(), + MachineType::Float32(), MachineType::Float32()); + Node* const p0 = m.Parameter(0); + Node* const p1 = m.Parameter(1); + Node* const p2 = m.Parameter(2); + Node* const n = m.Float32Add(p0, m.Float32Mul(p1, p2)); + m.Return(n); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + if (IsMipsArchVariant(kMips32r2)) { + EXPECT_EQ(kMipsMaddS, s[0]->arch_opcode()); + } else if (IsMipsArchVariant(kMips32r6)) { + EXPECT_EQ(kMipsMaddfS, s[0]->arch_opcode()); + } + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); + EXPECT_EQ(s.ToVreg(p2), s.ToVreg(s[0]->InputAt(2))); + ASSERT_EQ(1U, s[0]->OutputCount()); + if (IsMipsArchVariant(kMips32r2)) { + EXPECT_FALSE( + UnallocatedOperand::cast(s[0]->Output())->HasSameAsInputPolicy()); + } else if (IsMipsArchVariant(kMips32r6)) { + EXPECT_TRUE( + UnallocatedOperand::cast(s[0]->Output())->HasSameAsInputPolicy()); + } + EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); + EXPECT_EQ(kFlags_none, s[0]->flags_mode()); + } +} + +TEST_F(InstructionSelectorTest, Float64AddWithFloat64Mul) { + if (!IsMipsArchVariant(kMips32r2) && !IsMipsArchVariant(kMips32r6)) { + return; + } + { + StreamBuilder m(this, MachineType::Float64(), MachineType::Float64(), + MachineType::Float64(), MachineType::Float64()); + Node* const p0 = m.Parameter(0); + Node* const p1 = m.Parameter(1); + Node* const p2 = m.Parameter(2); + Node* const n = m.Float64Add(m.Float64Mul(p0, p1), p2); + m.Return(n); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + if (IsMipsArchVariant(kMips32r2)) { + EXPECT_EQ(kMipsMaddD, s[0]->arch_opcode()); + } else if (IsMipsArchVariant(kMips32r6)) { + EXPECT_EQ(kMipsMaddfD, s[0]->arch_opcode()); + } + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p2), s.ToVreg(s[0]->InputAt(0))); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1))); + EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(2))); + ASSERT_EQ(1U, s[0]->OutputCount()); + if (IsMipsArchVariant(kMips32r2)) { + EXPECT_FALSE( + UnallocatedOperand::cast(s[0]->Output())->HasSameAsInputPolicy()); + } else if (IsMipsArchVariant(kMips32r6)) { + EXPECT_TRUE( + UnallocatedOperand::cast(s[0]->Output())->HasSameAsInputPolicy()); + } + EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); + EXPECT_EQ(kFlags_none, s[0]->flags_mode()); + } + { + StreamBuilder m(this, MachineType::Float64(), MachineType::Float64(), + MachineType::Float64(), MachineType::Float64()); + Node* const p0 = m.Parameter(0); + Node* const p1 = m.Parameter(1); + Node* const p2 = m.Parameter(2); + Node* const n = m.Float64Add(p0, m.Float64Mul(p1, p2)); + m.Return(n); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + if (IsMipsArchVariant(kMips32r2)) { + EXPECT_EQ(kMipsMaddD, s[0]->arch_opcode()); + } else if (IsMipsArchVariant(kMips32r6)) { + EXPECT_EQ(kMipsMaddfD, s[0]->arch_opcode()); + } + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); + EXPECT_EQ(s.ToVreg(p2), s.ToVreg(s[0]->InputAt(2))); + ASSERT_EQ(1U, s[0]->OutputCount()); + if (IsMipsArchVariant(kMips32r2)) { + EXPECT_FALSE( + UnallocatedOperand::cast(s[0]->Output())->HasSameAsInputPolicy()); + } else if (IsMipsArchVariant(kMips32r6)) { + EXPECT_TRUE( + UnallocatedOperand::cast(s[0]->Output())->HasSameAsInputPolicy()); + } + EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); + EXPECT_EQ(kFlags_none, s[0]->flags_mode()); + } +} + +TEST_F(InstructionSelectorTest, Float32SubWithFloat32Mul) { + StreamBuilder m(this, MachineType::Float32(), MachineType::Float32(), + MachineType::Float32(), MachineType::Float32()); + Node* const p0 = m.Parameter(0); + Node* const p1 = m.Parameter(1); + Node* const p2 = m.Parameter(2); + Node* n = nullptr; + + if (!IsMipsArchVariant(kMips32r2) && !IsMipsArchVariant(kMips32r6)) { + return; + } + + if (IsMipsArchVariant(kMips32r2)) { + n = m.Float32Sub(m.Float32Mul(p1, p2), p0); + } else if (IsMipsArchVariant(kMips32r6)) { + n = m.Float32Sub(p0, m.Float32Mul(p1, p2)); + } + m.Return(n); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + if (IsMipsArchVariant(kMips32r2)) { + EXPECT_EQ(kMipsMsubS, s[0]->arch_opcode()); + } else if (IsMipsArchVariant(kMips32r6)) { + EXPECT_EQ(kMipsMsubfS, s[0]->arch_opcode()); + } + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); + EXPECT_EQ(s.ToVreg(p2), s.ToVreg(s[0]->InputAt(2))); + ASSERT_EQ(1U, s[0]->OutputCount()); + if (IsMipsArchVariant(kMips32r2)) { + EXPECT_FALSE( + UnallocatedOperand::cast(s[0]->Output())->HasSameAsInputPolicy()); + } else if (IsMipsArchVariant(kMips32r6)) { + EXPECT_TRUE( + UnallocatedOperand::cast(s[0]->Output())->HasSameAsInputPolicy()); + } + EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); + EXPECT_EQ(kFlags_none, s[0]->flags_mode()); +} + +TEST_F(InstructionSelectorTest, Float64SubWithFloat64Mul) { + StreamBuilder m(this, MachineType::Float64(), MachineType::Float64(), + MachineType::Float64(), MachineType::Float64()); + Node* const p0 = m.Parameter(0); + Node* const p1 = m.Parameter(1); + Node* const p2 = m.Parameter(2); + Node* n = nullptr; + + if (!IsMipsArchVariant(kMips32r2) && !IsMipsArchVariant(kMips32r6)) { + return; + } + + if (IsMipsArchVariant(kMips32r2)) { + n = m.Float64Sub(m.Float64Mul(p1, p2), p0); + } else if (IsMipsArchVariant(kMips32r6)) { + n = m.Float64Sub(p0, m.Float64Mul(p1, p2)); + } + m.Return(n); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + if (IsMipsArchVariant(kMips32r2)) { + EXPECT_EQ(kMipsMsubD, s[0]->arch_opcode()); + } else if (IsMipsArchVariant(kMips32r6)) { + EXPECT_EQ(kMipsMsubfD, s[0]->arch_opcode()); + } + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); + EXPECT_EQ(s.ToVreg(p2), s.ToVreg(s[0]->InputAt(2))); + ASSERT_EQ(1U, s[0]->OutputCount()); + if (IsMipsArchVariant(kMips32r2)) { + EXPECT_FALSE( + UnallocatedOperand::cast(s[0]->Output())->HasSameAsInputPolicy()); + } else if (IsMipsArchVariant(kMips32r6)) { + EXPECT_TRUE( + UnallocatedOperand::cast(s[0]->Output())->HasSameAsInputPolicy()); + } + EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); + EXPECT_EQ(kFlags_none, s[0]->flags_mode()); +} TEST_F(InstructionSelectorTest, Float64Max) { StreamBuilder m(this, MachineType::Float64(), MachineType::Float64(), diff --git a/deps/v8/test/unittests/compiler/mips64/instruction-selector-mips64-unittest.cc b/deps/v8/test/unittests/compiler/mips64/instruction-selector-mips64-unittest.cc index c82cb9fe4f..be77126688 100644 --- a/deps/v8/test/unittests/compiler/mips64/instruction-selector-mips64-unittest.cc +++ b/deps/v8/test/unittests/compiler/mips64/instruction-selector-mips64-unittest.cc @@ -719,6 +719,51 @@ TEST_F(InstructionSelectorTest, Word64ShlWithWord64And) { } } +TEST_F(InstructionSelectorTest, Word32SarWithWord32Shl) { + { + StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); + Node* const p0 = m.Parameter(0); + Node* const r = + m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(24)), m.Int32Constant(24)); + m.Return(r); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kMips64Seb, s[0]->arch_opcode()); + ASSERT_EQ(1U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output())); + } + { + StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); + Node* const p0 = m.Parameter(0); + Node* const r = + m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(16)), m.Int32Constant(16)); + m.Return(r); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kMips64Seh, s[0]->arch_opcode()); + ASSERT_EQ(1U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output())); + } + { + StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); + Node* const p0 = m.Parameter(0); + Node* const r = + m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(32)), m.Int32Constant(32)); + m.Return(r); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kMips64Shl, s[0]->arch_opcode()); + ASSERT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(1))); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output())); + } +} // ---------------------------------------------------------------------------- // MUL/DIV instructions. @@ -1491,6 +1536,203 @@ TEST_F(InstructionSelectorTest, Float64Abs) { EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); } +TEST_F(InstructionSelectorTest, Float32AddWithFloat32Mul) { + { + StreamBuilder m(this, MachineType::Float32(), MachineType::Float32(), + MachineType::Float32(), MachineType::Float32()); + Node* const p0 = m.Parameter(0); + Node* const p1 = m.Parameter(1); + Node* const p2 = m.Parameter(2); + Node* const n = m.Float32Add(m.Float32Mul(p0, p1), p2); + m.Return(n); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + if (kArchVariant == kMips64r2) { + EXPECT_EQ(kMips64MaddS, s[0]->arch_opcode()); + } else if (kArchVariant == kMips64r6) { + EXPECT_EQ(kMips64MaddfS, s[0]->arch_opcode()); + } + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p2), s.ToVreg(s[0]->InputAt(0))); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1))); + EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(2))); + ASSERT_EQ(1U, s[0]->OutputCount()); + if (kArchVariant == kMips64r2) { + EXPECT_FALSE( + UnallocatedOperand::cast(s[0]->Output())->HasSameAsInputPolicy()); + } else if (kArchVariant == kMips64r6) { + EXPECT_TRUE( + UnallocatedOperand::cast(s[0]->Output())->HasSameAsInputPolicy()); + } + EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); + EXPECT_EQ(kFlags_none, s[0]->flags_mode()); + } + { + StreamBuilder m(this, MachineType::Float32(), MachineType::Float32(), + MachineType::Float32(), MachineType::Float32()); + Node* const p0 = m.Parameter(0); + Node* const p1 = m.Parameter(1); + Node* const p2 = m.Parameter(2); + Node* const n = m.Float32Add(p0, m.Float32Mul(p1, p2)); + m.Return(n); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + if (kArchVariant == kMips64r2) { + EXPECT_EQ(kMips64MaddS, s[0]->arch_opcode()); + } else if (kArchVariant == kMips64r6) { + EXPECT_EQ(kMips64MaddfS, s[0]->arch_opcode()); + } + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); + EXPECT_EQ(s.ToVreg(p2), s.ToVreg(s[0]->InputAt(2))); + ASSERT_EQ(1U, s[0]->OutputCount()); + if (kArchVariant == kMips64r2) { + EXPECT_FALSE( + UnallocatedOperand::cast(s[0]->Output())->HasSameAsInputPolicy()); + } else if (kArchVariant == kMips64r6) { + EXPECT_TRUE( + UnallocatedOperand::cast(s[0]->Output())->HasSameAsInputPolicy()); + } + EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); + EXPECT_EQ(kFlags_none, s[0]->flags_mode()); + } +} + +TEST_F(InstructionSelectorTest, Float64AddWithFloat64Mul) { + { + StreamBuilder m(this, MachineType::Float64(), MachineType::Float64(), + MachineType::Float64(), MachineType::Float64()); + Node* const p0 = m.Parameter(0); + Node* const p1 = m.Parameter(1); + Node* const p2 = m.Parameter(2); + Node* const n = m.Float64Add(m.Float64Mul(p0, p1), p2); + m.Return(n); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + if (kArchVariant == kMips64r2) { + EXPECT_EQ(kMips64MaddD, s[0]->arch_opcode()); + } else if (kArchVariant == kMips64r6) { + EXPECT_EQ(kMips64MaddfD, s[0]->arch_opcode()); + } + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p2), s.ToVreg(s[0]->InputAt(0))); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1))); + EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(2))); + ASSERT_EQ(1U, s[0]->OutputCount()); + if (kArchVariant == kMips64r2) { + EXPECT_FALSE( + UnallocatedOperand::cast(s[0]->Output())->HasSameAsInputPolicy()); + } else if (kArchVariant == kMips64r6) { + EXPECT_TRUE( + UnallocatedOperand::cast(s[0]->Output())->HasSameAsInputPolicy()); + } + EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); + EXPECT_EQ(kFlags_none, s[0]->flags_mode()); + } + { + StreamBuilder m(this, MachineType::Float64(), MachineType::Float64(), + MachineType::Float64(), MachineType::Float64()); + Node* const p0 = m.Parameter(0); + Node* const p1 = m.Parameter(1); + Node* const p2 = m.Parameter(2); + Node* const n = m.Float64Add(p0, m.Float64Mul(p1, p2)); + m.Return(n); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + if (kArchVariant == kMips64r2) { + EXPECT_EQ(kMips64MaddD, s[0]->arch_opcode()); + } else if (kArchVariant == kMips64r6) { + EXPECT_EQ(kMips64MaddfD, s[0]->arch_opcode()); + } + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); + EXPECT_EQ(s.ToVreg(p2), s.ToVreg(s[0]->InputAt(2))); + ASSERT_EQ(1U, s[0]->OutputCount()); + if (kArchVariant == kMips64r2) { + EXPECT_FALSE( + UnallocatedOperand::cast(s[0]->Output())->HasSameAsInputPolicy()); + } else if (kArchVariant == kMips64r6) { + EXPECT_TRUE( + UnallocatedOperand::cast(s[0]->Output())->HasSameAsInputPolicy()); + } + EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); + EXPECT_EQ(kFlags_none, s[0]->flags_mode()); + } +} + +TEST_F(InstructionSelectorTest, Float32SubWithFloat32Mul) { + StreamBuilder m(this, MachineType::Float32(), MachineType::Float32(), + MachineType::Float32(), MachineType::Float32()); + Node* const p0 = m.Parameter(0); + Node* const p1 = m.Parameter(1); + Node* const p2 = m.Parameter(2); + Node* n; + if (kArchVariant == kMips64r2) { + n = m.Float32Sub(m.Float32Mul(p1, p2), p0); + } else if (kArchVariant == kMips64r6) { + n = m.Float32Sub(p0, m.Float32Mul(p1, p2)); + } + m.Return(n); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + if (kArchVariant == kMips64r2) { + EXPECT_EQ(kMips64MsubS, s[0]->arch_opcode()); + } else if (kArchVariant == kMips64r6) { + EXPECT_EQ(kMips64MsubfS, s[0]->arch_opcode()); + } + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); + EXPECT_EQ(s.ToVreg(p2), s.ToVreg(s[0]->InputAt(2))); + ASSERT_EQ(1U, s[0]->OutputCount()); + if (kArchVariant == kMips64r2) { + EXPECT_FALSE( + UnallocatedOperand::cast(s[0]->Output())->HasSameAsInputPolicy()); + } else if (kArchVariant == kMips64r6) { + EXPECT_TRUE( + UnallocatedOperand::cast(s[0]->Output())->HasSameAsInputPolicy()); + } + EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); + EXPECT_EQ(kFlags_none, s[0]->flags_mode()); +} + +TEST_F(InstructionSelectorTest, Float64SubWithFloat64Mul) { + StreamBuilder m(this, MachineType::Float64(), MachineType::Float64(), + MachineType::Float64(), MachineType::Float64()); + Node* const p0 = m.Parameter(0); + Node* const p1 = m.Parameter(1); + Node* const p2 = m.Parameter(2); + Node* n; + if (kArchVariant == kMips64r2) { + n = m.Float64Sub(m.Float64Mul(p1, p2), p0); + } else if (kArchVariant == kMips64r6) { + n = m.Float64Sub(p0, m.Float64Mul(p1, p2)); + } + m.Return(n); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + if (kArchVariant == kMips64r2) { + EXPECT_EQ(kMips64MsubD, s[0]->arch_opcode()); + } else if (kArchVariant == kMips64r6) { + EXPECT_EQ(kMips64MsubfD, s[0]->arch_opcode()); + } + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); + EXPECT_EQ(s.ToVreg(p2), s.ToVreg(s[0]->InputAt(2))); + ASSERT_EQ(1U, s[0]->OutputCount()); + if (kArchVariant == kMips64r2) { + EXPECT_FALSE( + UnallocatedOperand::cast(s[0]->Output())->HasSameAsInputPolicy()); + } else if (kArchVariant == kMips64r6) { + EXPECT_TRUE( + UnallocatedOperand::cast(s[0]->Output())->HasSameAsInputPolicy()); + } + EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); + EXPECT_EQ(kFlags_none, s[0]->flags_mode()); +} TEST_F(InstructionSelectorTest, Float64Max) { StreamBuilder m(this, MachineType::Float64(), MachineType::Float64(), diff --git a/deps/v8/test/unittests/compiler/node-test-utils.cc b/deps/v8/test/unittests/compiler/node-test-utils.cc index 5620b8bec1..3a5b2c3aeb 100644 --- a/deps/v8/test/unittests/compiler/node-test-utils.cc +++ b/deps/v8/test/unittests/compiler/node-test-utils.cc @@ -406,6 +406,35 @@ class IsTerminateMatcher final : public NodeMatcher { const Matcher<Node*> control_matcher_; }; +class IsTypeGuardMatcher final : public NodeMatcher { + public: + IsTypeGuardMatcher(const Matcher<Node*>& value_matcher, + const Matcher<Node*>& control_matcher) + : NodeMatcher(IrOpcode::kTypeGuard), + value_matcher_(value_matcher), + control_matcher_(control_matcher) {} + + void DescribeTo(std::ostream* os) const final { + NodeMatcher::DescribeTo(os); + *os << " whose value ("; + value_matcher_.DescribeTo(os); + *os << ") and control ("; + control_matcher_.DescribeTo(os); + *os << ")"; + } + + bool MatchAndExplain(Node* node, MatchResultListener* listener) const final { + return (NodeMatcher::MatchAndExplain(node, listener) && + PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), + "value", value_matcher_, listener) && + PrintMatchAndExplain(NodeProperties::GetControlInput(node), + "control", control_matcher_, listener)); + } + + private: + const Matcher<Node*> value_matcher_; + const Matcher<Node*> control_matcher_; +}; template <typename T> class IsConstantMatcher final : public NodeMatcher { @@ -1714,6 +1743,10 @@ Matcher<Node*> IsTerminate(const Matcher<Node*>& effect_matcher, return MakeMatcher(new IsTerminateMatcher(effect_matcher, control_matcher)); } +Matcher<Node*> IsTypeGuard(const Matcher<Node*>& value_matcher, + const Matcher<Node*>& control_matcher) { + return MakeMatcher(new IsTypeGuardMatcher(value_matcher, control_matcher)); +} Matcher<Node*> IsExternalConstant( const Matcher<ExternalReference>& value_matcher) { @@ -2274,7 +2307,9 @@ IS_BINOP_MATCHER(Float32LessThan) IS_BINOP_MATCHER(Float32LessThanOrEqual) IS_BINOP_MATCHER(Float64Max) IS_BINOP_MATCHER(Float64Min) +IS_BINOP_MATCHER(Float64Add) IS_BINOP_MATCHER(Float64Sub) +IS_BINOP_MATCHER(Float64Mul) IS_BINOP_MATCHER(Float64InsertLowWord32) IS_BINOP_MATCHER(Float64InsertHighWord32) #undef IS_BINOP_MATCHER @@ -2285,6 +2320,9 @@ IS_BINOP_MATCHER(Float64InsertHighWord32) return MakeMatcher(new IsUnopMatcher(IrOpcode::k##Name, input_matcher)); \ } IS_UNOP_MATCHER(BooleanNot) +IS_UNOP_MATCHER(BitcastTaggedToWord) +IS_UNOP_MATCHER(BitcastWordToTagged) +IS_UNOP_MATCHER(BitcastWordToTaggedSigned) IS_UNOP_MATCHER(TruncateFloat64ToWord32) IS_UNOP_MATCHER(ChangeFloat64ToInt32) IS_UNOP_MATCHER(ChangeFloat64ToUint32) @@ -2332,6 +2370,7 @@ IS_UNOP_MATCHER(NumberSqrt) IS_UNOP_MATCHER(NumberTan) IS_UNOP_MATCHER(NumberTanh) IS_UNOP_MATCHER(NumberTrunc) +IS_UNOP_MATCHER(NumberToBoolean) IS_UNOP_MATCHER(NumberToInt32) IS_UNOP_MATCHER(NumberToUint32) IS_UNOP_MATCHER(PlainPrimitiveToNumber) diff --git a/deps/v8/test/unittests/compiler/node-test-utils.h b/deps/v8/test/unittests/compiler/node-test-utils.h index 2a24803380..3afe2adf14 100644 --- a/deps/v8/test/unittests/compiler/node-test-utils.h +++ b/deps/v8/test/unittests/compiler/node-test-utils.h @@ -83,6 +83,8 @@ Matcher<Node*> IsReturn2(const Matcher<Node*>& value_matcher, const Matcher<Node*>& control_matcher); Matcher<Node*> IsTerminate(const Matcher<Node*>& effect_matcher, const Matcher<Node*>& control_matcher); +Matcher<Node*> IsTypeGuard(const Matcher<Node*>& value_matcher, + const Matcher<Node*>& control_matcher); Matcher<Node*> IsExternalConstant( const Matcher<ExternalReference>& value_matcher); Matcher<Node*> IsHeapConstant(Handle<HeapObject> value); @@ -384,6 +386,9 @@ Matcher<Node*> IsInt64Sub(const Matcher<Node*>& lhs_matcher, const Matcher<Node*>& rhs_matcher); Matcher<Node*> IsJSAdd(const Matcher<Node*>& lhs_matcher, const Matcher<Node*>& rhs_matcher); +Matcher<Node*> IsBitcastTaggedToWord(const Matcher<Node*>& input_matcher); +Matcher<Node*> IsBitcastWordToTagged(const Matcher<Node*>& input_matcher); +Matcher<Node*> IsBitcastWordToTaggedSigned(const Matcher<Node*>& input_matcher); Matcher<Node*> IsTruncateFloat64ToWord32(const Matcher<Node*>& input_matcher); Matcher<Node*> IsChangeFloat64ToInt32(const Matcher<Node*>& input_matcher); Matcher<Node*> IsChangeFloat64ToUint32(const Matcher<Node*>& input_matcher); @@ -405,8 +410,12 @@ Matcher<Node*> IsFloat64Max(const Matcher<Node*>& lhs_matcher, const Matcher<Node*>& rhs_matcher); Matcher<Node*> IsFloat64Min(const Matcher<Node*>& lhs_matcher, const Matcher<Node*>& rhs_matcher); +Matcher<Node*> IsFloat64Add(const Matcher<Node*>& lhs_matcher, + const Matcher<Node*>& rhs_matcher); Matcher<Node*> IsFloat64Sub(const Matcher<Node*>& lhs_matcher, const Matcher<Node*>& rhs_matcher); +Matcher<Node*> IsFloat64Mul(const Matcher<Node*>& lhs_matcher, + const Matcher<Node*>& rhs_matcher); Matcher<Node*> IsFloat64Abs(const Matcher<Node*>& input_matcher); Matcher<Node*> IsFloat64Neg(const Matcher<Node*>& input_matcher); Matcher<Node*> IsFloat64Sqrt(const Matcher<Node*>& input_matcher); @@ -425,6 +434,7 @@ Matcher<Node*> IsToNumber(const Matcher<Node*>& base_matcher, const Matcher<Node*>& control_matcher); Matcher<Node*> IsLoadContext(const Matcher<ContextAccess>& access_matcher, const Matcher<Node*>& context_matcher); +Matcher<Node*> IsNumberToBoolean(const Matcher<Node*>& input_matcher); Matcher<Node*> IsNumberToInt32(const Matcher<Node*>& input_matcher); Matcher<Node*> IsNumberToUint32(const Matcher<Node*>& input_matcher); Matcher<Node*> IsParameter(const Matcher<int> index_matcher); diff --git a/deps/v8/test/unittests/compiler/opcodes-unittest.cc b/deps/v8/test/unittests/compiler/opcodes-unittest.cc index 3bb65c2e13..a0e67ecb27 100644 --- a/deps/v8/test/unittests/compiler/opcodes-unittest.cc +++ b/deps/v8/test/unittests/compiler/opcodes-unittest.cc @@ -3,7 +3,7 @@ // found in the LICENSE file. #include "src/compiler/opcodes.h" -#include "testing/gtest/include/gtest/gtest.h" +#include "testing/gtest-support.h" namespace v8 { namespace internal { @@ -81,65 +81,60 @@ bool IsComparisonOpcode(IrOpcode::Value opcode) { const IrOpcode::Value kInvalidOpcode = static_cast<IrOpcode::Value>(123456789); -} // namespace +char const* const kMnemonics[] = { +#define OPCODE(Opcode) #Opcode, + ALL_OP_LIST(OPCODE) +#undef OPCODE +}; + +const IrOpcode::Value kOpcodes[] = { +#define OPCODE(Opcode) IrOpcode::k##Opcode, + ALL_OP_LIST(OPCODE) +#undef OPCODE +}; +} // namespace TEST(IrOpcodeTest, IsCommonOpcode) { EXPECT_FALSE(IrOpcode::IsCommonOpcode(kInvalidOpcode)); -#define OPCODE(Opcode) \ - EXPECT_EQ(IsCommonOpcode(IrOpcode::k##Opcode), \ - IrOpcode::IsCommonOpcode(IrOpcode::k##Opcode)); - ALL_OP_LIST(OPCODE) -#undef OPCODE + TRACED_FOREACH(IrOpcode::Value, opcode, kOpcodes) { + EXPECT_EQ(IsCommonOpcode(opcode), IrOpcode::IsCommonOpcode(opcode)); + } } - TEST(IrOpcodeTest, IsControlOpcode) { EXPECT_FALSE(IrOpcode::IsControlOpcode(kInvalidOpcode)); -#define OPCODE(Opcode) \ - EXPECT_EQ(IsControlOpcode(IrOpcode::k##Opcode), \ - IrOpcode::IsControlOpcode(IrOpcode::k##Opcode)); - ALL_OP_LIST(OPCODE) -#undef OPCODE + TRACED_FOREACH(IrOpcode::Value, opcode, kOpcodes) { + EXPECT_EQ(IsControlOpcode(opcode), IrOpcode::IsControlOpcode(opcode)); + } } - TEST(IrOpcodeTest, IsJsOpcode) { EXPECT_FALSE(IrOpcode::IsJsOpcode(kInvalidOpcode)); -#define OPCODE(Opcode) \ - EXPECT_EQ(IsJsOpcode(IrOpcode::k##Opcode), \ - IrOpcode::IsJsOpcode(IrOpcode::k##Opcode)); - ALL_OP_LIST(OPCODE) -#undef OPCODE + TRACED_FOREACH(IrOpcode::Value, opcode, kOpcodes) { + EXPECT_EQ(IsJsOpcode(opcode), IrOpcode::IsJsOpcode(opcode)); + } } - TEST(IrOpcodeTest, IsConstantOpcode) { EXPECT_FALSE(IrOpcode::IsConstantOpcode(kInvalidOpcode)); -#define OPCODE(Opcode) \ - EXPECT_EQ(IsConstantOpcode(IrOpcode::k##Opcode), \ - IrOpcode::IsConstantOpcode(IrOpcode::k##Opcode)); - ALL_OP_LIST(OPCODE) -#undef OPCODE + TRACED_FOREACH(IrOpcode::Value, opcode, kOpcodes) { + EXPECT_EQ(IsConstantOpcode(opcode), IrOpcode::IsConstantOpcode(opcode)); + } } - TEST(IrOpcodeTest, IsComparisonOpcode) { EXPECT_FALSE(IrOpcode::IsComparisonOpcode(kInvalidOpcode)); -#define OPCODE(Opcode) \ - EXPECT_EQ(IsComparisonOpcode(IrOpcode::k##Opcode), \ - IrOpcode::IsComparisonOpcode(IrOpcode::k##Opcode)); - ALL_OP_LIST(OPCODE) -#undef OPCODE + TRACED_FOREACH(IrOpcode::Value, opcode, kOpcodes) { + EXPECT_EQ(IsComparisonOpcode(opcode), IrOpcode::IsComparisonOpcode(opcode)); + } } - TEST(IrOpcodeTest, Mnemonic) { EXPECT_STREQ("UnknownOpcode", IrOpcode::Mnemonic(kInvalidOpcode)); -#define OPCODE(Opcode) \ - EXPECT_STREQ(#Opcode, IrOpcode::Mnemonic(IrOpcode::k##Opcode)); - ALL_OP_LIST(OPCODE) -#undef OPCODE + TRACED_FOREACH(IrOpcode::Value, opcode, kOpcodes) { + EXPECT_STREQ(kMnemonics[opcode], IrOpcode::Mnemonic(opcode)); + } } } // namespace compiler diff --git a/deps/v8/test/unittests/compiler/simplified-operator-reducer-unittest.cc b/deps/v8/test/unittests/compiler/simplified-operator-reducer-unittest.cc index b21a148718..6f37609f3a 100644 --- a/deps/v8/test/unittests/compiler/simplified-operator-reducer-unittest.cc +++ b/deps/v8/test/unittests/compiler/simplified-operator-reducer-unittest.cc @@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "src/compiler/simplified-operator.h" #include "src/compiler/access-builder.h" #include "src/compiler/js-graph.h" #include "src/compiler/node-properties.h" -#include "src/compiler/simplified-operator.h" #include "src/compiler/simplified-operator-reducer.h" +#include "src/compiler/types.h" #include "src/conversions-inl.h" -#include "src/types.h" #include "test/unittests/compiler/graph-unittest.h" #include "test/unittests/compiler/node-test-utils.h" #include "testing/gmock-support.h" @@ -97,10 +97,6 @@ const double kNaNs[] = {-std::numeric_limits<double>::quiet_NaN(), bit_cast<double>(V8_UINT64_C(0x7FFFFFFFFFFFFFFF)), bit_cast<double>(V8_UINT64_C(0xFFFFFFFFFFFFFFFF))}; -const CheckForMinusZeroMode kCheckForMinusZeroModes[] = { - CheckForMinusZeroMode::kDontCheckForMinusZero, - CheckForMinusZeroMode::kCheckForMinusZero}; - } // namespace @@ -191,13 +187,11 @@ TEST_F(SimplifiedOperatorReducerTest, ChangeTaggedToBitWithChangeBitToTagged) { // ChangeFloat64ToTagged TEST_F(SimplifiedOperatorReducerTest, ChangeFloat64ToTaggedWithConstant) { - TRACED_FOREACH(CheckForMinusZeroMode, mode, kCheckForMinusZeroModes) { - TRACED_FOREACH(double, n, kFloat64Values) { - Reduction reduction = Reduce(graph()->NewNode( - simplified()->ChangeFloat64ToTagged(mode), Float64Constant(n))); - ASSERT_TRUE(reduction.Changed()); - EXPECT_THAT(reduction.replacement(), IsNumberConstant(BitEq(n))); - } + TRACED_FOREACH(double, n, kFloat64Values) { + Reduction reduction = Reduce(graph()->NewNode( + simplified()->ChangeFloat64ToTagged(), Float64Constant(n))); + ASSERT_TRUE(reduction.Changed()); + EXPECT_THAT(reduction.replacement(), IsNumberConstant(BitEq(n))); } } @@ -222,13 +216,11 @@ TEST_F(SimplifiedOperatorReducerTest, ChangeInt32ToTaggedWithConstant) { TEST_F(SimplifiedOperatorReducerTest, ChangeTaggedToFloat64WithChangeFloat64ToTagged) { Node* param0 = Parameter(0); - TRACED_FOREACH(CheckForMinusZeroMode, mode, kCheckForMinusZeroModes) { - Reduction reduction = Reduce(graph()->NewNode( - simplified()->ChangeTaggedToFloat64(), - graph()->NewNode(simplified()->ChangeFloat64ToTagged(mode), param0))); - ASSERT_TRUE(reduction.Changed()); - EXPECT_EQ(param0, reduction.replacement()); - } + Reduction reduction = Reduce(graph()->NewNode( + simplified()->ChangeTaggedToFloat64(), + graph()->NewNode(simplified()->ChangeFloat64ToTagged(), param0))); + ASSERT_TRUE(reduction.Changed()); + EXPECT_EQ(param0, reduction.replacement()); } TEST_F(SimplifiedOperatorReducerTest, @@ -279,13 +271,11 @@ TEST_F(SimplifiedOperatorReducerTest, ChangeTaggedToFloat64WithNaNConstant) { TEST_F(SimplifiedOperatorReducerTest, ChangeTaggedToInt32WithChangeFloat64ToTagged) { Node* param0 = Parameter(0); - TRACED_FOREACH(CheckForMinusZeroMode, mode, kCheckForMinusZeroModes) { - Reduction reduction = Reduce(graph()->NewNode( - simplified()->ChangeTaggedToInt32(), - graph()->NewNode(simplified()->ChangeFloat64ToTagged(mode), param0))); - ASSERT_TRUE(reduction.Changed()); - EXPECT_THAT(reduction.replacement(), IsChangeFloat64ToInt32(param0)); - } + Reduction reduction = Reduce(graph()->NewNode( + simplified()->ChangeTaggedToInt32(), + graph()->NewNode(simplified()->ChangeFloat64ToTagged(), param0))); + ASSERT_TRUE(reduction.Changed()); + EXPECT_THAT(reduction.replacement(), IsChangeFloat64ToInt32(param0)); } TEST_F(SimplifiedOperatorReducerTest, @@ -305,13 +295,11 @@ TEST_F(SimplifiedOperatorReducerTest, TEST_F(SimplifiedOperatorReducerTest, ChangeTaggedToUint32WithChangeFloat64ToTagged) { Node* param0 = Parameter(0); - TRACED_FOREACH(CheckForMinusZeroMode, mode, kCheckForMinusZeroModes) { - Reduction reduction = Reduce(graph()->NewNode( - simplified()->ChangeTaggedToUint32(), - graph()->NewNode(simplified()->ChangeFloat64ToTagged(mode), param0))); - ASSERT_TRUE(reduction.Changed()); - EXPECT_THAT(reduction.replacement(), IsChangeFloat64ToUint32(param0)); - } + Reduction reduction = Reduce(graph()->NewNode( + simplified()->ChangeTaggedToUint32(), + graph()->NewNode(simplified()->ChangeFloat64ToTagged(), param0))); + ASSERT_TRUE(reduction.Changed()); + EXPECT_THAT(reduction.replacement(), IsChangeFloat64ToUint32(param0)); } TEST_F(SimplifiedOperatorReducerTest, @@ -331,13 +319,11 @@ TEST_F(SimplifiedOperatorReducerTest, TEST_F(SimplifiedOperatorReducerTest, TruncateTaggedToWord3WithChangeFloat64ToTagged) { Node* param0 = Parameter(0); - TRACED_FOREACH(CheckForMinusZeroMode, mode, kCheckForMinusZeroModes) { - Reduction reduction = Reduce(graph()->NewNode( - simplified()->TruncateTaggedToWord32(), - graph()->NewNode(simplified()->ChangeFloat64ToTagged(mode), param0))); - ASSERT_TRUE(reduction.Changed()); - EXPECT_THAT(reduction.replacement(), IsTruncateFloat64ToWord32(param0)); - } + Reduction reduction = Reduce(graph()->NewNode( + simplified()->TruncateTaggedToWord32(), + graph()->NewNode(simplified()->ChangeFloat64ToTagged(), param0))); + ASSERT_TRUE(reduction.Changed()); + EXPECT_THAT(reduction.replacement(), IsTruncateFloat64ToWord32(param0)); } TEST_F(SimplifiedOperatorReducerTest, TruncateTaggedToWord32WithConstant) { @@ -350,20 +336,20 @@ TEST_F(SimplifiedOperatorReducerTest, TruncateTaggedToWord32WithConstant) { } // ----------------------------------------------------------------------------- -// CheckTaggedPointer +// CheckHeapObject -TEST_F(SimplifiedOperatorReducerTest, CheckTaggedPointerWithChangeBitToTagged) { +TEST_F(SimplifiedOperatorReducerTest, CheckHeapObjectWithChangeBitToTagged) { Node* param0 = Parameter(0); Node* effect = graph()->start(); Node* control = graph()->start(); Node* value = graph()->NewNode(simplified()->ChangeBitToTagged(), param0); - Reduction reduction = Reduce(graph()->NewNode( - simplified()->CheckTaggedPointer(), value, effect, control)); + Reduction reduction = Reduce(graph()->NewNode(simplified()->CheckHeapObject(), + value, effect, control)); ASSERT_TRUE(reduction.Changed()); EXPECT_EQ(value, reduction.replacement()); } -TEST_F(SimplifiedOperatorReducerTest, CheckTaggedPointerWithHeapConstant) { +TEST_F(SimplifiedOperatorReducerTest, CheckHeapObjectWithHeapConstant) { Node* effect = graph()->start(); Node* control = graph()->start(); Handle<HeapObject> kHeapObjects[] = { @@ -372,34 +358,57 @@ TEST_F(SimplifiedOperatorReducerTest, CheckTaggedPointerWithHeapConstant) { TRACED_FOREACH(Handle<HeapObject>, object, kHeapObjects) { Node* value = HeapConstant(object); Reduction reduction = Reduce(graph()->NewNode( - simplified()->CheckTaggedPointer(), value, effect, control)); + simplified()->CheckHeapObject(), value, effect, control)); ASSERT_TRUE(reduction.Changed()); EXPECT_EQ(value, reduction.replacement()); } } +TEST_F(SimplifiedOperatorReducerTest, CheckHeapObjectWithCheckHeapObject) { + Node* param0 = Parameter(0); + Node* effect = graph()->start(); + Node* control = graph()->start(); + Node* value = effect = graph()->NewNode(simplified()->CheckHeapObject(), + param0, effect, control); + Reduction reduction = Reduce(graph()->NewNode(simplified()->CheckHeapObject(), + value, effect, control)); + ASSERT_TRUE(reduction.Changed()); + EXPECT_EQ(value, reduction.replacement()); +} + // ----------------------------------------------------------------------------- -// CheckTaggedSigned +// CheckSmi -TEST_F(SimplifiedOperatorReducerTest, - CheckTaggedSignedWithChangeInt31ToTaggedSigned) { +TEST_F(SimplifiedOperatorReducerTest, CheckSmiWithChangeInt31ToTaggedSigned) { Node* param0 = Parameter(0); Node* effect = graph()->start(); Node* control = graph()->start(); Node* value = graph()->NewNode(simplified()->ChangeInt31ToTaggedSigned(), param0); - Reduction reduction = Reduce(graph()->NewNode( - simplified()->CheckTaggedSigned(), value, effect, control)); + Reduction reduction = Reduce( + graph()->NewNode(simplified()->CheckSmi(), value, effect, control)); ASSERT_TRUE(reduction.Changed()); EXPECT_EQ(value, reduction.replacement()); } -TEST_F(SimplifiedOperatorReducerTest, CheckTaggedSignedWithNumberConstant) { +TEST_F(SimplifiedOperatorReducerTest, CheckSmiWithNumberConstant) { Node* effect = graph()->start(); Node* control = graph()->start(); Node* value = NumberConstant(1.0); - Reduction reduction = Reduce(graph()->NewNode( - simplified()->CheckTaggedSigned(), value, effect, control)); + Reduction reduction = Reduce( + graph()->NewNode(simplified()->CheckSmi(), value, effect, control)); + ASSERT_TRUE(reduction.Changed()); + EXPECT_EQ(value, reduction.replacement()); +} + +TEST_F(SimplifiedOperatorReducerTest, CheckSmiWithCheckSmi) { + Node* param0 = Parameter(0); + Node* effect = graph()->start(); + Node* control = graph()->start(); + Node* value = effect = + graph()->NewNode(simplified()->CheckSmi(), param0, effect, control); + Reduction reduction = Reduce( + graph()->NewNode(simplified()->CheckSmi(), value, effect, control)); ASSERT_TRUE(reduction.Changed()); EXPECT_EQ(value, reduction.replacement()); } diff --git a/deps/v8/test/unittests/compiler/simplified-operator-unittest.cc b/deps/v8/test/unittests/compiler/simplified-operator-unittest.cc index febd76a528..d32dcaec12 100644 --- a/deps/v8/test/unittests/compiler/simplified-operator-unittest.cc +++ b/deps/v8/test/unittests/compiler/simplified-operator-unittest.cc @@ -2,11 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "src/compiler/simplified-operator.h" #include "src/compiler/opcodes.h" -#include "src/compiler/operator.h" #include "src/compiler/operator-properties.h" -#include "src/compiler/simplified-operator.h" -#include "src/types.h" +#include "src/compiler/operator.h" +#include "src/compiler/types.h" #include "test/unittests/test-utils.h" namespace v8 { @@ -63,6 +63,8 @@ const PureOperator kPureOperators[] = { PURE(ChangeTaggedToBit, Operator::kNoProperties, 1), PURE(ChangeBitToTagged, Operator::kNoProperties, 1), PURE(TruncateTaggedToWord32, Operator::kNoProperties, 1), + PURE(TruncateTaggedToFloat64, Operator::kNoProperties, 1), + PURE(TruncateTaggedToBit, Operator::kNoProperties, 1), PURE(ObjectIsNumber, Operator::kNoProperties, 1), PURE(ObjectIsReceiver, Operator::kNoProperties, 1), PURE(ObjectIsSmi, Operator::kNoProperties, 1) diff --git a/deps/v8/test/unittests/compiler/typed-optimization-unittest.cc b/deps/v8/test/unittests/compiler/typed-optimization-unittest.cc new file mode 100644 index 0000000000..d73c72d4e0 --- /dev/null +++ b/deps/v8/test/unittests/compiler/typed-optimization-unittest.cc @@ -0,0 +1,226 @@ +// Copyright 2016 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "src/compiler/typed-optimization.h" +#include "src/code-factory.h" +#include "src/compilation-dependencies.h" +#include "src/compiler/access-builder.h" +#include "src/compiler/js-graph.h" +#include "src/compiler/js-operator.h" +#include "src/compiler/machine-operator.h" +#include "src/compiler/node-properties.h" +#include "src/compiler/operator-properties.h" +#include "src/isolate-inl.h" +#include "test/unittests/compiler/compiler-test-utils.h" +#include "test/unittests/compiler/graph-unittest.h" +#include "test/unittests/compiler/node-test-utils.h" +#include "testing/gmock-support.h" + +using testing::IsNaN; + +namespace v8 { +namespace internal { +namespace compiler { + +namespace { + +const double kFloat64Values[] = { + -V8_INFINITY, -4.23878e+275, -5.82632e+265, -6.60355e+220, + -6.26172e+212, -2.56222e+211, -4.82408e+201, -1.84106e+157, + -1.63662e+127, -1.55772e+100, -1.67813e+72, -2.3382e+55, + -3.179e+30, -1.441e+09, -1.0647e+09, -7.99361e+08, + -5.77375e+08, -2.20984e+08, -32757, -13171, + -9970, -3984, -107, -105, + -92, -77, -61, -0.000208163, + -1.86685e-06, -1.17296e-10, -9.26358e-11, -5.08004e-60, + -1.74753e-65, -1.06561e-71, -5.67879e-79, -5.78459e-130, + -2.90989e-171, -7.15489e-243, -3.76242e-252, -1.05639e-263, + -4.40497e-267, -2.19666e-273, -4.9998e-276, -5.59821e-278, + -2.03855e-282, -5.99335e-283, -7.17554e-284, -3.11744e-309, + -0.0, 0.0, 2.22507e-308, 1.30127e-270, + 7.62898e-260, 4.00313e-249, 3.16829e-233, 1.85244e-228, + 2.03544e-129, 1.35126e-110, 1.01182e-106, 5.26333e-94, + 1.35292e-90, 2.85394e-83, 1.78323e-77, 5.4967e-57, + 1.03207e-25, 4.57401e-25, 1.58738e-05, 2, + 125, 2310, 9636, 14802, + 17168, 28945, 29305, 4.81336e+07, + 1.41207e+08, 4.65962e+08, 1.40499e+09, 2.12648e+09, + 8.80006e+30, 1.4446e+45, 1.12164e+54, 2.48188e+89, + 6.71121e+102, 3.074e+112, 4.9699e+152, 5.58383e+166, + 4.30654e+172, 7.08824e+185, 9.6586e+214, 2.028e+223, + 6.63277e+243, 1.56192e+261, 1.23202e+269, 5.72883e+289, + 8.5798e+290, 1.40256e+294, 1.79769e+308, V8_INFINITY}; + +const double kIntegerValues[] = {-V8_INFINITY, INT_MIN, -1000.0, -42.0, + -1.0, 0.0, 1.0, 42.0, + 1000.0, INT_MAX, UINT_MAX, V8_INFINITY}; + +} // namespace + +class TypedOptimizationTest : public TypedGraphTest { + public: + TypedOptimizationTest() + : TypedGraphTest(3), javascript_(zone()), deps_(isolate(), zone()) {} + ~TypedOptimizationTest() override {} + + protected: + Reduction Reduce(Node* node) { + MachineOperatorBuilder machine(zone()); + SimplifiedOperatorBuilder simplified(zone()); + JSGraph jsgraph(isolate(), graph(), common(), javascript(), &simplified, + &machine); + // TODO(titzer): mock the GraphReducer here for better unit testing. + GraphReducer graph_reducer(zone(), graph()); + TypedOptimization reducer(&graph_reducer, &deps_, + TypedOptimization::kDeoptimizationEnabled, + &jsgraph); + return reducer.Reduce(node); + } + + JSOperatorBuilder* javascript() { return &javascript_; } + + private: + JSOperatorBuilder javascript_; + CompilationDependencies deps_; +}; + +TEST_F(TypedOptimizationTest, ParameterWithMinusZero) { + { + Reduction r = Reduce( + Parameter(Type::Constant(factory()->minus_zero_value(), zone()))); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsNumberConstant(-0.0)); + } + { + Reduction r = Reduce(Parameter(Type::MinusZero())); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsNumberConstant(-0.0)); + } + { + Reduction r = Reduce(Parameter( + Type::Union(Type::MinusZero(), + Type::Constant(factory()->NewNumber(0), zone()), zone()))); + EXPECT_FALSE(r.Changed()); + } +} + +TEST_F(TypedOptimizationTest, ParameterWithNull) { + Handle<HeapObject> null = factory()->null_value(); + { + Reduction r = Reduce(Parameter(Type::Constant(null, zone()))); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsHeapConstant(null)); + } + { + Reduction r = Reduce(Parameter(Type::Null())); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsHeapConstant(null)); + } +} + +TEST_F(TypedOptimizationTest, ParameterWithNaN) { + const double kNaNs[] = {-std::numeric_limits<double>::quiet_NaN(), + std::numeric_limits<double>::quiet_NaN(), + std::numeric_limits<double>::signaling_NaN()}; + TRACED_FOREACH(double, nan, kNaNs) { + Handle<Object> constant = factory()->NewNumber(nan); + Reduction r = Reduce(Parameter(Type::Constant(constant, zone()))); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsNumberConstant(IsNaN())); + } + { + Reduction r = + Reduce(Parameter(Type::Constant(factory()->nan_value(), zone()))); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsNumberConstant(IsNaN())); + } + { + Reduction r = Reduce(Parameter(Type::NaN())); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsNumberConstant(IsNaN())); + } +} + +TEST_F(TypedOptimizationTest, ParameterWithPlainNumber) { + TRACED_FOREACH(double, value, kFloat64Values) { + Handle<Object> constant = factory()->NewNumber(value); + Reduction r = Reduce(Parameter(Type::Constant(constant, zone()))); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsNumberConstant(value)); + } + TRACED_FOREACH(double, value, kIntegerValues) { + Reduction r = Reduce(Parameter(Type::Range(value, value, zone()))); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsNumberConstant(value)); + } +} + +TEST_F(TypedOptimizationTest, ParameterWithUndefined) { + Handle<HeapObject> undefined = factory()->undefined_value(); + { + Reduction r = Reduce(Parameter(Type::Undefined())); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsHeapConstant(undefined)); + } + { + Reduction r = Reduce(Parameter(Type::Constant(undefined, zone()))); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsHeapConstant(undefined)); + } +} + +TEST_F(TypedOptimizationTest, JSToBooleanWithFalsish) { + Node* input = Parameter( + Type::Union( + Type::MinusZero(), + Type::Union( + Type::NaN(), + Type::Union( + Type::Null(), + Type::Union( + Type::Undefined(), + Type::Union( + Type::Undetectable(), + Type::Union( + Type::Constant(factory()->false_value(), zone()), + Type::Range(0.0, 0.0, zone()), zone()), + zone()), + zone()), + zone()), + zone()), + zone()), + 0); + Node* context = Parameter(Type::Any(), 1); + Reduction r = Reduce(graph()->NewNode( + javascript()->ToBoolean(ToBooleanHint::kAny), input, context)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsFalseConstant()); +} + +TEST_F(TypedOptimizationTest, JSToBooleanWithTruish) { + Node* input = Parameter( + Type::Union( + Type::Constant(factory()->true_value(), zone()), + Type::Union(Type::DetectableReceiver(), Type::Symbol(), zone()), + zone()), + 0); + Node* context = Parameter(Type::Any(), 1); + Reduction r = Reduce(graph()->NewNode( + javascript()->ToBoolean(ToBooleanHint::kAny), input, context)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsTrueConstant()); +} + +TEST_F(TypedOptimizationTest, JSToBooleanWithNonZeroPlainNumber) { + Node* input = Parameter(Type::Range(1, V8_INFINITY, zone()), 0); + Node* context = Parameter(Type::Any(), 1); + Reduction r = Reduce(graph()->NewNode( + javascript()->ToBoolean(ToBooleanHint::kAny), input, context)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsTrueConstant()); +} + +} // namespace compiler +} // namespace internal +} // namespace v8 diff --git a/deps/v8/test/unittests/compiler/zone-pool-unittest.cc b/deps/v8/test/unittests/compiler/zone-pool-unittest.cc index 47f1cc5c75..5bbdbfd45d 100644 --- a/deps/v8/test/unittests/compiler/zone-pool-unittest.cc +++ b/deps/v8/test/unittests/compiler/zone-pool-unittest.cc @@ -38,7 +38,7 @@ class ZonePoolTest : public TestWithIsolate { } private: - base::AccountingAllocator allocator_; + v8::internal::AccountingAllocator allocator_; ZonePool zone_pool_; base::RandomNumberGenerator rng; }; |