https://gcc.gnu.org/g:41f293e72c253301f71fefc5a5e1040cb468e4ed
commit r16-7160-g41f293e72c253301f71fefc5a5e1040cb468e4ed Author: Andrew Pinski <[email protected]> Date: Wed Jan 28 16:50:52 2026 -0800 optabs: Fix expansion of abs and neg for Float16 [PR123869] 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]> Diff: --- gcc/optabs.cc | 65 ++++++++++++++++++++++++++++++----------------------------- 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/gcc/optabs.cc b/gcc/optabs.cc index 5a1d4c757046..c3b51465248f 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))
