Index: src/arm/macro-assembler-arm.cc |
diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc |
index 496d9bd69261f266eeae53d86aa90834fb24bfad..2e9356967c6e10ce9af35557bba74f7985e78cf2 100644 |
--- a/src/arm/macro-assembler-arm.cc |
+++ b/src/arm/macro-assembler-arm.cc |
@@ -250,15 +250,17 @@ void MacroAssembler::Move(Register dst, Register src, Condition cond) { |
} |
} |
-void MacroAssembler::Move(SwVfpRegister dst, SwVfpRegister src) { |
+void MacroAssembler::Move(SwVfpRegister dst, SwVfpRegister src, |
+ Condition cond) { |
if (!dst.is(src)) { |
- vmov(dst, src); |
+ vmov(dst, src, cond); |
} |
} |
-void MacroAssembler::Move(DwVfpRegister dst, DwVfpRegister src) { |
+void MacroAssembler::Move(DwVfpRegister dst, DwVfpRegister src, |
+ Condition cond) { |
if (!dst.is(src)) { |
- vmov(dst, src); |
+ vmov(dst, src, cond); |
} |
} |
@@ -3428,6 +3430,144 @@ void MacroAssembler::RestoreFPRegs(Register location, Register scratch) { |
add(location, location, Operand(16 * kDoubleSize), LeaveCC, eq); |
} |
+template <typename T> |
+void MacroAssembler::FloatMaxHelper(T result, T left, T right, |
+ Label* out_of_line) { |
+ // This trivial case is caught sooner, so that the out-of-line code can be |
+ // completely avoided. |
+ DCHECK(!left.is(right)); |
+ |
+ if (CpuFeatures::IsSupported(ARMv8)) { |
+ CpuFeatureScope scope(this, ARMv8); |
+ VFPCompareAndSetFlags(left, right); |
+ b(vs, out_of_line); |
+ vmaxnm(result, left, right); |
+ } else { |
+ Label done; |
+ VFPCompareAndSetFlags(left, right); |
+ b(vs, out_of_line); |
+ // Avoid a conditional instruction if the result register is unique. |
+ bool aliased_result_reg = result.is(left) || result.is(right); |
+ Move(result, right, aliased_result_reg ? mi : al); |
+ Move(result, left, gt); |
+ b(ne, &done); |
+ // Left and right are equal, but check for +/-0. |
+ VFPCompareAndSetFlags(left, 0.0); |
+ b(eq, out_of_line); |
+ // The arguments are equal and not zero, so it doesn't matter which input we |
+ // pick. We have already moved one input into the result (if it didn't |
+ // already alias) so there's nothing more to do. |
+ bind(&done); |
+ } |
+} |
+ |
+template <typename T> |
+void MacroAssembler::FloatMaxOutOfLineHelper(T result, T left, T right) { |
+ DCHECK(!left.is(right)); |
+ |
+ // ARMv8: At least one of left and right is a NaN. |
+ // Anything else: At least one of left and right is a NaN, or both left and |
+ // right are zeroes with unknown sign. |
+ |
+ // If left and right are +/-0, select the one with the most positive sign. |
+ // If left or right are NaN, vadd propagates the appropriate one. |
+ vadd(result, left, right); |
+} |
+ |
+template <typename T> |
+void MacroAssembler::FloatMinHelper(T result, T left, T right, |
+ Label* out_of_line) { |
+ // This trivial case is caught sooner, so that the out-of-line code can be |
+ // completely avoided. |
+ DCHECK(!left.is(right)); |
+ |
+ if (CpuFeatures::IsSupported(ARMv8)) { |
+ CpuFeatureScope scope(this, ARMv8); |
+ VFPCompareAndSetFlags(left, right); |
+ b(vs, out_of_line); |
+ vminnm(result, left, right); |
+ } else { |
+ Label done; |
+ VFPCompareAndSetFlags(left, right); |
+ b(vs, out_of_line); |
+ // Avoid a conditional instruction if the result register is unique. |
+ bool aliased_result_reg = result.is(left) || result.is(right); |
+ Move(result, left, aliased_result_reg ? mi : al); |
+ Move(result, right, gt); |
+ b(ne, &done); |
+ // Left and right are equal, but check for +/-0. |
+ VFPCompareAndSetFlags(left, 0.0); |
+ // If the arguments are equal and not zero, it doesn't matter which input we |
+ // pick. We have already moved one input into the result (if it didn't |
+ // already alias) so there's nothing more to do. |
+ b(ne, &done); |
+ // At this point, both left and right are either 0 or -0. |
+ // We could use a single 'vorr' instruction here if we had NEON support. |
+ // The algorithm used is -((-L) + (-R)), which is most efficiently expressed |
+ // as -((-L) - R). |
+ if (left.is(result)) { |
+ DCHECK(!right.is(result)); |
+ vneg(result, left); |
+ vsub(result, result, right); |
+ vneg(result, result); |
+ } else { |
+ DCHECK(!left.is(result)); |
+ vneg(result, right); |
+ vsub(result, result, left); |
+ vneg(result, result); |
+ } |
+ bind(&done); |
+ } |
+} |
+ |
+template <typename T> |
+void MacroAssembler::FloatMinOutOfLineHelper(T result, T left, T right) { |
+ DCHECK(!left.is(right)); |
+ |
+ // At least one of left and right is a NaN. Use vadd to propagate the NaN |
+ // appropriately. +/-0 is handled inline. |
+ vadd(result, left, right); |
+} |
+ |
+void MacroAssembler::FloatMax(SwVfpRegister result, SwVfpRegister left, |
+ SwVfpRegister right, Label* out_of_line) { |
+ FloatMaxHelper(result, left, right, out_of_line); |
+} |
+ |
+void MacroAssembler::FloatMin(SwVfpRegister result, SwVfpRegister left, |
+ SwVfpRegister right, Label* out_of_line) { |
+ FloatMinHelper(result, left, right, out_of_line); |
+} |
+ |
+void MacroAssembler::FloatMax(DwVfpRegister result, DwVfpRegister left, |
+ DwVfpRegister right, Label* out_of_line) { |
+ FloatMaxHelper(result, left, right, out_of_line); |
+} |
+ |
+void MacroAssembler::FloatMin(DwVfpRegister result, DwVfpRegister left, |
+ DwVfpRegister right, Label* out_of_line) { |
+ FloatMinHelper(result, left, right, out_of_line); |
+} |
+ |
+void MacroAssembler::FloatMaxOutOfLine(SwVfpRegister result, SwVfpRegister left, |
+ SwVfpRegister right) { |
+ FloatMaxOutOfLineHelper(result, left, right); |
+} |
+ |
+void MacroAssembler::FloatMinOutOfLine(SwVfpRegister result, SwVfpRegister left, |
+ SwVfpRegister right) { |
+ FloatMinOutOfLineHelper(result, left, right); |
+} |
+ |
+void MacroAssembler::FloatMaxOutOfLine(DwVfpRegister result, DwVfpRegister left, |
+ DwVfpRegister right) { |
+ FloatMaxOutOfLineHelper(result, left, right); |
+} |
+ |
+void MacroAssembler::FloatMinOutOfLine(DwVfpRegister result, DwVfpRegister left, |
+ DwVfpRegister right) { |
+ FloatMinOutOfLineHelper(result, left, right); |
+} |
void MacroAssembler::JumpIfBothInstanceTypesAreNotSequentialOneByte( |
Register first, Register second, Register scratch1, Register scratch2, |