return vs;
case kNotOverflow:
return vc;
- case kUnorderedEqual:
- case kUnorderedNotEqual:
+ default:
break;
}
UNREACHABLE();
return ls;
case kUnsignedGreaterThan:
return hi;
+ case kFloatLessThanOrUnordered:
+ return lt;
+ case kFloatGreaterThanOrEqual:
+ return ge;
+ case kFloatLessThanOrEqual:
+ return ls;
+ case kFloatGreaterThanOrUnordered:
+ return hi;
+ case kFloatLessThan:
+ return lo;
+ case kFloatGreaterThanOrEqualOrUnordered:
+ return hs;
+ case kFloatLessThanOrEqualOrUnordered:
+ return le;
+ case kFloatGreaterThan:
+ return gt;
case kOverflow:
return vs;
case kNotOverflow:
}
-// Shared routine for multiple float64 compare operations.
+// Shared routine for multiple float32 compare operations.
void VisitFloat32Compare(InstructionSelector* selector, Node* node,
FlagsContinuation* cont) {
Arm64OperandGenerator g(selector);
if (m.right().Is(0.0f)) {
VisitCompare(selector, kArm64Float32Cmp, g.UseRegister(m.left().node()),
g.UseImmediate(m.right().node()), cont);
+ } else if (m.left().Is(0.0f)) {
+ cont->Commute();
+ VisitCompare(selector, kArm64Float32Cmp, g.UseRegister(m.right().node()),
+ g.UseImmediate(m.left().node()), cont);
} else {
VisitCompare(selector, kArm64Float32Cmp, g.UseRegister(m.left().node()),
g.UseRegister(m.right().node()), cont);
if (m.right().Is(0.0)) {
VisitCompare(selector, kArm64Float64Cmp, g.UseRegister(m.left().node()),
g.UseImmediate(m.right().node()), cont);
+ } else if (m.left().Is(0.0)) {
+ cont->Commute();
+ VisitCompare(selector, kArm64Float64Cmp, g.UseRegister(m.right().node()),
+ g.UseImmediate(m.left().node()), cont);
} else {
VisitCompare(selector, kArm64Float64Cmp, g.UseRegister(m.left().node()),
g.UseRegister(m.right().node()), cont);
cont.OverwriteAndNegateIfEqual(kEqual);
return VisitFloat32Compare(this, value, &cont);
case IrOpcode::kFloat32LessThan:
- cont.OverwriteAndNegateIfEqual(kUnsignedLessThan);
+ cont.OverwriteAndNegateIfEqual(kFloatLessThan);
return VisitFloat32Compare(this, value, &cont);
case IrOpcode::kFloat32LessThanOrEqual:
- cont.OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
+ cont.OverwriteAndNegateIfEqual(kFloatLessThanOrEqual);
return VisitFloat32Compare(this, value, &cont);
case IrOpcode::kFloat64Equal:
cont.OverwriteAndNegateIfEqual(kEqual);
return VisitFloat64Compare(this, value, &cont);
case IrOpcode::kFloat64LessThan:
- cont.OverwriteAndNegateIfEqual(kUnsignedLessThan);
+ cont.OverwriteAndNegateIfEqual(kFloatLessThan);
return VisitFloat64Compare(this, value, &cont);
case IrOpcode::kFloat64LessThanOrEqual:
- cont.OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
+ cont.OverwriteAndNegateIfEqual(kFloatLessThanOrEqual);
return VisitFloat64Compare(this, value, &cont);
case IrOpcode::kProjection:
// Check if this is the overflow output projection of an
void InstructionSelector::VisitFloat32LessThan(Node* node) {
- FlagsContinuation cont(kUnsignedLessThan, node);
+ FlagsContinuation cont(kFloatLessThan, node);
VisitFloat32Compare(this, node, &cont);
}
void InstructionSelector::VisitFloat32LessThanOrEqual(Node* node) {
- FlagsContinuation cont(kUnsignedLessThanOrEqual, node);
+ FlagsContinuation cont(kFloatLessThanOrEqual, node);
VisitFloat32Compare(this, node, &cont);
}
void InstructionSelector::VisitFloat64LessThan(Node* node) {
- FlagsContinuation cont(kUnsignedLessThan, node);
+ FlagsContinuation cont(kFloatLessThan, node);
VisitFloat64Compare(this, node, &cont);
}
void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
- FlagsContinuation cont(kUnsignedLessThanOrEqual, node);
+ FlagsContinuation cont(kFloatLessThanOrEqual, node);
VisitFloat64Compare(this, node, &cont);
}
case kNotOverflow:
__ j(no_overflow, tlabel);
break;
+ default:
+ UNREACHABLE();
+ break;
}
// Add a jump if not falling through to the next block.
if (!branch->fallthru) __ jmp(flabel);
case kNotOverflow:
cc = no_overflow;
break;
+ default:
+ UNREACHABLE();
+ break;
}
__ bind(&check);
if (reg.is_byte_register()) {
kUnsignedGreaterThanOrEqual,
kUnsignedLessThanOrEqual,
kUnsignedGreaterThan,
+ kFloatLessThanOrUnordered,
+ kFloatGreaterThanOrEqual,
+ kFloatLessThanOrEqual,
+ kFloatGreaterThanOrUnordered,
+ kFloatLessThan,
+ kFloatGreaterThanOrEqualOrUnordered,
+ kFloatLessThanOrEqualOrUnordered,
+ kFloatGreaterThan,
kUnorderedEqual,
kUnorderedNotEqual,
kOverflow,
return static_cast<FlagsCondition>(condition ^ 1);
}
+FlagsCondition CommuteFlagsCondition(FlagsCondition condition);
+
std::ostream& operator<<(std::ostream& os, const FlagsCondition& fc);
// The InstructionCode is an opaque, target-specific integer that encodes
typedef BitField<ArchOpcode, 0, 8> ArchOpcodeField;
typedef BitField<AddressingMode, 8, 5> AddressingModeField;
typedef BitField<FlagsMode, 13, 2> FlagsModeField;
-typedef BitField<FlagsCondition, 15, 4> FlagsConditionField;
-typedef BitField<int, 19, 13> MiscField;
+typedef BitField<FlagsCondition, 15, 5> FlagsConditionField;
+typedef BitField<int, 20, 12> MiscField;
} // namespace compiler
} // namespace internal
void Commute() {
DCHECK(!IsNone());
- switch (condition_) {
- case kEqual:
- case kNotEqual:
- case kOverflow:
- case kNotOverflow:
- return;
- case kSignedLessThan:
- condition_ = kSignedGreaterThan;
- return;
- case kSignedGreaterThanOrEqual:
- condition_ = kSignedLessThanOrEqual;
- return;
- case kSignedLessThanOrEqual:
- condition_ = kSignedGreaterThanOrEqual;
- return;
- case kSignedGreaterThan:
- condition_ = kSignedLessThan;
- return;
- case kUnsignedLessThan:
- condition_ = kUnsignedGreaterThan;
- return;
- case kUnsignedGreaterThanOrEqual:
- condition_ = kUnsignedLessThanOrEqual;
- return;
- case kUnsignedLessThanOrEqual:
- condition_ = kUnsignedGreaterThanOrEqual;
- return;
- case kUnsignedGreaterThan:
- condition_ = kUnsignedLessThan;
- return;
- case kUnorderedEqual:
- case kUnorderedNotEqual:
- return;
- }
- UNREACHABLE();
+ condition_ = CommuteFlagsCondition(condition_);
}
void OverwriteAndNegateIfEqual(FlagsCondition condition) {
namespace internal {
namespace compiler {
+
+FlagsCondition CommuteFlagsCondition(FlagsCondition condition) {
+ switch (condition) {
+ case kSignedLessThan:
+ return kSignedGreaterThan;
+ case kSignedGreaterThanOrEqual:
+ return kSignedLessThanOrEqual;
+ case kSignedLessThanOrEqual:
+ return kSignedGreaterThanOrEqual;
+ case kSignedGreaterThan:
+ return kSignedLessThan;
+ case kUnsignedLessThan:
+ return kUnsignedGreaterThan;
+ case kUnsignedGreaterThanOrEqual:
+ return kUnsignedLessThanOrEqual;
+ case kUnsignedLessThanOrEqual:
+ return kUnsignedGreaterThanOrEqual;
+ case kUnsignedGreaterThan:
+ return kUnsignedLessThan;
+ case kFloatLessThanOrUnordered:
+ return kFloatGreaterThanOrUnordered;
+ case kFloatGreaterThanOrEqual:
+ return kFloatLessThanOrEqual;
+ case kFloatLessThanOrEqual:
+ return kFloatGreaterThanOrEqual;
+ case kFloatGreaterThanOrUnordered:
+ return kFloatLessThanOrUnordered;
+ case kFloatLessThan:
+ return kFloatGreaterThan;
+ case kFloatGreaterThanOrEqualOrUnordered:
+ return kFloatLessThanOrEqualOrUnordered;
+ case kFloatLessThanOrEqualOrUnordered:
+ return kFloatGreaterThanOrEqualOrUnordered;
+ case kFloatGreaterThan:
+ return kFloatLessThan;
+ case kEqual:
+ case kNotEqual:
+ case kOverflow:
+ case kNotOverflow:
+ case kUnorderedEqual:
+ case kUnorderedNotEqual:
+ return condition;
+ }
+ UNREACHABLE();
+ return condition;
+}
+
+
std::ostream& operator<<(std::ostream& os,
const PrintableInstructionOperand& printable) {
const InstructionOperand& op = printable.op_;
return os << "unsigned less than or equal";
case kUnsignedGreaterThan:
return os << "unsigned greater than";
+ case kFloatLessThanOrUnordered:
+ return os << "less than or unordered (FP)";
+ case kFloatGreaterThanOrEqual:
+ return os << "greater than or equal (FP)";
+ case kFloatLessThanOrEqual:
+ return os << "less than or equal (FP)";
+ case kFloatGreaterThanOrUnordered:
+ return os << "greater than or unordered (FP)";
+ case kFloatLessThan:
+ return os << "less than (FP)";
+ case kFloatGreaterThanOrEqualOrUnordered:
+ return os << "greater than, equal or unordered (FP)";
+ case kFloatLessThanOrEqualOrUnordered:
+ return os << "less than, equal or unordered (FP)";
+ case kFloatGreaterThan:
+ return os << "greater than (FP)";
case kUnorderedEqual:
return os << "unordered equal";
case kUnorderedNotEqual:
#else
return ge;
#endif
- case kUnorderedEqual:
- case kUnorderedNotEqual:
+ default:
break;
}
UNREACHABLE();
case kNotOverflow:
__ j(no_overflow, tlabel);
break;
+ default:
+ UNREACHABLE();
+ break;
}
if (!branch->fallthru) __ jmp(flabel, flabel_distance);
}
case kNotOverflow:
cc = no_overflow;
break;
+ default:
+ UNREACHABLE();
+ break;
}
__ bind(&check);
__ setcc(cc, reg);
case kNotOverflow:
__ j(no_overflow, tlabel);
break;
+ default:
+ UNREACHABLE();
+ break;
}
// Add a jump if not falling through to the next block.
if (!branch->fallthru) __ jmp(flabel);
case kNotOverflow:
cc = no_overflow;
break;
+ default:
+ UNREACHABLE();
+ break;
}
__ bind(&check);
if (reg.is_byte_register()) {
kEqual},
{{&RawMachineAssembler::Float64LessThan, "Float64LessThan",
kArm64Float64Cmp, kMachFloat64},
- kUnsignedLessThan},
+ kFloatLessThan},
{{&RawMachineAssembler::Float64LessThanOrEqual, "Float64LessThanOrEqual",
kArm64Float64Cmp, kMachFloat64},
- kUnsignedLessThanOrEqual}};
+ kFloatLessThanOrEqual},
+ {{&RawMachineAssembler::Float32Equal, "Float32Equal", kArm64Float32Cmp,
+ kMachFloat32},
+ kEqual},
+ {{&RawMachineAssembler::Float32LessThan, "Float32LessThan",
+ kArm64Float32Cmp, kMachFloat32},
+ kFloatLessThan},
+ {{&RawMachineAssembler::Float32LessThanOrEqual, "Float32LessThanOrEqual",
+ kArm64Float32Cmp, kMachFloat32},
+ kFloatLessThanOrEqual}};
struct Conversion {
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)));
+ if (cmp.mi.machine_type == kMachFloat64) {
+ m.Return((m.*cmp.mi.constructor)(m.Parameter(0), m.Float64Constant(0.0)));
+ } else {
+ m.Return((m.*cmp.mi.constructor)(m.Parameter(0), m.Float32Constant(0.0f)));
+ }
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(cmp.mi.arch_opcode, s[0]->arch_opcode());
}
-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)));
+TEST_P(InstructionSelectorFPCmpTest, WithImmediateZeroOnLeft) {
+ const FPCmp cmp = GetParam();
+ StreamBuilder m(this, kMachInt32, cmp.mi.machine_type);
+ if (cmp.mi.machine_type == kMachFloat64) {
+ m.Return((m.*cmp.mi.constructor)(m.Float64Constant(0.0), m.Parameter(0)));
+ } else {
+ m.Return((m.*cmp.mi.constructor)(m.Float32Constant(0.0f), m.Parameter(0)));
+ }
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kArm64Float64Cmp, s[0]->arch_opcode());
+ 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(kEqual, s[0]->flags_condition());
+ EXPECT_EQ(CommuteFlagsCondition(cmp.cond), s[0]->flags_condition());
}
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorFPCmpTest,
+ ::testing::ValuesIn(kFPCmpInstructions));
+
+
// -----------------------------------------------------------------------------
// Conversions.