Commit e28ae8ca authored by pierre.langlois's avatar pierre.langlois Committed by Commit bot

[arm64] Optimize fcmp when lhs operand is #0.0

This patch checks the type of the lhs operand of a floating point
comparison, and commutes the operands if it is #0.0.  It allows us to
optimize a comparison with zero, as the fcmp instruction accepts #0.0 as
rhs operand.

Code before for "0.0 < 0.123":
------------------------------
fmov d1, xzr
ldr d0, pc+96
fcmp d1, d0
b.lo #+0xc

Code after:
-----------
ldr d0, pc+92
fcmp d0, #0.0
b.gt #+0xc

Before this patch, we used unsigned condition codes for floating point
comparisons, but the unordered case was not correctly commuted.

Review URL: https://codereview.chromium.org/1356283003

Cr-Commit-Position: refs/heads/master@{#30881}
parent 205d85af
...@@ -224,8 +224,7 @@ Condition FlagsConditionToCondition(FlagsCondition condition) { ...@@ -224,8 +224,7 @@ Condition FlagsConditionToCondition(FlagsCondition condition) {
return vs; return vs;
case kNotOverflow: case kNotOverflow:
return vc; return vc;
case kUnorderedEqual: default:
case kUnorderedNotEqual:
break; break;
} }
UNREACHABLE(); UNREACHABLE();
......
...@@ -259,6 +259,22 @@ Condition FlagsConditionToCondition(FlagsCondition condition) { ...@@ -259,6 +259,22 @@ Condition FlagsConditionToCondition(FlagsCondition condition) {
return ls; return ls;
case kUnsignedGreaterThan: case kUnsignedGreaterThan:
return hi; 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: case kOverflow:
return vs; return vs;
case kNotOverflow: case kNotOverflow:
......
...@@ -1671,7 +1671,7 @@ void VisitWord64Test(InstructionSelector* selector, Node* node, ...@@ -1671,7 +1671,7 @@ void VisitWord64Test(InstructionSelector* selector, Node* node,
} }
// Shared routine for multiple float64 compare operations. // Shared routine for multiple float32 compare operations.
void VisitFloat32Compare(InstructionSelector* selector, Node* node, void VisitFloat32Compare(InstructionSelector* selector, Node* node,
FlagsContinuation* cont) { FlagsContinuation* cont) {
Arm64OperandGenerator g(selector); Arm64OperandGenerator g(selector);
...@@ -1679,6 +1679,10 @@ void VisitFloat32Compare(InstructionSelector* selector, Node* node, ...@@ -1679,6 +1679,10 @@ void VisitFloat32Compare(InstructionSelector* selector, Node* node,
if (m.right().Is(0.0f)) { if (m.right().Is(0.0f)) {
VisitCompare(selector, kArm64Float32Cmp, g.UseRegister(m.left().node()), VisitCompare(selector, kArm64Float32Cmp, g.UseRegister(m.left().node()),
g.UseImmediate(m.right().node()), cont); 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 { } else {
VisitCompare(selector, kArm64Float32Cmp, g.UseRegister(m.left().node()), VisitCompare(selector, kArm64Float32Cmp, g.UseRegister(m.left().node()),
g.UseRegister(m.right().node()), cont); g.UseRegister(m.right().node()), cont);
...@@ -1694,6 +1698,10 @@ void VisitFloat64Compare(InstructionSelector* selector, Node* node, ...@@ -1694,6 +1698,10 @@ void VisitFloat64Compare(InstructionSelector* selector, Node* node,
if (m.right().Is(0.0)) { if (m.right().Is(0.0)) {
VisitCompare(selector, kArm64Float64Cmp, g.UseRegister(m.left().node()), VisitCompare(selector, kArm64Float64Cmp, g.UseRegister(m.left().node()),
g.UseImmediate(m.right().node()), cont); 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 { } else {
VisitCompare(selector, kArm64Float64Cmp, g.UseRegister(m.left().node()), VisitCompare(selector, kArm64Float64Cmp, g.UseRegister(m.left().node()),
g.UseRegister(m.right().node()), cont); g.UseRegister(m.right().node()), cont);
...@@ -1765,19 +1773,19 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch, ...@@ -1765,19 +1773,19 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
cont.OverwriteAndNegateIfEqual(kEqual); cont.OverwriteAndNegateIfEqual(kEqual);
return VisitFloat32Compare(this, value, &cont); return VisitFloat32Compare(this, value, &cont);
case IrOpcode::kFloat32LessThan: case IrOpcode::kFloat32LessThan:
cont.OverwriteAndNegateIfEqual(kUnsignedLessThan); cont.OverwriteAndNegateIfEqual(kFloatLessThan);
return VisitFloat32Compare(this, value, &cont); return VisitFloat32Compare(this, value, &cont);
case IrOpcode::kFloat32LessThanOrEqual: case IrOpcode::kFloat32LessThanOrEqual:
cont.OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual); cont.OverwriteAndNegateIfEqual(kFloatLessThanOrEqual);
return VisitFloat32Compare(this, value, &cont); return VisitFloat32Compare(this, value, &cont);
case IrOpcode::kFloat64Equal: case IrOpcode::kFloat64Equal:
cont.OverwriteAndNegateIfEqual(kEqual); cont.OverwriteAndNegateIfEqual(kEqual);
return VisitFloat64Compare(this, value, &cont); return VisitFloat64Compare(this, value, &cont);
case IrOpcode::kFloat64LessThan: case IrOpcode::kFloat64LessThan:
cont.OverwriteAndNegateIfEqual(kUnsignedLessThan); cont.OverwriteAndNegateIfEqual(kFloatLessThan);
return VisitFloat64Compare(this, value, &cont); return VisitFloat64Compare(this, value, &cont);
case IrOpcode::kFloat64LessThanOrEqual: case IrOpcode::kFloat64LessThanOrEqual:
cont.OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual); cont.OverwriteAndNegateIfEqual(kFloatLessThanOrEqual);
return VisitFloat64Compare(this, value, &cont); return VisitFloat64Compare(this, value, &cont);
case IrOpcode::kProjection: case IrOpcode::kProjection:
// Check if this is the overflow output projection of an // Check if this is the overflow output projection of an
...@@ -2018,13 +2026,13 @@ void InstructionSelector::VisitFloat32Equal(Node* node) { ...@@ -2018,13 +2026,13 @@ void InstructionSelector::VisitFloat32Equal(Node* node) {
void InstructionSelector::VisitFloat32LessThan(Node* node) { void InstructionSelector::VisitFloat32LessThan(Node* node) {
FlagsContinuation cont(kUnsignedLessThan, node); FlagsContinuation cont(kFloatLessThan, node);
VisitFloat32Compare(this, node, &cont); VisitFloat32Compare(this, node, &cont);
} }
void InstructionSelector::VisitFloat32LessThanOrEqual(Node* node) { void InstructionSelector::VisitFloat32LessThanOrEqual(Node* node) {
FlagsContinuation cont(kUnsignedLessThanOrEqual, node); FlagsContinuation cont(kFloatLessThanOrEqual, node);
VisitFloat32Compare(this, node, &cont); VisitFloat32Compare(this, node, &cont);
} }
...@@ -2036,13 +2044,13 @@ void InstructionSelector::VisitFloat64Equal(Node* node) { ...@@ -2036,13 +2044,13 @@ void InstructionSelector::VisitFloat64Equal(Node* node) {
void InstructionSelector::VisitFloat64LessThan(Node* node) { void InstructionSelector::VisitFloat64LessThan(Node* node) {
FlagsContinuation cont(kUnsignedLessThan, node); FlagsContinuation cont(kFloatLessThan, node);
VisitFloat64Compare(this, node, &cont); VisitFloat64Compare(this, node, &cont);
} }
void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) { void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
FlagsContinuation cont(kUnsignedLessThanOrEqual, node); FlagsContinuation cont(kFloatLessThanOrEqual, node);
VisitFloat64Compare(this, node, &cont); VisitFloat64Compare(this, node, &cont);
} }
......
...@@ -1026,6 +1026,9 @@ void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) { ...@@ -1026,6 +1026,9 @@ void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
case kNotOverflow: case kNotOverflow:
__ j(no_overflow, tlabel); __ j(no_overflow, tlabel);
break; break;
default:
UNREACHABLE();
break;
} }
// Add a jump if not falling through to the next block. // Add a jump if not falling through to the next block.
if (!branch->fallthru) __ jmp(flabel); if (!branch->fallthru) __ jmp(flabel);
...@@ -1096,6 +1099,9 @@ void CodeGenerator::AssembleArchBoolean(Instruction* instr, ...@@ -1096,6 +1099,9 @@ void CodeGenerator::AssembleArchBoolean(Instruction* instr,
case kNotOverflow: case kNotOverflow:
cc = no_overflow; cc = no_overflow;
break; break;
default:
UNREACHABLE();
break;
} }
__ bind(&check); __ bind(&check);
if (reg.is_byte_register()) { if (reg.is_byte_register()) {
......
...@@ -114,6 +114,14 @@ enum FlagsCondition { ...@@ -114,6 +114,14 @@ enum FlagsCondition {
kUnsignedGreaterThanOrEqual, kUnsignedGreaterThanOrEqual,
kUnsignedLessThanOrEqual, kUnsignedLessThanOrEqual,
kUnsignedGreaterThan, kUnsignedGreaterThan,
kFloatLessThanOrUnordered,
kFloatGreaterThanOrEqual,
kFloatLessThanOrEqual,
kFloatGreaterThanOrUnordered,
kFloatLessThan,
kFloatGreaterThanOrEqualOrUnordered,
kFloatLessThanOrEqualOrUnordered,
kFloatGreaterThan,
kUnorderedEqual, kUnorderedEqual,
kUnorderedNotEqual, kUnorderedNotEqual,
kOverflow, kOverflow,
...@@ -124,6 +132,8 @@ inline FlagsCondition NegateFlagsCondition(FlagsCondition condition) { ...@@ -124,6 +132,8 @@ inline FlagsCondition NegateFlagsCondition(FlagsCondition condition) {
return static_cast<FlagsCondition>(condition ^ 1); return static_cast<FlagsCondition>(condition ^ 1);
} }
FlagsCondition CommuteFlagsCondition(FlagsCondition condition);
std::ostream& operator<<(std::ostream& os, const FlagsCondition& fc); std::ostream& operator<<(std::ostream& os, const FlagsCondition& fc);
// The InstructionCode is an opaque, target-specific integer that encodes // The InstructionCode is an opaque, target-specific integer that encodes
...@@ -139,8 +149,8 @@ typedef int32_t InstructionCode; ...@@ -139,8 +149,8 @@ typedef int32_t InstructionCode;
typedef BitField<ArchOpcode, 0, 8> ArchOpcodeField; typedef BitField<ArchOpcode, 0, 8> ArchOpcodeField;
typedef BitField<AddressingMode, 8, 5> AddressingModeField; typedef BitField<AddressingMode, 8, 5> AddressingModeField;
typedef BitField<FlagsMode, 13, 2> FlagsModeField; typedef BitField<FlagsMode, 13, 2> FlagsModeField;
typedef BitField<FlagsCondition, 15, 4> FlagsConditionField; typedef BitField<FlagsCondition, 15, 5> FlagsConditionField;
typedef BitField<int, 19, 13> MiscField; typedef BitField<int, 20, 12> MiscField;
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
......
...@@ -291,41 +291,7 @@ class FlagsContinuation final { ...@@ -291,41 +291,7 @@ class FlagsContinuation final {
void Commute() { void Commute() {
DCHECK(!IsNone()); DCHECK(!IsNone());
switch (condition_) { condition_ = CommuteFlagsCondition(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();
} }
void OverwriteAndNegateIfEqual(FlagsCondition condition) { void OverwriteAndNegateIfEqual(FlagsCondition condition) {
......
...@@ -11,6 +11,54 @@ namespace v8 { ...@@ -11,6 +11,54 @@ namespace v8 {
namespace internal { namespace internal {
namespace compiler { 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, std::ostream& operator<<(std::ostream& os,
const PrintableInstructionOperand& printable) { const PrintableInstructionOperand& printable) {
const InstructionOperand& op = printable.op_; const InstructionOperand& op = printable.op_;
...@@ -300,6 +348,22 @@ std::ostream& operator<<(std::ostream& os, const FlagsCondition& fc) { ...@@ -300,6 +348,22 @@ std::ostream& operator<<(std::ostream& os, const FlagsCondition& fc) {
return os << "unsigned less than or equal"; return os << "unsigned less than or equal";
case kUnsignedGreaterThan: case kUnsignedGreaterThan:
return os << "unsigned greater than"; 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: case kUnorderedEqual:
return os << "unordered equal"; return os << "unordered equal";
case kUnorderedNotEqual: case kUnorderedNotEqual:
......
...@@ -187,8 +187,7 @@ Condition FlagsConditionToCondition(FlagsCondition condition) { ...@@ -187,8 +187,7 @@ Condition FlagsConditionToCondition(FlagsCondition condition) {
#else #else
return ge; return ge;
#endif #endif
case kUnorderedEqual: default:
case kUnorderedNotEqual:
break; break;
} }
UNREACHABLE(); UNREACHABLE();
......
...@@ -1383,6 +1383,9 @@ void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) { ...@@ -1383,6 +1383,9 @@ void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
case kNotOverflow: case kNotOverflow:
__ j(no_overflow, tlabel); __ j(no_overflow, tlabel);
break; break;
default:
UNREACHABLE();
break;
} }
if (!branch->fallthru) __ jmp(flabel, flabel_distance); if (!branch->fallthru) __ jmp(flabel, flabel_distance);
} }
...@@ -1452,6 +1455,9 @@ void CodeGenerator::AssembleArchBoolean(Instruction* instr, ...@@ -1452,6 +1455,9 @@ void CodeGenerator::AssembleArchBoolean(Instruction* instr,
case kNotOverflow: case kNotOverflow:
cc = no_overflow; cc = no_overflow;
break; break;
default:
UNREACHABLE();
break;
} }
__ bind(&check); __ bind(&check);
__ setcc(cc, reg); __ setcc(cc, reg);
......
...@@ -1282,6 +1282,9 @@ void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) { ...@@ -1282,6 +1282,9 @@ void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
case kNotOverflow: case kNotOverflow:
__ j(no_overflow, tlabel); __ j(no_overflow, tlabel);
break; break;
default:
UNREACHABLE();
break;
} }
// Add a jump if not falling through to the next block. // Add a jump if not falling through to the next block.
if (!branch->fallthru) __ jmp(flabel); if (!branch->fallthru) __ jmp(flabel);
...@@ -1352,6 +1355,9 @@ void CodeGenerator::AssembleArchBoolean(Instruction* instr, ...@@ -1352,6 +1355,9 @@ void CodeGenerator::AssembleArchBoolean(Instruction* instr,
case kNotOverflow: case kNotOverflow:
cc = no_overflow; cc = no_overflow;
break; break;
default:
UNREACHABLE();
break;
} }
__ bind(&check); __ bind(&check);
if (reg.is_byte_register()) { if (reg.is_byte_register()) {
......
...@@ -235,10 +235,19 @@ const FPCmp kFPCmpInstructions[] = { ...@@ -235,10 +235,19 @@ const FPCmp kFPCmpInstructions[] = {
kEqual}, kEqual},
{{&RawMachineAssembler::Float64LessThan, "Float64LessThan", {{&RawMachineAssembler::Float64LessThan, "Float64LessThan",
kArm64Float64Cmp, kMachFloat64}, kArm64Float64Cmp, kMachFloat64},
kUnsignedLessThan}, kFloatLessThan},
{{&RawMachineAssembler::Float64LessThanOrEqual, "Float64LessThanOrEqual", {{&RawMachineAssembler::Float64LessThanOrEqual, "Float64LessThanOrEqual",
kArm64Float64Cmp, kMachFloat64}, kArm64Float64Cmp, kMachFloat64},
kUnsignedLessThanOrEqual}}; kFloatLessThanOrEqual},
{{&RawMachineAssembler::Float32Equal, "Float32Equal", kArm64Float32Cmp,
kMachFloat32},
kEqual},
{{&RawMachineAssembler::Float32LessThan, "Float32LessThan",
kArm64Float32Cmp, kMachFloat32},
kFloatLessThan},
{{&RawMachineAssembler::Float32LessThanOrEqual, "Float32LessThanOrEqual",
kArm64Float32Cmp, kMachFloat32},
kFloatLessThanOrEqual}};
struct Conversion { struct Conversion {
...@@ -1913,7 +1922,11 @@ TEST_P(InstructionSelectorFPCmpTest, Parameter) { ...@@ -1913,7 +1922,11 @@ TEST_P(InstructionSelectorFPCmpTest, Parameter) {
TEST_P(InstructionSelectorFPCmpTest, WithImmediateZeroOnRight) { TEST_P(InstructionSelectorFPCmpTest, WithImmediateZeroOnRight) {
const FPCmp cmp = GetParam(); const FPCmp cmp = GetParam();
StreamBuilder m(this, kMachInt32, cmp.mi.machine_type); 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(); Stream s = m.Build();
ASSERT_EQ(1U, s.size()); ASSERT_EQ(1U, s.size());
EXPECT_EQ(cmp.mi.arch_opcode, s[0]->arch_opcode()); EXPECT_EQ(cmp.mi.arch_opcode, s[0]->arch_opcode());
...@@ -1925,24 +1938,29 @@ TEST_P(InstructionSelectorFPCmpTest, WithImmediateZeroOnRight) { ...@@ -1925,24 +1938,29 @@ TEST_P(InstructionSelectorFPCmpTest, WithImmediateZeroOnRight) {
} }
INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorFPCmpTest, TEST_P(InstructionSelectorFPCmpTest, WithImmediateZeroOnLeft) {
::testing::ValuesIn(kFPCmpInstructions)); const FPCmp cmp = GetParam();
StreamBuilder m(this, kMachInt32, cmp.mi.machine_type);
if (cmp.mi.machine_type == kMachFloat64) {
TEST_F(InstructionSelectorTest, Float64EqualWithImmediateZeroOnLeft) { m.Return((m.*cmp.mi.constructor)(m.Float64Constant(0.0), m.Parameter(0)));
StreamBuilder m(this, kMachInt32, kMachFloat64); } else {
m.Return(m.Float64Equal(m.Float64Constant(0.0), m.Parameter(0))); m.Return((m.*cmp.mi.constructor)(m.Float32Constant(0.0f), m.Parameter(0)));
}
Stream s = m.Build(); Stream s = m.Build();
ASSERT_EQ(1U, s.size()); 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_EQ(2U, s[0]->InputCount());
EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate()); EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
EXPECT_EQ(1U, s[0]->OutputCount()); EXPECT_EQ(1U, s[0]->OutputCount());
EXPECT_EQ(kFlags_set, s[0]->flags_mode()); 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. // Conversions.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment