Skip to content

Commit 9f7ad5e

Browse files
GaoFei-ESWINJeffreyALaw
authored andcommitted
[PATCH 1/5][V3][ifcvt] optimize x=c ? (y op z) : y by RISC-V Zicond like insns
op=[PLUS, MINUS, IOR, XOR] Conditional op, if zero rd = (rc == 0) ? (rs1 op rs2) : rs1 --> czero.nez rd, rs2, rc op rd, rs1, rd Conditional op, if non-zero rd = (rc != 0) ? (rs1 op rs2) : rs1 --> czero.eqz rd, rs2, rc op rd, rs1, rd gcc/ChangeLog: * ifcvt.cc (noce_try_cond_zero_arith): New function. (noce_emit_czero, get_base_reg): Likewise. (noce_cond_zero_binary_op_supported): Likewise. (noce_bbs_ok_for_cond_zero_arith): Likewise. (noce_process_if_block): Use noce_try_cond_zero_arith. Co-authored-by: Xiao Zeng<[email protected]>
1 parent 775aeab commit 9f7ad5e

File tree

2 files changed

+753
-0
lines changed

2 files changed

+753
-0
lines changed

gcc/ifcvt.cc

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -787,6 +787,7 @@ static rtx noce_get_alt_condition (struct noce_if_info *, rtx, rtx_insn **);
787787
static bool noce_try_minmax (struct noce_if_info *);
788788
static bool noce_try_abs (struct noce_if_info *);
789789
static 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

Comments
 (0)