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