re PR target/52933 (SH Target: Use div0s for integer sign comparisons)
authorOleg Endo <olegendo@gcc.gnu.org>
Fri, 6 May 2016 09:52:35 +0000 (09:52 +0000)
committerOleg Endo <olegendo@gcc.gnu.org>
Fri, 6 May 2016 09:52:35 +0000 (09:52 +0000)
gcc/
PR target/52933
* config/sh/sh.md (*cmp_div0s_7, *cmp_div0s_8): Add div0s variants.
* config/sh/sh.c (sh_rtx_costs): Add another div0s case.

gcc/testsuite/
PR target/52933
* gcc.target/sh/pr52933-1.c (test_31, test_32, test_33, test_34,
test_35, test_36, test_37, test_38, test_39, test_40): New sub-tests.
Adjust expected instruction counts.
* gcc.target/sh/pr52933-2.c: Adjust expected instruction counts.

From-SVN: r235952

gcc/ChangeLog
gcc/config/sh/sh.c
gcc/config/sh/sh.md
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/sh/pr52933-1.c
gcc/testsuite/gcc.target/sh/pr52933-2.c

index 1c6c42ca52389eb7129bfb814cf88a11493a8a55..b575931ddb6914d6ceedb7b9045082edae6690c1 100644 (file)
@@ -1,3 +1,9 @@
+2016-05-06  Oleg Endo  <olegendo@gcc.gnu.org>
+
+       PR target/52933
+       * config/sh/sh.md (*cmp_div0s_7, *cmp_div0s_8): Add div0s variants.
+       * config/sh/sh.c (sh_rtx_costs): Add another div0s case.
+
 2016-05-06  Marek Polacek  <polacek@redhat.com>
 
        PR sanitizer/70875
index ebdb523cd17ab10598a91ada192e3ddab6df1117..809f679f807162b23f2d6d1482bc4599d5c3ab56 100644 (file)
@@ -3209,6 +3209,15 @@ sh_rtx_costs (rtx x, machine_mode mode ATTRIBUTE_UNUSED, int outer_code,
          *total = 1; //COSTS_N_INSNS (1);
          return true;
        }
+
+      /* div0s variant.  */
+      if (GET_CODE (XEXP (x, 0)) == XOR
+         && GET_CODE (XEXP (XEXP (x, 0), 0)) == XOR
+         && CONST_INT_P (XEXP (XEXP (x, 0), 1)))
+       {
+         *total = 1;
+         return true;
+       }
       return false;
 
     /* The cost of a sign or zero extend depends on whether the source is a
index 0ab76b562b944269f632dd101fd39456964aab09..e704e2ac3fdc3250d0079d8baa4ae14cd94c4d57 100644 (file)
        (lshiftrt:SI (xor:SI (match_dup 0) (match_dup 1)) (const_int 31)))
    (set (reg:SI T_REG) (xor:SI (reg:SI T_REG) (const_int 1)))])
 
+;; In some cases, it might be shorter to get a tested bit into bit 31 and
+;; use div0s.  Otherwise it's usually better to just leave the xor and tst
+;; sequence.  The only thing we can try to do here is avoiding the large
+;; tst constant.
+(define_insn_and_split "*cmp_div0s_7"
+  [(set (reg:SI T_REG)
+       (zero_extract:SI (xor:SI (match_operand:SI 0 "arith_reg_operand")
+                                (match_operand:SI 1 "arith_reg_operand"))
+                        (const_int 1)
+                        (match_operand 2 "const_int_operand")))]
+  "TARGET_SH1 && can_create_pseudo_p ()
+   && (INTVAL (operands[2]) == 7 || INTVAL (operands[2]) == 15
+       || INTVAL (operands[2]) == 23 || INTVAL (operands[2]) == 29
+       || INTVAL (operands[2]) == 30 || INTVAL (operands[2]) == 31)"
+  "#"
+  "&& 1"
+  [(const_int 0)]
+{
+  const int bitpos = INTVAL (operands[2]);
+
+  rtx op0 = gen_reg_rtx (SImode);
+  rtx op1 = gen_reg_rtx (SImode);
+
+  if (bitpos == 23 || bitpos == 30 || bitpos == 29)
+    {
+      emit_insn (gen_ashlsi3 (op0, operands[0], GEN_INT (31 - bitpos)));
+      emit_insn (gen_ashlsi3 (op1, operands[1], GEN_INT (31 - bitpos)));
+    }
+  else if (bitpos == 15)
+    {
+      emit_insn (gen_extendhisi2 (op0, gen_lowpart (HImode, operands[0])));
+      emit_insn (gen_extendhisi2 (op1, gen_lowpart (HImode, operands[1])));
+    }
+  else if (bitpos == 7)
+    {
+      emit_insn (gen_extendqisi2 (op0, gen_lowpart (QImode, operands[0])));
+      emit_insn (gen_extendqisi2 (op1, gen_lowpart (QImode, operands[1])));
+    }
+  else if (bitpos == 31)
+    {
+      op0 = operands[0];
+      op1 = operands[1];
+    }
+  else
+    gcc_unreachable ();
+
+  emit_insn (gen_cmp_div0s (op0, op1));
+  DONE;
+})
+
+;; For bits 0..7 using a xor and tst #imm,r0 sequence seems to be better.
+;; Thus allow the following patterns only for higher bit positions where
+;; we it's more likely to save the large tst constant.
+(define_insn_and_split "*cmp_div0s_8"
+  [(set (reg:SI T_REG)
+       (eq:SI (zero_extract:SI (match_operand:SI 0 "arith_reg_operand")
+                               (const_int 1)
+                               (match_operand 2 "const_int_operand"))
+              (zero_extract:SI (match_operand:SI 1 "arith_reg_operand")
+                               (const_int 1)
+                               (match_dup 2))))]
+  "TARGET_SH1 && can_create_pseudo_p ()
+   && (INTVAL (operands[2]) == 15
+       || INTVAL (operands[2]) == 23 || INTVAL (operands[2]) == 29
+       || INTVAL (operands[2]) == 30 || INTVAL (operands[2]) == 31)"
+  "#"
+  "&& 1"
+  [(set (reg:SI T_REG)
+       (zero_extract:SI (xor:SI (match_dup 0) (match_dup 1))
+                        (const_int 1) (match_dup 2)))
+   (set (reg:SI T_REG) (xor:SI (reg:SI T_REG) (const_int 1)))])
+
+(define_insn_and_split "*cmp_div0s_9"
+  [(set (reg:SI T_REG)
+       (zero_extract:SI (xor:SI (xor:SI (match_operand:SI 0 "arith_reg_operand")
+                                        (match_operand:SI 1 "arith_reg_operand"))
+                                (match_operand 2 "const_int_operand"))
+                        (const_int 1)
+                        (match_operand 3 "const_int_operand")))]
+  "TARGET_SH1 && can_create_pseudo_p ()
+   && (INTVAL (operands[2]) & 0xFFFFFFFF) == (1U << INTVAL (operands[3]))
+   && (INTVAL (operands[3]) == 15
+       || INTVAL (operands[3]) == 23 || INTVAL (operands[3]) == 29
+       || INTVAL (operands[3]) == 30 || INTVAL (operands[3]) == 31)"
+  "#"
+  "&& 1"
+  [(set (reg:SI T_REG)
+       (zero_extract:SI (xor:SI (match_dup 0) (match_dup 1))
+                        (const_int 1) (match_dup 3)))
+   (set (reg:SI T_REG) (xor:SI (reg:SI T_REG) (const_int 1)))])
+
 ;; -------------------------------------------------------------------------
 ;; SImode compare and branch
 ;; -------------------------------------------------------------------------
index aaf3e00c017badd6c6ff088b0c077bb46078e508..762c2a8036748502d409a6e3119b3e7ecb3d0044 100644 (file)
@@ -1,3 +1,11 @@
+2016-05-06  Oleg Endo  <olegendo@gcc.gnu.org>
+
+       PR target/52933
+       * gcc.target/sh/pr52933-1.c (test_31, test_32, test_33, test_34,
+       test_35, test_36, test_37, test_38, test_39, test_40): New sub-tests.
+       Adjust expected instruction counts.
+       * gcc.target/sh/pr52933-2.c: Adjust expected instruction counts.
+
 2016-05-06  Marek Polacek  <polacek@redhat.com>
 
        PR sanitizer/70875
index 138de7f4914bfbf37fb53d9e34188bf26418a936..81aa94fc8f0de4ee42ca0fca06a1f62d0f137e3c 100644 (file)
@@ -4,13 +4,13 @@
    logic usually show up as redundant tst insns.  */
 /* { dg-do compile }  */
 /* { dg-options "-O2" } */
-/* { dg-final { scan-assembler-times "div0s" 32 } } */
+/* { dg-final { scan-assembler-times "div0s" 42 } } */
 /* { dg-final { scan-assembler-not "tst" } } */
 /* { dg-final { scan-assembler-not "not\t" } }  */
 /* { dg-final { scan-assembler-not "nott" } }  */
 
-/* { dg-final { scan-assembler-times "negc" 9 { target { ! sh2a } } } }  */
-/* { dg-final { scan-assembler-times "movrt" 9 { target { sh2a } } } }  */
+/* { dg-final { scan-assembler-times "negc" 10 { target { ! sh2a } } } }  */
+/* { dg-final { scan-assembler-times "movrt" 10 { target { sh2a } } } }  */
 
 typedef unsigned char bool;
 
@@ -212,3 +212,75 @@ test_30 (int a, int b)
 {
   return ((a >> 31) ^ (b >> 31)) & 1;
 }
+
+// -------------------------------------------------------
+
+bool
+test_31 (int a, int b)
+{
+  /* 2x exts.w, div0s  */
+  return ((a & 0x8000) ^ (b & 0x8000)) != 0;
+}
+
+bool
+test_32 (int a, int b)
+{
+  /* 2x exts.w, div0s  */
+  return (a & 0x8000) != (b & 0x8000);
+}
+
+bool
+test_33 (int a, int b)
+{
+  /* 2x add/shll, div0s  */
+  return ((a & (1<<30)) ^ (b & (1<<30))) != 0;
+}
+
+bool
+test_34 (int a, int b)
+{
+  /* 2x exts.b, div0s  */
+  return (a & 0x80) != (b & 0x80);
+}
+
+bool
+test_35 (signed char a, signed char b)
+{
+  /* 2x exts.b, div0s  */
+  return (a < 0) != (b < 0);
+}
+
+bool
+test_36 (short a, short b)
+{
+  /* 2x exts.w, div0s  */
+  return (a < 0) != (b < 0);
+}
+
+int
+test_37 (short a, short b)
+{
+  /* 2x exts.w, div0s  */
+  return (a < 0) != (b < 0) ? 40 : -10;
+}
+
+bool
+test_38 (int a, int b)
+{
+  /* 2x shll8, div0s  */
+  return ((a & (1<<23)) ^ (b & (1<<23))) != 0;
+}
+
+bool
+test_39 (int a, int b)
+{
+  /* 2x shll2, div0s  */
+  return ((a & (1<<29)) ^ (b & (1<<29))) != 0;
+}
+
+bool
+test_40 (short a, short b)
+{
+  /* 2x exts.w, div0s, negc  */
+  return (a < 0) == (b < 0);
+}
index 4637f0ea17eed69dc77a17b8e7daf71133e62bd5..2b5d09ad0bb74ad27197f8374edc975a84e3084c 100644 (file)
@@ -5,12 +5,12 @@
    logic usually show up as redundant tst insns.  */
 /* { dg-do compile }  */
 /* { dg-options "-O2 -mpretend-cmove" } */
-/* { dg-final { scan-assembler-times "div0s" 32 } } */
+/* { dg-final { scan-assembler-times "div0s" 42 } } */
 /* { dg-final { scan-assembler-not "tst" } } */
 /* { dg-final { scan-assembler-not "not\t" } }  */
 /* { dg-final { scan-assembler-not "nott" } }  */
 
-/* { dg-final { scan-assembler-times "negc" 9 { target { ! sh2a } } } }  */
-/* { dg-final { scan-assembler-times "movrt" 9 { target { sh2a } } } }  */
+/* { dg-final { scan-assembler-times "negc" 10 { target { ! sh2a } } } }  */
+/* { dg-final { scan-assembler-times "movrt" 10 { target { sh2a } } } }  */
 
 #include "pr52933-1.c"