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_".
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 " 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_"
+ [(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 (, 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 ( == AND)
+ {
+dom_cc = DOM_CC_X_AND_Y;
+operands[5] = gen_rtx_fmt_ee (, SImode,
+ operands[4], operands[6]);
+ }
+else if ( == IOR)
+ {
+dom_cc = DOM_CC_X_OR_Y;
+operands[5] = gen_rtx_fmt_ee (, 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