@@ -787,6 +787,7 @@ static rtx noce_get_alt_condition (struct noce_if_info *, rtx, rtx_insn **);
787
787
static bool noce_try_minmax (struct noce_if_info *);
788
788
static bool noce_try_abs (struct noce_if_info *);
789
789
static bool noce_try_sign_mask (struct noce_if_info *);
790
+ static int noce_try_cond_zero_arith (struct noce_if_info *);
790
791
791
792
/* Return the comparison code for reversed condition for IF_INFO,
792
793
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,
1831
1832
return NULL_RTX;
1832
1833
}
1833
1834
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
+
1834
1864
/* Try only simple constants and registers here. More complex cases
1835
1865
are handled in noce_try_cmove_arith after noce_try_store_flag_arith
1836
1866
has had a go at it. */
@@ -2880,6 +2910,160 @@ noce_try_sign_mask (struct noce_if_info *if_info)
2880
2910
return true ;
2881
2911
}
2882
2912
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
+ }
2883
3067
2884
3068
/* Optimize away "if (x & C) x |= C" and similar bit manipulation
2885
3069
transformations. */
@@ -3937,6 +4121,9 @@ noce_process_if_block (struct noce_if_info *if_info)
3937
4121
goto success;
3938
4122
if (noce_try_store_flag_mask (if_info))
3939
4123
goto success;
4124
+ if (HAVE_conditional_move
4125
+ && noce_try_cond_zero_arith (if_info))
4126
+ goto success;
3940
4127
if (HAVE_conditional_move
3941
4128
&& noce_try_cmove_arith (if_info))
3942
4129
goto success;
0 commit comments