On 2023-11-20 14:59 Jeff Law <jeffreya...@gmail.com> wrote: > > > >On 10/30/23 01:25, Fei Gao wrote: >> Conditional add, if zero >> rd = (rc == 0) ? (rs1 + rs2) : rs1 >> --> >> czero.nez rd, rs2, rc >> add rd, rs1, rd >> >> Conditional add, if non-zero >> rd = (rc != 0) ? (rs1 + rs2) : rs1 >> --> >> czero.eqz rd, rs2, rc >> add rd, rs1, rd >> >> Co-authored-by: Xiao Zeng<zengx...@eswincomputing.com> >> >> gcc/ChangeLog: >> >> * ifcvt.cc (noce_emit_czero): helper for noce_try_cond_zero_arith >> (noce_try_cond_zero_arith): handler for condtional zero op >> (noce_process_if_block): add noce_try_cond_zero_arith with hook >>control >> >> gcc/testsuite/ChangeLog: >> >> * gcc.target/riscv/zicond_ifcvt_opt.c: New test. >> --- >> gcc/ifcvt.cc | 112 +++++++++++++++ >> .../gcc.target/riscv/zicond_ifcvt_opt.c | 130 ++++++++++++++++++ >> 2 files changed, 242 insertions(+) >> create mode 100644 gcc/testsuite/gcc.target/riscv/zicond_ifcvt_opt.c >> >> diff --git a/gcc/ifcvt.cc b/gcc/ifcvt.cc >> index a0af553b9ff..4f98c1c7bf9 100644 >> --- a/gcc/ifcvt.cc >> +++ b/gcc/ifcvt.cc >> @@ -781,12 +781,14 @@ static bool noce_try_store_flag_constants (struct >> noce_if_info *); >> static bool noce_try_store_flag_mask (struct noce_if_info *); >> static rtx noce_emit_cmove (struct noce_if_info *, rtx, enum rtx_code, rtx, >> rtx, rtx, rtx, rtx = NULL, rtx = NULL); >> +static rtx noce_emit_czero (struct noce_if_info *, enum rtx_code, rtx, rtx); >> static bool noce_try_cmove (struct noce_if_info *); >> static bool noce_try_cmove_arith (struct noce_if_info *); >> static rtx noce_get_alt_condition (struct noce_if_info *, rtx, rtx_insn >>**); >> static bool noce_try_minmax (struct noce_if_info *); >> static bool noce_try_abs (struct noce_if_info *); >> static bool noce_try_sign_mask (struct noce_if_info *); >> +static bool noce_try_cond_zero_arith (struct noce_if_info *); >> >> /* Return the comparison code for reversed condition for IF_INFO, >> or UNKNOWN if reversing the condition is not possible. */ >> @@ -1831,6 +1833,32 @@ noce_emit_cmove (struct noce_if_info *if_info, rtx x, >> enum rtx_code code, >> return NULL_RTX; >> } >> >> +static rtx >> +noce_emit_czero (struct noce_if_info *if_info, enum rtx_code czero_code, >> rtx z, rtx target) >Every function needs a comment describing what the function does, it's >return value(s) and its arguments. There are many examples in ifcvt.cc >you can use to guide you. I might start with something like this: > >/* Emit a conditional zero, returning the location of the result > or NULL_RTX upon failure. > > IF_INFO describes the if-conversion scenario under consideration. > CZERO_CODE selects the condition (EQ/NE). > Z is the nonzero operand of the conditional move > TARGET is the desired output register. */ > >Or something like that. I would suggest renaming "Z" to something more >meaningful. Hi Jeff
Thanks for your patients. All comments regarding coding style have been addressed in new patches. > > > >> >> +/* Convert x = c ? y + z : y or x = c ? y : y + z. */ >> + >> +static bool >> +noce_try_cond_zero_arith (struct noce_if_info *if_info) >The function comment really should be improved. For example it doesn't >indicate what the return value is. > >> + >> + /* cond must be EQ or NEQ comparision of a reg and 0. */ >In general when you refer to a variable in a comment, do so in upper >case. Use NE rather than NEQ as the former is how most code refers to a >not-equal rtx code. > > >> + if (GET_CODE (cond) != NE && GET_CODE (cond) != EQ) >> + return false; >> + if (!REG_P (XEXP (cond, 0)) || !rtx_equal_p (XEXP (cond, 1), const0_rtx)) >> + return false; >> + >> + /* check y + z:y*/ >> + if (GET_CODE (a) == PLUS && REG_P (XEXP (a, 0)) && REG_P (XEXP (a, 1)) >> + && REG_P (b) && rtx_equal_p (XEXP (a, 0), b)) >Write comments as complete sentences. > >> + { >> + common = b; >> + z = XEXP (a, 1); >Rather than "z" use a more descriptive variable name. > > >> + >> + /* If we have x = c ? x + z : x, use a new reg to avoid modifying x */ >> + if (common && rtx_equal_p (common, if_info->x)) >> + target = gen_reg_rtx (mode); >> + else >> + target = if_info->x; >if-conversion runs both before and after register allocation. So you >have to handle the case where you can not generate new registers. Use >can_create_pseudo_p () to test for that. You may need to fail if you >can't generate a new register. 1. In find_if_header function, I found the following piece of codes: if (!reload_completed && noce_find_if_block(...)), and find_if_header must be called before noce_try_cond_zero_arith(). 2. In noce_try_strore_flag_constants, new registers are also generated without can_create_pseudo_p() check. So I guess no need to add can_create_pseudo_p() here. > >> + >> + target = noce_emit_czero (if_info, czero_code, z, target); >> + if (!target) >> + { >> + end_sequence (); >> + return false; >> + } >> + >> + target = expand_simple_binop (mode, PLUS, common, target, if_info->x, 0, >> + OPTAB_DIRECT); >I think you want OPTAB_WIDEN and in the other calls. > >> @@ -3975,6 +4085,8 @@ noce_process_if_block (struct noce_if_info *if_info) >> goto success; >> if (noce_try_store_flag_mask (if_info)) >> goto success; >> + if (targetm.have_cond_zero () && noce_try_cond_zero_arith (if_info)) >> + goto success; >Replace targetm.have_cond_zero with HAVE_conditional_move since that's >the RTL primitive we're building from. Done. > > >> >> +**test_ADD_ceqz: >> +** czero\.eqz a3,a2,a3 >> +** add a0,a1,a3 >> +** ret >Please don't use explicit registers unless you know they will always be >correct. In this sequence there's no guarantee the register allocator >will put the result of the czero.eqz into $a3. Use a suitable regexp >instead to match a variety of registers. This will be an issue for all >your new tests. Done. BR, Fei > > > >Jeff