re PR target/52933 (SH Target: Use div0s for integer sign comparisons)
authorOleg Endo <olegendo@gcc.gnu.org>
Tue, 14 Aug 2012 17:59:03 +0000 (17:59 +0000)
committerOleg Endo <olegendo@gcc.gnu.org>
Tue, 14 Aug 2012 17:59:03 +0000 (17:59 +0000)
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

gcc/ChangeLog
gcc/config/sh/sh.c
gcc/config/sh/sh.md
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/sh/pr52933-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/sh/pr52933-2.c [new file with mode: 0644]

index 5b7457b..4f3aa1c 100644 (file)
@@ -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,
index bac849b..263ea3a 100644 (file)
@@ -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)
index 3462dd1..5d6fc84 100644 (file)
   "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
 ;; -------------------------------------------------------------------------
                           (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
 ;; -------------------------------------------------------------------------
index c1325cd..d00816e 100644 (file)
@@ -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 (file)
index 0000000..037f916
--- /dev/null
@@ -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 (file)
index 0000000..b0e650b
--- /dev/null
@@ -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"