This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[RFC] Optimization to conditional and/or in ARM back-end
- From: "Jiangning Liu" <jiangning dot liu at arm dot com>
- To: <gcc-patches at gcc dot gnu dot org>
- Cc: "'Richard Guenther'" <richard dot guenther at gmail dot com>, "Richard Henderson" <rth at redhat dot com>
- Date: Mon, 21 Nov 2011 10:17:50 +0800
- 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;
+}