DCHECK_EQ(SetCC, i.OutputSBit());
break;
case kArmVcmpF64:
- __ VFPCompareAndSetFlags(i.InputFloat64Register(0),
- i.InputFloat64Register(1));
+ if (instr->InputAt(1)->IsDoubleRegister()) {
+ __ VFPCompareAndSetFlags(i.InputFloat64Register(0),
+ i.InputFloat64Register(1));
+ } else {
+ DCHECK(instr->InputAt(1)->IsImmediate());
+ // 0.0 is the only immediate supported by vcmp instructions.
+ DCHECK(i.InputDouble(1) == 0.0);
+ __ VFPCompareAndSetFlags(i.InputFloat64Register(0), i.InputDouble(1));
+ }
DCHECK_EQ(SetCC, i.OutputSBit());
break;
case kArmVaddF64:
FlagsContinuation* cont) {
ArmOperandGenerator g(selector);
Float64BinopMatcher m(node);
+ InstructionOperand* rhs = m.right().Is(0.0) ? g.UseImmediate(m.right().node())
+ : g.UseRegister(m.right().node());
if (cont->IsBranch()) {
selector->Emit(cont->Encode(kArmVcmpF64), nullptr,
- g.UseRegister(m.left().node()),
- g.UseRegister(m.right().node()), g.Label(cont->true_block()),
+ g.UseRegister(m.left().node()), rhs,
+ g.Label(cont->true_block()),
g.Label(cont->false_block()))->MarkAsControl();
} else {
DCHECK(cont->IsSet());
- selector->Emit(
- cont->Encode(kArmVcmpF64), g.DefineAsRegister(cont->result()),
- g.UseRegister(m.left().node()), g.UseRegister(m.right().node()));
+ selector->Emit(cont->Encode(kArmVcmpF64),
+ g.DefineAsRegister(cont->result()),
+ g.UseRegister(m.left().node()), rhs);
}
}
__ Tst(i.InputRegister32(0), i.InputOperand32(1));
break;
case kArm64Float64Cmp:
- __ Fcmp(i.InputDoubleRegister(0), i.InputDoubleRegister(1));
+ if (instr->InputAt(1)->IsDoubleRegister()) {
+ __ Fcmp(i.InputDoubleRegister(0), i.InputDoubleRegister(1));
+ } else {
+ DCHECK(instr->InputAt(1)->IsImmediate());
+ // 0.0 is the only immediate supported by fcmp instructions.
+ DCHECK(i.InputDouble(1) == 0.0);
+ __ Fcmp(i.InputDoubleRegister(0), i.InputDouble(1));
+ }
break;
case kArm64Float64Add:
__ Fadd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
static void VisitFloat64Compare(InstructionSelector* selector, Node* node,
FlagsContinuation* cont) {
Arm64OperandGenerator g(selector);
- Node* left = node->InputAt(0);
- Node* right = node->InputAt(1);
- VisitCompare(selector, kArm64Float64Cmp, g.UseRegister(left),
- g.UseRegister(right), cont);
+ Float64BinopMatcher m(node);
+ if (m.right().Is(0.0)) {
+ VisitCompare(selector, kArm64Float64Cmp, g.UseRegister(m.left().node()),
+ g.UseImmediate(m.right().node()), cont);
+ } else {
+ VisitCompare(selector, kArm64Float64Cmp, g.UseRegister(m.left().node()),
+ g.UseRegister(m.right().node()), cont);
+ }
}
// -----------------------------------------------------------------------------
+// Floating point comparisons.
+
+
+const Comparison kFPComparisons[] = {
+ {&RawMachineAssembler::Float64Equal, "Float64Equal", kEqual, kNotEqual},
+ {&RawMachineAssembler::Float64LessThan, "Float64LessThan",
+ kUnsignedLessThan, kUnsignedGreaterThanOrEqual},
+ {&RawMachineAssembler::Float64LessThanOrEqual, "Float64LessThanOrEqual",
+ kUnsignedLessThanOrEqual, kUnsignedGreaterThan}};
+
+
+typedef InstructionSelectorTestWithParam<Comparison>
+ InstructionSelectorFPComparisonTest;
+
+
+TEST_P(InstructionSelectorFPComparisonTest, WithParameters) {
+ const Comparison& cmp = GetParam();
+ StreamBuilder m(this, kMachInt32, kMachFloat64, kMachFloat64);
+ m.Return((m.*cmp.constructor)(m.Parameter(0), m.Parameter(1)));
+ Stream const s = m.Build();
+ ASSERT_EQ(1U, s.size());
+ EXPECT_EQ(kArmVcmpF64, s[0]->arch_opcode());
+ ASSERT_EQ(2U, s[0]->InputCount());
+ ASSERT_EQ(1U, s[0]->OutputCount());
+ EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+ EXPECT_EQ(cmp.flags_condition, s[0]->flags_condition());
+}
+
+
+TEST_P(InstructionSelectorFPComparisonTest, NegatedWithParameters) {
+ const Comparison& cmp = GetParam();
+ StreamBuilder m(this, kMachInt32, kMachFloat64, kMachFloat64);
+ m.Return(
+ m.WordBinaryNot((m.*cmp.constructor)(m.Parameter(0), m.Parameter(1))));
+ Stream const s = m.Build();
+ ASSERT_EQ(1U, s.size());
+ EXPECT_EQ(kArmVcmpF64, s[0]->arch_opcode());
+ ASSERT_EQ(2U, s[0]->InputCount());
+ ASSERT_EQ(1U, s[0]->OutputCount());
+ EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+ EXPECT_EQ(cmp.negated_flags_condition, s[0]->flags_condition());
+}
+
+
+TEST_P(InstructionSelectorFPComparisonTest, WithImmediateZeroOnRight) {
+ const Comparison& cmp = GetParam();
+ StreamBuilder m(this, kMachInt32, kMachFloat64);
+ m.Return((m.*cmp.constructor)(m.Parameter(0), m.Float64Constant(0.0)));
+ Stream const s = m.Build();
+ ASSERT_EQ(1U, s.size());
+ EXPECT_EQ(kArmVcmpF64, s[0]->arch_opcode());
+ ASSERT_EQ(2U, s[0]->InputCount());
+ EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
+ ASSERT_EQ(1U, s[0]->OutputCount());
+ EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+ EXPECT_EQ(cmp.flags_condition, s[0]->flags_condition());
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+ InstructionSelectorFPComparisonTest,
+ ::testing::ValuesIn(kFPComparisons));
+
+
+TEST_F(InstructionSelectorTest, Float64EqualWithImmediateZeroOnLeft) {
+ StreamBuilder m(this, kMachInt32, kMachFloat64);
+ m.Return(m.Float64Equal(m.Float64Constant(0.0), m.Parameter(0)));
+ Stream s = m.Build();
+ ASSERT_EQ(1U, s.size());
+ EXPECT_EQ(kArmVcmpF64, s[0]->arch_opcode());
+ EXPECT_EQ(2U, s[0]->InputCount());
+ EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
+ EXPECT_EQ(1U, s[0]->OutputCount());
+ EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+ EXPECT_EQ(kEqual, s[0]->flags_condition());
+}
+
+
+// -----------------------------------------------------------------------------
// Miscellaneous.
}
+TEST_P(InstructionSelectorFPCmpTest, WithImmediateZeroOnRight) {
+ const FPCmp cmp = GetParam();
+ StreamBuilder m(this, kMachInt32, cmp.mi.machine_type);
+ m.Return((m.*cmp.mi.constructor)(m.Parameter(0), m.Float64Constant(0.0)));
+ Stream s = m.Build();
+ ASSERT_EQ(1U, s.size());
+ EXPECT_EQ(cmp.mi.arch_opcode, s[0]->arch_opcode());
+ EXPECT_EQ(2U, s[0]->InputCount());
+ EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
+ EXPECT_EQ(1U, s[0]->OutputCount());
+ EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+ EXPECT_EQ(cmp.cond, s[0]->flags_condition());
+}
+
+
INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorFPCmpTest,
::testing::ValuesIn(kFPCmpInstructions));
+TEST_F(InstructionSelectorTest, Float64EqualWithImmediateZeroOnLeft) {
+ StreamBuilder m(this, kMachInt32, kMachFloat64);
+ m.Return(m.Float64Equal(m.Float64Constant(0.0), m.Parameter(0)));
+ Stream s = m.Build();
+ ASSERT_EQ(1U, s.size());
+ EXPECT_EQ(kArm64Float64Cmp, s[0]->arch_opcode());
+ EXPECT_EQ(2U, s[0]->InputCount());
+ EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
+ EXPECT_EQ(1U, s[0]->OutputCount());
+ EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+ EXPECT_EQ(kEqual, s[0]->flags_condition());
+}
+
+
// -----------------------------------------------------------------------------
// Conversions.