Patch is rebased and merged with other changes according to comments. Thanks! -Zhenqiang
> -----Original Message----- > From: gcc-patches-ow...@gcc.gnu.org [mailto:gcc-patches- > ow...@gcc.gnu.org] On Behalf Of Zhenqiang Chen > Sent: Tuesday, September 23, 2014 2:44 PM > To: gcc-patches@gcc.gnu.org > Subject: [Ping] [PATCH, 4/10] expand ccmp > > Ping? > > Patch is rebased and regenerated since "[PATCH, 3/10] skip swapping > operands used in ccmp" is discarded. > > Please find the updated patch in attachment. > > Bootstrap and no make check regression on X86-64. > > Thanks! > -Zhenqiang > > ChangeLog: > 2014-09-23 Zhenqiang Chen <zhenqiang.c...@linaro.org> > > * ccmp.c: New file. > * ccmp.h: New file. > * Makefile.in: Add ccmp.o > * expr.c: #include "ccmp.h" > (expand_expr_real_1): Try to expand ccmp. > > > -----Original Message----- > > From: gcc-patches-ow...@gcc.gnu.org [mailto:gcc-patches- > > ow...@gcc.gnu.org] On Behalf Of Zhenqiang Chen > > Sent: Tuesday, July 01, 2014 4:01 PM > > To: Richard Earnshaw > > Cc: gcc-patches@gcc.gnu.org > > Subject: Re: [PATCH, 4/10] expand ccmp > > > > On 25 June 2014 23:16, Richard Earnshaw <rearn...@arm.com> wrote: > > > On 23/06/14 07:59, Zhenqiang Chen wrote: > > >> Hi, > > >> > > >> This patch includes the main logic to expand ccmp instructions. > > >> > > >> In the patch, > > >> * ccmp_candidate_p is used to identify the CCMP candidate > > >> * expand_ccmp_expr is the main entry, which calls > > expand_ccmp_expr_1 > > >> to expand CCMP. > > >> * expand_ccmp_expr_1 uses a recursive algorithm to expand CCMP. > > >> It calls gen_ccmp_first and gen_ccmp_next to generate CCMP > > instructions. > > >> > > >> During expanding, we must make sure that no instruction can > > >> clobber > > the > > >> CC reg except the compares. So clobber_cc_p and > > >> check_clobber_cc > > are > > >> introduced to do the check. > > >> > > >> * If the final result is not used in a COND_EXPR (checked by function > > >> used_in_cond_stmt_p), it calls cstorecc4 pattern to store the > > >> CC to > a > > >> general register. > > >> > > >> Bootstrap and no make check regression on X86-64. > > >> > > >> OK for trunk? > > >> > > >> Thanks! > > >> -Zhenqiang > > >> > > >> ChangeLog: > > >> 2014-06-23 Zhenqiang Chen <zhenqiang.c...@linaro.org> > > >> > > >> * ccmp.c (ccmp_candidate_p, used_in_cond_stmt_p, > > check_clobber_cc, > > >> clobber_cc_p, expand_ccmp_next, expand_ccmp_expr_1, > > expand_ccmp_expr): > > >> New functions to expand ccmp. > > >> * ccmp.h (expand_ccmp_expr): New prototype. > > >> * expr.c: #include "ccmp.h" > > >> (expand_expr_real_1): Try to expand ccmp. > > >> > > >> diff --git a/gcc/ccmp.c b/gcc/ccmp.c index 665c2a5..97b3910 100644 > > >> --- a/gcc/ccmp.c > > >> +++ b/gcc/ccmp.c > > >> @@ -47,6 +47,262 @@ along with GCC; see the file COPYING3. If not > > >> see #include "expmed.h" > > >> #include "ccmp.h" > > >> > > >> +/* The following functions expand conditional compare (CCMP) > > instructions. > > >> + Here is a short description about the over all algorithm: > > >> + * ccmp_candidate_p is used to identify the CCMP candidate > > >> + > > >> + * expand_ccmp_expr is the main entry, which calls > > expand_ccmp_expr_1 > > >> + to expand CCMP. > > >> + > > >> + * expand_ccmp_expr_1 uses a recursive algorithm to expand CCMP. > > >> + It calls two target hooks gen_ccmp_first and gen_ccmp_next > > >> + to > > generate > > >> + CCMP instructions. > > >> + - gen_ccmp_first expands the first compare in CCMP. > > >> + - gen_ccmp_next expands the following compares. > > >> + > > >> + During expanding, we must make sure that no instruction can > clobber > > the > > >> + CC reg except the compares. So clobber_cc_p and > check_clobber_cc > > are > > >> + introduced to do the check. > > >> + > > >> + * If the final result is not used in a COND_EXPR (checked by > function > > >> + used_in_cond_stmt_p), it calls cstorecc4 pattern to store > > >> + the > CC to a > > >> + general register. */ > > >> + > > >> +/* Check whether G is a potential conditional compare candidate. > > >> +*/ static bool ccmp_candidate_p (gimple g) { > > >> + tree rhs = gimple_assign_rhs_to_tree (g); > > >> + tree lhs, op0, op1; > > >> + gimple gs0, gs1; > > >> + enum tree_code tcode, tcode0, tcode1; > > >> + tcode = TREE_CODE (rhs); > > >> + > > >> + if (tcode != BIT_AND_EXPR && tcode != BIT_IOR_EXPR) > > >> + return false; > > >> + > > >> + lhs = gimple_assign_lhs (g); > > >> + op0 = TREE_OPERAND (rhs, 0); > > >> + op1 = TREE_OPERAND (rhs, 1); > > >> + > > >> + if ((TREE_CODE (op0) != SSA_NAME) || (TREE_CODE (op1) != > > SSA_NAME) > > >> + || !has_single_use (lhs)) > > >> + return false; > > >> + > > >> + gs0 = get_gimple_for_ssa_name (op0); > > >> + gs1 = get_gimple_for_ssa_name (op1); if (!gs0 || !gs1 || > > >> + !is_gimple_assign (gs0) || !is_gimple_assign (gs1) > > >> + /* g, gs0 and gs1 must be in the same basic block, since > > >> + current > stage > > >> + is out-of-ssa. We can not guarantee the correctness when > > forwording > > >> + the gs0 and gs1 into g whithout DATAFLOW analysis. */ > > >> + || gimple_bb (gs0) != gimple_bb (gs1) > > >> + || gimple_bb (gs0) != gimple_bb (g)) > > >> + return false; > > >> + > > >> + if (!(INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (gs0))) > > >> + || POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (gs0)))) > > >> + || !(INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (gs1))) > > >> + || POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (gs1))))) > > >> + return false; > > >> + > > >> + tcode0 = gimple_assign_rhs_code (gs0); > > >> + tcode1 = gimple_assign_rhs_code (gs1); > > >> + if (TREE_CODE_CLASS (tcode0) == tcc_comparison > > >> + && TREE_CODE_CLASS (tcode1) == tcc_comparison) > > >> + return true; > > >> + if (TREE_CODE_CLASS (tcode0) == tcc_comparison > > >> + && ccmp_candidate_p (gs1)) > > >> + return true; > > >> + else if (TREE_CODE_CLASS (tcode1) == tcc_comparison > > >> + && ccmp_candidate_p (gs0)) > > >> + return true; > > >> + /* We skip ccmp_candidate_p (gs1) && ccmp_candidate_p (gs0) since > > >> + there is no way to set the CC flag. */ > > >> + return false; > > >> +} > > >> + > > >> +/* Check whether EXP is used in a GIMPLE_COND statement or not. > > >> +*/ static bool used_in_cond_stmt_p (tree exp) { > > >> + bool expand_cond = false; > > >> + imm_use_iterator ui; > > >> + gimple use_stmt; > > >> + FOR_EACH_IMM_USE_STMT (use_stmt, ui, exp) > > >> + if (gimple_code (use_stmt) == GIMPLE_COND) > > >> + { > > >> + tree op1 = gimple_cond_rhs (use_stmt); > > >> + if (integer_zerop (op1)) > > >> + expand_cond = true; > > >> + BREAK_FROM_IMM_USE_STMT (ui); > > >> + } > > >> + return expand_cond; > > >> +} > > >> + > > >> +/* If SETTER clobber CC reg, set DATA to TRUE. */ static void > > >> +check_clobber_cc (rtx reg, const_rtx setter, void *data) { > > >> + if (GET_CODE (setter) == CLOBBER && GET_MODE (reg) == CCmode) > > > > > > You shouldn't assume that CC regs will only ever have mode CCmode. > > > It's probably better to check for the mode class being MODE_CC. > > > Also, not all architectures have a single CC register, so this test > > > might be unduly restrictive on targets with multiple predicate registers. > > > > Thanks for the comments. The code segment is removed as the update for > > the following comments "hoist any preparation operations above the > > entire conditional compare sequence" > > > > >> + *(bool *)data = true; > > >> +} > > >> + > > >> +/* Check whether INSN and all its NEXT_INSN clobber CC reg or not. > > >> +*/ static bool clobber_cc_p (rtx insn) { > > >> + bool clobber = false; > > >> + for (; insn; insn = NEXT_INSN (insn)) > > >> + { > > >> + note_stores (PATTERN (insn), check_clobber_cc, &clobber); > > >> + if (clobber) > > >> + return true; > > >> + } > > >> + return false; > > >> +} > > >> + > > >> +/* Help function to generate conditional compare. PREV is the > > >> +result > of > > >> + GEN_CCMP_FIRST or GEN_CCMP_NEXT. G is the next compare. > > >> + CODE is BIT_AND_EXPR or BIT_IOR_EXPR. */ static rtx > > >> +expand_ccmp_next (rtx prev, gimple g, enum tree_code code) { > > >> + rtx op0, op1; > > >> + int unsignedp = TYPE_UNSIGNED (TREE_TYPE (gimple_assign_rhs1 > > >> +(g))); > > >> + enum rtx_code rcode = get_rtx_code (gimple_assign_rhs_code (g), > > >> +unsignedp); > > >> + rtx last = get_last_insn (); > > >> + > > >> + expand_operands (gimple_assign_rhs1 (g), > > >> + gimple_assign_rhs2 (g), > > >> + NULL_RTX, &op0, &op1, EXPAND_NORMAL); > > >> + > > >> + /* If any operand clobbers CC reg, we will give up. */ if > > >> + (clobber_cc_p (NEXT_INSN (last))) > > >> + return NULL_RTX; > > >> + > > > > > > I suspect it might be better to just hoist any preparation > > > operations above the entire conditional compare sequence, so that by > > > the time we start the ccmp expansion we're dealing with operands > > > that are in the 'natural' sizes for the machine (breaking up the > > > conditional compare sequence for what are almost side-effect > > > operationssounds like a source of potential bugs). This would also > > > ensure that the back-end can safely re-order at least some > > > comparison operations if this leads a workable conditional compare > sequence. > > > > Updated. All the preparation operations are moved above the entire > > conditional compare sequence. > > > > > For example, in ARM > > > > > > (a < b && c <= d) > > > > > > has to be computed as > > > cmp c, d > > > cmple a, b > > > ...lt true-op > > > ...ge false-op > > > > > > since the sequence > > > cmp a, b > > > cmplt c, d > > > ...le true-op > > > > > > would lead to the wrong behaviour when a == b and c == d. > > > > > > > > >> + return targetm.gen_ccmp_next (prev, rcode, op0, op1, > > >> +get_rtx_code (code, 0)); } > > >> + > > >> +/* Expand conditional compare gimple G. A typical CCMP sequence > > >> +is > > like: > > >> + > > >> + CC0 = CMP (a, b); > > >> + CC1 = CCMP (NE (CC0, 0), CMP (e, f)); > > >> + ... > > >> + CCn = CCMP (NE (CCn-1, 0), CMP (...)); > > >> + > > >> + hook gen_ccmp_first is used to expand the first compare. > > >> + hook gen_ccmp_next is used to expand the following CCMP. */ > > >> +static rtx > > >> +expand_ccmp_expr_1 (gimple g) > > >> +{ > > >> + tree exp = gimple_assign_rhs_to_tree (g); > > >> + enum tree_code code = TREE_CODE (exp); > > >> + gimple gs0 = get_gimple_for_ssa_name (TREE_OPERAND (exp, 0)); > > >> + gimple gs1 = get_gimple_for_ssa_name (TREE_OPERAND (exp, 1)); > > >> + rtx tmp; > > >> + enum tree_code code0 = gimple_assign_rhs_code (gs0); > > >> + enum tree_code code1 = gimple_assign_rhs_code (gs1); > > >> + > > >> + gcc_assert (code == BIT_AND_EXPR || code == BIT_IOR_EXPR); > > >> + gcc_assert (gs0 && gs1 && is_gimple_assign (gs0) && > > >> + is_gimple_assign (gs1)); > > >> + > > >> + if (TREE_CODE_CLASS (code0) == tcc_comparison) > > >> + { > > >> + if (TREE_CODE_CLASS (code1) == tcc_comparison) > > >> + { > > >> + int unsignedp0, unsignedp1; > > >> + enum rtx_code rcode0, rcode1; > > >> + rtx op0, op1, op2, op3, tmp; > > >> + > > >> + unsignedp0 = TYPE_UNSIGNED (TREE_TYPE (gimple_assign_rhs1 > > (gs0))); > > >> + rcode0 = get_rtx_code (code0, unsignedp0); > > >> + unsignedp1 = TYPE_UNSIGNED (TREE_TYPE (gimple_assign_rhs1 > > (gs1))); > > >> + rcode1 = get_rtx_code (code1, unsignedp1); > > >> + > > >> + expand_operands (gimple_assign_rhs1 (gs0), > > >> + gimple_assign_rhs2 (gs0), > > >> + NULL_RTX, &op0, &op1, EXPAND_NORMAL); > > >> + > > >> + /* Since the operands of GS1 might clobber CC reg, we > > >> + expand > the > > >> + operands of GS1 before GEN_CCMP_FIRST. */ > > >> + expand_operands (gimple_assign_rhs1 (gs1), > > >> + gimple_assign_rhs2 (gs1), > > >> + NULL_RTX, &op2, &op3, EXPAND_NORMAL); > > >> + tmp = targetm.gen_ccmp_first (rcode0, op0, op1); > > >> + if (!tmp) > > >> + return NULL_RTX; > > >> + > > >> + return targetm.gen_ccmp_next (tmp, rcode1, op2, op3, > > >> + get_rtx_code (code, 0)); > > >> + } > > >> + else > > >> + { > > >> + gcc_assert (code1 == BIT_AND_EXPR || code1 == > > >> + BIT_IOR_EXPR); > > >> + > > >> + /* Note: We swap the order to make the recursive function > work. > > */ > > >> + tmp = expand_ccmp_expr_1 (gs1); > > >> + if (tmp) > > >> + return expand_ccmp_next (tmp, gs0, code); > > >> + } > > >> + } > > >> + else > > >> + { > > >> + gcc_assert (gimple_assign_rhs_code (gs0) == BIT_AND_EXPR > > >> + || gimple_assign_rhs_code (gs0) == BIT_IOR_EXPR); > > >> + if (TREE_CODE_CLASS (gimple_assign_rhs_code (gs1)) == > > tcc_comparison) > > >> + { > > >> + tmp = expand_ccmp_expr_1 (gs0); > > >> + if (tmp) > > >> + return expand_ccmp_next (tmp, gs1, code); > > >> + } > > >> + else > > >> + { > > >> + gcc_assert (gimple_assign_rhs_code (gs1) == BIT_AND_EXPR > > >> + || gimple_assign_rhs_code (gs1) == BIT_IOR_EXPR); > > >> + } > > >> + } > > >> + > > >> + return NULL_RTX; > > >> +} > > >> + > > >> +rtx > > >> +expand_ccmp_expr (gimple g) > > >> +{ > > >> + rtx last, tmp; > > >> + > > >> + if (!ccmp_candidate_p (g)) > > >> + return NULL_RTX; > > >> + > > >> + last = get_last_insn (); > > >> + tmp = expand_ccmp_expr_1 (g); > > >> + > > >> + if (tmp) > > >> + { > > >> + enum insn_code icode; > > >> + tree lhs = gimple_assign_lhs (g); > > >> + /* TMP should be CC. If it is used in a GIMPLE_COND, just > return it. > > >> + Note: Target needs to define "cbranchcc4". */ > > >> + if (used_in_cond_stmt_p (lhs)) > > >> + return tmp; > > >> + > > >> + /* If TMP is not used in a GIMPLE_COND, store it with a > > csctorecc4_optab. > > >> + Note: Target needs to define "cstorecc4". */ > > >> + icode = optab_handler (cstore_optab, CCmode); > > > > > > I think you should be using SELECT_CC_MODE here. > > > > Updated. > > > > diff --git a/gcc/ccmp.c b/gcc/ccmp.c > > index fb51129..e0670f1 100644 > > --- a/gcc/ccmp.c > > +++ b/gcc/ccmp.c > > @@ -22,6 +22,7 @@ along with GCC; see the file COPYING3. If not see > > #include "coretypes.h" > > #include "tm.h" > > #include "rtl.h" > > +#include "tm_p.h" > > #include "tree.h" > > #include "stringpool.h" > > #include "regs.h" > > @@ -47,6 +48,245 @@ along with GCC; see the file COPYING3. If not see > > #include "expmed.h" > > #include "ccmp.h" > > > > +/* The following functions expand conditional compare (CCMP) > instructions. > > + Here is a short description about the over all algorithm: > > + * ccmp_candidate_p is used to identify the CCMP candidate > > + > > + * expand_ccmp_expr is the main entry, which calls > > expand_ccmp_expr_1 > > + to expand CCMP. > > + > > + * expand_ccmp_expr_1 uses a recursive algorithm to expand CCMP. > > + It calls two target hooks gen_ccmp_first and gen_ccmp_next to > > generate > > + CCMP instructions. > > + - gen_ccmp_first expands the first compare in CCMP. > > + - gen_ccmp_next expands the following compares. > > + > > + * If the final result is not used in a COND_EXPR (checked by > function > > + used_in_cond_stmt_p), it calls cstorecc4 pattern to store the > > + CC > to a > > + general register. */ > > + > > +/* Check whether G is a potential conditional compare candidate. */ > > +static bool ccmp_candidate_p (gimple g) { > > + tree rhs = gimple_assign_rhs_to_tree (g); > > + tree lhs, op0, op1; > > + gimple gs0, gs1; > > + enum tree_code tcode, tcode0, tcode1; > > + tcode = TREE_CODE (rhs); > > + > > + if (tcode != BIT_AND_EXPR && tcode != BIT_IOR_EXPR) > > + return false; > > + > > + lhs = gimple_assign_lhs (g); > > + op0 = TREE_OPERAND (rhs, 0); > > + op1 = TREE_OPERAND (rhs, 1); > > + > > + if ((TREE_CODE (op0) != SSA_NAME) || (TREE_CODE (op1) != SSA_NAME) > > + || !has_single_use (lhs)) > > + return false; > > + > > + gs0 = get_gimple_for_ssa_name (op0); > > + gs1 = get_gimple_for_ssa_name (op1); if (!gs0 || !gs1 || > > + !is_gimple_assign (gs0) || !is_gimple_assign (gs1) > > + /* g, gs0 and gs1 must be in the same basic block, since > > + current > stage > > + is out-of-ssa. We can not guarantee the correctness when > forwording > > + the gs0 and gs1 into g whithout DATAFLOW analysis. */ > > + || gimple_bb (gs0) != gimple_bb (gs1) > > + || gimple_bb (gs0) != gimple_bb (g)) > > + return false; > > + > > + if (!(INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (gs0))) > > + || POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (gs0)))) > > + || !(INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (gs1))) > > + || POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (gs1))))) > > + return false; > > + > > + tcode0 = gimple_assign_rhs_code (gs0); > > + tcode1 = gimple_assign_rhs_code (gs1); > > + if (TREE_CODE_CLASS (tcode0) == tcc_comparison > > + && TREE_CODE_CLASS (tcode1) == tcc_comparison) > > + return true; > > + if (TREE_CODE_CLASS (tcode0) == tcc_comparison > > + && ccmp_candidate_p (gs1)) > > + return true; > > + else if (TREE_CODE_CLASS (tcode1) == tcc_comparison > > + && ccmp_candidate_p (gs0)) > > + return true; > > + /* We skip ccmp_candidate_p (gs1) && ccmp_candidate_p (gs0) since > > + there is no way to set the CC flag. */ > > + return false; > > +} > > + > > +/* Check whether EXP is used in a GIMPLE_COND statement or not. */ > > +static bool used_in_cond_stmt_p (tree exp) { > > + bool expand_cond = false; > > + imm_use_iterator ui; > > + gimple use_stmt; > > + FOR_EACH_IMM_USE_STMT (use_stmt, ui, exp) > > + if (gimple_code (use_stmt) == GIMPLE_COND) > > + { > > + tree op1 = gimple_cond_rhs (use_stmt); > > + if (integer_zerop (op1)) > > + expand_cond = true; > > + BREAK_FROM_IMM_USE_STMT (ui); > > + } > > + return expand_cond; > > +} > > + > > +/* Expand conditional compare gimple G. A typical CCMP sequence is like: > > + > > + CC0 = CMP (a, b); > > + CC1 = CCMP (NE (CC0, 0), CMP (e, f)); > > + ... > > + CCn = CCMP (NE (CCn-1, 0), CMP (...)); > > + > > + hook gen_ccmp_first is used to expand the first compare. > > + hook gen_ccmp_next is used to expand the following CCMP. */ > > +static rtx > > +expand_ccmp_expr_1 (gimple g) > > +{ > > + tree exp = gimple_assign_rhs_to_tree (g); > > + enum tree_code code = TREE_CODE (exp); > > + gimple gs0 = get_gimple_for_ssa_name (TREE_OPERAND (exp, 0)); > > + gimple gs1 = get_gimple_for_ssa_name (TREE_OPERAND (exp, 1)); > > + rtx tmp; > > + enum tree_code code0 = gimple_assign_rhs_code (gs0); > > + enum tree_code code1 = gimple_assign_rhs_code (gs1); > > + > > + gcc_assert (code == BIT_AND_EXPR || code == BIT_IOR_EXPR); > > + gcc_assert (gs0 && gs1 && is_gimple_assign (gs0) && is_gimple_assign > > + (gs1)); > > + > > + if (TREE_CODE_CLASS (code0) == tcc_comparison) > > + { > > + if (TREE_CODE_CLASS (code1) == tcc_comparison) > > + { > > + int unsignedp0, unsignedp1; > > + enum rtx_code rcode0, rcode1; > > + rtx op0, op1, op2, op3, tmp; > > + > > + unsignedp0 = TYPE_UNSIGNED (TREE_TYPE (gimple_assign_rhs1 > (gs0))); > > + rcode0 = get_rtx_code (code0, unsignedp0); > > + unsignedp1 = TYPE_UNSIGNED (TREE_TYPE (gimple_assign_rhs1 > (gs1))); > > + rcode1 = get_rtx_code (code1, unsignedp1); > > + > > + expand_operands (gimple_assign_rhs1 (gs0), > > + gimple_assign_rhs2 (gs0), > > + NULL_RTX, &op0, &op1, EXPAND_NORMAL); > > + > > + /* Since the operands of GS1 might clobber CC reg, we expand the > > + operands of GS1 before GEN_CCMP_FIRST. */ > > + expand_operands (gimple_assign_rhs1 (gs1), > > + gimple_assign_rhs2 (gs1), > > + NULL_RTX, &op2, &op3, EXPAND_NORMAL); > > + tmp = targetm.gen_ccmp_first (rcode0, op0, op1); > > + if (!tmp) > > + return NULL_RTX; > > + > > + return targetm.gen_ccmp_next (tmp, rcode1, op2, op3, > > + get_rtx_code (code, 0)); > > + } > > + else > > + { > > + rtx op0, op1; > > + enum rtx_code rcode; > > + int unsignedp = TYPE_UNSIGNED (TREE_TYPE (gimple_assign_rhs1 > > + (gs0))); > > + > > + rcode = get_rtx_code (gimple_assign_rhs_code (gs0), > > + unsignedp); > > + > > + /* Hoist the preparation operations above the entire > > + conditional compare sequence. */ > > + expand_operands (gimple_assign_rhs1 (gs0), > > + gimple_assign_rhs2 (gs0), > > + NULL_RTX, &op0, &op1, EXPAND_NORMAL); > > + > > + gcc_assert (code1 == BIT_AND_EXPR || code1 == BIT_IOR_EXPR); > > + > > + /* Note: We swap the order to make the recursive function work. > */ > > + tmp = expand_ccmp_expr_1 (gs1); > > + if (tmp) > > + return targetm.gen_ccmp_next (tmp, rcode, op0, op1, > > + get_rtx_code (code, 0)); > > + } > > + } > > + else > > + { > > + gcc_assert (gimple_assign_rhs_code (gs0) == BIT_AND_EXPR > > + || gimple_assign_rhs_code (gs0) == BIT_IOR_EXPR); > > + > > + if (TREE_CODE_CLASS (gimple_assign_rhs_code (gs1)) == > > tcc_comparison) > > + { > > + rtx op0, op1; > > + enum rtx_code rcode; > > + int unsignedp = TYPE_UNSIGNED (TREE_TYPE (gimple_assign_rhs1 > > + (gs1))); > > + > > + rcode = get_rtx_code (gimple_assign_rhs_code (gs1), > > + unsignedp); > > + > > + /* Hoist the preparation operations above the entire > > + conditional compare sequence. */ > > + expand_operands (gimple_assign_rhs1 (gs1), > > + gimple_assign_rhs2 (gs1), > > + NULL_RTX, &op0, &op1, EXPAND_NORMAL); > > + tmp = expand_ccmp_expr_1 (gs0); > > + if (tmp) > > + return targetm.gen_ccmp_next (tmp, rcode, op0, op1, > > + get_rtx_code (code, 0)); > > + } > > + else > > + { > > + gcc_assert (gimple_assign_rhs_code (gs1) == BIT_AND_EXPR > > + || gimple_assign_rhs_code (gs1) == BIT_IOR_EXPR); > > + } > > + } > > + > > + return NULL_RTX; > > +} > > + > > +rtx > > +expand_ccmp_expr (gimple g) > > +{ > > + rtx last, tmp; > > + > > + if (!ccmp_candidate_p (g)) > > + return NULL_RTX; > > + > > + last = get_last_insn (); > > + tmp = expand_ccmp_expr_1 (g); > > + > > + if (tmp) > > + { > > + enum insn_code icode; > > + enum machine_mode cc_mode = CCmode; > > + > > + tree lhs = gimple_assign_lhs (g); > > + /* TMP should be CC. If it is used in a GIMPLE_COND, just > > + return > it. > > + Note: Target needs to define "cbranchcc4". */ > > + if (used_in_cond_stmt_p (lhs)) > > + return tmp; > > + > > +#ifdef SELECT_CC_MODE > > + cc_mode = SELECT_CC_MODE (NE, tmp, const0_rtx); #endif > > + /* If TMP is not used in a GIMPLE_COND, store it with a > > csctorecc4_optab. > > + Note: Target needs to define "cstorecc4". */ > > + icode = optab_handler (cstore_optab, cc_mode); > > + if (icode != CODE_FOR_nothing) > > + { > > + rtx target = gen_reg_rtx (word_mode); > > + tmp = emit_cstore (target, icode, NE, cc_mode, cc_mode, > > + 0, tmp, const0_rtx, 1, word_mode); > > + if (tmp) > > + return tmp; > > + } > > + } > > + > > + /* Clean up. */ > > + delete_insns_since (last); > > + return NULL_RTX; > > +} > > + > > bool > > ccmp_insn_p (rtx object) > > { > > diff --git a/gcc/ccmp.h b/gcc/ccmp.h > > index 7e139aa..56f3ac2 100644 > > --- a/gcc/ccmp.h > > +++ b/gcc/ccmp.h > > @@ -20,6 +20,8 @@ along with GCC; see the file COPYING3. If not see > > #ifndef GCC_CCMP_H #define GCC_CCMP_H > > > > +extern rtx expand_ccmp_expr (gimple); > > + > > extern bool ccmp_insn_p (rtx); > > > > #endif /* GCC_CCMP_H */ > > diff --git a/gcc/expr.c b/gcc/expr.c > > index 04cf56e..4c31521 100644 > > --- a/gcc/expr.c > > +++ b/gcc/expr.c > > @@ -68,6 +68,7 @@ along with GCC; see the file COPYING3. If not see > > #include "tree-ssa-address.h" > > #include "cfgexpand.h" > > #include "builtins.h" > > +#include "ccmp.h" > > > > #ifndef STACK_PUSH_CODE > > #ifdef STACK_GROWS_DOWNWARD > > @@ -9379,6 +9380,15 @@ expand_expr_real_1 (tree exp, rtx target, enum > > machine_mode tmode, > > /* Fallthru */ > > case GIMPLE_BINARY_RHS: > > ops.op1 = gimple_assign_rhs2 (g); > > + > > + /* Try to expand conditonal compare. */ > > + if (targetm.gen_ccmp_first != NULL) > > + { > > + gcc_checking_assert (targetm.gen_ccmp_next != NULL); > > + r = expand_ccmp_expr (g); > > + if (r) > > + break; > > + } > > /* Fallthru */ > > case GIMPLE_UNARY_RHS: > > ops.op0 = gimple_assign_rhs1 (g);
3-4-ccmp.patch
Description: Binary data