aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOleg Endo <olegendo@gcc.gnu.org>2012-08-14 17:59:03 +0000
committerOleg Endo <olegendo@gcc.gnu.org>2012-08-14 17:59:03 +0000
commit669d4d702b35346b357bf77c194029eb96ba13b6 (patch)
tree629b7e509bd0dbb34c8e9c2ec44996dc9d68abba
parent24c18ad8f18bc0f02ce6c7d85e1f38f7d8760925 (diff)
downloadgcc-669d4d702b35346b357bf77c194029eb96ba13b6.zip
gcc-669d4d702b35346b357bf77c194029eb96ba13b6.tar.gz
gcc-669d4d702b35346b357bf77c194029eb96ba13b6.tar.bz2
re PR target/52933 (SH Target: Use div0s for integer sign comparisons)
PR target/52933 * config/sh/sh.md (cmp_div0s_0, cmp_div0s_1, *cmp_div0s_0, *cmp_div0s_1, *cbranch_div0s, *movsicc_div0s): New insns. * config/sh/sh.c (sh_rtx_costs): Handle div0s patterns. PR target/52933 * gcc.target/sh/pr52933-1.c: New. * gcc.target/sh/pr52933-2.c: New. From-SVN: r190396
-rw-r--r--gcc/ChangeLog7
-rw-r--r--gcc/config/sh/sh.c26
-rw-r--r--gcc/config/sh/sh.md121
-rw-r--r--gcc/testsuite/ChangeLog6
-rw-r--r--gcc/testsuite/gcc.target/sh/pr52933-1.c168
-rw-r--r--gcc/testsuite/gcc.target/sh/pr52933-2.c12
6 files changed, 339 insertions, 1 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 5b7457b..4f3aa1c 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,12 @@
2012-08-14 Oleg Endo <olegendo@gcc.gnu.org>
+ PR target/52933
+ * config/sh/sh.md (cmp_div0s_0, cmp_div0s_1, *cmp_div0s_0,
+ *cmp_div0s_1, *cbranch_div0s, *movsicc_div0s): New insns.
+ * config/sh/sh.c (sh_rtx_costs): Handle div0s patterns.
+
+2012-08-14 Oleg Endo <olegendo@gcc.gnu.org>
+
PR target/50751
* config/sh/constraints.md (Sra): New constraint.
* config/sh/predicates.md (simple_mem_operand,
diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c
index bac849b..263ea3a 100644
--- a/gcc/config/sh/sh.c
+++ b/gcc/config/sh/sh.c
@@ -3186,9 +3186,33 @@ sh_rtx_costs (rtx x, int code, int outer_code, int opno ATTRIBUTE_UNUSED,
*total = COSTS_N_INSNS (multcosts (x));
return true;
+ case LT:
+ case GE:
+ /* div0s sign comparison. */
+ if (GET_CODE (XEXP (x, 0)) == XOR
+ && REG_P ((XEXP (XEXP (x, 0), 0)))
+ && REG_P ((XEXP (XEXP (x, 0), 1)))
+ && satisfies_constraint_Z (XEXP (x, 1)))
+ {
+ *total = COSTS_N_INSNS (1);
+ return true;
+ }
+ else
+ return false;
+
+ case LSHIFTRT:
+ /* div0s sign comparison. */
+ if (GET_CODE (XEXP (x, 0)) == XOR
+ && REG_P ((XEXP (XEXP (x, 0), 0)))
+ && REG_P ((XEXP (XEXP (x, 0), 1)))
+ && CONST_INT_P (XEXP (x, 1)) && INTVAL (XEXP (x, 1)) == 31)
+ {
+ *total = COSTS_N_INSNS (1);
+ return true;
+ }
+ /* Fall through to shiftcosts. */
case ASHIFT:
case ASHIFTRT:
- case LSHIFTRT:
{
int cost = shiftcosts (x);
if (cost < 0)
diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md
index 3462dd1..5d6fc84 100644
--- a/gcc/config/sh/sh.md
+++ b/gcc/config/sh/sh.md
@@ -801,6 +801,70 @@
"cmp/pl %0"
[(set_attr "type" "mt_group")])
+;; Some integer sign comparison patterns can be realized with the div0s insn.
+;; div0s Rm,Rn T = (Rm >> 31) ^ (Rn >> 31)
+(define_insn "cmp_div0s_0"
+ [(set (reg:SI T_REG)
+ (lshiftrt:SI (xor:SI (match_operand:SI 0 "arith_reg_operand" "%r")
+ (match_operand:SI 1 "arith_reg_operand" "r"))
+ (const_int 31)))]
+ "TARGET_SH1"
+ "div0s %0,%1"
+ [(set_attr "type" "arith")])
+
+(define_insn "cmp_div0s_1"
+ [(set (reg:SI T_REG)
+ (lt:SI (xor:SI (match_operand:SI 0 "arith_reg_operand" "%r")
+ (match_operand:SI 1 "arith_reg_operand" "r"))
+ (const_int 0)))]
+ "TARGET_SH1"
+ "div0s %0,%1"
+ [(set_attr "type" "arith")])
+
+(define_insn_and_split "*cmp_div0s_0"
+ [(set (match_operand:SI 0 "arith_reg_dest" "")
+ (lshiftrt:SI (xor:SI (match_operand:SI 1 "arith_reg_operand" "")
+ (match_operand:SI 2 "arith_reg_operand" ""))
+ (const_int 31)))
+ (clobber (reg:SI T_REG))]
+ "TARGET_SH1"
+ "#"
+ "&& 1"
+ [(set (reg:SI T_REG)
+ (lshiftrt:SI (xor:SI (match_dup 1) (match_dup 2)) (const_int 31)))
+ (set (match_dup 0) (reg:SI T_REG))])
+
+(define_insn_and_split "*cmp_div0s_1"
+ [(set (match_operand:SI 0 "arith_reg_dest" "")
+ (ge:SI (xor:SI (match_operand:SI 1 "arith_reg_operand" "")
+ (match_operand:SI 2 "arith_reg_operand" ""))
+ (const_int 0)))
+ (clobber (reg:SI T_REG))]
+ "TARGET_SH1"
+ "#"
+ "&& can_create_pseudo_p ()"
+ [(const_int 0)]
+;; We have to go through the movnegt expander here which will handle the
+;; SH2A vs non-SH2A cases.
+{
+ emit_insn (gen_cmp_div0s_1 (operands[1], operands[2]));
+ emit_insn (gen_movnegt (operands[0], get_t_reg_rtx ()));
+ DONE;
+})
+
+(define_insn_and_split "*cmp_div0s_1"
+ [(set (reg:SI T_REG)
+ (ge:SI (xor:SI (match_operand:SI 0 "arith_reg_operand" "")
+ (match_operand:SI 1 "arith_reg_operand" ""))
+ (const_int 0)))]
+ "TARGET_SH1"
+ "#"
+ "&& can_create_pseudo_p ()"
+ [(set (reg:SI T_REG) (lt:SI (xor:SI (match_dup 0) (match_dup 1))
+ (const_int 0)))
+ (set (reg:SI T_REG) (xor:SI (reg:SI T_REG) (const_int 1)))])
+
+
;; -------------------------------------------------------------------------
;; SImode compare and branch
;; -------------------------------------------------------------------------
@@ -918,6 +982,63 @@
(label_ref (match_dup 2))
(pc)))])
+;; Compare and branch combine patterns for div0s comparisons.
+(define_insn_and_split "*cbranch_div0s"
+ [(set (pc)
+ (if_then_else (lt (xor:SI (match_operand:SI 0 "arith_reg_operand" "")
+ (match_operand:SI 1 "arith_reg_operand" ""))
+ (const_int 0))
+ (label_ref (match_operand 2))
+ (pc)))
+ (clobber (reg:SI T_REG))]
+ "TARGET_SH1"
+ "#"
+ "&& 1"
+ [(set (reg:SI T_REG)
+ (lt:SI (xor:SI (match_dup 0) (match_dup 1)) (const_int 0)))
+ (set (pc)
+ (if_then_else (ne (reg:SI T_REG) (const_int 0))
+ (label_ref (match_dup 2))
+ (pc)))])
+
+(define_insn_and_split "*cbranch_div0s"
+ [(set (pc)
+ (if_then_else (ge (xor:SI (match_operand:SI 0 "arith_reg_operand" "")
+ (match_operand:SI 1 "arith_reg_operand" ""))
+ (const_int 0))
+ (label_ref (match_operand 2))
+ (pc)))
+ (clobber (reg:SI T_REG))]
+ "TARGET_SH1"
+ "#"
+ "&& 1"
+ [(set (reg:SI T_REG)
+ (lt:SI (xor:SI (match_dup 0) (match_dup 1)) (const_int 0)))
+ (set (pc)
+ (if_then_else (eq (reg:SI T_REG) (const_int 0))
+ (label_ref (match_dup 2))
+ (pc)))])
+
+;; Conditional move combine pattern for div0s comparisons.
+;; This is used when TARGET_PRETEND_CMOVE is in effect.
+(define_insn_and_split "*movsicc_div0s"
+ [(set (match_operand:SI 0 "arith_reg_dest" "")
+ (if_then_else:SI (ge (xor:SI (match_operand:SI 1 "arith_reg_operand" "")
+ (match_operand:SI 2 "arith_reg_operand" ""))
+ (const_int 0))
+ (match_operand:SI 3 "arith_reg_operand" "")
+ (match_operand:SI 4 "general_movsrc_operand" "")))
+ (clobber (reg:SI T_REG))]
+ "TARGET_PRETEND_CMOVE"
+ "#"
+ "&& 1"
+ [(set (reg:SI T_REG) (lt:SI (xor:SI (match_dup 1) (match_dup 2))
+ (const_int 0)))
+ (set (match_dup 0)
+ (if_then_else (ne (reg:SI T_REG) (const_int 0))
+ (match_dup 4)
+ (match_dup 3)))])
+
;; -------------------------------------------------------------------------
;; SImode unsigned integer comparisons
;; -------------------------------------------------------------------------
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index c1325cd..d00816e 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,5 +1,11 @@
2012-08-14 Oleg Endo <olegendo@gcc.gnu.org>
+ PR target/52933
+ * gcc.target/sh/pr52933-1.c: New.
+ * gcc.target/sh/pr52933-2.c: New.
+
+2012-08-14 Oleg Endo <olegendo@gcc.gnu.org>
+
PR target/50751
* gcc.target/sh/pr50751-8.c: New.
diff --git a/gcc/testsuite/gcc.target/sh/pr52933-1.c b/gcc/testsuite/gcc.target/sh/pr52933-1.c
new file mode 100644
index 0000000..037f916
--- /dev/null
+++ b/gcc/testsuite/gcc.target/sh/pr52933-1.c
@@ -0,0 +1,168 @@
+/* Check that the div0s instruction is used for integer sign comparisons.
+ Each test case is expected to emit at least one div0s insn.
+ Problems when combining the div0s comparison result with surrounding
+ logic usually show up as redundant tst insns. */
+/* { dg-do compile { target "sh*-*-*" } } */
+/* { dg-options "-O2" } */
+/* { dg-skip-if "" { "sh*-*-*" } { "-m5*" } { "" } } */
+/* { dg-final { scan-assembler-times "div0s" 25 } } */
+/* { dg-final { scan-assembler-not "tst" } } */
+
+typedef unsigned char bool;
+
+int other_func_a (int, int);
+int other_func_b (int, int);
+
+bool
+test_00 (int a, int b)
+{
+ return (a ^ b) >= 0;
+}
+
+bool
+test_01 (int a, int b)
+{
+ return (a ^ b) < 0;
+}
+
+int
+test_02 (int a, int b, int c, int d)
+{
+ if ((a ^ b) < 0)
+ return other_func_a (a, c);
+ else
+ return other_func_b (d, b);
+}
+
+int
+test_03 (int a, int b, int c, int d)
+{
+ if ((a ^ b) >= 0)
+ return other_func_a (a, c);
+ else
+ return other_func_b (d, b);
+}
+
+int
+test_04 (int a, int b)
+{
+ return (a ^ b) >= 0 ? -20 : -40;
+}
+
+bool
+test_05 (int a, int b)
+{
+ return (a ^ b) < 0;
+}
+
+int
+test_06 (int a, int b)
+{
+ return (a ^ b) < 0 ? -20 : -40;
+}
+
+bool
+test_07 (int a, int b)
+{
+ return (a < 0) == (b < 0);
+}
+
+int
+test_08 (int a, int b)
+{
+ return (a < 0) == (b < 0) ? -20 : -40;
+}
+
+bool
+test_09 (int a, int b)
+{
+ return (a < 0) != (b < 0);
+}
+
+int
+test_10 (int a, int b)
+{
+ return (a < 0) != (b < 0) ? -20 : -40;
+}
+
+bool
+test_11 (int a, int b)
+{
+ return (a >= 0) ^ (b < 0);
+}
+
+int
+test_12 (int a, int b)
+{
+ return (a >= 0) ^ (b < 0) ? -20 : -40;
+}
+
+bool
+test_13 (int a, int b)
+{
+ return !((a >= 0) ^ (b < 0));
+}
+
+int
+test_14 (int a, int b)
+{
+ return !((a >= 0) ^ (b < 0)) ? -20 : -40;
+}
+
+bool
+test_15 (int a, int b)
+{
+ return (a & 0x80000000) == (b & 0x80000000);
+}
+
+int
+test_16 (int a, int b)
+{
+ return (a & 0x80000000) == (b & 0x80000000) ? -20 : -40;
+}
+
+bool
+test_17 (int a, int b)
+{
+ return (a & 0x80000000) != (b & 0x80000000);
+}
+
+int
+test_18 (int a, int b)
+{
+ return (a & 0x80000000) != (b & 0x80000000) ? -20 : -40;
+}
+
+int
+test_19 (unsigned int a, unsigned int b)
+{
+ return (a ^ b) >> 31;
+}
+
+int
+test_20 (unsigned int a, unsigned int b)
+{
+ return (a >> 31) ^ (b >> 31);
+}
+
+int
+test_21 (int a, int b)
+{
+ return ((a & 0x80000000) ^ (b & 0x80000000)) >> 31 ? -30 : -10;
+}
+
+int
+test_22 (int a, int b, int c, int d)
+{
+ if ((a < 0) == (b < 0))
+ return other_func_a (a, b);
+ else
+ return other_func_b (c, d);
+}
+
+bool
+test_23 (int a, int b, int c, int d)
+{
+ /* Should emit 2x div0s. */
+ return ((a < 0) == (b < 0)) | ((c < 0) == (d < 0));
+}
diff --git a/gcc/testsuite/gcc.target/sh/pr52933-2.c b/gcc/testsuite/gcc.target/sh/pr52933-2.c
new file mode 100644
index 0000000..b0e650b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/sh/pr52933-2.c
@@ -0,0 +1,12 @@
+/* Check that the div0s instruction is used for integer sign comparisons
+ when -mpretend-cmove is enabled.
+ Each test case is expected to emit at least one div0s insn.
+ Problems when combining the div0s comparison result with surrounding
+ logic usually show up as redundant tst insns. */
+/* { dg-do compile { target "sh*-*-*" } } */
+/* { dg-options "-O2 -mpretend-cmove" } */
+/* { dg-skip-if "" { "sh*-*-*" } { "-m5*" } { "" } } */
+/* { dg-final { scan-assembler-times "div0s" 25 } } */
+/* { dg-final { scan-assembler-not "tst" } } */
+
+#include "pr52933-1.c"