Message ID | 000001cca7f3$c7f07d60$57d17820$@liu@arm.com |
---|---|
State | New |
Headers | show |
The original subject doesn't catch the key point, so I changed the subject to get more people noticed. My question is essentially is "May I really use REG_EXPR in back-end code?" like the patch I gave below? Thanks, -Jiangning > -----Original Message----- > From: gcc-patches-owner@gcc.gnu.org [mailto:gcc-patches- > owner@gcc.gnu.org] On Behalf Of Jiangning Liu > Sent: Monday, November 21, 2011 10:18 AM > To: gcc-patches@gcc.gnu.org > Cc: 'Richard Guenther'; Richard Henderson > Subject: [RFC] Optimization to conditional and/or in ARM back-end > > Hi, > > This patch is to implement a peephole like optimization in ARM back-end. > > If we have an if condition expression like "((r3 != 0) & r1) != 0", > originally the binary code to be generated is like, > > cmp r3, #0 > ite eq > moveq r1, #0 > andne r1, r1, #1 > cmp r1, #0 > > But actually this expression could be transformed into "((r3 != x) & > (r1 != > 0)) != 0", if we know r2 is with bool type. This way we could generate > new > binary code like, > > cmp r3, #0 > it ne > cmpne r1, #0 > > The question is how to judge r2 is a bool variable in back-end. I'm > using > REG_EXPR in function arm_check_logic_with_bool_reg to check if r2 is a > bool, > this function is being invoked in pattern "*cond_<code>". > > May I really use REG_EXPR this way in GCC back-end code? I posted a > related > topic at http://gcc.gnu.org/ml/gcc/2011-11/msg00417.html. > > If the answer is No, is there any suggestions about either how to judge > this > bool type or how to implement this optimization? > > Appreciate your comments in advance! > > Thanks, > -Jiangning > > > diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h > index 23a29c6..8b12d48 > --- a/gcc/config/arm/arm-protos.h > +++ b/gcc/config/arm/arm-protos.h > @@ -114,6 +114,7 @@ extern rtx arm_gen_load_multiple (int *, int, rtx, > int, > rtx, HOST_WIDE_INT *); > extern rtx arm_gen_store_multiple (int *, int, rtx, int, rtx, > HOST_WIDE_INT > *); > extern int arm_gen_movmemqi (rtx *); > extern enum machine_mode arm_select_cc_mode (RTX_CODE, rtx, rtx); > +extern bool arm_check_logic_with_bool_reg (RTX_CODE, rtx, rtx); > extern enum machine_mode arm_select_dominance_cc_mode (rtx, rtx, > HOST_WIDE_INT); > extern rtx arm_gen_compare_reg (RTX_CODE, rtx, rtx); > diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c > index a429c19..e96f24a > --- a/gcc/config/arm/arm.c > +++ b/gcc/config/arm/arm.c > @@ -10910,6 +10910,41 @@ arm_gen_movmemqi (rtx *operands) > return 1; > } > > +/* Check whether the expression "rc <cmp1> <bool_reg>" can be > transformed > + to use conditional comparison or not. */ > +bool > +arm_check_logic_with_bool_reg (RTX_CODE rc, rtx bool_reg, rtx cmp1) { > + rtx cmp2; > + HOST_WIDE_INT dom_cc; > + > + if (!REG_P (bool_reg)) > + return false; > + > + if (REG_EXPR (bool_reg) == NULL) > + return false; > + > + if (TREE_CODE (REG_EXPR (bool_reg)) != VAR_DECL) > + return false; > + > + if (TREE_CODE (TREE_TYPE (REG_EXPR (bool_reg))) != BOOLEAN_TYPE) > + return false; > + > + cmp2 = gen_rtx_NE (GET_MODE (bool_reg), bool_reg, const0_rtx); > + > + if (rc == AND) > + dom_cc = DOM_CC_X_AND_Y; > + else if (rc == IOR) > + dom_cc = DOM_CC_X_OR_Y; > + else > + gcc_unreachable (); > + > + if (arm_select_dominance_cc_mode (cmp1, cmp2, dom_cc) == CCmode) > + return false; > + > + return true; > +} > + > + > /* Select a dominance comparison mode if possible for a test of the > general > form (OP (COND_OR (X) (Y)) (const_int 0)). We support three forms. > COND_OR == DOM_CC_X_AND_Y => (X && Y) > diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md > index a78ba88..e90a78e > --- a/gcc/config/arm/arm.md > +++ b/gcc/config/arm/arm.md > @@ -9172,6 +9172,64 @@ > (set_attr "length" "4,4,8")] > ) > > +; This pattern matches expression like example "((r1 != x) & r2) != 0". > +; Here r2 is a register with data type boolean. > +; This pattern can transform to code matching patterns cmp_and. > +; Likewise, code matching pattern cmp_ior could be generated, if it is > | > +; rather than & in the example. > +(define_insn_and_split "*cond_<code>" > + [(set (match_operand 0 "cc_register" "") > + (compare > + (ior_and:SI > + (match_operator:SI 4 "arm_comparison_operator" > + [(match_operand:SI 2 "s_register_operand" "r,r") > + (match_operand:SI 3 "arm_add_operand" "rI,L")]) > + (match_operand:SI 1 "s_register_operand" "r,r")) > + (const_int 0)))] > + "TARGET_32BIT > + && arm_check_logic_with_bool_reg (<CODE>, operands[1], > operands[4])" > + "#" > + "&& 1" > + [(set (match_dup 7) > + (compare > + (match_op_dup 5 > + [(match_op_dup 4 [(match_dup 2) (match_dup 3)]) > + (match_op_dup 6 [(match_dup 1) (const_int 0)])]) > + (const_int 0)))] > + " > + { > + HOST_WIDE_INT dom_cc; > + > + operands[6] = gen_rtx_NE (SImode, operands[1], const0_rtx); > + > + if (<CODE> == AND) > + { > + dom_cc = DOM_CC_X_AND_Y; > + operands[5] = gen_rtx_fmt_ee (<CODE>, SImode, > + operands[4], operands[6]); > + } > + else if (<CODE> == IOR) > + { > + dom_cc = DOM_CC_X_OR_Y; > + operands[5] = gen_rtx_fmt_ee (<CODE>, SImode, > + operands[4], operands[6]); > + } > + else > + gcc_unreachable (); > + > + operands[7] > + = gen_rtx_REG (arm_select_dominance_cc_mode (operands[4], > + operands[6], > + dom_cc), > + CC_REGNUM); > + }" > + [(set_attr "conds" "clob") > + (set (attr "length") > + (if_then_else (eq_attr "is_thumb" "yes") > + (const_int 10) > + (const_int 8)))] > +) > + > (define_insn "*cond_arith" > [(set (match_operand:SI 0 "s_register_operand" "=r,r") > (match_operator:SI 5 "shiftable_operator" > diff --git a/gcc/config/arm/iterators.md b/gcc/config/arm/iterators.md > index 85dd641..f0a7c7e > --- a/gcc/config/arm/iterators.md > +++ b/gcc/config/arm/iterators.md > @@ -173,6 +173,9 @@ > ;; A list of ... > (define_code_iterator ior_xor [ior xor]) > > +;; A list of ... > +(define_code_iterator ior_and [ior and]) > + > ;; Operations on two halves of a quadword vector. > (define_code_iterator vqh_ops [plus smin smax umin umax]) > > diff --git a/gcc/testsuite/gcc.target/arm/cond-and.c > b/gcc/testsuite/gcc.target/arm/cond-and.c > new file mode 100644 > index 0000000..1320dcb > --- /dev/null > +++ b/gcc/testsuite/gcc.target/arm/cond-and.c > @@ -0,0 +1,27 @@ > +/* Simplify code generation for conditional and. */ > +/* { dg-options "-O2" } */ > +/* { dg-final { scan-assembler-not "andne" } } */ > + > +int f(char *t) { > + int s=0; > + > + while (*t && s != 1) > + { > + switch (s) > + { > + case 0: > + s = 2; > + break; > + case 2: > + s = 3; > + break; > + default: > + if (*t == '-') > + s = 2; > + break; > + } > + t++; > + } > + > + return s; > +} > > >
On 11/21/2011 05:31 PM, Jiangning Liu wrote: > My question is essentially is "May I really use REG_EXPR in back-end code?" > like the patch I gave below? I suppose. Another alternative is to use BImode for booleans. Dunno how much of that you'd be able to gleen from mere rtl expansion or if you'd need boolean decls to be expanded with BImode. The later would probably need a target hook. I've often wondered how much ia64 would benefit from that too, being able to store bool variables directly in predicate registers. All of this almost certainly must wait until stage1 opens up again though... r~
On Tue, Nov 22, 2011 at 2:55 AM, Richard Henderson <rth@redhat.com> wrote: > On 11/21/2011 05:31 PM, Jiangning Liu wrote: >> My question is essentially is "May I really use REG_EXPR in back-end code?" >> like the patch I gave below? > > I suppose. I'm not so sure ;) At least checking for BOOLEAN_TYPE is incomplete - you miss 1-bit precision types of the same signedness as bool. The middle-end doesn't distinguish between them anymore (semantically, that is)... > Another alternative is to use BImode for booleans. Dunno how much of that > you'd be able to gleen from mere rtl expansion or if you'd need boolean > decls to be expanded with BImode. ... which probably also means consistently getting BImode won't work? Richard. > The later would probably need a target hook. I've often wondered how much > ia64 would benefit from that too, being able to store bool variables directly > in predicate registers. > > All of this almost certainly must wait until stage1 opens up again though... > > > r~
> -----Original Message----- > From: Richard Henderson [mailto:rth@redhat.com] > Sent: Tuesday, November 22, 2011 9:55 AM > To: Jiangning Liu > Cc: gcc-patches@gcc.gnu.org; 'Richard Guenther' > Subject: Re: [RFC] Use REG_EXPR in back-end (introduced by optimization > to conditional and/or in ARM back-end) > > On 11/21/2011 05:31 PM, Jiangning Liu wrote: > > My question is essentially is "May I really use REG_EXPR in back-end > code?" > > like the patch I gave below? > > I suppose. > > Another alternative is to use BImode for booleans. Dunno how much of > that > you'd be able to gleen from mere rtl expansion or if you'd need boolean > decls to be expanded with BImode. Hi Richard, The output of expand pass requires the operands must meet the requirement of general_operand for binary operations, i.e. all RTX operations on top level must meet the hardware instruction requirement. Generally for a hardware not directly supporting a single bit logic operation, we can't generate BI mode rtx dest. So if I simply generate BImode for NE in expand pass, like "subreg:SI (ne:BI (reg:SI xxx) (const_int 0)))", there would be an assertion failure due to failing to find an appropriate instruction code to operate on a single bit. This looks like a GCC design level issue. How would you suggest generating a legitimate rtx expression containing BImode? Thanks, -Jiangning > > The later would probably need a target hook. I've often wondered how > much > ia64 would benefit from that too, being able to store bool variables > directly > in predicate registers. > > All of this almost certainly must wait until stage1 opens up again > though... > > > r~
> -----Original Message----- > From: gcc-patches-owner@gcc.gnu.org [mailto:gcc-patches- > owner@gcc.gnu.org] On Behalf Of Jiangning Liu > Sent: Wednesday, December 21, 2011 2:48 PM > To: 'Richard Henderson' > Cc: gcc-patches@gcc.gnu.org; 'Richard Guenther' > Subject: RE: [RFC] Use REG_EXPR in back-end (introduced by optimization > to conditional and/or in ARM back-end) > > > > -----Original Message----- > > From: Richard Henderson [mailto:rth@redhat.com] > > Sent: Tuesday, November 22, 2011 9:55 AM > > To: Jiangning Liu > > Cc: gcc-patches@gcc.gnu.org; 'Richard Guenther' > > Subject: Re: [RFC] Use REG_EXPR in back-end (introduced by > optimization > > to conditional and/or in ARM back-end) > > > > On 11/21/2011 05:31 PM, Jiangning Liu wrote: > > > My question is essentially is "May I really use REG_EXPR in back- > end > > code?" > > > like the patch I gave below? > > > > I suppose. > > > > Another alternative is to use BImode for booleans. Dunno how much of > > that > > you'd be able to gleen from mere rtl expansion or if you'd need > boolean > > decls to be expanded with BImode. > > Hi Richard, > > The output of expand pass requires the operands must meet the > requirement of > general_operand for binary operations, i.e. all RTX operations on top > level > must meet the hardware instruction requirement. Generally for a > hardware not > directly supporting a single bit logic operation, we can't generate BI > mode > rtx dest. > > So if I simply generate BImode for NE in expand pass, like "subreg:SI > (ne:BI > (reg:SI xxx) (const_int 0)))", there would be an assertion failure due > to > failing to find an appropriate instruction code to operate on a single > bit. > > This looks like a GCC design level issue. How would you suggest > generating a > legitimate rtx expression containing BImode? > Can anybody give me useful suggestions on this issue? My question essentially is may I really use BImode to solve my original problem? Thanks, -Jiangning > Thanks, > -Jiangning > > > > > The later would probably need a target hook. I've often wondered how > > much > > ia64 would benefit from that too, being able to store bool variables > > directly > > in predicate registers. > > > > All of this almost certainly must wait until stage1 opens up again > > though... > > > > > > r~ > > > >
diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h index 23a29c6..8b12d48 --- a/gcc/config/arm/arm-protos.h +++ b/gcc/config/arm/arm-protos.h @@ -114,6 +114,7 @@ extern rtx arm_gen_load_multiple (int *, int, rtx, int, rtx, HOST_WIDE_INT *); extern rtx arm_gen_store_multiple (int *, int, rtx, int, rtx, HOST_WIDE_INT *); extern int arm_gen_movmemqi (rtx *); extern enum machine_mode arm_select_cc_mode (RTX_CODE, rtx, rtx); +extern bool arm_check_logic_with_bool_reg (RTX_CODE, rtx, rtx); extern enum machine_mode arm_select_dominance_cc_mode (rtx, rtx, HOST_WIDE_INT); extern rtx arm_gen_compare_reg (RTX_CODE, rtx, rtx); diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index a429c19..e96f24a --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -10910,6 +10910,41 @@ arm_gen_movmemqi (rtx *operands) return 1; } +/* Check whether the expression "rc <cmp1> <bool_reg>" can be transformed + to use conditional comparison or not. */ +bool +arm_check_logic_with_bool_reg (RTX_CODE rc, rtx bool_reg, rtx cmp1) { + rtx cmp2; + HOST_WIDE_INT dom_cc; + + if (!REG_P (bool_reg)) + return false; + + if (REG_EXPR (bool_reg) == NULL) + return false; + + if (TREE_CODE (REG_EXPR (bool_reg)) != VAR_DECL) + return false; + + if (TREE_CODE (TREE_TYPE (REG_EXPR (bool_reg))) != BOOLEAN_TYPE) + return false; + + cmp2 = gen_rtx_NE (GET_MODE (bool_reg), bool_reg, const0_rtx); + + if (rc == AND) + dom_cc = DOM_CC_X_AND_Y; + else if (rc == IOR) + dom_cc = DOM_CC_X_OR_Y; + else + gcc_unreachable (); + + if (arm_select_dominance_cc_mode (cmp1, cmp2, dom_cc) == CCmode) + return false; + + return true; +} + + /* Select a dominance comparison mode if possible for a test of the general form (OP (COND_OR (X) (Y)) (const_int 0)). We support three forms. COND_OR == DOM_CC_X_AND_Y => (X && Y) diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index a78ba88..e90a78e --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -9172,6 +9172,64 @@ (set_attr "length" "4,4,8")] ) +; This pattern matches expression like example "((r1 != x) & r2) != 0". +; Here r2 is a register with data type boolean. +; This pattern can transform to code matching patterns cmp_and. +; Likewise, code matching pattern cmp_ior could be generated, if it is | +; rather than & in the example. +(define_insn_and_split "*cond_<code>" + [(set (match_operand 0 "cc_register" "") + (compare + (ior_and:SI + (match_operator:SI 4 "arm_comparison_operator" + [(match_operand:SI 2 "s_register_operand" "r,r") + (match_operand:SI 3 "arm_add_operand" "rI,L")]) + (match_operand:SI 1 "s_register_operand" "r,r")) + (const_int 0)))] + "TARGET_32BIT + && arm_check_logic_with_bool_reg (<CODE>, operands[1], operands[4])" + "#" + "&& 1" + [(set (match_dup 7) + (compare + (match_op_dup 5 + [(match_op_dup 4 [(match_dup 2) (match_dup 3)]) + (match_op_dup 6 [(match_dup 1) (const_int 0)])]) + (const_int 0)))] + " + { + HOST_WIDE_INT dom_cc; + + operands[6] = gen_rtx_NE (SImode, operands[1], const0_rtx); + + if (<CODE> == AND) + { + dom_cc = DOM_CC_X_AND_Y; + operands[5] = gen_rtx_fmt_ee (<CODE>, SImode, + operands[4], operands[6]); + } + else if (<CODE> == IOR) + { + dom_cc = DOM_CC_X_OR_Y; + operands[5] = gen_rtx_fmt_ee (<CODE>, SImode, + operands[4], operands[6]); + } + else + gcc_unreachable (); + + operands[7] + = gen_rtx_REG (arm_select_dominance_cc_mode (operands[4], + operands[6], + dom_cc), + CC_REGNUM); + }" + [(set_attr "conds" "clob") + (set (attr "length") + (if_then_else (eq_attr "is_thumb" "yes") + (const_int 10) + (const_int 8)))] +) + (define_insn "*cond_arith" [(set (match_operand:SI 0 "s_register_operand" "=r,r") (match_operator:SI 5 "shiftable_operator" diff --git a/gcc/config/arm/iterators.md b/gcc/config/arm/iterators.md index 85dd641..f0a7c7e --- a/gcc/config/arm/iterators.md +++ b/gcc/config/arm/iterators.md @@ -173,6 +173,9 @@ ;; A list of ... (define_code_iterator ior_xor [ior xor]) +;; A list of ... +(define_code_iterator ior_and [ior and]) + ;; Operations on two halves of a quadword vector. (define_code_iterator vqh_ops [plus smin smax umin umax]) diff --git a/gcc/testsuite/gcc.target/arm/cond-and.c b/gcc/testsuite/gcc.target/arm/cond-and.c new file mode 100644 index 0000000..1320dcb --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/cond-and.c @@ -0,0 +1,27 @@ +/* Simplify code generation for conditional and. */ +/* { dg-options "-O2" } */ +/* { dg-final { scan-assembler-not "andne" } } */ + +int f(char *t) { + int s=0; + + while (*t && s != 1) + { + switch (s) + { + case 0: + s = 2; + break; + case 2: + s = 3; + break; + default: + if (*t == '-') + s = 2; + break; + } + t++; + } + + return s; +}