The problem here is we try to use the widening type before
doing the bitwise expansion of neg/and for floating point types.
This moves the code around to try the bitwise expansion first.

Note this mostly matters for NaNs where you widening (promotion)
would cause a NaN to be slightly different when doing the rounding
back.

Bootstrapped and tested on x86_64-linux-gnu.

        PR middle-end/123869

gcc/ChangeLog:

        * optabs.cc (expand_unop): Move the NEG optab
        handling before the widening code.
        Move the ABS bitwise expansion from expand_abs_nojump
        to before the widening code.
        (expand_abs_nojump): Remove the bitwise expansion trial
        since expand_unop is called right above.

Signed-off-by: Andrew Pinski <[email protected]>
---
 gcc/optabs.cc | 65 ++++++++++++++++++++++++++-------------------------
 1 file changed, 33 insertions(+), 32 deletions(-)

diff --git a/gcc/optabs.cc b/gcc/optabs.cc
index 5a1d4c75704..f94d2e49820 100644
--- a/gcc/optabs.cc
+++ b/gcc/optabs.cc
@@ -3376,6 +3376,39 @@ expand_unop (machine_mode mode, optab unoptab, rtx op0, 
rtx target,
       goto try_libcall;
     }
 
+  /* Neg should be tried via expand_absneg_bit before widening. */
+  if (optab_to_code (unoptab) == NEG)
+    {
+      /* Try negating floating point values by flipping the sign bit.  */
+      if (is_a <scalar_float_mode> (GET_MODE_INNER (mode), &float_mode))
+       {
+         temp = expand_absneg_bit (NEG, mode, float_mode, op0, target);
+         if (temp)
+           return temp;
+       }
+
+      /* If there is no negation pattern, and we have no negative zero,
+        try subtracting from zero.  */
+      if (!HONOR_SIGNED_ZEROS (mode))
+       {
+         temp = expand_binop (mode, (unoptab == negv_optab
+                                     ? subv_optab : sub_optab),
+                              CONST0_RTX (mode), op0, target,
+                              unsignedp, OPTAB_DIRECT);
+         if (temp)
+           return temp;
+       }
+    }
+
+  /* ABS also needs to be handled similarly. */
+  if (optab_to_code (unoptab) == ABS
+      && is_a <scalar_float_mode> (GET_MODE_INNER (mode), &float_mode))
+    {
+      temp = expand_absneg_bit (ABS, mode, float_mode, op0, target);
+      if (temp)
+       return temp;
+    }
+
   if (CLASS_HAS_WIDER_MODES_P (mclass))
     FOR_EACH_WIDER_MODE (wider_mode, mode)
       {
@@ -3460,29 +3493,6 @@ expand_unop (machine_mode mode, optab unoptab, rtx op0, 
rtx target,
        return temp;
     }
 
-  if (optab_to_code (unoptab) == NEG)
-    {
-      /* Try negating floating point values by flipping the sign bit.  */
-      if (is_a <scalar_float_mode> (GET_MODE_INNER (mode), &float_mode))
-       {
-         temp = expand_absneg_bit (NEG, mode, float_mode, op0, target);
-         if (temp)
-           return temp;
-       }
-
-      /* If there is no negation pattern, and we have no negative zero,
-        try subtracting from zero.  */
-      if (!HONOR_SIGNED_ZEROS (mode))
-       {
-         temp = expand_binop (mode, (unoptab == negv_optab
-                                     ? subv_optab : sub_optab),
-                              CONST0_RTX (mode), op0, target,
-                              unsignedp, OPTAB_DIRECT);
-         if (temp)
-           return temp;
-       }
-    }
-
   /* Try calculating parity (x) as popcount (x) % 2.  */
   if (unoptab == parity_optab && is_a <scalar_int_mode> (mode, &int_mode))
     {
@@ -3680,15 +3690,6 @@ expand_abs_nojump (machine_mode mode, rtx op0, rtx 
target,
   if (temp != 0)
     return temp;
 
-  /* For floating point modes, try clearing the sign bit.  */
-  scalar_float_mode float_mode;
-  if (is_a <scalar_float_mode> (GET_MODE_INNER (mode), &float_mode))
-    {
-      temp = expand_absneg_bit (ABS, mode, float_mode, op0, target);
-      if (temp)
-       return temp;
-    }
-
   /* If we have a MAX insn, we can do this as MAX (x, -x).  */
   if (optab_handler (smax_optab, mode) != CODE_FOR_nothing
       && !HONOR_SIGNED_ZEROS (mode))
-- 
2.43.0

Reply via email to