https://gcc.gnu.org/g:2c49e5bac3724a6565d7b7664e43e40ceb0a4dca
commit 2c49e5bac3724a6565d7b7664e43e40ceb0a4dca Author: Michael Meissner <meiss...@linux.ibm.com> Date: Thu Aug 14 18:20:36 2025 -0400 Fix PR 118541, do not generate floating point cmoves for IEEE compares. In bug PR target/118541 on power9, power10, and power11 systems, for the function: extern double __ieee754_acos (double); double __acospi (double x) { double ret = __ieee754_acos (x) / 3.14; return __builtin_isgreater (ret, 1.0) ? 1.0 : ret; } GCC currently generates the following code: Power9 Power10 and Power11 ====== =================== bl __ieee754_acos bl __ieee754_acos@notoc nop plfd 0,.LC0@pcrel addis 9,2,.LC2@toc@ha xxspltidp 12,1065353216 addi 1,1,32 addi 1,1,32 lfd 0,.LC2@toc@l(9) ld 0,16(1) addis 9,2,.LC0@toc@ha fdiv 0,1,0 ld 0,16(1) mtlr 0 lfd 12,.LC0@toc@l(9) xscmpgtdp 1,0,12 fdiv 0,1,0 xxsel 1,0,12,1 mtlr 0 blr xscmpgtdp 1,0,12 xxsel 1,0,12,1 blr This is because ifcvt.cc optimizes the conditional floating point move to use the XSCMPGTDP instruction. However, the XSCMPGTDP instruction will generate an interrupt if one of the arguments is a signalling NaN and signalling NaNs can generate an interrupt. The IEEE comparison functions (isgreater, etc.) require that the comparison not raise an interrupt. This patch just eliminates the generation of XSCMPEQDP, XSCMPEQQP, XSCMPGTDP, XSCMPGTQP, XSCMPGEDP, and XSCMPGEQP instructions. 2025-08-14 Michael Meissner <meiss...@linux.ibm.com> gcc/ PR target/118541 * config/rs6000/predicates.md (fpmask_comparison_operator): Delete predicate. (invert_fpmask_comparison_operator): Likewise. * config/rs6000/rs6000.cc (rs6000_maybe_emit_fp_cmove): Delete function. (have_fp_cmin_cmax): Rename from have_compare_and_set_mask since we no longer generate the floating point compare and set mask instructions, but we also need the test for fp. min/max. (rs6000_emit_cmove): Delete support for generating floating point compare and set mask instructions since those instructions can raise NaN exceptions. * config/rs6000/rs6000.md (mov<SFDF:mode><SFDF2:mode>cc_p9): Delete insn. (fpmask<mode>, SFDF iterator): Likewise. (xxsel<mode>): Likewise. (mov<mode>cc): Likewise. (mov<mode>cc_p10): Likewise. (mov<mode>cc_invert_p10): Likewise. (fpmask<mode>, IEEE128 iterator): Likewise. Diff: --- gcc/config/rs6000/predicates.md | 11 --- gcc/config/rs6000/rs6000.cc | 109 ++-------------------- gcc/config/rs6000/rs6000.md | 197 ---------------------------------------- 3 files changed, 8 insertions(+), 309 deletions(-) diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md index 647e89afb6a7..065cdb10e10f 100644 --- a/gcc/config/rs6000/predicates.md +++ b/gcc/config/rs6000/predicates.md @@ -1458,17 +1458,6 @@ (and (match_operand 0 "branch_comparison_operator") (match_code "ne,le,ge,leu,geu,ordered"))) -;; Return 1 if OP is a comparison operator suitable for floating point -;; vector/scalar comparisons that generate a -1/0 mask. -(define_predicate "fpmask_comparison_operator" - (match_code "eq,gt,ge")) - -;; Return 1 if OP is a comparison operator suitable for vector/scalar -;; comparisons that generate a 0/-1 mask (i.e. the inverse of -;; fpmask_comparison_operator). -(define_predicate "invert_fpmask_comparison_operator" - (match_code "ne,unlt,unle")) - ;; Return 1 if OP is a comparison operation suitable for integer vector/scalar ;; comparisons that generate a -1/0 mask. (define_predicate "vecint_comparison_operator" diff --git a/gcc/config/rs6000/rs6000.cc b/gcc/config/rs6000/rs6000.cc index 781beb0a26a5..24f453bee659 100644 --- a/gcc/config/rs6000/rs6000.cc +++ b/gcc/config/rs6000/rs6000.cc @@ -16353,98 +16353,11 @@ rs6000_maybe_emit_maxc_minc (rtx dest, rtx op, rtx true_cond, rtx false_cond) return true; } -/* Possibly emit a floating point conditional move by generating a compare that - sets a mask instruction and a XXSEL select instruction. - - Move TRUE_COND to DEST if OP of the operands of the last comparison is - nonzero/true, FALSE_COND if it is zero/false. - - Return false if the operation cannot be generated, and true if we could - generate the instruction. */ - -static bool -rs6000_maybe_emit_fp_cmove (rtx dest, rtx op, rtx true_cond, rtx false_cond) -{ - enum rtx_code code = GET_CODE (op); - rtx op0 = XEXP (op, 0); - rtx op1 = XEXP (op, 1); - machine_mode compare_mode = GET_MODE (op0); - machine_mode result_mode = GET_MODE (dest); - rtx compare_rtx; - rtx cmove_rtx; - rtx clobber_rtx; - - if (!can_create_pseudo_p ()) - return 0; - - /* We allow the comparison to be either SFmode/DFmode and the true/false - condition to be either SFmode/DFmode. I.e. we allow: - - float a, b; - double c, d, r; - - r = (a == b) ? c : d; - - and: - - double a, b; - float c, d, r; - - r = (a == b) ? c : d; - - but we don't allow intermixing the IEEE 128-bit floating point types with - the 32/64-bit scalar types. */ - - if (!(compare_mode == result_mode - || (compare_mode == SFmode && result_mode == DFmode) - || (compare_mode == DFmode && result_mode == SFmode))) - return false; - - switch (code) - { - case EQ: - case GE: - case GT: - break; - - case NE: - case LT: - case LE: - code = swap_condition (code); - std::swap (op0, op1); - break; - - default: - return false; - } - - /* Generate: [(parallel [(set (dest) - (if_then_else (op (cmp1) (cmp2)) - (true) - (false))) - (clobber (scratch))])]. */ - - compare_rtx = gen_rtx_fmt_ee (code, CCFPmode, op0, op1); - cmove_rtx = gen_rtx_SET (dest, - gen_rtx_IF_THEN_ELSE (result_mode, - compare_rtx, - true_cond, - false_cond)); - - clobber_rtx = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (V2DImode)); - emit_insn (gen_rtx_PARALLEL (VOIDmode, - gen_rtvec (2, cmove_rtx, clobber_rtx))); - - return true; -} - -/* Helper function to return true if the target has instructions to do a - compare and set mask instruction that can be used with XXSEL to implement a - conditional move. It is also assumed that such a target also supports the - "C" minimum and maximum instructions. */ +/* Helper function to return true if the target supports the "C" minimum and + maximum instructions. */ static bool -have_compare_and_set_mask (machine_mode mode) +have_fp_cmin_cmax (machine_mode mode) { switch (mode) { @@ -16489,17 +16402,11 @@ rs6000_emit_cmove (rtx dest, rtx op, rtx true_cond, rtx false_cond) if (GET_MODE (false_cond) != result_mode) return false; - /* See if we can use the "C" minimum, "C" maximum, and compare and set mask - instructions. */ - if (have_compare_and_set_mask (compare_mode) - && have_compare_and_set_mask (result_mode)) - { - if (rs6000_maybe_emit_maxc_minc (dest, op, true_cond, false_cond)) - return true; - - if (rs6000_maybe_emit_fp_cmove (dest, op, true_cond, false_cond)) - return true; - } + /* See if we can use the "C" minimum, "C" maximum instructions. */ + if (have_fp_cmin_cmax (compare_mode) + && compare_mode == result_mode + && rs6000_maybe_emit_maxc_minc (dest, op, true_cond, false_cond)) + return true; /* Don't allow using floating point comparisons for integer results for now. */ diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index 4b0467ba1b80..aa0b49d6e080 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -5747,203 +5747,6 @@ "TARGET_HARD_FLOAT && TARGET_PPC_GFXOPT" "fsel %0,%1,%2,%3" [(set_attr "type" "fp")]) - -(define_insn_and_split "*mov<SFDF:mode><SFDF2:mode>cc_p9" - [(set (match_operand:SFDF 0 "vsx_register_operand" "=&wa,wa") - (if_then_else:SFDF - (match_operator:CCFP 1 "fpmask_comparison_operator" - [(match_operand:SFDF2 2 "vsx_register_operand" "wa,wa") - (match_operand:SFDF2 3 "vsx_register_operand" "wa,wa")]) - (match_operand:SFDF 4 "vsx_register_operand" "wa,wa") - (match_operand:SFDF 5 "vsx_register_operand" "wa,wa"))) - (clobber (match_scratch:V2DI 6 "=0,&wa"))] - "TARGET_P9_MINMAX" - "#" - "&& 1" - [(set (match_dup 6) - (if_then_else:V2DI (match_dup 1) - (match_dup 7) - (match_dup 8))) - (set (match_dup 0) - (if_then_else:SFDF (ne (match_dup 6) - (match_dup 8)) - (match_dup 4) - (match_dup 5)))] -{ - if (GET_CODE (operands[6]) == SCRATCH) - operands[6] = gen_reg_rtx (V2DImode); - - operands[7] = CONSTM1_RTX (V2DImode); - operands[8] = CONST0_RTX (V2DImode); -} - [(set_attr "length" "8") - (set_attr "type" "vecperm")]) - -;; Handle inverting the fpmask comparisons. -(define_insn_and_split "*mov<SFDF:mode><SFDF2:mode>cc_invert_p9" - [(set (match_operand:SFDF 0 "vsx_register_operand" "=&wa,wa") - (if_then_else:SFDF - (match_operator:CCFP 1 "invert_fpmask_comparison_operator" - [(match_operand:SFDF2 2 "vsx_register_operand" "wa,wa") - (match_operand:SFDF2 3 "vsx_register_operand" "wa,wa")]) - (match_operand:SFDF 4 "vsx_register_operand" "wa,wa") - (match_operand:SFDF 5 "vsx_register_operand" "wa,wa"))) - (clobber (match_scratch:V2DI 6 "=0,&wa"))] - "TARGET_P9_MINMAX" - "#" - "&& 1" - [(set (match_dup 6) - (if_then_else:V2DI (match_dup 9) - (match_dup 7) - (match_dup 8))) - (set (match_dup 0) - (if_then_else:SFDF (ne (match_dup 6) - (match_dup 8)) - (match_dup 5) - (match_dup 4)))] -{ - rtx op1 = operands[1]; - enum rtx_code cond = reverse_condition_maybe_unordered (GET_CODE (op1)); - - if (GET_CODE (operands[6]) == SCRATCH) - operands[6] = gen_reg_rtx (V2DImode); - - operands[7] = CONSTM1_RTX (V2DImode); - operands[8] = CONST0_RTX (V2DImode); - - operands[9] = gen_rtx_fmt_ee (cond, CCFPmode, operands[2], operands[3]); -} - [(set_attr "length" "8") - (set_attr "type" "vecperm")]) - -(define_insn "*fpmask<mode>" - [(set (match_operand:V2DI 0 "vsx_register_operand" "=wa") - (if_then_else:V2DI - (match_operator:CCFP 1 "fpmask_comparison_operator" - [(match_operand:SFDF 2 "vsx_register_operand" "wa") - (match_operand:SFDF 3 "vsx_register_operand" "wa")]) - (match_operand:V2DI 4 "all_ones_constant" "") - (match_operand:V2DI 5 "zero_constant" "")))] - "TARGET_P9_MINMAX" - "xscmp%V1dp %x0,%x2,%x3" - [(set_attr "type" "fpcompare")]) - -(define_insn "*xxsel<mode>" - [(set (match_operand:SFDF 0 "vsx_register_operand" "=wa") - (if_then_else:SFDF (ne (match_operand:V2DI 1 "vsx_register_operand" "wa") - (match_operand:V2DI 2 "zero_constant" "")) - (match_operand:SFDF 3 "vsx_register_operand" "wa") - (match_operand:SFDF 4 "vsx_register_operand" "wa")))] - "TARGET_P9_MINMAX" - "xxsel %x0,%x4,%x3,%x1" - [(set_attr "type" "vecmove")]) - -;; Support for ISA 3.1 IEEE 128-bit conditional move. The mode used in the -;; comparison must be the same as used in the move. -(define_expand "mov<mode>cc" - [(set (match_operand:IEEE128 0 "gpc_reg_operand") - (if_then_else:IEEE128 (match_operand 1 "comparison_operator") - (match_operand:IEEE128 2 "gpc_reg_operand") - (match_operand:IEEE128 3 "gpc_reg_operand")))] - "TARGET_POWER10 && TARGET_FLOAT128_HW" -{ - if (rs6000_emit_cmove (operands[0], operands[1], operands[2], operands[3])) - DONE; - else - FAIL; -}) - -(define_insn_and_split "*mov<mode>cc_p10" - [(set (match_operand:IEEE128 0 "altivec_register_operand" "=&v,v") - (if_then_else:IEEE128 - (match_operator:CCFP 1 "fpmask_comparison_operator" - [(match_operand:IEEE128 2 "altivec_register_operand" "v,v") - (match_operand:IEEE128 3 "altivec_register_operand" "v,v")]) - (match_operand:IEEE128 4 "altivec_register_operand" "v,v") - (match_operand:IEEE128 5 "altivec_register_operand" "v,v"))) - (clobber (match_scratch:V2DI 6 "=0,&v"))] - "TARGET_POWER10 && TARGET_FLOAT128_HW" - "#" - "&& 1" - [(set (match_dup 6) - (if_then_else:V2DI (match_dup 1) - (match_dup 7) - (match_dup 8))) - (set (match_dup 0) - (if_then_else:IEEE128 (ne (match_dup 6) - (match_dup 8)) - (match_dup 4) - (match_dup 5)))] -{ - if (GET_CODE (operands[6]) == SCRATCH) - operands[6] = gen_reg_rtx (V2DImode); - - operands[7] = CONSTM1_RTX (V2DImode); - operands[8] = CONST0_RTX (V2DImode); -} - [(set_attr "length" "8") - (set_attr "type" "vecperm")]) - -;; Handle inverting the fpmask comparisons. -(define_insn_and_split "*mov<mode>cc_invert_p10" - [(set (match_operand:IEEE128 0 "altivec_register_operand" "=&v,v") - (if_then_else:IEEE128 - (match_operator:CCFP 1 "invert_fpmask_comparison_operator" - [(match_operand:IEEE128 2 "altivec_register_operand" "v,v") - (match_operand:IEEE128 3 "altivec_register_operand" "v,v")]) - (match_operand:IEEE128 4 "altivec_register_operand" "v,v") - (match_operand:IEEE128 5 "altivec_register_operand" "v,v"))) - (clobber (match_scratch:V2DI 6 "=0,&v"))] - "TARGET_POWER10 && TARGET_FLOAT128_HW" - "#" - "&& 1" - [(set (match_dup 6) - (if_then_else:V2DI (match_dup 9) - (match_dup 7) - (match_dup 8))) - (set (match_dup 0) - (if_then_else:IEEE128 (ne (match_dup 6) - (match_dup 8)) - (match_dup 5) - (match_dup 4)))] -{ - rtx op1 = operands[1]; - enum rtx_code cond = reverse_condition_maybe_unordered (GET_CODE (op1)); - - if (GET_CODE (operands[6]) == SCRATCH) - operands[6] = gen_reg_rtx (V2DImode); - - operands[7] = CONSTM1_RTX (V2DImode); - operands[8] = CONST0_RTX (V2DImode); - - operands[9] = gen_rtx_fmt_ee (cond, CCFPmode, operands[2], operands[3]); -} - [(set_attr "length" "8") - (set_attr "type" "vecperm")]) - -(define_insn "*fpmask<mode>" - [(set (match_operand:V2DI 0 "altivec_register_operand" "=v") - (if_then_else:V2DI - (match_operator:CCFP 1 "fpmask_comparison_operator" - [(match_operand:IEEE128 2 "altivec_register_operand" "v") - (match_operand:IEEE128 3 "altivec_register_operand" "v")]) - (match_operand:V2DI 4 "all_ones_constant" "") - (match_operand:V2DI 5 "zero_constant" "")))] - "TARGET_POWER10 && TARGET_FLOAT128_HW" - "xscmp%V1qp %0,%2,%3" - [(set_attr "type" "fpcompare")]) - -(define_insn "*xxsel<mode>" - [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v") - (if_then_else:IEEE128 - (ne (match_operand:V2DI 1 "altivec_register_operand" "v") - (match_operand:V2DI 2 "zero_constant" "")) - (match_operand:IEEE128 3 "altivec_register_operand" "v") - (match_operand:IEEE128 4 "altivec_register_operand" "v")))] - "TARGET_POWER10 && TARGET_FLOAT128_HW" - "xxsel %x0,%x4,%x3,%x1" - [(set_attr "type" "vecmove")]) - ;; Conversions to and from floating-point.