Fuse long and FP compare & condition on ARM64 in Optimizing.
Bug: 21120453
Change-Id: I701e808600fb5ba9ff4d0f5e19e4ce22b1d34b29
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index a9a95d3..4882981 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -77,10 +77,9 @@
case kCondLE: return le;
case kCondGT: return gt;
case kCondGE: return ge;
- default:
- LOG(FATAL) << "Unknown if condition";
}
- return nv; // Unreachable.
+ LOG(FATAL) << "Unreachable";
+ UNREACHABLE();
}
Location ARM64ReturnLocation(Primitive::Type return_type) {
@@ -1645,6 +1644,11 @@
GenerateClassInitializationCheck(slow_path, InputRegisterAt(check, 0));
}
+static bool IsFloatingPointZeroConstant(HInstruction* instruction) {
+ return (instruction->IsFloatConstant() && (instruction->AsFloatConstant()->GetValue() == 0.0f))
+ || (instruction->IsDoubleConstant() && (instruction->AsDoubleConstant()->GetValue() == 0.0));
+}
+
void LocationsBuilderARM64::VisitCompare(HCompare* compare) {
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
@@ -1659,13 +1663,10 @@
case Primitive::kPrimFloat:
case Primitive::kPrimDouble: {
locations->SetInAt(0, Location::RequiresFpuRegister());
- HInstruction* right = compare->InputAt(1);
- if ((right->IsFloatConstant() && (right->AsFloatConstant()->GetValue() == 0.0f)) ||
- (right->IsDoubleConstant() && (right->AsDoubleConstant()->GetValue() == 0.0))) {
- locations->SetInAt(1, Location::ConstantLocation(right->AsConstant()));
- } else {
- locations->SetInAt(1, Location::RequiresFpuRegister());
- }
+ locations->SetInAt(1,
+ IsFloatingPointZeroConstant(compare->InputAt(1))
+ ? Location::ConstantLocation(compare->InputAt(1)->AsConstant())
+ : Location::RequiresFpuRegister());
locations->SetOut(Location::RequiresRegister());
break;
}
@@ -1696,12 +1697,8 @@
Register result = OutputRegister(compare);
FPRegister left = InputFPRegisterAt(compare, 0);
if (compare->GetLocations()->InAt(1).IsConstant()) {
- if (kIsDebugBuild) {
- HInstruction* right = compare->GetLocations()->InAt(1).GetConstant();
- DCHECK((right->IsFloatConstant() && (right->AsFloatConstant()->GetValue() == 0.0f)) ||
- (right->IsDoubleConstant() && (right->AsDoubleConstant()->GetValue() == 0.0)));
- }
- // 0.0 is the only immediate that can be encoded directly in a FCMP instruction.
+ DCHECK(IsFloatingPointZeroConstant(compare->GetLocations()->InAt(1).GetConstant()));
+ // 0.0 is the only immediate that can be encoded directly in an FCMP instruction.
__ Fcmp(left, 0.0);
} else {
__ Fcmp(left, InputFPRegisterAt(compare, 1));
@@ -1721,8 +1718,19 @@
void LocationsBuilderARM64::VisitCondition(HCondition* instruction) {
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
- locations->SetInAt(0, Location::RequiresRegister());
- locations->SetInAt(1, ARM64EncodableConstantOrRegister(instruction->InputAt(1), instruction));
+
+ if (Primitive::IsFloatingPointType(instruction->InputAt(0)->GetType())) {
+ locations->SetInAt(0, Location::RequiresFpuRegister());
+ locations->SetInAt(1,
+ IsFloatingPointZeroConstant(instruction->InputAt(1))
+ ? Location::ConstantLocation(instruction->InputAt(1)->AsConstant())
+ : Location::RequiresFpuRegister());
+ } else {
+ // Integer cases.
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(1, ARM64EncodableConstantOrRegister(instruction->InputAt(1), instruction));
+ }
+
if (instruction->NeedsMaterialization()) {
locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
}
@@ -1734,13 +1742,32 @@
}
LocationSummary* locations = instruction->GetLocations();
- Register lhs = InputRegisterAt(instruction, 0);
- Operand rhs = InputOperandAt(instruction, 1);
Register res = RegisterFrom(locations->Out(), instruction->GetType());
- Condition cond = ARM64Condition(instruction->GetCondition());
+ IfCondition if_cond = instruction->GetCondition();
+ Condition arm64_cond = ARM64Condition(if_cond);
- __ Cmp(lhs, rhs);
- __ Cset(res, cond);
+ if (Primitive::IsFloatingPointType(instruction->InputAt(0)->GetType())) {
+ FPRegister lhs = InputFPRegisterAt(instruction, 0);
+ if (locations->InAt(1).IsConstant()) {
+ DCHECK(IsFloatingPointZeroConstant(locations->InAt(1).GetConstant()));
+ // 0.0 is the only immediate that can be encoded directly in an FCMP instruction.
+ __ Fcmp(lhs, 0.0);
+ } else {
+ __ Fcmp(lhs, InputFPRegisterAt(instruction, 1));
+ }
+ __ Cset(res, arm64_cond);
+ if (instruction->IsFPConditionTrueIfNaN()) {
+ __ Csel(res, res, Operand(1), vs); // VS for unordered.
+ } else if (instruction->IsFPConditionFalseIfNaN()) {
+ __ Csel(res, res, Operand(0), vs); // VS for unordered.
+ }
+ } else {
+ // Integer cases.
+ Register lhs = InputRegisterAt(instruction, 0);
+ Operand rhs = InputOperandAt(instruction, 1);
+ __ Cmp(lhs, rhs);
+ __ Cset(res, arm64_cond);
+ }
}
#define FOR_EACH_CONDITION_INSTRUCTION(M) \
@@ -2072,33 +2099,58 @@
} else {
// The condition instruction has not been materialized, use its inputs as
// the comparison and its condition as the branch condition.
- Register lhs = InputRegisterAt(condition, 0);
- Operand rhs = InputOperandAt(condition, 1);
- Condition arm64_cond = ARM64Condition(condition->GetCondition());
- if ((arm64_cond != gt && arm64_cond != le) && rhs.IsImmediate() && (rhs.immediate() == 0)) {
- switch (arm64_cond) {
- case eq:
- __ Cbz(lhs, true_target);
- break;
- case ne:
- __ Cbnz(lhs, true_target);
- break;
- case lt:
- // Test the sign bit and branch accordingly.
- __ Tbnz(lhs, (lhs.IsX() ? kXRegSize : kWRegSize) - 1, true_target);
- break;
- case ge:
- // Test the sign bit and branch accordingly.
- __ Tbz(lhs, (lhs.IsX() ? kXRegSize : kWRegSize) - 1, true_target);
- break;
- default:
- // Without the `static_cast` the compiler throws an error for
- // `-Werror=sign-promo`.
- LOG(FATAL) << "Unexpected condition: " << static_cast<int>(arm64_cond);
+ Primitive::Type type =
+ cond->IsCondition() ? cond->InputAt(0)->GetType() : Primitive::kPrimInt;
+
+ if (Primitive::IsFloatingPointType(type)) {
+ // FP compares don't like null false_targets.
+ if (false_target == nullptr) {
+ false_target = codegen_->GetLabelOf(instruction->AsIf()->IfFalseSuccessor());
}
+ FPRegister lhs = InputFPRegisterAt(condition, 0);
+ if (condition->GetLocations()->InAt(1).IsConstant()) {
+ DCHECK(IsFloatingPointZeroConstant(condition->GetLocations()->InAt(1).GetConstant()));
+ // 0.0 is the only immediate that can be encoded directly in an FCMP instruction.
+ __ Fcmp(lhs, 0.0);
+ } else {
+ __ Fcmp(lhs, InputFPRegisterAt(condition, 1));
+ }
+ if (condition->IsFPConditionTrueIfNaN()) {
+ __ B(vs, true_target); // VS for unordered.
+ } else if (condition->IsFPConditionFalseIfNaN()) {
+ __ B(vs, false_target); // VS for unordered.
+ }
+ __ B(ARM64Condition(condition->GetCondition()), true_target);
} else {
- __ Cmp(lhs, rhs);
- __ B(arm64_cond, true_target);
+ // Integer cases.
+ Register lhs = InputRegisterAt(condition, 0);
+ Operand rhs = InputOperandAt(condition, 1);
+ Condition arm64_cond = ARM64Condition(condition->GetCondition());
+ if ((arm64_cond != gt && arm64_cond != le) && rhs.IsImmediate() && (rhs.immediate() == 0)) {
+ switch (arm64_cond) {
+ case eq:
+ __ Cbz(lhs, true_target);
+ break;
+ case ne:
+ __ Cbnz(lhs, true_target);
+ break;
+ case lt:
+ // Test the sign bit and branch accordingly.
+ __ Tbnz(lhs, (lhs.IsX() ? kXRegSize : kWRegSize) - 1, true_target);
+ break;
+ case ge:
+ // Test the sign bit and branch accordingly.
+ __ Tbz(lhs, (lhs.IsX() ? kXRegSize : kWRegSize) - 1, true_target);
+ break;
+ default:
+ // Without the `static_cast` the compiler throws an error for
+ // `-Werror=sign-promo`.
+ LOG(FATAL) << "Unexpected condition: " << static_cast<int>(arm64_cond);
+ }
+ } else {
+ __ Cmp(lhs, rhs);
+ __ B(arm64_cond, true_target);
+ }
}
}
if (false_target != nullptr) {
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index 017b678..04ba4e1 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -517,10 +517,10 @@
void InstructionSimplifierVisitor::VisitCondition(HCondition* condition) {
// Try to fold an HCompare into this HCondition.
- // This simplification is currently only supported on x86, x86_64 and ARM.
- // TODO: Implement it for ARM64 and MIPS64.
+ // This simplification is currently supported on x86, x86_64, ARM and ARM64.
+ // TODO: Implement it for MIPS64.
InstructionSet instruction_set = GetGraph()->GetInstructionSet();
- if (instruction_set != kX86 && instruction_set != kX86_64 && instruction_set != kThumb2) {
+ if (instruction_set == kMips64) {
return;
}