]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
optabs: Fix expansion of abs and neg for Float16 [PR123869]
authorAndrew Pinski <andrew.pinski@oss.qualcomm.com>
Thu, 29 Jan 2026 00:50:52 +0000 (16:50 -0800)
committerAndrew Pinski <andrew.pinski@oss.qualcomm.com>
Thu, 29 Jan 2026 21:50:47 +0000 (13:50 -0800)
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 <andrew.pinski@oss.qualcomm.com>
gcc/optabs.cc

index 5a1d4c757046ef4c0bf94d7faf2fc36a5d4009b3..c3b51465248fa92cbfaeff3ffedc1a78f283ecb0 100644 (file)
@@ -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))