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; +}