@@ -787,6 +787,7 @@ static rtx noce_get_alt_condition (struct noce_if_info *, rtx, rtx_insn **);
787787static bool noce_try_minmax (struct noce_if_info *);
788788static bool noce_try_abs (struct noce_if_info *);
789789static bool noce_try_sign_mask (struct noce_if_info *);
790+ static int noce_try_cond_zero_arith (struct noce_if_info *);
790791
791792/* Return the comparison code for reversed condition for IF_INFO,
792793 or UNKNOWN if reversing the condition is not possible. */
@@ -1831,6 +1832,35 @@ noce_emit_cmove (struct noce_if_info *if_info, rtx x, enum rtx_code code,
18311832 return NULL_RTX;
18321833}
18331834
1835+ /* Emit a conditional zero, returning TARGET or NULL_RTX upon failure.
1836+ IF_INFO describes the if-conversion scenario under consideration.
1837+ CZERO_CODE selects the condition (EQ/NE).
1838+ NON_ZERO_OP is the nonzero operand of the conditional move
1839+ TARGET is the desired output register. */
1840+
1841+ static rtx
1842+ noce_emit_czero (struct noce_if_info *if_info, enum rtx_code czero_code,
1843+ rtx non_zero_op, rtx target)
1844+ {
1845+ machine_mode mode = GET_MODE (target);
1846+ rtx cond_op0 = XEXP (if_info->cond , 0 );
1847+ rtx czero_cond
1848+ = gen_rtx_fmt_ee (czero_code, GET_MODE (cond_op0), cond_op0, const0_rtx);
1849+ rtx if_then_else
1850+ = gen_rtx_IF_THEN_ELSE (mode, czero_cond, const0_rtx, non_zero_op);
1851+ rtx set = gen_rtx_SET (target, if_then_else);
1852+
1853+ rtx_insn *insn = make_insn_raw (set);
1854+
1855+ if (recog_memoized (insn) >= 0 )
1856+ {
1857+ add_insn (insn);
1858+ return target;
1859+ }
1860+
1861+ return NULL_RTX;
1862+ }
1863+
18341864/* Try only simple constants and registers here. More complex cases
18351865 are handled in noce_try_cmove_arith after noce_try_store_flag_arith
18361866 has had a go at it. */
@@ -2880,6 +2910,160 @@ noce_try_sign_mask (struct noce_if_info *if_info)
28802910 return true ;
28812911}
28822912
2913+ /* Check if OP is supported by conditional zero based if conversion,
2914+ returning TRUE if satisfied otherwise FALSE.
2915+
2916+ OP is the operation to check. */
2917+
2918+ static bool
2919+ noce_cond_zero_binary_op_supported (rtx op)
2920+ {
2921+ enum rtx_code opcode = GET_CODE (op);
2922+
2923+ if (opcode == PLUS || opcode == MINUS || opcode == IOR || opcode == XOR)
2924+ return true ;
2925+
2926+ return false ;
2927+ }
2928+
2929+ /* Helper function to return REG itself,
2930+ otherwise NULL_RTX for other RTX_CODE. */
2931+
2932+ static rtx
2933+ get_base_reg (rtx exp)
2934+ {
2935+ if (REG_P (exp))
2936+ return exp;
2937+
2938+ return NULL_RTX;
2939+ }
2940+
2941+ /* Check if IF-BB and THEN-BB satisfy the condition for conditional zero
2942+ based if conversion, returning TRUE if satisfied otherwise FALSE.
2943+
2944+ IF_INFO describes the if-conversion scenario under consideration.
2945+ COMMON_PTR points to the common REG of canonicalized IF_INFO->A and
2946+ IF_INFO->B.
2947+ CZERO_CODE_PTR points to the comparison code to use in czero RTX.
2948+ A_PTR points to the A expression of canonicalized IF_INFO->A.
2949+ TO_REPLACE points to the RTX to be replaced by czero RTX destnation. */
2950+
2951+ static bool
2952+ noce_bbs_ok_for_cond_zero_arith (struct noce_if_info *if_info, rtx *common_ptr,
2953+ enum rtx_code *czero_code_ptr, rtx *a_ptr,
2954+ rtx **to_replace)
2955+ {
2956+ rtx common = NULL_RTX;
2957+ rtx cond = if_info->cond ;
2958+ rtx a = copy_rtx (if_info->a );
2959+ rtx b = copy_rtx (if_info->b );
2960+ rtx bin_op1 = NULL_RTX;
2961+ enum rtx_code czero_code = UNKNOWN;
2962+ bool reverse = false ;
2963+ rtx op0, op1, bin_exp;
2964+
2965+ if (!noce_simple_bbs (if_info))
2966+ return false ;
2967+
2968+ /* COND must be EQ or NE comparision of a reg and 0. */
2969+ if (GET_CODE (cond) != NE && GET_CODE (cond) != EQ)
2970+ return false ;
2971+ if (!REG_P (XEXP (cond, 0 )) || !rtx_equal_p (XEXP (cond, 1 ), const0_rtx))
2972+ return false ;
2973+
2974+ /* Canonicalize x = y : (y op z) to x = (y op z) : y. */
2975+ if (REG_P (a) && noce_cond_zero_binary_op_supported (b))
2976+ {
2977+ std::swap (a, b);
2978+ reverse = !reverse;
2979+ }
2980+
2981+ /* Check if x = (y op z) : y is supported by czero based ifcvt. */
2982+ if (!(noce_cond_zero_binary_op_supported (a) && REG_P (b)))
2983+ return false ;
2984+
2985+ bin_exp = a;
2986+
2987+ /* Canonicalize x = (z op y) : y to x = (y op z) : y */
2988+ op1 = get_base_reg (XEXP (bin_exp, 1 ));
2989+ if (op1 && rtx_equal_p (op1, b) && COMMUTATIVE_ARITH_P (bin_exp))
2990+ std::swap (XEXP (bin_exp, 0 ), XEXP (bin_exp, 1 ));
2991+
2992+ op0 = get_base_reg (XEXP (bin_exp, 0 ));
2993+ if (op0 && rtx_equal_p (op0, b))
2994+ {
2995+ common = b;
2996+ bin_op1 = XEXP (bin_exp, 1 );
2997+ czero_code = reverse
2998+ ? noce_reversed_cond_code (if_info)
2999+ : GET_CODE (cond);
3000+ }
3001+ else
3002+ return false ;
3003+
3004+ if (czero_code == UNKNOWN)
3005+ return false ;
3006+
3007+ if (REG_P (bin_op1))
3008+ *to_replace = &XEXP (bin_exp, 1 );
3009+ else
3010+ return false ;
3011+
3012+ *common_ptr = common;
3013+ *czero_code_ptr = czero_code;
3014+ *a_ptr = a;
3015+
3016+ return true ;
3017+ }
3018+
3019+ /* Try to covert if-then-else with conditional zero,
3020+ returning TURE on success or FALSE on failure.
3021+ IF_INFO describes the if-conversion scenario under consideration. */
3022+
3023+ static int
3024+ noce_try_cond_zero_arith (struct noce_if_info *if_info)
3025+ {
3026+ rtx target, a;
3027+ rtx_insn *seq;
3028+ machine_mode mode = GET_MODE (if_info->x );
3029+ rtx common = NULL_RTX;
3030+ enum rtx_code czero_code = UNKNOWN;
3031+ rtx non_zero_op = NULL_RTX;
3032+ rtx *to_replace = NULL ;
3033+
3034+ if (!noce_bbs_ok_for_cond_zero_arith (if_info, &common, &czero_code, &a,
3035+ &to_replace))
3036+ return false ;
3037+
3038+ non_zero_op = *to_replace;
3039+
3040+ start_sequence ();
3041+
3042+ /* If x is used in both input and out like x = c ? x + z : x,
3043+ use a new reg to avoid modifying x */
3044+ if (common && rtx_equal_p (common, if_info->x ))
3045+ target = gen_reg_rtx (mode);
3046+ else
3047+ target = if_info->x ;
3048+
3049+ target = noce_emit_czero (if_info, czero_code, non_zero_op, target);
3050+ if (!target || !to_replace)
3051+ {
3052+ end_sequence ();
3053+ return false ;
3054+ }
3055+
3056+ *to_replace = target;
3057+ noce_emit_move_insn (if_info->x , a);
3058+
3059+ seq = end_ifcvt_sequence (if_info);
3060+ if (!seq || !targetm.noce_conversion_profitable_p (seq, if_info))
3061+ return false ;
3062+
3063+ emit_insn_before_setloc (seq, if_info->jump , INSN_LOCATION (if_info->insn_a ));
3064+ if_info->transform_name = " noce_try_cond_zero_arith" ;
3065+ return true ;
3066+ }
28833067
28843068/* Optimize away "if (x & C) x |= C" and similar bit manipulation
28853069 transformations. */
@@ -3937,6 +4121,9 @@ noce_process_if_block (struct noce_if_info *if_info)
39374121 goto success;
39384122 if (noce_try_store_flag_mask (if_info))
39394123 goto success;
4124+ if (HAVE_conditional_move
4125+ && noce_try_cond_zero_arith (if_info))
4126+ goto success;
39404127 if (HAVE_conditional_move
39414128 && noce_try_cmove_arith (if_info))
39424129 goto success;
0 commit comments